Skip to content

feat(cli): add non-interactive flag to hydrogen upgrade command#3744

Open
z0n wants to merge 2 commits intoShopify:mainfrom
z0n:feat/hydrogen-upgrade-non-interactive
Open

feat(cli): add non-interactive flag to hydrogen upgrade command#3744
z0n wants to merge 2 commits intoShopify:mainfrom
z0n:feat/hydrogen-upgrade-non-interactive

Conversation

@z0n
Copy link
Copy Markdown

@z0n z0n commented Apr 22, 2026

WHY are these changes introduced?

Fixes #3743

I needed a non-interactive flag for the shopify hydrogen upgrade command to easily use the upgrade command via an agent skill.

WHAT is this pull request doing?

This PR adds a --non-interactive (alternatives: -y/--yes) flag which only works when a version is specified via --version. It then skips all interactive prompts and overwrites upgrade instructions if there are already some for that version upgrade.

I worked around the --version=next a bit awkwardly as it already does a few things this flag does but I didn't want to break it as I'm not sure how it's used currently.

HOW to test your changes?

In an outdated Hydrogen project, run shopify hydrogen upgrade --version 2026.4.1 --non-interactive -> it should upgrade the project without any prompts.

You can also try shopify hydrogen upgrade --version 2026.4.1 --non-interactive < /dev/null which would throw an error in previous versions as it would trigger a Failed to prompt error.

Post-merge steps

Docs need to be updated with the new flag.

Checklist

  • I've read the Contributing Guidelines
  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've added a changeset if this PR contains user-facing or functional changes. Test changes or internal-only config changes do not require a changeset.
  • I've added tests to cover my changes
  • I've added or updated the documentation

@z0n z0n marked this pull request as ready for review April 22, 2026 14:56
@z0n z0n requested a review from a team as a code owner April 22, 2026 14:56
availableUpgrades: Array<Release>;
currentVersion: string;
currentDependencies: Record<string, string>;
nonInteractive?: boolean;
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.

non-blocking: the caller guarantees that when nonInteractive is true, targetVersion is defined (via the precondition at the top of runUpgrade). the types don't express this constraint though -- a new call site could call getSelectedRelease({nonInteractive: true}) without the precondition, and the error message below would interpolate undefined. the runtime guard makes this safe in practice, just noting the type-level information leakage.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I can fix it if necessary, would be a bit more work though.

cumulativeRelease,
currentVersion,
selectedRelease,
nonInteractive: nonInteractive || targetVersion === 'next',
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.

non-blocking: the caller computes the effective non-interactive state here (nonInteractive: nonInteractive || targetVersion === 'next'), but displayConfirmation handles it internally (if (targetVersion === 'next' || nonInteractive)). the same decision is split between two layers. this is pre-existing -- the targetVersion === 'next' check was already inside displayConfirmation -- and the PR correctly extends the pattern to generateUpgradeInstructionsFile. just noting the inconsistency for context.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The better handling would probably be not having this targetVersion === 'next' special handling at all and just relying on nonInteractive.

As it was in the code before I don't want to break things, it's like this now.

'Run without any interactive prompts. Requires --version. Auto-accepts the upgrade confirmation and overwrites any existing upgrade instructions file.',
env: 'SHOPIFY_HYDROGEN_FLAG_NON_INTERACTIVE',
char: 'y',
aliases: ['yes'],
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.

non-blocking: in the broader CLI ecosystem, --yes/-y traditionally means "auto-confirm" (think apt-get -y). here, --non-interactive goes a bit further -- it requires --version, auto-overwrites files, and changes TTY detection. a user who writes shopify hydrogen upgrade -y expecting auto-confirm behaviour will get a clear error message ("requires --version"), so it's mitigated in practice. just noting the potential UX friction.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think it's okay-ish here as you get immediate feedback if you've missed the --version.

Comment thread packages/cli/src/commands/hydrogen/upgrade.ts Outdated
Comment thread packages/cli/src/commands/hydrogen/upgrade.test.ts
Comment thread packages/cli/src/commands/hydrogen/upgrade-e2e.test.ts
Comment thread .changeset/upgrade-non-interactive.md
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