Skip to content

feat: add vercel-build action input for local Vercel build step - #361

Merged
amondnet merged 13 commits into
masterfrom
amondnet/vercel-build-step
Apr 30, 2026
Merged

feat: add vercel-build action input for local Vercel build step#361
amondnet merged 13 commits into
masterfrom
amondnet/vercel-build-step

Conversation

@amondnet

@amondnet amondnet commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Track

  • Track: auto-vercel-build-20260430
  • Spec: .please/docs/tracks/active/auto-vercel-build-20260430/spec.md
  • Plan: .please/docs/tracks/active/auto-vercel-build-20260430/plan.md

Refs #360

Summary

Add an opt-in vercel-build action input that, when set to true, executes the official Vercel CLI workflow locally before deployment: vercel pull --environment=<target>vercel build → upload .vercel/output via the existing prebuilt deploy path.

This mirrors the Vercel KB recommended GitHub Actions workflow and lets users build inside CI (with their own secrets and runtime) instead of relying on Vercel's remote build.

Behavior

vercel-build prebuilt Behavior
false (default) any Unchanged — current source-upload behavior
true false Run vercel pull + vercel build locally, then deploy .vercel/output as prebuilt
true true Fail fast — mutually exclusive

Status

  • Spec & plan
  • Implementation (16 tasks, in progress)
  • Tests (>80% coverage)
  • Integration test (emulate.dev)
  • README update
  • dist/ rebuild

Summary by cubic

Adds an opt-in vercel-build input to run vercel pull and vercel build inside the action, then deploy .vercel/output or a custom vercel-output-dir via the prebuilt path. Adds failure comments for broken builds, keeps current behavior by default, and hardens token handling. Addresses #360.

  • New Features

    • vercel-build (default: false): runs vercel pull --environment=<target>vercel build (--prod for production; respects --output <dir> when vercel-output-dir is set), then uploads the build output; on failure, exits non-zero and posts a short PR/commit comment (when enabled).
    • Input guards: mutually exclusive with prebuilt and with a non-empty vercel-args; both fail fast with a clear error at config parse time.
    • Forwards build-env to vercel build and passes --scope when a team scope is set.
  • Bug Fixes

    • Hardened logging and comments: pass the Vercel token via VERCEL_TOKEN with @actions/exec silent: true to avoid token leakage; escape triple backticks in failure comments to prevent Markdown injection.
    • Bound captured build stdout/stderr to ~64 KB per stream to prevent runner OOM on long builds while keeping the tail in failure comments.
    • Tests: clear GITHUB_ACTIONS in the Vitest unit project to prevent auto-invoking run() on import.
    • Rebuilt dist/ to match source; no behavior change.

Written for commit faeeff0. Summary will update on new commits. Review in cubic

Verification Checklist

Manual verification (run after T013):

  • Happy path (preview): In example/nextjs, set vercel-build: 'true', prebuilt: 'false'. Run the action against a real Vercel project (preview token). Expect: log shows vercel pull then vercel build invocations, .vercel/output is uploaded, deployment URL returned.
  • Happy path (production): Set target: production + vercel-build: 'true'. Expect: vercel pull --environment=production and vercel build --prod invoked.
  • Mutual exclusivity: Set vercel-build: 'true' AND prebuilt: 'true'. Expect: action fails immediately with a clear conflict message; no API calls made.
  • Custom output dir: Set vercel-build: 'true' + vercel-output-dir: 'custom/out'. Expect: vercel build --output <abs>/custom/out invoked, deploy reads from same path.
  • Build failure: In a fixture project, introduce a syntax error so vercel build fails. Expect: action exits non-zero, GitHub Actions log shows the build error, PR comment is posted with truncated tail (when github-comment: true).
  • github-comment: false suppression: With vercel-build: 'true' and github-comment: 'false', trigger a build failure. Expect: action fails non-zero, no PR/commit comment posted.
  • Backward compatibility: With vercel-build unset (or false), run an existing-style deployment. Expect: identical behavior to current main branch — no vercel pull/vercel build invocations.
  • Token redaction: Inspect logs from steps above. The Vercel token MUST NOT appear in any log line, comment, or error message. Token is now passed via VERCEL_TOKEN env var (never via argv).

Automated:

  • pnpm test — all 285 tests passing
  • pnpm test --coveragesrc/vercel-build.ts 94%+ coverage
  • pnpm run lint — 0 errors
  • pnpm run build — clean dist/ rebuild

Add track for opt-in vercel-build action input that runs vercel pull and
vercel build locally before deployment, then routes through the existing
prebuilt deploy path.

Refs #360
@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for file ready!

Project:file
Status: ✅  Deploy successful!
Preview URL:https://team-scope-test-efcqjf3hd-dietfriends.vercel.app
Latest Commit:faeeff0
Inspect:View deployment

Deployed with vercel-action

@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for static ready!

Project:static
Status: ✅  Deploy successful!
Preview URL:https://zeit-now-deployment-action-example-angular-jp716zewh.vercel.app
Latest Commit:faeeff0
Alias:https://staging.static.vercel-action.amond.dev
Alias:https://pr-361.static.vercel-action.amond.dev
Inspect:View deployment

Deployed with vercel-action

@github-actions

github-actions Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for express-basic-auth ready!

Project:express-basic-auth
Status: ✅  Deploy successful!
Preview URL:https://express-basic-auth-d6b2yawtn-minsu-lees-projects-b1e388b7.vercel.app
Latest Commit:faeeff0
Inspect:View deployment

Deployed with vercel-action

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the vercel-build feature, which enables local execution of the Vercel CLI workflow within GitHub Actions. The changes include a new track entry, metadata, a detailed implementation plan, and a product specification. Feedback focuses on enhancing security by using environment variables for tokens, ensuring team scope propagation with the --scope flag, and supporting custom output directories via the --output flag.

Comment thread .please/docs/tracks/active/auto-vercel-build-20260430/spec.md Outdated
Comment thread .please/docs/tracks/active/auto-vercel-build-20260430/spec.md Outdated
Comment thread .please/docs/tracks/active/auto-vercel-build-20260430/plan.md Outdated
Add a new boolean action input `vercel-build` that opts into running
`vercel pull` + `vercel build` locally before deployment. When combined
with `prebuilt: true`, the action fails fast at config parse time
since the two flags are conceptually mutually exclusive.

T001+T002+T003 of auto-vercel-build-20260430.

Refs #360
…rator

Add new module src/vercel-build.ts:
- BuildFailedError with stderr-tail capture (last 20 lines, fallback to
  stdout when stderr is empty)
- runVercelPull(config): `vercel pull --yes --environment=<target>`
- runVercelBuild(config): `vercel build [--prod]` with buildEnv merged
  into the exec environment
- runBuildStep(config): pull → build sequencing, returns
  { prebuilt: true, vercelOutputDir } so callers can route through the
  existing prebuilt deploy path

T004–T009 of auto-vercel-build-20260430.

Refs #360
Wire runBuildStep into run() before deployment when vercel-build: true.
On success, mutate the config to set prebuilt=true and vercelOutputDir
so the existing API client uploads the produced .vercel/output.

On BuildFailedError, post a build-failure comment (PR or commit) with
the captured stderr tail (last 20 lines), then rethrow so the action
exits non-zero.

Also export run() and guard the top-level invocation behind
`process.env.VITEST` so tests can drive run() without triggering the
module-level fire-and-forget call.

T010-T013 of auto-vercel-build-20260430.

Refs #360
- Integration test (src/__integration__/vercel-build.test.ts):
  3 tests covering runBuildStep output, end-to-end deploy via emulator
  with the prebuilt path, and fail-fast on pull error.
- README: `vercel-build` input row in the API inputs table, plus a new
  "Method 4 - Build inside the action" section with a workflow example
  and notes on mutual exclusivity, build-env, target=production, and
  failure-comment behavior.
- dist/: regenerated via @vercel/ncc.

Coverage: vercel-build.ts 94.39% (NFR-4 target >80%), suite 272 tests
passing.

T014-T016 of auto-vercel-build-20260430.

Refs #360
Address code-review findings on PR #361:

- Critical (security): Stop passing the Vercel token via `-t <token>` argv,
  which @actions/exec echoes verbatim to stdout via toolrunner's
  [command]... line before the runner's secret mask can claim it. Pass
  the token through the VERCEL_TOKEN environment variable instead — the
  documented non-interactive auth path per the Vercel CLI source
  (packages/cli/src/commands/build/index.ts:309). Also set silent: true
  on the ExecOptions to suppress the [command] echo entirely.

