From 5792ed90499ebcd48754e2defa7656665cc1c311 Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Tue, 18 Aug 2026 11:31:50 -0700 Subject: [PATCH 1/3] feat(cloudflare): support new wrangler preview command in varlock-wrangler --- .bumpy/wrangler-preview-command.md | 5 +++++ .../cloudflare/src/varlock-wrangler.ts | 14 +++++++++++++- .../src/content/docs/integrations/cloudflare.mdx | 4 +++- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 .bumpy/wrangler-preview-command.md diff --git a/.bumpy/wrangler-preview-command.md b/.bumpy/wrangler-preview-command.md new file mode 100644 index 000000000..005caec0e --- /dev/null +++ b/.bumpy/wrangler-preview-command.md @@ -0,0 +1,5 @@ +--- +"@varlock/cloudflare-integration": minor +--- + +varlock-wrangler now supports the new `wrangler preview` command, uploading resolved vars and secrets to branch preview deployments diff --git a/packages/integrations/cloudflare/src/varlock-wrangler.ts b/packages/integrations/cloudflare/src/varlock-wrangler.ts index ab3e9b128..d23ea4828 100644 --- a/packages/integrations/cloudflare/src/varlock-wrangler.ts +++ b/packages/integrations/cloudflare/src/varlock-wrangler.ts @@ -352,9 +352,19 @@ function isVersionsUploadCommand(args: Array) { return args[0] === 'versions' && args[1] === 'upload'; } +// `wrangler preview` subcommands that manage existing previews rather than +// deploying one - these are passed through to wrangler unchanged +const PREVIEW_SUBCOMMANDS = ['delete', 'settings', 'secret', 'base-config']; + +function isPreviewDeployCommand(args: Array) { + // bare `preview` deploys a branch preview; its only positional is a script path + return args[0] === 'preview' && !PREVIEW_SUBCOMMANDS.includes(args[1]); +} + function isDeployCommand(args: Array) { if (args[0] === 'deploy') return true; if (isVersionsUploadCommand(args)) return true; + if (isPreviewDeployCommand(args)) return true; return false; } @@ -444,7 +454,8 @@ async function handleDeploy(args: Array) { try { debug('deploy: spawning wrangler'); const wranglerArgs = [...args, ...varFlags, '--secrets-file', tmp.filePath]; - if (!isVersionsUploadCommand(args)) wranglerArgs.push('--keep-vars=false'); + // --keep-vars only applies to `deploy` (not `versions upload` or `preview`) + if (args[0] === 'deploy') wranglerArgs.push('--keep-vars=false'); exitCode = await spawnWrangler(wranglerArgs); debug('deploy: wrangler exited with code', exitCode); } finally { @@ -751,6 +762,7 @@ async function main() { console.log('Enhanced commands:'); console.log(' dev - injects resolved env via named pipe (no secrets on disk)'); console.log(' deploy / versions upload - uploads env as Cloudflare vars and secrets'); + console.log(' preview - deploys a branch preview with env as vars and secrets'); console.log(' types - generates types including varlock-managed env vars'); console.log(''); console.log('All other commands are passed through to wrangler unchanged.'); diff --git a/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx b/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx index 5cad224bd..c7c111232 100644 --- a/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx +++ b/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx @@ -204,10 +204,12 @@ Wraps `wrangler dev` with automatic env injection. Resolves your environment var
-### `varlock-wrangler deploy` / `versions upload` +### `varlock-wrangler deploy` / `versions upload` / `preview` Resolves your environment variables from `.env.schema` + `.env` files, then uploads non-sensitive values as Cloudflare vars (`--var`), sensitive values as Cloudflare secrets (`--secrets-file`), and includes a `__VARLOCK_ENV` secret containing the full resolved env graph for the varlock runtime. +`varlock-wrangler preview` works the same way for [branch preview deployments](https://developers.cloudflare.com/workers/configuration/previews/). Subcommands that manage existing previews (`preview delete`, `preview settings`, `preview secret`, `preview base-config`) are passed through to wrangler unchanged. + :::note[Secure secret handling] On Unix, secrets are passed to wrangler commands via a named pipe (FIFO) and never written to disk. On Windows, a temporary file is used and immediately deleted after the deploy completes. ::: From b3619a24fc632f000d0039f3f3c1eabd59f2e7bf Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Tue, 18 Aug 2026 11:38:32 -0700 Subject: [PATCH 2/3] docs: note wrangler preview is in beta --- .../src/content/docs/integrations/cloudflare.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx b/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx index c7c111232..03f2293a2 100644 --- a/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx +++ b/packages/varlock-website/src/content/docs/integrations/cloudflare.mdx @@ -208,7 +208,7 @@ Wraps `wrangler dev` with automatic env injection. Resolves your environment var Resolves your environment variables from `.env.schema` + `.env` files, then uploads non-sensitive values as Cloudflare vars (`--var`), sensitive values as Cloudflare secrets (`--secrets-file`), and includes a `__VARLOCK_ENV` secret containing the full resolved env graph for the varlock runtime. -`varlock-wrangler preview` works the same way for [branch preview deployments](https://developers.cloudflare.com/workers/configuration/previews/). Subcommands that manage existing previews (`preview delete`, `preview settings`, `preview secret`, `preview base-config`) are passed through to wrangler unchanged. +`varlock-wrangler preview` works the same way for [branch preview deployments](https://developers.cloudflare.com/workers/configuration/previews/). Note that `wrangler preview` is currently in beta on Cloudflare's side. Subcommands that manage existing previews (`preview delete`, `preview settings`, `preview secret`, `preview base-config`) are passed through to wrangler unchanged. :::note[Secure secret handling] On Unix, secrets are passed to wrangler commands via a named pipe (FIFO) and never written to disk. On Windows, a temporary file is used and immediately deleted after the deploy completes. From c604f563e60a77ddb13106b673620062ff4217ca Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2026 18:50:04 +0000 Subject: [PATCH 3/3] fix cloudflare preview command routing --- .../cloudflare/src/varlock-wrangler.ts | 10 +------ .../src/wrangler-command-detection.ts | 28 +++++++++++++++++++ .../test/wrangler-command-detection.test.ts | 26 +++++++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 packages/integrations/cloudflare/src/wrangler-command-detection.ts create mode 100644 packages/integrations/cloudflare/test/wrangler-command-detection.test.ts diff --git a/packages/integrations/cloudflare/src/varlock-wrangler.ts b/packages/integrations/cloudflare/src/varlock-wrangler.ts index d23ea4828..44646fcf9 100644 --- a/packages/integrations/cloudflare/src/varlock-wrangler.ts +++ b/packages/integrations/cloudflare/src/varlock-wrangler.ts @@ -11,6 +11,7 @@ import { spawn, execSync } from 'node:child_process'; import { execSyncVarlock, VarlockExecError } from 'varlock/exec-sync-varlock'; import { encryptEnvBlobSync, generateEncryptionKeyHex } from 'varlock/encrypt-env'; import { formatEnvLine } from './format-env-line'; +import { isPreviewDeployCommand } from './wrangler-command-detection'; const isWindows = process.platform === 'win32'; const debugEnabled = !!process.env.VARLOCK_DEBUG; @@ -352,15 +353,6 @@ function isVersionsUploadCommand(args: Array) { return args[0] === 'versions' && args[1] === 'upload'; } -// `wrangler preview` subcommands that manage existing previews rather than -// deploying one - these are passed through to wrangler unchanged -const PREVIEW_SUBCOMMANDS = ['delete', 'settings', 'secret', 'base-config']; - -function isPreviewDeployCommand(args: Array) { - // bare `preview` deploys a branch preview; its only positional is a script path - return args[0] === 'preview' && !PREVIEW_SUBCOMMANDS.includes(args[1]); -} - function isDeployCommand(args: Array) { if (args[0] === 'deploy') return true; if (isVersionsUploadCommand(args)) return true; diff --git a/packages/integrations/cloudflare/src/wrangler-command-detection.ts b/packages/integrations/cloudflare/src/wrangler-command-detection.ts new file mode 100644 index 000000000..16b3f930c --- /dev/null +++ b/packages/integrations/cloudflare/src/wrangler-command-detection.ts @@ -0,0 +1,28 @@ +const PREVIEW_SUBCOMMANDS = ['delete', 'settings', 'secret', 'base-config']; + +const GLOBAL_OPTIONS_WITH_VALUES = [ + '--config', + '-c', + '--cwd', + '--env', + '-e', + '--env-file', + '--profile', +]; + +export function isPreviewDeployCommand(args: Array) { + if (args[0] !== 'preview' || args.includes('--help') || args.includes('-h')) return false; + + for (let i = 1; i < args.length; i++) { + const arg = args[i]; + if (arg === '--') return true; + if (GLOBAL_OPTIONS_WITH_VALUES.includes(arg)) { + i++; + continue; + } + if (arg.startsWith('-')) continue; + return !PREVIEW_SUBCOMMANDS.includes(arg); + } + + return true; +} diff --git a/packages/integrations/cloudflare/test/wrangler-command-detection.test.ts b/packages/integrations/cloudflare/test/wrangler-command-detection.test.ts new file mode 100644 index 000000000..b339321d7 --- /dev/null +++ b/packages/integrations/cloudflare/test/wrangler-command-detection.test.ts @@ -0,0 +1,26 @@ +import { + describe, expect, it, +} from 'vitest'; +import { isPreviewDeployCommand } from '../src/wrangler-command-detection'; + +describe('isPreviewDeployCommand', () => { + it.each([ + ['preview', '--help'], + ['preview', '-h'], + ['preview', '--config', 'wrangler.jsonc', 'settings', '--help'], + ['preview', '--config=wrangler.jsonc', 'delete'], + ['preview', '-c', 'wrangler.jsonc', 'secret', 'list'], + ['preview', '--env', 'staging', 'base-config', 'secret', 'list'], + ])('passes through non-deploying invocation %j', (...args) => { + expect(isPreviewDeployCommand(args)).toBe(false); + }); + + it.each([ + ['preview'], + ['preview', 'src/index.ts'], + ['preview', '--config', 'wrangler.jsonc'], + ['preview', '--config=wrangler.jsonc', 'src/index.ts'], + ])('routes deployment invocation %j through varlock', (...args) => { + expect(isPreviewDeployCommand(args)).toBe(true); + }); +});