Skip to content

Commit

Permalink
Automatic Canary Releases for PRs (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
dotansimha committed Nov 16, 2021
1 parent 4b19e05 commit 0ec01d2
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 0 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/canary.yml
@@ -0,0 +1,60 @@
name: Canary Release

on:
pull_request:
branches:
- master

jobs:
publish-canary:
name: Publish Canary
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
steps:
- name: Checkout master
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Use Node
uses: actions/setup-node@v2
with:
node-version: '16.x'
- uses: bahmutov/npm-install@v1
- name: Setup NPM credentials
run: echo "//registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
- name: Release Canary
id: canary
uses: 'kamilkisiela/release-canary@master'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
with:
npm-token: ${{ secrets.NODE_AUTH_TOKEN }}
npm-script: 'yarn release:canary'
changesets: true
- name: Publish a message
if: steps.canary.outputs.released == 'true'
uses: 'kamilkisiela/pr-comment@master'
with:
commentKey: canary
message: |
The latest changes of this PR are available as canary in npm (based on the declared `changesets`):
```
${{ steps.canary.outputs.changesetsPublishedPackages}}
```
bot-token: ${{ secrets.GITHUB_TOKEN }}
bot: 'github-actions[bot]'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish a empty message
if: steps.canary.outputs.released == 'false'
uses: 'kamilkisiela/pr-comment@master'
with:
commentKey: canary
message: |
The latest changes of this PR are not available as canary, since there are no linked `changesets` for this PR.
bot-token: ${{ secrets.GITHUB_TOKEN }}
bot: 'github-actions[bot]'
github-token: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -17,6 +17,7 @@
"prepare": "yarn husky install",
"prerelease": "yarn build",
"release": "changeset publish",
"release:canary": "(node scripts/canary-release.js && yarn build && yarn changeset publish --tag canary) || echo Skipping Canary...",
"build": "yarn workspace graphql-helix build",
"lint": "eslint --ext .ts,.tsx .",
"update-examples": "node scripts/update-examples",
Expand Down
74 changes: 74 additions & 0 deletions scripts/canary-release.js
@@ -0,0 +1,74 @@
/* eslint-disable */
const semver = require("semver");
const cp = require("child_process");
const { basename } = require("path");

const { read: readConfig } = require("@changesets/config");
const readChangesets = require("@changesets/read").default;
const assembleReleasePlan = require("@changesets/assemble-release-plan").default;
const applyReleasePlan = require("@changesets/apply-release-plan").default;
const { getPackages } = require("@manypkg/get-packages");

function getNewVersion(version, type) {
const gitHash = cp.spawnSync("git", ["rev-parse", "--short", "HEAD"]).stdout.toString().trim();

return semver.inc(version, `pre${type}`, true, "canary-" + gitHash);
}

function getRelevantChangesets(baseBranch) {
const comparePoint = cp
.spawnSync("git", ["merge-base", `origin/${baseBranch}`, "HEAD"])
.stdout.toString()
.trim();
const listModifiedFiles = cp.spawnSync("git", ["diff", "--name-only", comparePoint]).stdout.toString().trim().split("\n");

const items = listModifiedFiles.filter((f) => f.startsWith(".changeset")).map((f) => basename(f, ".md"));

return items;
}

async function updateVersions() {
const cwd = process.cwd();
const packages = await getPackages(cwd);
const config = await readConfig(cwd, packages);
const modifiedChangesets = getRelevantChangesets(config.baseBranch);
const changesets = (await readChangesets(cwd)).filter((change) => modifiedChangesets.includes(change.id));

if (changesets.length === 0) {
console.warn(`Unable to find any relevant package for canary publishing. Please make sure changesets exists!`);
process.exit(1);
} else {
const releasePlan = assembleReleasePlan(changesets, packages, config, [], false);

if (releasePlan.releases.length === 0) {
console.warn(`Unable to find any relevant package for canary releasing. Please make sure changesets exists!`);
process.exit(1);
} else {
for (const release of releasePlan.releases) {
if (release.type !== "none") {
release.newVersion = getNewVersion(release.oldVersion, release.type);
}
}

await applyReleasePlan(
releasePlan,
packages,
{
...config,
commit: false,
},
false,
true
);
}
}
}

updateVersions()
.then(() => {
console.info(`Done!`);
})
.catch((err) => {
console.error(err);
process.exit(1);
});

0 comments on commit 0ec01d2

Please sign in to comment.