- Important (security): `stderrTail` is interpolated into a Markdown
  fenced code block in PR/commit comments. Untrusted build output
  containing triple-backticks could close the fence and inject Markdown.
  Escape any run of 3+ backticks before interpolation.

- Important (tests): Add three orchestration tests in run-build.test.ts:
  1. Asserts createBuildFailureCommentOnPullRequest is called with
     the BuildFailedError's exitCode and stderrTail (AC-4 wiring)
  2. Asserts createBuildFailureCommentOnCommit is called for push
     events instead of the PR helper
  3. Asserts no failure comment is posted when github-comment is false

- Add 4 vercel-build.test.ts tests asserting the token is NOT in argv
  and IS in env, plus that exec runs with silent: true.

dist/ rebuilt. Suite: 280 tests passing (was 272).

Refs #360
@github-actions

github-actions Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for angular ready!

Project:angular
Status: ✅  Deploy successful!
Preview URL:https://zeit-now-deployment-action-example-angular-9ij602lhx.vercel.app
Latest Commit:faeeff0
Alias:https://staging.angular.vercel-action.amond.dev
Alias:https://pr-361.angular.vercel-action.amond.dev
Inspect:View deployment

Deployed with vercel-action

Previously, when a user combined `vercel-build: true` with a custom
`vercel-output-dir`, the build wrote to the default `.vercel/output`
while the prebuilt deploy looked at `config.vercelOutputDir` —
silently mismatched. The user's vercel-output-dir was effectively
ignored during the build.

Fix:
- runVercelBuild now passes `--output <dir>` to `vercel build`
  whenever `config.vercelOutputDir` is set (relative paths resolved
  against working-directory; absolute paths used as-is).
- runBuildStep now returns the user's `vercelOutputDir` (resolved)
  instead of always defaulting to `<workingDir>/.vercel/output`,
  so the deploy reads from the same place the build wrote to.
- Spec FR-2 + new AC-7 + plan architecture diagram updated to reflect
  `[--output <dir>]` and the VERCEL_TOKEN env transport.
- README documents both the env-var auth path and the --output
  passthrough.
- 5 new unit tests covering --output omission, absolute path, and
  relative-path resolution.

Addresses gemini-code-assist[bot] review threads on PR #361.

Refs #360
@amondnet
amondnet marked this pull request as ready for review April 30, 2026 00:46
Copilot AI review requested due to automatic review settings April 30, 2026 00:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in vercel-build input to run a local Vercel CLI build (vercel pullvercel build) inside the GitHub Action, then deploy the resulting .vercel/output via the existing prebuilt upload path, including build-failure PR/commit comments and expanded test coverage.

Changes:

  • Introduces vercel-build input + config/type wiring and mutual exclusivity with prebuilt.
  • Adds src/vercel-build.ts runner (pull/build orchestration) and build-failure comment helpers.
  • Updates docs/tests/integration tests and rebuilds dist/ outputs.

Reviewed changes

Copilot reviewed 16 out of 22 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/vercel-build.ts New local vercel pull/vercel build runner and BuildFailedError plumbing.
src/types.ts Adds vercelBuild flag to ActionConfig.
src/index.ts Runs build step before deploy and posts build-failure comments; exports run().
src/github-comments.ts Adds PR/commit build-failure comment helpers with fenced-block escaping.
src/config.ts Parses vercel-build input and enforces vercel-build XOR prebuilt.
src/tests/vercel-build.test.ts Unit tests for build runner behavior, args/env handling, and error tails.
src/tests/run-build.test.ts Orchestration tests ensuring build runs before deploy and failure comments post.
src/tests/github-comments.test.ts Tests for new build-failure comment formatting + escaping.
src/tests/config.test.ts Tests for vercel-build parsing and mutual exclusivity with prebuilt.
src/integration/vercel-build.test.ts emulate.dev integration coverage for the build-step + prebuilt deploy boundary.
dist/vercel-build.d.ts Generated declarations for the new build module.
dist/types.d.ts Generated declarations for updated ActionConfig.
dist/index.js Rebuilt ncc bundle including new feature and exports.
dist/index.d.ts Exposes run() in the published type surface.
dist/github-comments.d.ts Declarations for new build-failure comment functions.
action.yml Adds vercel-build action input.
README.md Documents vercel-build and adds “Method 4 - Build inside the action” example.
.please/docs/tracks/active/auto-vercel-build-20260430/spec.md Track spec documenting requirements/acceptance criteria.
.please/docs/tracks/active/auto-vercel-build-20260430/plan.md Implementation plan and progress log for the track.
.please/docs/tracks/active/auto-vercel-build-20260430/metadata.json Track metadata for #360/#361.
.please/docs/tracks.jsonl Registers the new track as active.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/vercel-build.ts
Comment thread src/index.ts Outdated
Comment thread src/config.ts
- Move track active/ → completed/
- Update metadata: status=review, updated_at, pr=#361
- Update tracks.jsonl: section=completed, phase=finalize
- Sync to product-specs: SPEC-001 deployment/vercel-build.md (created)
- Append retrospective + tech-debt items (TD-001 vercel-cli token transport, TD-002 e2e gap)

Refs #360

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 22 files

Requires human review: This is a significant feature addition that modifies the core execution path in src/index.ts and introduces new external CLI orchestration. Such changes require human review.

Architecture diagram
sequenceDiagram
    participant GH as GitHub Actions Runner
    participant CFG as getActionConfig
    participant BR as NEW: runBuildStep (vercel-build.ts)
    participant CLI as Vercel CLI (npx)
    participant API as Vercel API Client
    participant GHA as GitHub API

    Note over GH,GHA: Configuration & Initialization

    GH->>CFG: Fetch Action Inputs
    CFG->>CFG: CHANGED: Validate vercel-build XOR prebuilt
    CFG-->>GH: ActionConfig object

    alt NEW: vercel-build is true
        Note over GH,CLI: Local Build Workflow (FR-2)
        GH->>BR: runBuildStep(config)
        
        BR->>CLI: NEW: vercel pull --environment=[target]
        Note right of CLI: Auth via VERCEL_TOKEN env var (NFR-3)
        CLI-->>BR: project settings

        BR->>CLI: NEW: vercel build [--prod] [--output dir]
        Note right of CLI: Forward build-env & scope (FR-6, FR-7)
        
        alt Build Success
            CLI-->>BR: 0 (Success)
            BR-->>GH: { prebuilt: true, vercelOutputDir }
            Note over GH: Mutate config to treat as prebuilt
        else Build Failure
            CLI-->>BR: Non-zero exit code
            BR-->>GH: throw BuildFailedError (with stderr tail)
            
            opt github-comment is true
                GH->>GHA: NEW: postBuildFailureComment()
                Note right of GHA: Truncated tail + escape backticks
            end
            Note over GH: Action fails (setFailed)
        end
    end

    Note over GH,API: Deployment Phase

    GH->>API: createVercelClient(config)
    GH->>API: client.deploy(config, context)
    
    alt prebuilt is true (from input OR build step)
        API->>API: Upload .vercel/output artifacts
    else source deployment (default)
        API->>API: Upload source files for remote build
    end
    
    API-->>GH: deploymentUrl
Loading

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 25 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/github-comments.ts">

<violation number="1" location="src/github-comments.ts:139">
P3: The failure comment body is reused for commit comments but contains PR-only wording, which produces incorrect messaging on push events.</violation>
</file>

<file name="README.md">

<violation number="1" location="README.md:70">
P3: The internal README link for `vercel-build` points to the wrong anchor, so navigation to the new section breaks.</violation>
</file>

<file name="dist/index.js">

<violation number="1" location="dist/index.js:99784">
P1: The `!process.env.VITEST` guard will silently prevent the action from executing in any workflow where the `VITEST` environment variable is set — which Vitest sets automatically. Repositories that run Vitest in the same job or share env vars across steps will hit this. Use a more specific guard such as a dedicated internal env var set by the test harness (e.g., `__VERCEL_ACTION_TEST`), or check `require.main === module`.</violation>
</file>

<file name="src/config.ts">

