Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/cli/mint.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Required environment variables:
| `--region` | `us-central1` | Cloud region for the function (GCP only) |
| `--pem-dir` | | Directory containing role PEM files (GCP only, first-time bootstrap) |
| `--public` | `false` | Deploy public mint (GCP only) |
| `--source-dir` | | Path to local mint source (default: embedded) |
| `--source-dir` | | Path to local mint source (default: checkout path when present, embedded otherwise) |
| `--dry-run` | `false` | Preview changes without making them |
| `--worker-name` | `fullsend-mint` | Cloudflare Worker script name (Cloudflare only) |
| `--preview` | `""` | Preview alias for `wrangler versions upload` (Cloudflare only). Example: `--preview=bt-run-42` |
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/infrastructure/mint-administration.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ Redeploying or upgrading an existing mint must use the same mode: `--public` for
| `--region` | `us-central1` | Cloud region for the mint function |
| `--pem-dir` | | Path to directory containing `{role}.pem` files (first-time bootstrap only); uses the default app set (`fullsend-ai`) |
| `--public` | `false` | Deploy public mint (`ALLOWED_ORGS=*`, permissive WIF); required to redeploy an existing public mint |
| `--source-dir` | (embedded) | Path to local mint source directory (for development; default uses the embedded copy) |
| `--source-dir` | | Path to local mint source directory (default: checkout path when present, embedded otherwise) |
| `--skip-deploy` | `false` | Skip code upload, reuse existing function (only update WIF/config) |
| `--dry-run` | `false` | Preview changes without making them |

Expand Down
28 changes: 17 additions & 11 deletions internal/cli/mint.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ Cloudflare mode (--platform=cloudflare):

// Common flags.
cmd.Flags().StringVar(&platform, "platform", "gcp", "target platform: gcp or cloudflare")
cmd.Flags().StringVar(&sourceDir, "source-dir", "", "path to local mint source (default: embedded)")
cmd.Flags().StringVar(&sourceDir, "source-dir", "", "path to local mint source (default: checkout path when present, embedded otherwise)")
cmd.Flags().BoolVar(&dryRun, "dry-run", false, "preview changes without making them")

// GCP-specific flags.
Expand Down Expand Up @@ -500,11 +500,18 @@ func runMintDeployGCP(ctx context.Context, project, region, sourceDir string, sk
printer.Header("Deploying token mint (GCP)")
printer.Blank()

explicitSourceDir := sourceDir != ""
if sourceDir == "" {
Comment thread
ifireball marked this conversation as resolved.
Comment thread
ifireball marked this conversation as resolved.
sourceDir = gcf.DefaultFunctionSourceDir()
}

if dryRun {
printer.StepInfo("Dry run — no changes will be made")
printer.Blank()
printer.StepInfo(fmt.Sprintf("Would deploy mint to project %s, region %s", project, region))
if sourceDir != "" {
if explicitSourceDir {
printer.StepInfo(fmt.Sprintf("Source directory: %s", sourceDir))
} else if _, err := os.Stat(sourceDir); err == nil {
printer.StepInfo(fmt.Sprintf("Source directory: %s", sourceDir))
} else {
printer.StepInfo("Source: embedded mint function")
Expand All @@ -526,10 +533,6 @@ func runMintDeployGCP(ctx context.Context, project, region, sourceDir string, sk

gcpClient := mintGCFClientFactory(project)

if sourceDir == "" {
sourceDir = gcf.DefaultFunctionSourceDir()
}

deployMode := gcf.DeployAuto
if skipDeploy {
deployMode = gcf.DeploySkip
Expand Down Expand Up @@ -622,6 +625,11 @@ func runMintDeployCloudflare(ctx context.Context, workerName, sourceDir, preview
deployMode = cf.DeployPreview
}

explicitSourceDir := sourceDir != ""
if sourceDir == "" {
sourceDir = cf.DefaultWorkerSourceDir()
}

effectiveName := workerName
if effectiveName == "" {
effectiveName = "fullsend-mint"
Expand All @@ -636,7 +644,9 @@ func runMintDeployCloudflare(ctx context.Context, workerName, sourceDir, preview
}
printer.StepInfo(fmt.Sprintf("Would deploy Worker %s", dryRunName))
printer.StepInfo(fmt.Sprintf("Account: %s", accountID))
if sourceDir != "" {
if explicitSourceDir {
printer.StepInfo(fmt.Sprintf("Source directory: %s", sourceDir))
} else if _, err := os.Stat(sourceDir); err == nil {
printer.StepInfo(fmt.Sprintf("Source directory: %s", sourceDir))
} else {
printer.StepInfo("Source: embedded Worker adapter")
Expand All @@ -651,10 +661,6 @@ func runMintDeployCloudflare(ctx context.Context, workerName, sourceDir, preview
return nil
}

if sourceDir == "" {
sourceDir = cf.DefaultWorkerSourceDir()
}

cfg := cf.Config{
AccountID: accountID,
WorkerName: workerName,
Expand Down
152 changes: 152 additions & 0 deletions internal/cli/mint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,80 @@ func TestMintDeployCmd_DryRun(t *testing.T) {
require.NoError(t, err)
}

func TestMintDeployCmd_DryRunShowsResolvedSource(t *testing.T) {
// When --source-dir is not provided and the default checkout path
// exists on disk, dry-run should show the resolved path.
tmpDir := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, gcf.DefaultFunctionSourceDir()), 0o755))
t.Chdir(tmpDir)

oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--project=my-project-id", "--dry-run"})
err := cmd.Execute()

w.Close()
os.Stdout = oldStdout

out, _ := io.ReadAll(r)
stdout := string(out)

require.NoError(t, err)
assert.Contains(t, stdout, gcf.DefaultFunctionSourceDir(),
"dry-run should show resolved checkout path")
assert.NotContains(t, stdout, "embedded mint function",
"dry-run should not claim embedded source when checkout path exists")
}

func TestMintDeployCmd_DryRunShowsEmbeddedWhenPathMissing(t *testing.T) {
// When --source-dir is not provided and the default checkout path
// does not exist on disk, dry-run should report embedded source.
t.Chdir(t.TempDir())

oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--project=my-project-id", "--dry-run"})
err := cmd.Execute()

w.Close()
os.Stdout = oldStdout

out, _ := io.ReadAll(r)
stdout := string(out)

require.NoError(t, err)
assert.Contains(t, stdout, "embedded mint function",
"dry-run should report embedded source when checkout path is missing")
assert.NotContains(t, stdout, gcf.DefaultFunctionSourceDir(),
"dry-run should not show non-existent checkout path")
}

func TestMintDeployCmd_DryRunWithExplicitSourceDir(t *testing.T) {
oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--project=my-project-id", "--dry-run", "--source-dir=/custom/path"})
err := cmd.Execute()

w.Close()
os.Stdout = oldStdout

out, _ := io.ReadAll(r)
stdout := string(out)

require.NoError(t, err)
assert.Contains(t, stdout, "/custom/path",
"dry-run should show the explicitly provided source-dir")
}

func TestMintDeployCmd_DryRunPublic(t *testing.T) {
cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--project=my-project-id", "--dry-run", "--public"})
Expand Down Expand Up @@ -321,6 +395,84 @@ func TestMintDeployCmd_CloudflareDryRun(t *testing.T) {
require.NoError(t, err)
}

func TestMintDeployCmd_CloudflareDryRunShowsResolvedSource(t *testing.T) {
withCFEnvVars(t)

// Create the expected checkout path so os.Stat succeeds.
tmpDir := t.TempDir()
require.NoError(t, os.MkdirAll(filepath.Join(tmpDir, cf.DefaultWorkerSourceDir()), 0o755))
t.Chdir(tmpDir)

oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--platform=cloudflare", "--dry-run"})
err := cmd.Execute()

w.Close()
os.Stdout = oldStdout

out, _ := io.ReadAll(r)
stdout := string(out)

require.NoError(t, err)
assert.Contains(t, stdout, cf.DefaultWorkerSourceDir(),
"dry-run should show resolved checkout path")
assert.NotContains(t, stdout, "embedded Worker adapter",
"dry-run should not claim embedded source when checkout path exists")
}

func TestMintDeployCmd_CloudflareDryRunShowsEmbeddedWhenPathMissing(t *testing.T) {
withCFEnvVars(t)

// Run from a temp dir where the default checkout path does not exist.
t.Chdir(t.TempDir())

oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--platform=cloudflare", "--dry-run"})
err := cmd.Execute()

w.Close()
os.Stdout = oldStdout

out, _ := io.ReadAll(r)
stdout := string(out)

require.NoError(t, err)
assert.Contains(t, stdout, "embedded Worker adapter",
"dry-run should report embedded source when checkout path is missing")
assert.NotContains(t, stdout, cf.DefaultWorkerSourceDir(),
"dry-run should not show non-existent checkout path")
}

func TestMintDeployCmd_CloudflareDryRunWithExplicitSourceDir(t *testing.T) {
withCFEnvVars(t)

oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

cmd := newRootCmd()
cmd.SetArgs([]string{"mint", "deploy", "--platform=cloudflare", "--dry-run", "--source-dir=/custom/worker/path"})
err := cmd.Execute()

w.Close()
os.Stdout = oldStdout

out, _ := io.ReadAll(r)
stdout := string(out)

require.NoError(t, err)
assert.Contains(t, stdout, "/custom/worker/path",
"dry-run should show the explicitly provided source-dir")
}

func TestMintDeployCmd_CloudflareDryRunPreview(t *testing.T) {
origAccount := os.Getenv("CLOUDFLARE_ACCOUNT_ID")
origToken := os.Getenv("CLOUDFLARE_API_TOKEN")
Expand Down
Loading