diff --git a/.changeset/hungry-carrots-run.md b/.changeset/hungry-carrots-run.md new file mode 100644 index 000000000000..e4bb305b25fe --- /dev/null +++ b/.changeset/hungry-carrots-run.md @@ -0,0 +1,7 @@ +--- +"wrangler": patch +--- + +feat: Added the update check that will check the package once a day against the beta release, `distTag` can be changed later, then prints the latestbeta version to the user. + +resolves #762 diff --git a/package-lock.json b/package-lock.json index e55c3fcff94a..258e8da49c3b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5145,6 +5145,15 @@ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "license": "MIT" @@ -7901,6 +7910,12 @@ "version": "2.0.4", "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/ink": { "version": "3.2.0", "dev": true, @@ -14396,6 +14411,30 @@ "node": ">= 0.6" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "17.0.2", "license": "MIT", @@ -14699,6 +14738,28 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/remark-frontmatter": { "version": "4.0.1", "dev": true, @@ -16871,6 +16932,16 @@ "node": ">=0.10.0" } }, + "node_modules/update-check": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", + "dev": true, + "dependencies": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -17449,7 +17520,7 @@ "extraneous": true }, "packages/wrangler": { - "version": "0.0.24", + "version": "0.0.22", "license": "MIT OR Apache-2.0", "dependencies": { "esbuild": "0.14.23", @@ -17507,6 +17578,7 @@ "supports-color": "^9.2.1", "tmp-promise": "^3.0.3", "undici": "^4.15.1", + "update-check": "^1.5.4", "ws": "^8.3.0", "yargs": "^17.3.0" }, @@ -21101,6 +21173,12 @@ "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { "version": "0.1.4" }, @@ -22825,6 +22903,12 @@ "inherits": { "version": "2.0.4" }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "ink": { "version": "3.2.0", "dev": true, @@ -27151,6 +27235,26 @@ "version": "1.2.1", "dev": true }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, "react": { "version": "17.0.2", "requires": { @@ -27341,6 +27445,25 @@ "regexpp": { "version": "3.2.0" }, + "registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, "remark-frontmatter": { "version": "4.0.1", "dev": true, @@ -28842,6 +28965,16 @@ } } }, + "update-check": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", + "dev": true, + "requires": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -29086,6 +29219,7 @@ "supports-color": "^9.2.1", "tmp-promise": "^3.0.3", "undici": "^4.15.1", + "update-check": "^1.5.4", "ws": "^8.3.0", "xxhash-wasm": "^1.0.1", "yargs": "^17.3.0" diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index c6a3426e9a4a..85b12b8adea0 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -90,6 +90,7 @@ "supports-color": "^9.2.1", "tmp-promise": "^3.0.3", "undici": "^4.15.1", + "update-check": "^1.5.4", "ws": "^8.3.0", "yargs": "^17.3.0" }, diff --git a/packages/wrangler/src/index.tsx b/packages/wrangler/src/index.tsx index a5d61bfdc60a..9fc228cc363e 100644 --- a/packages/wrangler/src/index.tsx +++ b/packages/wrangler/src/index.tsx @@ -58,6 +58,7 @@ import type { TailCLIFilters } from "./tail"; import type { RawData } from "ws"; import type { CommandModule } from "yargs"; import type Yargs from "yargs"; +import { updateCheck } from "./update-check"; type ConfigPath = string | undefined; @@ -83,12 +84,13 @@ ${TOML.stringify({ rules: config.build.upload.rules })}` return rules; } -function printWranglerBanner() { +async function printWranglerBanner() { // Let's not print this in tests if (typeof jest !== "undefined") { return; } - const text = ` ⛅️ wrangler ${wranglerVersion} `; + + const text = ` ⛅️ wrangler ${wranglerVersion} ${await updateCheck()}`; console.log( text + @@ -286,7 +288,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); if (args.type) { let message = "The --type option is no longer supported."; if (args.type === "webpack") { @@ -723,7 +725,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); const configPath = (args.config as ConfigPath) || (args.script && findWranglerToml(path.dirname(args.script))); @@ -989,7 +991,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); if (args["experimental-public"]) { console.warn( "🚨 The --experimental-public field is experimental and will change in the future." @@ -1105,7 +1107,7 @@ export async function main(argv: string[]): Promise { }, async (args) => { if (args.format === "pretty") { - printWranglerBanner(); + await printWranglerBanner(); } const config = readConfig(args.config as ConfigPath, args); @@ -1408,7 +1410,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); const scriptName = getLegacyScriptName(args, config); @@ -1508,8 +1510,8 @@ export async function main(argv: string[]): Promise { .command( "delete ", "Delete a secret variable from a script", - (yargs) => { - printWranglerBanner(); + async (yargs) => { + await printWranglerBanner(); return yargs .positional("key", { describe: "The variable name to be accessible in the script", @@ -1627,7 +1629,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); if (!isValidNamespaceBinding(args.namespace)) { throw new CommandLineArgsError( @@ -1708,7 +1710,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); let id; @@ -1804,7 +1806,7 @@ export async function main(argv: string[]): Promise { .check(demandOneOfOption("value", "path")); }, async ({ key, ttl, expiration, ...args }) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); const namespaceId = getNamespaceId(args, config); // One of `args.path` and `args.value` must be defined @@ -1952,7 +1954,7 @@ export async function main(argv: string[]): Promise { }); }, async ({ key, ...args }) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); const namespaceId = getNamespaceId(args, config); @@ -2008,7 +2010,7 @@ export async function main(argv: string[]): Promise { }); }, async ({ filename, ...args }) => { - printWranglerBanner(); + await printWranglerBanner(); // The simplest implementation I could think of. // This could be made more efficient with a streaming parser/uploader // but we'll do that in the future if needed. @@ -2119,7 +2121,7 @@ export async function main(argv: string[]): Promise { }); }, async ({ filename, ...args }) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); const namespaceId = getNamespaceId(args, config); @@ -2204,7 +2206,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); @@ -2235,7 +2237,7 @@ export async function main(argv: string[]): Promise { }); }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); const config = readConfig(args.config as ConfigPath, args); @@ -2275,7 +2277,7 @@ export async function main(argv: string[]): Promise { // TODO: scopes }, async (args) => { - printWranglerBanner(); + await printWranglerBanner(); if (args["scopes-list"]) { listScopes(); return; @@ -2309,7 +2311,7 @@ export async function main(argv: string[]): Promise { "🚪 Logout from Cloudflare", () => {}, async () => { - printWranglerBanner(); + await printWranglerBanner(); await logout(); } ); @@ -2320,7 +2322,7 @@ export async function main(argv: string[]): Promise { "🕵️ Retrieve your user info and test your auth config", () => {}, async () => { - printWranglerBanner(); + await printWranglerBanner(); await whoami(); } ); diff --git a/packages/wrangler/src/update-check.ts b/packages/wrangler/src/update-check.ts new file mode 100644 index 000000000000..a9d3c50c4718 --- /dev/null +++ b/packages/wrangler/src/update-check.ts @@ -0,0 +1,19 @@ +import chalk from "chalk"; +import checkForUpdate from "update-check"; +import pkg from "../package.json"; + +export async function updateCheck(): Promise { + let update = null; + try { + // default cache for update check is 1 day + update = await checkForUpdate(pkg, { + distTag: "beta", + }); + } catch (err) { + // ignore error + } + + if (update) return `(update available ${chalk.green(update.latest)})`; + + return ""; +}