<violation number="1" location="src/config.ts:90">
P1: Missing mutual-exclusivity check: `vercel-build: true` combined with a non-empty `vercel-args` will silently build locally and then deploy via the CLI path (which ignores the prebuilt output). Add a fail-fast validation here, similar to the `prebuilt` check, to reject the `vercel-build` + `vercel-args` combination.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Runner as Action Runner
    participant GH as GitHub API
    participant CLI as Vercel CLI (npx)
    participant Vercel as Vercel API

    Note over Runner: NEW: Validate vercel-build XOR prebuilt

    alt vercel-build: true
        Runner->>CLI: NEW: vercel pull --environment (env: VERCEL_TOKEN)
        Note right of CLI: CLI runs with silent: true to hide tokens
        CLI-->>Runner: Exit status

        Runner->>CLI: NEW: vercel build (env: VERCEL_TOKEN + build-env)
        Note right of CLI: Optional --output dir if vercel-output-dir set
        CLI-->>Runner: Output + Exit code

        alt NEW: Build Failure (Exit > 0)
            Runner->>Runner: Capture last 20 lines of stderr
            Runner->>GH: NEW: Post failure comment to PR/Commit
            Note over Runner,GH: Markdown escaped to prevent fence breakout
            Runner-->>Runner: Throw BuildFailedError (Stop)
        else Build Success
            Runner->>Runner: CHANGED: Mutate config to prebuilt = true
        end
    end

    Runner->>Vercel: deploy() (via @vercel/client)
    Note right of Vercel: If prebuilt, uploads .vercel/output artifact
    Vercel-->>Runner: Deployment Metadata / URL
    Runner-->>Runner: setOutput(preview-url)
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread dist/index.js Outdated
Comment thread src/config.ts
Comment thread src/github-comments.ts Outdated
Comment thread README.md Outdated
…ld-step

# Conflicts:
#	.please/docs/tracks.jsonl
#	dist/index.js
#	dist/index.js.map
Apply 5 review suggestions from copilot + cubic-dev-ai on PR #361:

- src/vercel-build.ts: bound captured stdout/stderr to ~64 KB per stream
  (appendBounded helper). Long vercel build runs no longer risk runner
  OOM; the stderrTail tail-line behavior is preserved.
- src/index.ts: replace negative `!process.env.VITEST` auto-invoke
  guard with positive `process.env.GITHUB_ACTIONS === 'true'` check.
  The previous guard would silently disable the action in any workflow
  that happens to set VITEST. GITHUB_ACTIONS is the canonical
  runner-set sentinel.
- src/config.ts: add fail-fast mutex between `vercel-build: true` and
  non-empty `vercel-args`. Without it, the action would build locally
  via the prebuilt path then route the deploy through the CLI path,
  silently ignoring the local build output.
- src/github-comments.ts: change build-failure comment wording from
  'this pull request' to 'this workflow run' so the same body works
  for both PR comments and commit comments (push events).
- README.md: fix broken `vercel-build` anchor link to use the actual
  GitHub-rendered slug (`#method-4---build-inside-the-action-vercel-build`).

3 new tests: vercel-args mutex (positive + whitespace edge case),
huge-stderr bounded buffer.

Suite: 305 tests passing (was 302). Lint clean, tsc clean. dist/
rebuilt.

Refs #360

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 9 files (changes from recent commits).

Requires human review: This is a significant feature addition that modifies the core deployment execution path and orchestration logic. While opt-in, it requires architectural context to ensure subprocess management and/or

…t auto-invocation on import

Agent-Logs-Url: https://github.com/amondnet/vercel-action/sessions/e840b930-a078-4381-91dc-06dc24402e36

Co-authored-by: amondnet <1964421+amondnet@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Requires human review: This is a significant new feature that adds local process execution and modifies the core orchestration flow. While opt-in, it requires human review of the architectural changes.

The check-dist CI step regenerates dist/ and fails if it differs from
the committed bundle. Commit 45de99c updated the auto-invoke guard
comment in src/index.ts and added a vitest env override but did not
rebuild dist/. Regenerate via @vercel/ncc so the committed bundle
matches source.

Refs #360
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot
7.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@amondnet
amondnet merged commit 4076535 into master Apr 30, 2026
13 of 15 checks passed
@amondnet
amondnet deleted the amondnet/vercel-build-step branch April 30, 2026 02:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants