From 883fef07c50e4fb0cef7ffe72dad04e10a844dba Mon Sep 17 00:00:00 2001 From: vincentezw <59287019+vincentezw@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:29:46 +0000 Subject: [PATCH 1/4] Check for uncommited changes, write JSON output in CI --- .changeset/slimy-sloths-nail.md | 18 +++ examples/customer-api/package.json | 2 +- examples/express/package.json | 2 +- package-lock.json | 108 +++++++------- packages/cli/oclif.manifest.json | 15 ++ packages/cli/package.json | 4 +- .../cli/src/commands/hydrogen/deploy.test.ts | 135 +++++++++++++++++- packages/cli/src/commands/hydrogen/deploy.ts | 105 +++++++++++++- templates/demo-store/package.json | 2 +- templates/hello-world/package.json | 2 +- templates/skeleton/package.json | 2 +- 11 files changed, 320 insertions(+), 75 deletions(-) create mode 100644 .changeset/slimy-sloths-nail.md diff --git a/.changeset/slimy-sloths-nail.md b/.changeset/slimy-sloths-nail.md new file mode 100644 index 0000000000..f4d461c0d1 --- /dev/null +++ b/.changeset/slimy-sloths-nail.md @@ -0,0 +1,18 @@ +--- +'@shopify/cli-hydrogen': minor +--- + +The `deploy` command now displays an error if there are uncommited changes in a project's Git repository. If you'd like to go ahead with the deployment regardless, you can use the new `force` flag. +When deploying with uncommited changes, we use a default description in the form of ` with additional changes` (where `` represents the hash of the last commit). This description will be visible in the Shopify Admin for the deployment, and the `metadata-description` flag can be used to specify a different description. + +In CI environments, the `deploy` command now creates a file "h2_deploy_output.log" file in the current working directory, for successful deployments. This file holds a JSON object with the URL of the deployment. This can be useful for scripting purposes, where consequent steps in your CI workflow require the deployment URL. The flag `--no-json-output` can be used to prevent this behaviour. In the future, we may add further keys to the JSON object. + +Updated internal dependencies for bug resolution. +Please update the `@shopify/cli` dependency in your app to avoid duplicated subdependencies: + +```diff + "dependencies": { +- "@shopify/cli": "3.50.2", ++ "@shopify/cli": "3.51.0", + } +``` diff --git a/examples/customer-api/package.json b/examples/customer-api/package.json index d8268b4e5f..d83797e5a4 100644 --- a/examples/customer-api/package.json +++ b/examples/customer-api/package.json @@ -15,7 +15,7 @@ "dependencies": { "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.0", "@shopify/hydrogen": "^2023.10.0", "@shopify/remix-oxygen": "^2.0.0", diff --git a/examples/express/package.json b/examples/express/package.json index 8af88cf9f3..ab44dc2ca8 100644 --- a/examples/express/package.json +++ b/examples/express/package.json @@ -28,7 +28,7 @@ "devDependencies": { "@remix-run/dev": "2.1.0", "@remix-run/eslint-config": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@types/compression": "^1.7.2", "@types/express": "^4.17.17", diff --git a/package-lock.json b/package-lock.json index dedf3d0aff..0d797b9be8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,7 @@ "dependencies": { "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.0", "@shopify/hydrogen": "^2023.10.0", "@shopify/remix-oxygen": "^2.0.0", @@ -120,7 +120,7 @@ "devDependencies": { "@remix-run/dev": "2.1.0", "@remix-run/eslint-config": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@types/compression": "^1.7.2", "@types/express": "^4.17.17", @@ -7493,9 +7493,9 @@ "license": "MIT" }, "node_modules/@shopify/cli": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@shopify/cli/-/cli-3.50.2.tgz", - "integrity": "sha512-7Lzgcpk/Ic/mKb4cvXy9CLlU3/VPs0ZLD/8rviL+yV35th/rsYeoeEpTO2xzzYTkhdcQMJM0+TzsggS3sQLKeQ==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@shopify/cli/-/cli-3.51.0.tgz", + "integrity": "sha512-0cnXHjltH7ql/UpUBpIgjvxkZ8tzJz4mq7FapuFqGSX7uMkfAJrWWCCmZsFbO3EtojBJ0vV60dIX0wsfrTyDYg==", "os": [ "darwin", "linux", @@ -7506,8 +7506,8 @@ "@oclif/plugin-commands": "2.2.24", "@oclif/plugin-help": "5.2.18", "@oclif/plugin-plugins": "3.1.8", - "@shopify/cli-kit": "3.50.2", - "@shopify/plugin-did-you-mean": "3.50.2", + "@shopify/cli-kit": "3.51.0", + "@shopify/plugin-did-you-mean": "3.51.0", "zod-to-json-schema": "3.21.4" }, "bin": { @@ -7522,9 +7522,9 @@ "link": true }, "node_modules/@shopify/cli-kit": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@shopify/cli-kit/-/cli-kit-3.50.2.tgz", - "integrity": "sha512-EqScyHo9EudDz6nGpvwBbkjUmDx5g8Uhy0Ls05ZTWBqGMP9tm9RdLqRYjyq6q6iEjrBMgois4Bw9De6Zcf9JOw==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@shopify/cli-kit/-/cli-kit-3.51.0.tgz", + "integrity": "sha512-9lnkgjKrgeV7mfEiM0uA+FotyvmNh9Op93dtkTgYSkyc4ungdrW6W8sMSGOqVWXUIkJvIZi1bNLOZ0Csk+B6WQ==", "os": [ "darwin", "linux", @@ -7594,7 +7594,7 @@ "terminal-link": "3.0.0", "ts-error": "1.0.6", "unique-string": "3.0.0", - "zod": "3.22.2" + "zod": "3.22.3" }, "engines": { "node": ">=14.17.0" @@ -7966,9 +7966,9 @@ "link": true }, "node_modules/@shopify/oxygen-cli": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@shopify/oxygen-cli/-/oxygen-cli-2.6.1.tgz", - "integrity": "sha512-MFQP96Dna5t4WxIRWcqmsOGKDB3AJstxo0WogJRcWnytXqy/gyenWzGJYE02BPDWGQLQFCZMW8DUO+qmHSsZkg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@shopify/oxygen-cli/-/oxygen-cli-2.6.2.tgz", + "integrity": "sha512-vN5G3HmMNgy0VKZw0VWPVndQpCELzVBLHrflp6Edn4te/iVwXJXQLyIqWGGoTz/pfmyo9eF1qV4e18rTvI1afw==", "os": [ "darwin", "linux", @@ -7979,7 +7979,7 @@ "@bugsnag/js": "^7.21.0", "@bugsnag/node": "^7.19.0", "@oclif/core": "2.11.7", - "@shopify/cli-kit": "^3.50.2", + "@shopify/cli-kit": "^3.51.0", "async": "^3.2.5" }, "bin": { @@ -7997,9 +7997,9 @@ "hasInstallScript": true }, "node_modules/@shopify/plugin-did-you-mean": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@shopify/plugin-did-you-mean/-/plugin-did-you-mean-3.50.2.tgz", - "integrity": "sha512-7i8HlEq06YIq8c3qfkoqa9uO5PhNmf6Cj5V/LZWzmhJgIPeXndJvrAxomyYwAHBugDm6Zx/kKEcIOlk4O4ZQFw==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@shopify/plugin-did-you-mean/-/plugin-did-you-mean-3.51.0.tgz", + "integrity": "sha512-E7blfd/el4Xryg4cl3Hfwia2KrqYMdK0V5ccoyW/hVY4zlZJzdHRI2w9Ix1cETcCsMo/QQMN0+wWnHw80GZufQ==", "os": [ "darwin", "linux", @@ -8007,7 +8007,7 @@ ], "dependencies": { "@oclif/core": "2.11.7", - "@shopify/cli-kit": "3.50.2", + "@shopify/cli-kit": "3.51.0", "n-gram": "2.0.2" }, "engines": { @@ -29846,9 +29846,9 @@ } }, "node_modules/zod": { - "version": "3.22.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", - "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", + "version": "3.22.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", + "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -29878,10 +29878,10 @@ "@ast-grep/napi": "0.11.0", "@graphql-codegen/cli": "5.0.0", "@oclif/core": "2.11.7", - "@shopify/cli-kit": "3.50.2", + "@shopify/cli-kit": "3.51.0", "@shopify/hydrogen-codegen": "^0.1.0", "@shopify/mini-oxygen": "^2.2.3", - "@shopify/oxygen-cli": "2.6.1", + "@shopify/oxygen-cli": "2.6.2", "ansi-escapes": "^6.2.0", "diff": "^5.1.0", "fs-extra": "^11.1.0", @@ -30542,7 +30542,7 @@ "@headlessui/react": "^1.7.2", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/hydrogen": "~2023.10.2", "@shopify/remix-oxygen": "^2.0.1", @@ -30591,7 +30591,7 @@ "dependencies": { "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/hydrogen": "~2023.10.2", "@shopify/remix-oxygen": "^2.0.1", @@ -30623,7 +30623,7 @@ "dependencies": { "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.0", "@shopify/hydrogen": "~2023.10.2", "@shopify/remix-oxygen": "^2.0.1", @@ -35563,16 +35563,16 @@ "dev": true }, "@shopify/cli": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@shopify/cli/-/cli-3.50.2.tgz", - "integrity": "sha512-7Lzgcpk/Ic/mKb4cvXy9CLlU3/VPs0ZLD/8rviL+yV35th/rsYeoeEpTO2xzzYTkhdcQMJM0+TzsggS3sQLKeQ==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@shopify/cli/-/cli-3.51.0.tgz", + "integrity": "sha512-0cnXHjltH7ql/UpUBpIgjvxkZ8tzJz4mq7FapuFqGSX7uMkfAJrWWCCmZsFbO3EtojBJ0vV60dIX0wsfrTyDYg==", "requires": { "@oclif/core": "2.11.7", "@oclif/plugin-commands": "2.2.24", "@oclif/plugin-help": "5.2.18", "@oclif/plugin-plugins": "3.1.8", - "@shopify/cli-kit": "3.50.2", - "@shopify/plugin-did-you-mean": "3.50.2", + "@shopify/cli-kit": "3.51.0", + "@shopify/plugin-did-you-mean": "3.51.0", "zod-to-json-schema": "3.21.4" } }, @@ -35583,10 +35583,10 @@ "@graphql-codegen/cli": "5.0.0", "@oclif/core": "2.11.7", "@parcel/watcher": "^2.3.0", - "@shopify/cli-kit": "3.50.2", + "@shopify/cli-kit": "3.51.0", "@shopify/hydrogen-codegen": "^0.1.0", "@shopify/mini-oxygen": "^2.2.3", - "@shopify/oxygen-cli": "2.6.1", + "@shopify/oxygen-cli": "2.6.2", "@types/diff": "^5.0.2", "@types/fs-extra": "^11.0.1", "@types/gunzip-maybe": "^1.4.0", @@ -35697,9 +35697,9 @@ } }, "@shopify/cli-kit": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@shopify/cli-kit/-/cli-kit-3.50.2.tgz", - "integrity": "sha512-EqScyHo9EudDz6nGpvwBbkjUmDx5g8Uhy0Ls05ZTWBqGMP9tm9RdLqRYjyq6q6iEjrBMgois4Bw9De6Zcf9JOw==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@shopify/cli-kit/-/cli-kit-3.51.0.tgz", + "integrity": "sha512-9lnkgjKrgeV7mfEiM0uA+FotyvmNh9Op93dtkTgYSkyc4ungdrW6W8sMSGOqVWXUIkJvIZi1bNLOZ0Csk+B6WQ==", "requires": { "@bugsnag/js": "7.21.0", "@iarna/toml": "2.2.5", @@ -35764,7 +35764,7 @@ "terminal-link": "3.0.0", "ts-error": "1.0.6", "unique-string": "3.0.0", - "zod": "3.22.2" + "zod": "3.22.3" }, "dependencies": { "ansi-escapes": { @@ -36262,15 +36262,15 @@ } }, "@shopify/oxygen-cli": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@shopify/oxygen-cli/-/oxygen-cli-2.6.1.tgz", - "integrity": "sha512-MFQP96Dna5t4WxIRWcqmsOGKDB3AJstxo0WogJRcWnytXqy/gyenWzGJYE02BPDWGQLQFCZMW8DUO+qmHSsZkg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@shopify/oxygen-cli/-/oxygen-cli-2.6.2.tgz", + "integrity": "sha512-vN5G3HmMNgy0VKZw0VWPVndQpCELzVBLHrflp6Edn4te/iVwXJXQLyIqWGGoTz/pfmyo9eF1qV4e18rTvI1afw==", "requires": { "@bugsnag/core": "^7.19.0", "@bugsnag/js": "^7.21.0", "@bugsnag/node": "^7.19.0", "@oclif/core": "2.11.7", - "@shopify/cli-kit": "^3.50.2", + "@shopify/cli-kit": "^3.51.0", "async": "^3.2.5" } }, @@ -36281,12 +36281,12 @@ "dev": true }, "@shopify/plugin-did-you-mean": { - "version": "3.50.2", - "resolved": "https://registry.npmjs.org/@shopify/plugin-did-you-mean/-/plugin-did-you-mean-3.50.2.tgz", - "integrity": "sha512-7i8HlEq06YIq8c3qfkoqa9uO5PhNmf6Cj5V/LZWzmhJgIPeXndJvrAxomyYwAHBugDm6Zx/kKEcIOlk4O4ZQFw==", + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/@shopify/plugin-did-you-mean/-/plugin-did-you-mean-3.51.0.tgz", + "integrity": "sha512-E7blfd/el4Xryg4cl3Hfwia2KrqYMdK0V5ccoyW/hVY4zlZJzdHRI2w9Ix1cETcCsMo/QQMN0+wWnHw80GZufQ==", "requires": { "@oclif/core": "2.11.7", - "@shopify/cli-kit": "3.50.2", + "@shopify/cli-kit": "3.51.0", "n-gram": "2.0.2" } }, @@ -39004,7 +39004,7 @@ "@remix-run/dev": "2.1.0", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.0", "@shopify/hydrogen": "^2023.10.0", "@shopify/oxygen-workers-types": "^4.0.0", @@ -39247,7 +39247,7 @@ "@remix-run/eslint-config": "2.1.0", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/eslint-plugin": "^42.0.1", "@shopify/hydrogen": "~2023.10.2", @@ -41414,7 +41414,7 @@ "@remix-run/dev": "2.1.0", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/hydrogen": "~2023.10.2", "@shopify/oxygen-workers-types": "^4.0.0", @@ -41573,7 +41573,7 @@ "@remix-run/node": "2.1.0", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/hydrogen": "2023.10.2", "@types/compression": "^1.7.2", @@ -48385,7 +48385,7 @@ "@remix-run/eslint-config": "2.1.0", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.0", "@shopify/hydrogen": "~2023.10.2", "@shopify/oxygen-workers-types": "^4.0.0", @@ -50506,9 +50506,9 @@ } }, "zod": { - "version": "3.22.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", - "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==" + "version": "3.22.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", + "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==" }, "zod-to-json-schema": { "version": "3.21.4", diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 6f092c18c7..22ab204600 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -171,6 +171,14 @@ "required": false, "multiple": false }, + "force": { + "name": "force", + "type": "boolean", + "char": "f", + "description": "Allows a deployment to proceed if there are uncommited changes in the Git repository.", + "required": false, + "allowNo": false + }, "path": { "name": "path", "type": "option", @@ -199,6 +207,13 @@ "required": false, "multiple": false }, + "metadata-description": { + "name": "metadata-description", + "type": "option", + "description": "Description of the changes in the deployment. Defaults to the commit message of the latest commit if there are no uncommited changes.", + "required": false, + "multiple": false + }, "metadata-url": { "name": "metadata-url", "type": "option", diff --git a/packages/cli/package.json b/packages/cli/package.json index 843ccc2527..ad58bdf044 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -35,10 +35,10 @@ "@ast-grep/napi": "0.11.0", "@graphql-codegen/cli": "5.0.0", "@oclif/core": "2.11.7", - "@shopify/cli-kit": "3.50.2", + "@shopify/cli-kit": "3.51.0", "@shopify/hydrogen-codegen": "^0.1.0", "@shopify/mini-oxygen": "^2.2.3", - "@shopify/oxygen-cli": "2.6.1", + "@shopify/oxygen-cli": "2.6.2", "ansi-escapes": "^6.2.0", "diff": "^5.1.0", "fs-extra": "^11.1.0", diff --git a/packages/cli/src/commands/hydrogen/deploy.test.ts b/packages/cli/src/commands/hydrogen/deploy.test.ts index 78a05f3e5a..a54307ed2f 100644 --- a/packages/cli/src/commands/hydrogen/deploy.test.ts +++ b/packages/cli/src/commands/hydrogen/deploy.test.ts @@ -2,19 +2,28 @@ import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest'; import {type AdminSession, login} from '../../lib/auth.js'; import {getStorefronts} from '../../lib/graphql/admin/link-storefront.js'; import {AbortError} from '@shopify/cli-kit/node/error'; +import {writeFile} from '@shopify/cli-kit/node/fs'; import { renderSelectPrompt, renderFatalError, renderSuccess, + renderWarning, } from '@shopify/cli-kit/node/ui'; -import {getLatestGitCommit} from '@shopify/cli-kit/node/git'; +import { + ensureIsClean, + getLatestGitCommit, + GitDirectoryNotCleanError, +} from '@shopify/cli-kit/node/git'; import {deploymentLogger, oxygenDeploy} from './deploy.js'; import {getOxygenDeploymentData} from '../../lib/get-oxygen-deployment-data.js'; import {createDeploy, parseToken} from '@shopify/oxygen-cli/deploy'; +import {ciPlatform} from '@shopify/cli-kit/node/context/local'; vi.mock('../../lib/get-oxygen-deployment-data.js'); vi.mock('@shopify/oxygen-cli/deploy'); +vi.mock('@shopify/cli-kit/node/fs'); +vi.mock('@shopify/cli-kit/node/context/local'); vi.mock('../../lib/auth.js'); vi.mock('../../lib/shopify-config.js'); vi.mock('../../lib/graphql/admin/link-storefront.js'); @@ -34,16 +43,15 @@ vi.mock('@shopify/cli-kit/node/ui', async () => { renderSelectPrompt: vi.fn(), renderSuccess: vi.fn(), renderTasks: vi.fn(), + renderWarning: vi.fn(), }; }); vi.mock('@shopify/cli-kit/node/git', async () => { + const actual = await vi.importActual('@shopify/cli-kit/node/git'); return { + ...(actual as object), getLatestGitCommit: vi.fn(), - }; -}); -vi.mock('@shopify/cli-kit/node/context/local', async () => { - return { - ciPlatform: () => ({isCI: false}), + ensureIsClean: vi.fn(), }; }); @@ -70,6 +78,8 @@ describe('deploy', () => { const originalExit = process.exit; const deployParams = { + force: false, + noJsonOutput: false, path: './', shop: 'snowdevil.myshopify.com', publicDeployment: false, @@ -122,7 +132,7 @@ describe('deploy', () => { session: ADMIN_SESSION, config: UNLINKED_SHOPIFY_CONFIG, }); - + vi.mocked(ciPlatform).mockReturnValue({isCI: false}); vi.mocked(getStorefronts).mockResolvedValue([ { ...FULL_SHOPIFY_CONFIG.storefront, @@ -166,6 +176,92 @@ describe('deploy', () => { expect(vi.mocked(renderSuccess)).toHaveBeenCalled; }); + it('returns when there are uncommited changes', async () => { + vi.mocked(ensureIsClean).mockRejectedValue( + new GitDirectoryNotCleanError('Uncommitted changes'), + ); + + await oxygenDeploy(deployParams); + + expect(vi.mocked(createDeploy)).not.toHaveBeenCalled; + expect(vi.mocked(renderWarning)).toHaveBeenCalledWith({ + body: expect.stringContaining('Uncommitted changes detected'), + nextSteps: expect.anything(), + }); + }); + + it('proceeds with warning and modified description when there are uncommited changes and the force flag is used', async () => { + vi.mocked(ensureIsClean).mockRejectedValue( + new GitDirectoryNotCleanError('Uncommitted changes'), + ); + vi.mocked(getLatestGitCommit).mockResolvedValue({ + hash: '123', + message: 'test commit', + date: '2021-01-01', + author_name: 'test author', + author_email: 'test@author.com', + body: 'test body', + refs: 'HEAD -> main', + }); + + await oxygenDeploy({ + ...deployParams, + force: true, + }); + + expect(vi.mocked(renderWarning)).toHaveBeenCalledWith({ + body: expect.stringContaining('no description has been provided'), + nextSteps: expect.anything(), + }); + expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({ + config: { + ...expectedConfig, + environmentTag: 'main', + metadata: { + ...expectedConfig.metadata, + description: '123 with additional changes', + }, + }, + hooks: expectedHooks, + logger: deploymentLogger, + }); + }); + + it('proceeds with provided description without warning when there are uncommited changes and the force flag is used', async () => { + vi.mocked(ensureIsClean).mockRejectedValue( + new GitDirectoryNotCleanError('Uncommitted changes'), + ); + vi.mocked(getLatestGitCommit).mockResolvedValue({ + hash: '123', + message: 'test commit', + date: '2021-01-01', + author_name: 'test author', + author_email: 'test@author.com', + body: 'test body', + refs: 'HEAD -> main', + }); + + await oxygenDeploy({ + ...deployParams, + force: true, + metadataDescription: 'cool new stuff', + }); + + expect(vi.mocked(renderWarning)).not.toHaveBeenCalled; + expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({ + config: { + ...expectedConfig, + environmentTag: 'main', + metadata: { + ...expectedConfig.metadata, + description: 'cool new stuff', + }, + }, + hooks: expectedHooks, + logger: deploymentLogger, + }); + }); + it('calls createDeploy with the checked out branch name', async () => { vi.mocked(getLatestGitCommit).mockResolvedValue({ hash: '123', @@ -207,6 +303,31 @@ describe('deploy', () => { }); }); + it('writes a file with JSON content in CI environments', async () => { + vi.mocked(ciPlatform).mockReturnValue({ + isCI: true, + name: 'github', + metadata: {}, + }); + const ciDeployParams = { + ...deployParams, + token: 'some-token', + metadataDescription: 'cool new stuff', + }; + + await oxygenDeploy(ciDeployParams); + + expect(vi.mocked(writeFile)).toHaveBeenCalledWith( + 'h2_deploy_output.log', + JSON.stringify({url: 'https://a-lovely-deployment.com'}), + ); + + vi.mocked(writeFile).mockClear(); + ciDeployParams.noJsonOutput = true; + await oxygenDeploy(ciDeployParams); + expect(vi.mocked(writeFile)).not.toHaveBeenCalled(); + }); + it('handles error during uploadFiles', async () => { const mockRenderFatalError = vi.fn(); vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError); diff --git a/packages/cli/src/commands/hydrogen/deploy.ts b/packages/cli/src/commands/hydrogen/deploy.ts index 157e333df1..78b1b4cacb 100644 --- a/packages/cli/src/commands/hydrogen/deploy.ts +++ b/packages/cli/src/commands/hydrogen/deploy.ts @@ -7,13 +7,19 @@ import { outputWarn, } from '@shopify/cli-kit/node/output'; import {AbortError} from '@shopify/cli-kit/node/error'; -import {getLatestGitCommit} from '@shopify/cli-kit/node/git'; +import {writeFile} from '@shopify/cli-kit/node/fs'; +import { + ensureIsClean, + getLatestGitCommit, + GitDirectoryNotCleanError, +} from '@shopify/cli-kit/node/git'; import {resolvePath} from '@shopify/cli-kit/node/path'; import { renderFatalError, renderSelectPrompt, renderSuccess, renderTasks, + renderWarning, } from '@shopify/cli-kit/node/ui'; import {Logger, LogLevel} from '@shopify/cli-kit/node/output'; import {ciPlatform} from '@shopify/cli-kit/node/context/local'; @@ -45,6 +51,14 @@ export default class Deploy extends Command { description: 'Environment branch (tag) for environment to deploy to', required: false, }), + force: Flags.boolean({ + char: 'f', + description: + 'Forces a deployment to proceed if there are uncommited changes in its Git repository.', + default: false, + env: 'SHOPIFY_HYDROGEN_FLAG_FORCE', + required: false, + }), path: commonFlags.path, shop: commonFlags.shop, 'public-deployment': Flags.boolean({ @@ -53,12 +67,24 @@ export default class Deploy extends Command { required: false, default: false, }), + 'no-json-output': Flags.boolean({ + description: + 'Prevents the command from creating a JSON file containing the deployment URL (in CI environments).', + required: false, + default: false, + }), token: Flags.string({ char: 't', description: 'Oxygen deployment token', env: 'SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN', required: false, }), + 'metadata-description': Flags.string({ + description: + 'Description of the changes in the deployment. Defaults to the commit message of the latest commit if there are no uncommited changes.', + required: false, + env: 'SHOPIFY_HYDROGEN_FLAG_METADATA_DESCRIPTION', + }), 'metadata-url': Flags.string({ description: 'URL that links to the deployment. Will be saved and displayed in the Shopify admin', @@ -112,10 +138,13 @@ export default class Deploy extends Command { interface OxygenDeploymentOptions { environmentTag?: string; + force: boolean; + noJsonOutput: boolean; path: string; publicDeployment: boolean; shop: string; token?: string; + metadataDescription?: string; metadataUrl?: string; metadataUser?: string; metadataVersion?: string; @@ -123,6 +152,7 @@ interface OxygenDeploymentOptions { interface GitCommit { refs: string; + hash: string; } export async function oxygenDeploy( @@ -130,6 +160,8 @@ export async function oxygenDeploy( ): Promise { const { environmentTag, + force: forceOnUncommitedChanges, + noJsonOutput, path, shop, publicDeployment, @@ -137,9 +169,34 @@ export async function oxygenDeploy( metadataUser, metadataVersion, } = options; - const ci = ciPlatform(); + let {metadataDescription} = options; + + let isCleanGit = true; + try { + await ensureIsClean(path); + } catch (error) { + if (error instanceof GitDirectoryNotCleanError) { + isCleanGit = false; + } + if (!forceOnUncommitedChanges && !isCleanGit) { + renderWarning({ + body: 'Uncommitted changes detected.', + nextSteps: [ + [ + 'Commit your changes before deploying or use the ', + {command: '--force'}, + ' flag to deploy with uncommitted changes.', + ], + ], + }); + return; + } + } + + const isCI = ciPlatform().isCI; let token = options.token; let branch: string | undefined; + let commitHash: string | undefined; let deploymentData: OxygenDeploymentData | undefined; let deploymentEnvironmentTag: string | undefined = undefined; let gitCommit: GitCommit; @@ -147,12 +204,32 @@ export async function oxygenDeploy( try { gitCommit = await getLatestGitCommit(path); branch = (/HEAD -> ([^,]*)/.exec(gitCommit.refs) || [])[1]; + commitHash = gitCommit.hash; } catch (error) { outputWarn('Could not retrieve Git history.'); branch = undefined; } - if (!ci.isCI) { + if (!metadataDescription && !isCleanGit) { + renderWarning({ + body: 'Deploying uncommited changes, but no description has been provided.', + nextSteps: [ + [ + 'Use the ', + {command: '--metadata-description'}, + ' flag to provide a description.', + ], + [ + 'If no description is provided, the description defaults to ', + {userInput: ' with additional changes'}, + ' using the SHA of the last commit.', + ], + ], + }); + metadataDescription = `${commitHash} with additional changes`; + } + + if (!isCI) { deploymentData = await getOxygenDeploymentData({ root: path, flagShop: shop, @@ -166,7 +243,7 @@ export async function oxygenDeploy( } if (!token) { - const errMessage = ci.isCI + const errMessage = isCI ? [ 'No deployment token provided. Use the ', {command: '--token'}, @@ -176,7 +253,7 @@ export async function oxygenDeploy( throw new AbortError(errMessage); } - if (!ci.isCI && !environmentTag && deploymentData?.environments) { + if (!isCI && !environmentTag && deploymentData?.environments) { if (deploymentData.environments.length > 1) { const choices = [ ...deploymentData.environments.map(({name, branch}) => ({ @@ -197,14 +274,23 @@ export async function oxygenDeploy( } } + let deploymentUrl = 'https://oxygen.shopifyapps.com'; + if (process.env.UNSAFE_SHOPIFY_HYDROGEN_DEPLOYMENT_URL) { + deploymentUrl = process.env.UNSAFE_SHOPIFY_HYDROGEN_DEPLOYMENT_URL; + outputWarn( + "Using a custom deployment service. Don't do this in production!", + ); + } + const config: DeploymentConfig = { assetsDir: 'dist/client', bugsnag: true, - deploymentUrl: 'https://oxygen.shopifyapps.com', + deploymentUrl, deploymentToken: parseToken(token as string), environmentTag: environmentTag || deploymentEnvironmentTag || branch, verificationMaxDuration: 180, metadata: { + ...(metadataDescription ? {description: metadataDescription} : {}), ...(metadataUrl ? {url: metadataUrl} : {}), ...(metadataUser ? {user: metadataUser} : {}), ...(metadataVersion ? {version: metadataVersion} : {}), @@ -281,7 +367,7 @@ export async function oxygenDeploy( }; await createDeploy({config, hooks, logger: deploymentLogger}) - .then((url: string | undefined) => { + .then(async (url: string | undefined) => { const deploymentType = config.publicDeployment ? 'public' : 'private'; renderSuccess({ body: ['Successfully deployed to Oxygen'], @@ -291,6 +377,11 @@ export async function oxygenDeploy( ], ], }); + // in CI environments, output to a file so consequent steps can access the URL + // the formatting of this file is likely to change in future versions. + if (isCI && !noJsonOutput) { + await writeFile('h2_deploy_output.log', JSON.stringify({url: url!})); + } resolveDeploy(); }) .catch((error) => { diff --git a/templates/demo-store/package.json b/templates/demo-store/package.json index 0d937edbbd..f314f0821f 100644 --- a/templates/demo-store/package.json +++ b/templates/demo-store/package.json @@ -20,7 +20,7 @@ "@headlessui/react": "^1.7.2", "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/hydrogen": "~2023.10.2", "@shopify/remix-oxygen": "^2.0.1", diff --git a/templates/hello-world/package.json b/templates/hello-world/package.json index a72d70db95..a5c001085d 100644 --- a/templates/hello-world/package.json +++ b/templates/hello-world/package.json @@ -15,7 +15,7 @@ "dependencies": { "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.2", "@shopify/hydrogen": "~2023.10.2", "@shopify/remix-oxygen": "^2.0.1", diff --git a/templates/skeleton/package.json b/templates/skeleton/package.json index 276d3bcca6..ea7099cf11 100644 --- a/templates/skeleton/package.json +++ b/templates/skeleton/package.json @@ -15,7 +15,7 @@ "dependencies": { "@remix-run/react": "2.1.0", "@remix-run/server-runtime": "2.1.0", - "@shopify/cli": "3.50.2", + "@shopify/cli": "3.51.0", "@shopify/cli-hydrogen": "^6.0.0", "@shopify/hydrogen": "~2023.10.2", "@shopify/remix-oxygen": "^2.0.1", From 9258916bdae731ca95ca7bd3e9ae57b1499185fe Mon Sep 17 00:00:00 2001 From: Vincent Zwanenburg Date: Wed, 15 Nov 2023 15:17:12 +0000 Subject: [PATCH 2/4] fix typecheck issues, allow bun as cli command --- packages/cli/oclif.manifest.json | 9 ++++++++- packages/cli/src/commands/hydrogen/dev.ts | 1 + packages/cli/src/commands/hydrogen/shortcut.ts | 1 + packages/cli/src/lib/check-lockfile.ts | 1 + packages/cli/src/lib/codegen.ts | 1 + packages/cli/src/lib/log.ts | 1 + packages/cli/src/lib/onboarding/common.ts | 2 +- packages/cli/src/lib/render-errors.ts | 2 ++ packages/cli/src/lib/shell.ts | 7 ++++--- 9 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 22ab204600..3cc3ce33e7 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -175,7 +175,7 @@ "name": "force", "type": "boolean", "char": "f", - "description": "Allows a deployment to proceed if there are uncommited changes in the Git repository.", + "description": "Forces a deployment to proceed if there are uncommited changes in its Git repository.", "required": false, "allowNo": false }, @@ -199,6 +199,13 @@ "required": false, "allowNo": false }, + "no-json-output": { + "name": "no-json-output", + "type": "boolean", + "description": "Prevents the command from creating a JSON file containing the deployment URL (in CI environments).", + "required": false, + "allowNo": false + }, "token": { "name": "token", "type": "option", diff --git a/packages/cli/src/commands/hydrogen/dev.ts b/packages/cli/src/commands/hydrogen/dev.ts index 813bc487af..f4b4e56ca9 100644 --- a/packages/cli/src/commands/hydrogen/dev.ts +++ b/packages/cli/src/commands/hydrogen/dev.ts @@ -249,6 +249,7 @@ async function runDev({ type: 0, message: 'MiniOxygen cannot start because the server bundle has not been generated.', + skipOclifErrorHandling: true, tryMessage: 'This is likely due to an error in your app and Remix is unable to compile. Try fixing the app and MiniOxygen will start.', }); diff --git a/packages/cli/src/commands/hydrogen/shortcut.ts b/packages/cli/src/commands/hydrogen/shortcut.ts index 821a765747..5a2fdeaa35 100644 --- a/packages/cli/src/commands/hydrogen/shortcut.ts +++ b/packages/cli/src/commands/hydrogen/shortcut.ts @@ -24,6 +24,7 @@ export async function runCreateShortcut() { name: 'error', type: 0, message: 'No supported shell found.', + skipOclifErrorHandling: true, tryMessage: 'Please create a shortcut manually.', }); } diff --git a/packages/cli/src/lib/check-lockfile.ts b/packages/cli/src/lib/check-lockfile.ts index 9310084089..9461508203 100644 --- a/packages/cli/src/lib/check-lockfile.ts +++ b/packages/cli/src/lib/check-lockfile.ts @@ -33,6 +33,7 @@ function missingLockfileWarning(shouldExit: boolean) { function multipleLockfilesWarning(lockfiles: Lockfile[], shouldExit: boolean) { const packageManagers = { + 'bun.lockb': 'bun', 'yarn.lock': 'yarn', 'package-lock.json': 'npm', 'pnpm-lock.yaml': 'pnpm', diff --git a/packages/cli/src/lib/codegen.ts b/packages/cli/src/lib/codegen.ts index ed15a16e7f..68b0dafbd2 100644 --- a/packages/cli/src/lib/codegen.ts +++ b/packages/cli/src/lib/codegen.ts @@ -80,6 +80,7 @@ export function spawnCodegenProcess({ type: 0, name: 'CodegenError', message: `Codegen process exited with code ${code}`, + skipOclifErrorHandling: true, tryMessage: 'Try restarting the dev server.', }); diff --git a/packages/cli/src/lib/log.ts b/packages/cli/src/lib/log.ts index 7f658dbc65..f7d8ae0505 100644 --- a/packages/cli/src/lib/log.ts +++ b/packages/cli/src/lib/log.ts @@ -372,6 +372,7 @@ export function createRemixLogger() { name: 'error', type: 0, message: buildMessageBody(message, options?.details), + skipOclifErrorHandling: true, tryMessage: '', }); }, diff --git a/packages/cli/src/lib/onboarding/common.ts b/packages/cli/src/lib/onboarding/common.ts index 8c340a1c5b..2c68539b7f 100644 --- a/packages/cli/src/lib/onboarding/common.ts +++ b/packages/cli/src/lib/onboarding/common.ts @@ -503,7 +503,7 @@ export async function commitAll(directory: string, message: string) { export type SetupSummary = { language?: Language; - packageManager: 'npm' | 'pnpm' | 'yarn' | 'unknown'; + packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun' | 'unknown'; cssStrategy?: CssStrategy; hasCreatedShortcut: boolean; depsInstalled: boolean; diff --git a/packages/cli/src/lib/render-errors.ts b/packages/cli/src/lib/render-errors.ts index fb629815db..f7e2b1952b 100644 --- a/packages/cli/src/lib/render-errors.ts +++ b/packages/cli/src/lib/render-errors.ts @@ -22,6 +22,7 @@ export function renderMissingStorefront({ message: outputContent`${outputToken.errorText( 'Couldn’t find Hydrogen storefront.', )}`.value, + skipOclifErrorHandling: true, tryMessage: outputContent`Couldn’t find ${storefront.title} (ID: ${parseGid( storefront.id, )}) on ${ @@ -45,6 +46,7 @@ export function renderMissingLink({session, cliCommand}: MissingLink) { name: 'NoLinkedStorefrontError', type: 0, message: `No linked Hydrogen storefront on ${session.storeFqdn}`, + skipOclifErrorHandling: true, tryMessage: [ 'To pull environment variables or to deploy to Oxygen, link this project to a Hydrogen storefront. To select a storefront to link, run', {command: `${cliCommand} link`}, diff --git a/packages/cli/src/lib/shell.ts b/packages/cli/src/lib/shell.ts index cecd2d5bf1..7771d6e991 100644 --- a/packages/cli/src/lib/shell.ts +++ b/packages/cli/src/lib/shell.ts @@ -206,17 +206,18 @@ async function createShortcutsForWindows() { export async function getCliCommand( directory = process.cwd(), - forcePkgManager?: 'npm' | 'pnpm' | 'yarn' | 'unknown', + forcePkgManager?: 'npm' | 'pnpm' | 'yarn' | 'bun' | 'unknown', ) { if (!forcePkgManager && (await hasCliAlias())) { return ALIAS_NAME; } - let cli: 'npx' | 'pnpm' | 'yarn' = 'npx'; + let cli: 'bun' | 'npx' | 'pnpm' | 'yarn' = 'npx'; const pkgManager = forcePkgManager ?? (await getPackageManager(directory).catch(() => null)); - if (pkgManager === 'pnpm' || pkgManager === 'yarn') cli = pkgManager; + if (pkgManager === 'bun' || pkgManager === 'pnpm' || pkgManager === 'yarn') + cli = pkgManager; return `${cli} shopify hydrogen` as const; } From 38e870643f1d7ac6cb3836d40fe9e69edeec9e35 Mon Sep 17 00:00:00 2001 From: Vincent Zwanenburg Date: Thu, 16 Nov 2023 10:39:02 +0000 Subject: [PATCH 3/4] PR feedback --- .changeset/happy-eagles-attack.md | 13 +++++++ .changeset/slimy-sloths-nail.md | 12 +----- .../cli/src/commands/hydrogen/deploy.test.ts | 20 +++++----- packages/cli/src/commands/hydrogen/deploy.ts | 38 ++++++++----------- 4 files changed, 40 insertions(+), 43 deletions(-) create mode 100644 .changeset/happy-eagles-attack.md diff --git a/.changeset/happy-eagles-attack.md b/.changeset/happy-eagles-attack.md new file mode 100644 index 0000000000..a4c2126fc3 --- /dev/null +++ b/.changeset/happy-eagles-attack.md @@ -0,0 +1,13 @@ +--- +'skeleton': patch +--- + +Updated internal dependencies for bug resolution. +Please update the `@shopify/cli` dependency in your app to avoid duplicated subdependencies: + +```diff + "dependencies": { +- "@shopify/cli": "3.50.2", ++ "@shopify/cli": "3.51.0", + } +``` diff --git a/.changeset/slimy-sloths-nail.md b/.changeset/slimy-sloths-nail.md index f4d461c0d1..4514ad592c 100644 --- a/.changeset/slimy-sloths-nail.md +++ b/.changeset/slimy-sloths-nail.md @@ -5,14 +5,4 @@ The `deploy` command now displays an error if there are uncommited changes in a project's Git repository. If you'd like to go ahead with the deployment regardless, you can use the new `force` flag. When deploying with uncommited changes, we use a default description in the form of ` with additional changes` (where `` represents the hash of the last commit). This description will be visible in the Shopify Admin for the deployment, and the `metadata-description` flag can be used to specify a different description. -In CI environments, the `deploy` command now creates a file "h2_deploy_output.log" file in the current working directory, for successful deployments. This file holds a JSON object with the URL of the deployment. This can be useful for scripting purposes, where consequent steps in your CI workflow require the deployment URL. The flag `--no-json-output` can be used to prevent this behaviour. In the future, we may add further keys to the JSON object. - -Updated internal dependencies for bug resolution. -Please update the `@shopify/cli` dependency in your app to avoid duplicated subdependencies: - -```diff - "dependencies": { -- "@shopify/cli": "3.50.2", -+ "@shopify/cli": "3.51.0", - } -``` +In CI environments, the `deploy` command now creates a file "h2_deploy_output_log.json" file in the current working directory, for successful deployments. This file holds a JSON object with the URL of the deployment. This can be useful for scripting purposes, where consequent steps in your CI workflow require the deployment URL. The flag `--no-json-output` can be used to prevent this behaviour. In the future, we may add further keys to the JSON object. diff --git a/packages/cli/src/commands/hydrogen/deploy.test.ts b/packages/cli/src/commands/hydrogen/deploy.test.ts index a54307ed2f..9bab7a0be8 100644 --- a/packages/cli/src/commands/hydrogen/deploy.test.ts +++ b/packages/cli/src/commands/hydrogen/deploy.test.ts @@ -176,18 +176,20 @@ describe('deploy', () => { expect(vi.mocked(renderSuccess)).toHaveBeenCalled; }); - it('returns when there are uncommited changes', async () => { + it('errors when there are uncommited changes', async () => { vi.mocked(ensureIsClean).mockRejectedValue( new GitDirectoryNotCleanError('Uncommitted changes'), ); - await oxygenDeploy(deployParams); + try { + await oxygenDeploy(deployParams); + } catch (error) { + expect(error).toBeInstanceOf(AbortError); + const abortError = error as AbortError; + expect(abortError.message).toBe('Uncommitted changes detected.'); + } expect(vi.mocked(createDeploy)).not.toHaveBeenCalled; - expect(vi.mocked(renderWarning)).toHaveBeenCalledWith({ - body: expect.stringContaining('Uncommitted changes detected'), - nextSteps: expect.anything(), - }); }); it('proceeds with warning and modified description when there are uncommited changes and the force flag is used', async () => { @@ -210,8 +212,8 @@ describe('deploy', () => { }); expect(vi.mocked(renderWarning)).toHaveBeenCalledWith({ - body: expect.stringContaining('no description has been provided'), - nextSteps: expect.anything(), + headline: 'No deployment description provided', + body: expect.anything(), }); expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({ config: { @@ -318,7 +320,7 @@ describe('deploy', () => { await oxygenDeploy(ciDeployParams); expect(vi.mocked(writeFile)).toHaveBeenCalledWith( - 'h2_deploy_output.log', + 'h2_deploy_log.json', JSON.stringify({url: 'https://a-lovely-deployment.com'}), ); diff --git a/packages/cli/src/commands/hydrogen/deploy.ts b/packages/cli/src/commands/hydrogen/deploy.ts index 78b1b4cacb..eec824f18d 100644 --- a/packages/cli/src/commands/hydrogen/deploy.ts +++ b/packages/cli/src/commands/hydrogen/deploy.ts @@ -178,18 +178,15 @@ export async function oxygenDeploy( if (error instanceof GitDirectoryNotCleanError) { isCleanGit = false; } + if (!forceOnUncommitedChanges && !isCleanGit) { - renderWarning({ - body: 'Uncommitted changes detected.', - nextSteps: [ - [ - 'Commit your changes before deploying or use the ', - {command: '--force'}, - ' flag to deploy with uncommitted changes.', - ], + throw new AbortError('Uncommitted changes detected.', null, [ + [ + 'Commit your changes before deploying or use the ', + {command: '--force'}, + ' flag to deploy with uncommitted changes.', ], - }); - return; + ]); } } @@ -212,18 +209,13 @@ export async function oxygenDeploy( if (!metadataDescription && !isCleanGit) { renderWarning({ - body: 'Deploying uncommited changes, but no description has been provided.', - nextSteps: [ - [ - 'Use the ', - {command: '--metadata-description'}, - ' flag to provide a description.', - ], - [ - 'If no description is provided, the description defaults to ', - {userInput: ' with additional changes'}, - ' using the SHA of the last commit.', - ], + headline: 'No deployment description provided', + body: [ + 'Deploying uncommited changes, but no description has been provided. Use the ', + {command: '--metadata-description'}, + 'flag to provide a description. If no description is provided, the description defaults to ', + {userInput: ' with additional changes'}, + ' using the SHA of the last commit.', ], }); metadataDescription = `${commitHash} with additional changes`; @@ -380,7 +372,7 @@ export async function oxygenDeploy( // in CI environments, output to a file so consequent steps can access the URL // the formatting of this file is likely to change in future versions. if (isCI && !noJsonOutput) { - await writeFile('h2_deploy_output.log', JSON.stringify({url: url!})); + await writeFile('h2_deploy_log.json', JSON.stringify({url: url!})); } resolveDeploy(); }) From 0b49695a555c344fd8c29357eb65653a1fca6518 Mon Sep 17 00:00:00 2001 From: Vincent Zwanenburg Date: Fri, 17 Nov 2023 10:46:44 +0000 Subject: [PATCH 4/4] simplify test, remove changelog --- .changeset/slimy-sloths-nail.md | 8 -------- packages/cli/src/commands/hydrogen/deploy.test.ts | 12 +++--------- 2 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 .changeset/slimy-sloths-nail.md diff --git a/.changeset/slimy-sloths-nail.md b/.changeset/slimy-sloths-nail.md deleted file mode 100644 index 4514ad592c..0000000000 --- a/.changeset/slimy-sloths-nail.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@shopify/cli-hydrogen': minor ---- - -The `deploy` command now displays an error if there are uncommited changes in a project's Git repository. If you'd like to go ahead with the deployment regardless, you can use the new `force` flag. -When deploying with uncommited changes, we use a default description in the form of ` with additional changes` (where `` represents the hash of the last commit). This description will be visible in the Shopify Admin for the deployment, and the `metadata-description` flag can be used to specify a different description. - -In CI environments, the `deploy` command now creates a file "h2_deploy_output_log.json" file in the current working directory, for successful deployments. This file holds a JSON object with the URL of the deployment. This can be useful for scripting purposes, where consequent steps in your CI workflow require the deployment URL. The flag `--no-json-output` can be used to prevent this behaviour. In the future, we may add further keys to the JSON object. diff --git a/packages/cli/src/commands/hydrogen/deploy.test.ts b/packages/cli/src/commands/hydrogen/deploy.test.ts index 9bab7a0be8..3bb5aca1bc 100644 --- a/packages/cli/src/commands/hydrogen/deploy.test.ts +++ b/packages/cli/src/commands/hydrogen/deploy.test.ts @@ -180,15 +180,9 @@ describe('deploy', () => { vi.mocked(ensureIsClean).mockRejectedValue( new GitDirectoryNotCleanError('Uncommitted changes'), ); - - try { - await oxygenDeploy(deployParams); - } catch (error) { - expect(error).toBeInstanceOf(AbortError); - const abortError = error as AbortError; - expect(abortError.message).toBe('Uncommitted changes detected.'); - } - + await expect(oxygenDeploy(deployParams)).rejects.toThrowError( + 'Uncommitted changes detected', + ); expect(vi.mocked(createDeploy)).not.toHaveBeenCalled; });