-
Notifications
You must be signed in to change notification settings - Fork 747
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: cache account id selection (#1395)
This adds caching for account id fetch/selection for all wrangler commands. Currently, if we have an api/oauth token, but haven't provided an account id, we fetch account information from cloudflare. If a user has just one account id, we automatically choose that. If there are more than one, then we show a dropdown and ask the user to pick one. This is convenient, and lets the user not have to specify their account id when starting a project. However, if does make startup slow, since it has to do that fetch every time. It's also annoying for folks with multiple account ids because they have to pick their account id every time. So we now cache the account details into `node_modules/.cache/wrangler` (much like pages already does with account id and project name). This patch also refactors `config-cache.ts`; it only caches if there's a `node_modules` folder, and it looks for the closest node_modules folder (and not directly in cwd). I also added tests for when a `node_modules` folder isn't available. It also trims the message that we log to terminal. Closes #300
- Loading branch information
1 parent
4112001
commit 88f2702
Showing
9 changed files
with
218 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
"wrangler": patch | ||
--- | ||
|
||
feat: cache account id selection | ||
|
||
This adds caching for account id fetch/selection for all wrangler commands. | ||
|
||
Currently, if we have an api/oauth token, but haven't provided an account id, we fetch account information from cloudflare. If a user has just one account id, we automatically choose that. If there are more than one, then we show a dropdown and ask the user to pick one. This is convenient, and lets the user not have to specify their account id when starting a project. | ||
|
||
However, if does make startup slow, since it has to do that fetch every time. It's also annoying for folks with multiple account ids because they have to pick their account id every time. | ||
|
||
So we now cache the account details into `node_modules/.cache/wrangler` (much like pages already does with account id and project name). | ||
|
||
This patch also refactors `config-cache.ts`; it only caches if there's a `node_modules` folder, and it looks for the closest node_modules folder (and not directly in cwd). I also added tests for when a `node_modules` folder isn't available. It also trims the message that we log to terminal. | ||
|
||
Closes https://github.com/cloudflare/wrangler2/issues/300 |
38 changes: 38 additions & 0 deletions
38
packages/wrangler/src/__tests__/config-cache-without-cache-dir.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { getConfigCache, saveToConfigCache } from "../config-cache"; | ||
import { mockConsoleMethods } from "./helpers/mock-console"; | ||
import { runInTempDir } from "./helpers/run-in-tmp"; | ||
|
||
interface PagesConfigCache { | ||
account_id: string; | ||
pages_project_name: string; | ||
} | ||
|
||
describe("config cache", () => { | ||
runInTempDir(); | ||
mockConsoleMethods(); | ||
// In this set of tests, we don't create a node_modules folder | ||
const pagesConfigCacheFilename = "pages-config-cache.json"; | ||
|
||
it("should return an empty config if no file exists", () => { | ||
expect( | ||
getConfigCache<PagesConfigCache>(pagesConfigCacheFilename) | ||
).toMatchInlineSnapshot(`Object {}`); | ||
}); | ||
|
||
it("should ignore attempts to cache values ", () => { | ||
saveToConfigCache<PagesConfigCache>(pagesConfigCacheFilename, { | ||
account_id: "some-account-id", | ||
pages_project_name: "foo", | ||
}); | ||
expect(getConfigCache<PagesConfigCache>(pagesConfigCacheFilename)).toEqual( | ||
{} | ||
); | ||
|
||
saveToConfigCache<PagesConfigCache>(pagesConfigCacheFilename, { | ||
pages_project_name: "bar", | ||
}); | ||
expect(getConfigCache<PagesConfigCache>(pagesConfigCacheFilename)).toEqual( | ||
{} | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,83 @@ | ||
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs"; | ||
import { dirname, join } from "path"; | ||
import * as path from "path"; | ||
import { findUpSync } from "find-up"; | ||
import isInteractive from "./is-interactive"; | ||
import { logger } from "./logger"; | ||
|
||
let cacheMessageShown = false; | ||
|
||
const cacheFolder = "node_modules/.cache/wrangler"; | ||
let __cacheFolder: string | null; | ||
function getCacheFolder() { | ||
if (__cacheFolder || __cacheFolder === null) return __cacheFolder; | ||
|
||
const showCacheMessage = () => { | ||
if (!cacheMessageShown) { | ||
console.log( | ||
`Using cached values in '${cacheFolder}'. This is used as a temporary store to improve the developer experience for some commands. It may be purged at any time. It doesn't contain any sensitive information, but it should not be commited into source control.` | ||
); | ||
cacheMessageShown = true; | ||
const closestNodeModulesDirectory = findUpSync("node_modules", { | ||
type: "directory", | ||
}); | ||
__cacheFolder = closestNodeModulesDirectory | ||
? path.join(closestNodeModulesDirectory, ".cache/wrangler") | ||
: null; | ||
|
||
if (!__cacheFolder) { | ||
logger.debug("No folder available to cache configuration"); | ||
} | ||
return __cacheFolder; | ||
} | ||
|
||
const arrayFormatter = new Intl.ListFormat("en", { | ||
style: "long", | ||
type: "conjunction", | ||
}); | ||
|
||
function showCacheMessage(fields: string[], folder: string) { | ||
if (!cacheMessageShown && isInteractive()) { | ||
if (fields.length > 0) { | ||
logger.log( | ||
`Retrieving cached values for ${arrayFormatter.format( | ||
fields | ||
)} from ${path.relative(process.cwd(), folder)}` | ||
); | ||
cacheMessageShown = true; | ||
} | ||
} | ||
}; | ||
} | ||
|
||
export const getConfigCache = <T>(fileName: string): Partial<T> => { | ||
export function getConfigCache<T>(fileName: string): Partial<T> { | ||
try { | ||
const configCacheLocation = join(cacheFolder, fileName); | ||
const configCache = JSON.parse(readFileSync(configCacheLocation, "utf-8")); | ||
showCacheMessage(); | ||
return configCache; | ||
} catch { | ||
const cacheFolder = getCacheFolder(); | ||
if (cacheFolder) { | ||
const configCacheLocation = path.join(cacheFolder, fileName); | ||
const configCache = JSON.parse( | ||
readFileSync(configCacheLocation, "utf-8") | ||
); | ||
showCacheMessage(Object.keys(configCache), cacheFolder); | ||
return configCache; | ||
} else return {}; | ||
} catch (err) { | ||
return {}; | ||
} | ||
}; | ||
} | ||
|
||
export const saveToConfigCache = <T>( | ||
export function saveToConfigCache<T>( | ||
fileName: string, | ||
newValues: Partial<T> | ||
) => { | ||
const configCacheLocation = join(cacheFolder, fileName); | ||
const existingValues = getConfigCache(fileName); | ||
|
||
mkdirSync(dirname(configCacheLocation), { recursive: true }); | ||
writeFileSync( | ||
configCacheLocation, | ||
JSON.stringify({ ...existingValues, ...newValues }, null, 2) | ||
); | ||
}; | ||
|
||
export const purgeConfigCaches = () => { | ||
rmSync(cacheFolder, { recursive: true, force: true }); | ||
}; | ||
): void { | ||
const cacheFolder = getCacheFolder(); | ||
if (cacheFolder) { | ||
logger.debug(`Saving to cache: ${JSON.stringify(newValues)}`); | ||
const configCacheLocation = path.join(cacheFolder, fileName); | ||
const existingValues = getConfigCache(fileName); | ||
|
||
mkdirSync(path.dirname(configCacheLocation), { recursive: true }); | ||
writeFileSync( | ||
configCacheLocation, | ||
JSON.stringify({ ...existingValues, ...newValues }, null, 2) | ||
); | ||
} | ||
} | ||
|
||
export function purgeConfigCaches() { | ||
const cacheFolder = getCacheFolder(); | ||
if (cacheFolder) { | ||
rmSync(cacheFolder, { recursive: true, force: true }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* Test whether the process is "interactive". | ||
* Reasons it may not be interactive: it could be running in CI, | ||
* or you're piping values from / to another process, etc | ||
*/ | ||
export default function isInteractive(): boolean { | ||
try { | ||
return Boolean(process.stdin.isTTY && process.stdout.isTTY); | ||
} catch { | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters