Created
March 17, 2021 17:30
-
-
Save eliashussary/63e3ed1f7d1b2e063f99c431f237279e to your computer and use it in GitHub Desktop.
Yarn v2 workspaces changeset publish workaround
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# .github/actions/yarn-changeset-publish/action.yml | |
name: "Yarn Changeset Publish" | |
description: "Creates release tags from changesets" | |
outputs: | |
published: | |
description: "The published state" | |
runs: | |
using: "node12" | |
main: "index.js" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Release | |
on: | |
push: | |
tags-ignore: | |
- "**" | |
branches: | |
- main | |
jobs: | |
release: | |
name: Release | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout Repo | |
uses: actions/checkout@master | |
with: | |
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits | |
fetch-depth: 0 | |
- name: Use Node 14 | |
uses: actions/setup-node@v1 | |
with: | |
node-version: 14.x | |
- name: Use cached node_modules | |
uses: actions/cache@v1 | |
with: | |
path: node_modules | |
key: nodeModules-${{ hashFiles('**/yarn.lock') }} | |
restore-keys: | | |
nodeModules- | |
- name: Setup .yarnrc.yml | |
run: | | |
yarn config set npmAuthToken $NPM_TOKEN | |
yarn config set npmAlwaysAuth true | |
env: | |
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
- name: Install | |
run: yarn install --immutable | |
env: | |
CI: true | |
# this order matters | |
- name: Publish & Release or Skip to Changesets | |
id: create_github_releases | |
uses: ./.github/actions/yarn-changeset-publish | |
env: | |
GITHUB_TOKEN: ${{ secrets.GH_PAT }} | |
- name: Create Release Pull Request | |
id: changesets | |
uses: changesets/action@master | |
with: | |
commit: "docs(changeset): changelogs and version bump" | |
version: yarn version | |
env: | |
GITHUB_TOKEN: ${{ secrets.GH_PAT }} | |
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// .github/actions/yarn-changeset-publish/index.js | |
// @ts-check | |
const core = require("@actions/core"); | |
const { getOctokit, context } = require("@actions/github"); | |
const { exec } = require("@actions/exec"); | |
const fs = require("fs"); | |
const readChangesets = require("@changesets/read").default; | |
async function execWithOutput(command, args, options) { | |
let myOutput = ""; | |
let myError = ""; | |
return { | |
code: await exec(command, args, { | |
listeners: { | |
stdout: (data) => { | |
myOutput += data.toString(); | |
}, | |
stderr: (data) => { | |
myError += data.toString(); | |
}, | |
}, | |
...options, | |
}), | |
stdout: myOutput, | |
stderr: myError, | |
}; | |
} | |
function nthIndexOf(str, re, n) { | |
let match = re.exec(str); | |
let i = 1; | |
let lastIndex = -1; | |
while ((match = re.exec(str)) != null) { | |
if (i >= n) { | |
break; | |
} | |
lastIndex = match.index; | |
i++; | |
} | |
return lastIndex; | |
} | |
function getChangeLogForRelease(pkg) { | |
try { | |
const VERSION_MD_HEADING = /## \d+\.\d+\.\d+/g; | |
const changeLogPath = require.resolve(pkg.name + "/CHANGELOG.md"); | |
const changelog = fs.readFileSync(changeLogPath, "utf-8"); | |
const lastVersionHeadingIdx = nthIndexOf(changelog, VERSION_MD_HEADING, 2); | |
if (lastVersionHeadingIdx === -1) { | |
return changelog; | |
} | |
return changelog.substring(0, lastVersionHeadingIdx); | |
} catch (err) { | |
console.error(err); | |
return ""; | |
} | |
} | |
async function runPublish() { | |
const { stdout } = await execWithOutput( | |
"yarn", | |
[ | |
"workspaces", | |
"foreach", | |
"-ipv", | |
"--no-private", | |
"npm", | |
"publish", | |
"--tolerate-republish", | |
], | |
{ | |
cwd: process.cwd(), | |
}, | |
); | |
const lines = stdout.split("\n"); | |
const publishedRgx = /\[([@?a-zA-Z\-\/]+)\]:.*Package archive published/; | |
const publishedPackages = []; | |
for (const line of lines) { | |
const didPublish = line.match(publishedRgx); | |
if (didPublish) { | |
const pkgName = didPublish[1]; | |
const pkgJson = require(pkgName + "/package.json"); | |
publishedPackages.push(pkgJson); | |
} | |
} | |
return publishedPackages; | |
} | |
async function main() { | |
const githubToken = process.env.GITHUB_TOKEN; | |
const client = getOctokit(githubToken); | |
const changesets = await readChangesets(process.cwd()); | |
const shouldRelease = changesets.length === 0; | |
if (!shouldRelease) { | |
core.info("changesets exist, skipping publish"); | |
process.exit(0); | |
} | |
const publishedPackages = await runPublish(); | |
for (const pkg of publishedPackages) { | |
const tag_name = `${pkg.name}@${pkg.version}`; | |
core.info(`creating release for ${tag_name}`); | |
const body = getChangeLogForRelease(pkg); | |
await client.repos.createRelease({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
tag_name, | |
body, | |
name: tag_name, | |
}); | |
} | |
} | |
main().catch((err) => core.setFailed(err)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment