Skip to content

fix: retry alias command without --scope for personal accounts - #310

Merged
amondnet merged 5 commits into
masterfrom
amondnet/placid-marmot
Mar 26, 2026
Merged

fix: retry alias command without --scope for personal accounts#310
amondnet merged 5 commits into
masterfrom
amondnet/placid-marmot

Conversation

@amondnet

Copy link
Copy Markdown
Owner

Summary

  • Refactors aliasDomainsToDeployment to capture stderr and inspect the exit code per alias command invocation
  • When the Vercel CLI rejects --scope for personal accounts (matching PERSONAL_ACCOUNT_SCOPE_ERROR), emits a warning and retries the alias without --scope
  • Throws a descriptive error if either the initial or the retry invocation fails
  • Mirrors the existing fallback pattern already used for the main deployment command

Test Plan

  • Verify alias assignment succeeds for org accounts (scope accepted, no retry)
  • Verify alias assignment succeeds for personal accounts (scope rejected, retries without --scope)
  • Verify a hard alias failure (non-scope error) surfaces a clear error message with the exit code
  • Run pnpm run all (lint + build + tests) locally to confirm no regressions

Copilot AI review requested due to automatic review settings March 26, 2026 05:37
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the reliability of Vercel alias assignments by introducing sophisticated error handling and a targeted retry mechanism. It addresses a common issue where Vercel CLI might incorrectly reject the --scope argument for personal accounts, causing alias commands to fail. By intelligently capturing command output and retrying under specific conditions, the system ensures more robust domain aliasing, aligning with existing fallback patterns for deployment commands.

Highlights

  • Robust Alias Command Execution: Refactored the aliasDomainsToDeployment function to capture stderr and inspect the exit code for each alias command invocation, enhancing error detection.
  • Personal Account Scope Handling: Implemented a retry mechanism for the Vercel alias command: if the Vercel CLI rejects the --scope argument for personal accounts, the command is automatically retried without the --scope.
  • Improved Error Reporting: Enhanced error handling to throw descriptive errors if either the initial or the retry alias command fails, providing clearer feedback on command execution issues.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions

github-actions Bot commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for team-scope-test ready!

✅ Preview
https://team-scope-test-jnrv35ei8-dietfriends.vercel.app

Built with commit b1560bd.
This pull request is being automatically 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 enhances the aliasDomainsToDeployment function by implementing more robust error handling for Vercel domain aliasing. It now captures stderr to detect specific scope-related errors and retries the alias command without the --scope argument if such an error occurs. The review feedback correctly points out a critical issue where the ignoreReturnCode option is missing in the retry execution, making the subsequent error check unreachable, and suggests including the exit code in the error message for better debugging.

Comment thread index.js Outdated

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

This PR updates the action’s Vercel aliasing flow to better handle personal-account scenarios where the Vercel CLI rejects --scope, aligning alias behavior with the existing deploy fallback strategy.

Changes:

  • Refactors aliasDomainsToDeployment to capture CLI stderr and evaluate exit codes per alias invocation.
  • Detects PERSONAL_ACCOUNT_SCOPE_ERROR, warns, and retries vercel alias without --scope.
  • Improves surfaced failures by throwing errors when aliasing does not succeed.

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

Comment thread index.js Outdated
+ 'Retrying without --scope.',
)
const retryArgs = [vercelBin, '-t', vercelToken, 'alias', deploymentUrl, domain]
const retryExitCode = await exec.exec('npx', retryArgs)

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

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

exec.exec('npx', retryArgs) will throw on non-zero exit code unless ignoreReturnCode: true is set, so retryExitCode may never be returned and the if (retryExitCode !== 0) branch becomes ineffective. Use ignoreReturnCode: true (and/or wrap in try/catch) for the retry invocation so failures can be handled with the intended descriptive error path.

Suggested change
const retryExitCode = await exec.exec('npx', retryArgs)
const retryExitCode = await exec.exec('npx', retryArgs, { ignoreReturnCode: true })

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Already addressed in a previous commit — the retry exec call already has ignoreReturnCode: true set. This thread is outdated.

Comment thread index.js
Comment on lines +446 to +458
let myError = ''
const exitCode = await exec.exec('npx', args, {
ignoreReturnCode: true,
listeners: {
stderr: (data) => {
myError += data.toString()
},
},
})

if (exitCode !== 0) {
if (myError.includes(PERSONAL_ACCOUNT_SCOPE_ERROR)) {
core.warning(

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

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

The personal-account scope detection only inspects myError (stderr). Elsewhere (e.g., vercelDeploy) the code checks combined stdout+stderr for PERSONAL_ACCOUNT_SCOPE_ERROR, so this alias fallback may not trigger if the CLI prints the message on stdout. Capture stdout as well (or combine streams) before checking for PERSONAL_ACCOUNT_SCOPE_ERROR.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

The code already captures both stdout (myOutput) and stderr (myError) and checks combinedOutput = myOutput + myError before checking for PERSONAL_ACCOUNT_SCOPE_ERROR. This is already addressed.

Comment thread index.js
@@ -432,15 +432,43 @@ async function aliasDomainsToDeployment(deploymentUrl) {
if (!deploymentUrl) {
core.error('deployment url is null')

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

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

If deploymentUrl is missing, this function logs an error but still continues and will attempt to run vercel alias with an undefined URL, producing a harder-to-debug failure later. Consider throwing (or returning early) after logging so the action fails fast with a clear cause.

Suggested change
core.error('deployment url is null')
core.error('deployment url is null')
throw new Error('deployment url is null')

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Applied in 8a4e031 — changed return to throw new Error('deployment url is null') so the action fails fast with a clear cause when deploymentUrl is null.

Comment thread index.js Outdated
Comment on lines +463 to +469
const retryExitCode = await exec.exec('npx', retryArgs)
if (retryExitCode !== 0) {
throw new Error(`Alias command failed for domain ${domain}`)
}
return
}
throw new Error(`Alias command failed for domain ${domain} with exit code ${exitCode}`)

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

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

On retry failure, the thrown error (Alias command failed for domain ...) drops useful context like the retry exit code and stderr output, which makes diagnosing alias failures harder. Include the retry exit code (and ideally captured stderr/stdout) in the error message, consistent with the initial failure path.

Suggested change
const retryExitCode = await exec.exec('npx', retryArgs)
if (retryExitCode !== 0) {
throw new Error(`Alias command failed for domain ${domain}`)
}
return
}
throw new Error(`Alias command failed for domain ${domain} with exit code ${exitCode}`)
let retryError = ''
let retryOutput = ''
const retryExitCode = await exec.exec('npx', retryArgs, {
ignoreReturnCode: true,
listeners: {
stderr: (data) => {
retryError += data.toString()
},
stdout: (data) => {
retryOutput += data.toString()
},
},
})
if (retryExitCode !== 0) {
throw new Error(
`Alias command failed for domain ${domain} with exit code ${retryExitCode}`
+ (retryError ? `, stderr: ${retryError.trim()}` : '')
+ (retryOutput ? `, stdout: ${retryOutput.trim()}` : ''),
)
}
return
}
throw new Error(
`Alias command failed for domain ${domain} with exit code ${exitCode}`
+ (myError ? `, stderr: ${myError.trim()}` : ''),
)

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Applied in 8a4e031 — added stdout listener to the retry exec call and include both stderr and stdout in the error message using template literals for consistency with the linting rules.

@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.

1 issue found across 1 file

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="index.js">

<violation number="1" location="index.js:463">
P1: Missing `ignoreReturnCode: true` on the retry `exec.exec` call. By default `@actions/exec` throws on non-zero exit, so the `retryExitCode !== 0` check is dead code and the error instead bubbles to the outer `retry()`, causing it to re-run the scope-based attempt in a wasteful loop.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Action as index.js (Action Logic)
    participant CLI as Vercel CLI (npx)
    participant API as Vercel API

    Note over Action, API: NEW: Domain Aliasing Flow with Personal Account Fallback

    Action->>CLI: exec: alias [url] [domain] --scope [scope]
    CLI->>API: Request alias assignment
    API-->>CLI: Response (Success or Error)
    CLI-->>Action: Return Exit Code + Capture stderr

    alt Exit Code != 0 AND stderr contains PERSONAL_ACCOUNT_SCOPE_ERROR
        Action->>Action: NEW: Emit Warning (Scope rejected)
        Action->>CLI: NEW: Retry: alias [url] [domain] (No --scope)
        CLI->>API: Request alias assignment
        API-->>CLI: Response
        CLI-->>Action: Return Exit Code
        
        alt Retry Failed
            Action->>Action: Throw Error
        end
    else Other Exit Code != 0
        Action->>Action: CHANGED: Throw Descriptive Error with Exit Code
    end

    Note over Action, API: Flow repeats for each domain in aliasDomains list
Loading

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

Comment thread index.js Outdated
@github-actions

github-actions Bot commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for express-basic-auth ready!

✅ Preview
https://express-basic-auth-3x9vs53hp-minsu-lees-projects-b1e388b7.vercel.app

Built with commit b1560bd.
This pull request is being automatically deployed with vercel-action

@amondnet amondnet self-assigned this Mar 26, 2026

@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 1 file (changes from recent commits).

Requires human review: Refactors core domain aliasing logic to add conditional retries and output capturing, which modifies execution flow and error handling.

@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 10 files (changes from recent commits).

Requires human review: The PR contains core logic changes for handling Vercel CLI errors and retrying commands, plus an unusual Node.js version bump to v24 which requires human verification.

When Vercel CLI rejects the scope during the alias command for personal
accounts, capture stderr and retry the alias without --scope, matching
the same fallback pattern used for the main deployment command.
- add early return when deploymentUrl is null to prevent downstream errors
- capture stdout in addition to stderr to match vercelDeploy pattern
- use ignoreReturnCode and capture stderr in retry exec call
- include stderr context in error messages for better diagnostics
- Throw an error immediately when deploymentUrl is null instead of returning
  silently, so the action fails fast with a clear cause
- Capture stdout in retry exec listener to include in error diagnostics,
  consistent with the suggestion to capture both streams for better
  troubleshooting context
@amondnet
amondnet force-pushed the amondnet/placid-marmot branch from 690ade9 to 20ea5ba Compare March 26, 2026 06:00
@sonarqubecloud

Copy link
Copy Markdown

@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 1 file (changes from recent commits).

Requires human review: This PR introduces significant logic changes and complex error-handling/retry logic for CLI commands in a core path, which exceeds the scope of a safe auto-approval.

@amondnet
amondnet merged commit b1a533d into master Mar 26, 2026
10 of 15 checks passed
@amondnet
amondnet deleted the amondnet/placid-marmot branch March 26, 2026 06:29
amondnet added a commit that referenced this pull request Mar 26, 2026
Capture stderr in alias exec and retry without --scope when Vercel CLI
rejects personal account scope, matching the deploy retry pattern.
Add tests for alias scope retry, retry failure, and non-scope failures.
amondnet added a commit that referenced this pull request Mar 26, 2026
Capture stderr in alias exec and retry without --scope when Vercel CLI
rejects personal account scope, matching the deploy retry pattern.
Add tests for alias scope retry, retry failure, and non-scope failures.
amondnet added a commit that referenced this pull request Mar 26, 2026
* refactor: migrate to TypeScript with Vitest and modern tooling

BREAKING CHANGE: @actions/github upgraded from v2 to v6

- Convert index.js to src/index.ts with strict TypeScript mode
- Extract pure utility functions to src/utils.ts for testability
- Add tsconfig.json with strict compiler options

- Replace Jest with Vitest for faster, ESM-native testing
- Add comprehensive unit tests for utility functions (43 tests)
- Add integration tests for GitHub Action structure (12 tests)
- Target: 80%+ code coverage

- Migrate from deprecated `new github.GitHub(token)` to `github.getOctokit(token)`
- Update all API calls from `octokit.repos.*` to `octokit.rest.repos.*`
- Update all API calls from `octokit.issues.*` to `octokit.rest.issues.*`
- Update all API calls from `octokit.git.*` to `octokit.rest.git.*`

- Enable TypeScript support in @antfu/eslint-config
- Replace Jest globals with Vitest globals (vi instead of jest)
- Add lib/ to ignore patterns

- Update ncc build to compile TypeScript directly
- Add source maps and licenses to dist output
- Add typecheck script for standalone type checking
- Update all npm scripts for TypeScript workflow

- index.js (migrated to src/index.ts)
- index.test.js (migrated to src/__tests__/*.test.ts)
- jest.config.js (replaced by vitest.config.ts)
- now.js (unused legacy file)

Closes #291

* chore: apply AI code review suggestions

- Move PullRequestPayload and ReleasePayload interfaces to top of file
- Use PullRequestPayload type instead of inline type assertion
- Simplify parseArgs regex match logic (remove redundant fallback)

* refactor: split index.ts into smaller modules

- Extract types to src/types.ts
- Extract config and initialization to src/config.ts
- Extract Vercel functions to src/vercel.ts
- Extract GitHub comment functions to src/github-comments.ts
- Refactor run() into smaller focused functions (< 50 LOC each)
- Add try-catch around execSync for git log with descriptive error
- Add error handling for GitHub API calls
- Make alias failures explicit with warning messages
- Extract magic numbers to named constants (RETRY_DELAY_MS, ALIAS_RETRY_COUNT)
- Use buildCommentPrefix() consistently in both comment functions

All files now under 300 LOC limit, all functions under 50 LOC limit.

* build: rebuild dist after refactoring

* build: update vercel to v50

* fix: improve error handling in vercel deploy and comment functions

- Extract and validate deployment URL from vercel CLI stdout
- Wrap vercelInspect exec in try-catch to prevent action failure
- Expand try-catch scope in comment functions to cover API lookups
- Route stderr to core.warning for better error visibility

* test: add tests for vercel, config, and github-comments modules

- Add vercel.test.ts: URL extraction, inspect regex, alias retry
- Add config.test.ts: alias domain substitution, env export
- Add github-comments.test.ts: comment create/update, error handling
- Total tests: 55 → 100

* fix: port personal account scope error handling from PR #297/#298

- Add core.setSecret for vercel token to prevent log exposure
- Disable telemetry with VERCEL_TELEMETRY_DISABLED env var
- Require both org and project IDs together (v41+ compat)
- Auto-retry deployment on personal account scope error
- Sanitize commit message newlines and quotes in metadata
- Add ignoreReturnCode for proper exit code handling
- Update tests for new behavior (105 total)

* refactor: use DeploymentContext object in vercelDeploy signature

Reduce parameter count from 6 to 2 by passing DeploymentContext
object instead of individual ref, commit, sha, commitOrg, commitRepo
arguments. Aligns with AGENTS.md parameter limit of 5.

* fix: port alias retry without --scope for personal accounts (#310)

Capture stderr in alias exec and retry without --scope when Vercel CLI
rejects personal account scope, matching the deploy retry pattern.
Add tests for alias scope retry, retry failure, and non-scope failures.

* fix: remove declaration maps to fix check-dist CI failure

Source map files (.d.ts.map) contain absolute local paths that differ
between local builds and CI runners, causing check-dist to fail.
Disable declarationMap in tsconfig.json since these files are not
needed for GitHub Action runtime execution.

* chore: apply AI code review suggestions

- Implement exponential backoff in retry function (was constant delay)
- Fix debug log for head_commit to use JSON.stringify
- Change vercelInspect stderr logging from warning to info level
- Fix retry after PERSONAL_ACCOUNT_SCOPE_ERROR to omit --scope
- Bump @types/node from ^20.0.0 to ^24.0.0 to match Node 24 runtime
- Add setSecret to @actions/core mock in index.test.ts
- Fix mock path in config.test.ts from ../package.json to ../../package.json
- Update test expectation to match mocked vercel version (30.0.0)
- Remove pull_request_target from PullRequestPayload (always undefined)
- Add per_page: 100 to comment listing API calls to reduce duplicate risk
- Fix Node version in session-summary.md (20 → 24)

* fix: make vercelScope optional to clean up retry cast in vercelDeploy

Co-authored-by: amondnet <1964421+amondnet@users.noreply.github.com>
Agent-Logs-Url: https://github.com/amondnet/vercel-action/sessions/16d171b4-3be8-43f8-a736-b5f3ff13deba

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: amondnet <1964421+amondnet@users.noreply.github.com>
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.

2 participants