Skip to content

Commit

Permalink
Merge pull request #863 from chromaui/action-versioning
Browse files Browse the repository at this point in the history
Support pinning GitHub Action to major or patch version
  • Loading branch information
ghengeveld authored Nov 30, 2023
2 parents 602d90c + 31fa350 commit 34eeb0e
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 34 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/chromatic-main-and-prs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/chromatic-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/chromatic-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <canary|next|latest>
yarn publish-action <canary|latest>
```
56 changes: 33 additions & 23 deletions scripts/publish-action.mjs
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -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;
Expand All @@ -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]
Expand All @@ -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}`);
Expand Down

0 comments on commit 34eeb0e

Please sign in to comment.