diff --git a/.github/workflows/chromatic-main-and-prs.yml b/.github/workflows/chromatic-main-and-prs.yml index 93f084bad..ddf8ab522 100644 --- a/.github/workflows/chromatic-main-and-prs.yml +++ b/.github/workflows/chromatic-main-and-prs.yml @@ -18,7 +18,7 @@ jobs: node-version: lts/* - name: install run: yarn install --frozen-lockfile - - uses: chromaui/action@v1 + - uses: chromaui/action@latest with: # 👇 Chromatic projectToken, refer to the manage page to obtain it. projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} diff --git a/.github/workflows/chromatic-prod.yml b/.github/workflows/chromatic-prod.yml index 5d962c9fe..56436b07d 100644 --- a/.github/workflows/chromatic-prod.yml +++ b/.github/workflows/chromatic-prod.yml @@ -13,7 +13,7 @@ jobs: node-version: lts/* - name: install run: yarn install --frozen-lockfile - - uses: chromaui/action-next@v1 + - uses: chromaui/action@latest with: exitOnceUploaded: true onlyChanged: true diff --git a/.github/workflows/chromatic-staging.yml b/.github/workflows/chromatic-staging.yml index 05869428f..6a982dcea 100644 --- a/.github/workflows/chromatic-staging.yml +++ b/.github/workflows/chromatic-staging.yml @@ -13,7 +13,7 @@ jobs: node-version: lts/* - name: install run: yarn install --frozen-lockfile - - uses: chromaui/action-canary@v1 + - uses: chromaui/action-canary@latest with: exitOnceUploaded: true onlyChanged: true diff --git a/README.md b/README.md index 0a9597c74..33dd732f2 100644 --- a/README.md +++ b/README.md @@ -81,20 +81,18 @@ We use `auto` to automate the release process. Versions are bumped, tags are cre Additionally, a PR **may** have exactly one of these labels: -- `release` creates a `latest` rather than a `next` release on npm -- `next-release` creates a `next` rather than a `latest` release on npm -- `skip-release` does not create a release at all +- `release` creates a `latest` release on npm +- `skip-release` does not create a release at all (changes roll into the next release) -We have three types of releases: +We have two types of releases: - `latest` releases are the general audience production releases, used by most people. Automatically created when merging a PR with the `release` label. -- `next` releases should be valid, working releases that can potentially be used by early adopters of new features, for example to handle a support request. Automatically created when merging a PR with the `next-release` label. -- `canary` releases are intended for testing purposes and should not be used in production, as they may only work against a staging or dev environment. Automatically created on every PR, but does not auto-publush the GitHub Action. +- `canary` releases are intended for testing purposes and should not be used in production, as they may only work against a staging or dev environment. Automatically created on every PR, but does not auto-publish the GitHub Action. -> For GitHub Actions, we publish `chromaui/action-next` and `chromaui/action-canary`. The latter is only published manually, rather than for every PR. +> For GitHub Actions, we may manually publish `chromaui/action-canary`. A script is provided to manually publish the GitHub Action, though it's typically only necessary for `action-canary` releases: ```sh -yarn publish-action +yarn publish-action ``` diff --git a/scripts/publish-action.mjs b/scripts/publish-action.mjs index 3811e12c4..0564e196c 100755 --- a/scripts/publish-action.mjs +++ b/scripts/publish-action.mjs @@ -1,38 +1,48 @@ #!/usr/bin/env node import cpy from 'cpy'; -import { execaCommand } from 'execa'; +import { $ } from 'execa'; import tmp from 'tmp-promise'; -const command = (cmd, opts) => execaCommand(cmd, { stdio: 'inherit', ...opts }); +const copy = (globs, ...args) => { + console.info(`📦 Copying:\n - ${globs.join('\n - ')}`); + return cpy(globs, ...args); +}; -const publishAction = async ({ version, repo }) => { +const publishAction = async ({ major, version, repo }) => { const dryRun = process.argv.includes('--dry-run'); - console.info(`✅ Publishing ${version} to ${repo} ${dryRun ? '(dry run)' : ''}`); + console.info(`🚀 Publishing ${version} to ${repo} ${dryRun ? '(dry run)' : ''}`); const { path, cleanup } = await tmp.dir({ unsafeCleanup: true, prefix: `chromatic-action-` }); - const run = (cmd) => command(cmd, { cwd: path }); - await cpy(['action/*.js', 'action/*.json', 'action.yml', 'package.json'], path, { - parents: true, + await copy(['action/*.js', 'action/*.json', 'action.yml', 'package.json'], path, { + parents: true, // keep directory structure (i.e. action dir) }); - await cpy(['action-src/CHANGELOG.md', 'action-src/LICENSE', 'action-src/README.md'], path); + await copy(['action-src/CHANGELOG.md', 'action-src/LICENSE', 'action-src/README.md'], path); + + const $$ = (strings, ...args) => { + console.info(strings.reduce((acc, s, i) => `${acc}${s}${args[i] || ''}`, '🏃 ')); + return $({ cwd: path })(strings, ...args); + }; - await run('git init -b main'); - await run('git config user.name "Chromatic"'); - await run('git config user.email "support@chromatic.com"'); - await run(`git remote add origin https://${process.env.GH_TOKEN}@github.com/${repo}.git`); - await run('git add .'); - await run(`git commit -m ${version}`); - await run('git tag -f v1'); // For backwards compatibility - await run('git tag -f latest'); + await $$`git init -b main`; + await $$`git config user.name Chromatic`; + await $$`git config user.email support@chromatic.com`; + await $$`git remote add origin https://${process.env.GH_TOKEN}@github.com/${repo}.git`; + await $$`git add .`; + await $$`git commit -m v${version}`; + await $$`git tag -a v${version} -m ${`v${version} without automatic upgrades (pinned)`}`; + await $$`git tag -a v${major} -m ${`v${version} with automatic upgrades to v${major}.x.x`}`; + await $$`git tag -a v1 -m ${`Deprecated, use 'latest' tag instead`}`; + await $$`git tag -a latest -m ${`v${version} with automatic upgrades to all versions`}`; if (dryRun) { console.info('✅ Skipping git push due to --dry-run'); } else { - await run('git push origin HEAD:main --force'); - await run('git push --tags --force'); + await $$`git push origin HEAD:main --force`; + await $$`git push --tags --force`; + console.info('✅ Done'); } return cleanup(); @@ -49,7 +59,7 @@ const publishAction = async ({ version, repo }) => { * Make sure to build the action before publishing manually. */ (async () => { - const { stdout: status } = await execaCommand('git status --porcelain'); + const { stdout: status } = await $`git status --porcelain`; if (status) { console.error(`❗️ Working directory is not clean:\n${status}`); return; @@ -63,7 +73,7 @@ const publishAction = async ({ version, repo }) => { return; } - const { stdout: branch } = await execaCommand('git rev-parse --abbrev-ref HEAD'); + const { stdout: branch } = await $`git rev-parse --abbrev-ref HEAD`; const defaultTag = branch === 'main' ? 'latest' : 'canary'; const context = ['canary', 'next', 'latest'].includes(process.argv[2]) ? process.argv[2] @@ -76,13 +86,13 @@ const publishAction = async ({ version, repo }) => { console.info('Run `yarn publish-action canary` to publish a canary action.'); return; } - await publishAction({ version: pkg.version, repo: 'chromaui/action-canary' }); + await publishAction({ major, version: pkg.version, repo: 'chromaui/action-canary' }); break; case 'next': - await publishAction({ version: pkg.version, repo: 'chromaui/action-next' }); + await publishAction({ major, version: pkg.version, repo: 'chromaui/action-next' }); break; case 'latest': - await publishAction({ version: pkg.version, repo: 'chromaui/action' }); + await publishAction({ major, version: pkg.version, repo: 'chromaui/action' }); break; default: console.error(`❗️ Unknown tag: ${tag}`);