diff --git a/README.md b/README.md index 59cac2f..e7cd0d8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,20 @@ This action for [Changesets](https://github.com/atlassian/changesets) creates a ## Usage -### Without Publishing + +### Inputs + +- publish - The command to use to build and publish packages +- version - The command to update version, edit CHANGELOG, read and delete changesets. Default to `changeset version` if not provided + +### Outputs + +- published - A boolean value to indicate whether a publishing is happened or not +- publishedPackages - A JSON array to present the published packages. The format is `[{"name": "@xx/xx", "version": "1.2.0"}, {"name": "@xx/xy", "version": "0.8.9"}]` + +### Example workflow: + +#### Without Publishing Create a file at `.github/workflows/release.yml` with the following content. @@ -41,7 +54,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` -### With Publishing +#### With Publishing Before you can setup this action with publishing, you'll need to have an [npm token](https://docs.npmjs.com/creating-and-viewing-authentication-tokens) that can publish the packages in the repo you're setting up the action for and doesn't have 2FA on publish enabled(2FA on auth can be enabled). You'll also need to [add it as a secret on your GitHub repo](https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables) with the name `NPM_TOKEN`. Once you've done that, you can create a file at `.github/workflows/release.yml` with the following content. @@ -73,16 +86,23 @@ jobs: run: yarn - name: Create Release Pull Request or Publish to npm + id: changesets uses: changesets/action@master with: - # this expects you to have a script called release which does a build for your packages and calls changeset publish + # This expects you to have a script called release which does a build for your packages and calls changeset publish publish: yarn release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Send a Slack notification if a publish happens + if: steps.changesets.outputs.published == 'true' + # You can do something when a publish happens. + run: my-slack-bot send-notification --message "A new version of ${GITHUB_REPOSITORY} was published!" + ``` -### With version script +#### With version script If you need to add additional logic to the version command, you can do so by using a version script. diff --git a/action.yml b/action.yml index 4b24e09..618ace4 100644 --- a/action.yml +++ b/action.yml @@ -7,6 +7,15 @@ inputs: publish: description: "The command to use to build and publish packages" required: false + version: + description: "The command to update version, edit CHANGELOG, read and delete changesets. Default to `changeset version` if not provided" + required: false +outputs: + published: + description: A boolean value to indicate whether a publishing is happened or not + publishedPackages: + description: > + A JSON array to present the published packages. The format is `[{"name": "@xx/xx", "version": "1.2.0"}, {"name": "@xx/xy", "version": "0.8.9"}]` branding: icon: "package" color: "blue" diff --git a/dist/index.js b/dist/index.js index 93bfd32..2e2b317 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1219,5 +1219,5 @@ var e=require("./conversions"),n=require("./route"),r={},o=Object.keys(e);functi },{"chalk":"ug4C"}],"PCsh":[function(require,module,exports) { "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var e=c(require("@babel/runtime/helpers/esm/defineProperty")),r=l(require("fs-extra")),t=c(require("path")),n=c(require("@changesets/parse")),a=require("@changesets/git"),i=c(require("chalk")),o=c(require("p-filter")),s=require("@changesets/logger");function l(e){if(e&&e.__esModule)return e;var r={};if(null!=e)for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t)){var n=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(e,t):{};n.get||n.set?Object.defineProperty(r,t,n):r[t]=e[t]}return r.default=e,r}function c(e){return e&&e.__esModule?e:{default:e}}let u=i.default.red("===============================IMPORTANT!==============================="),d=i.default.red("----------------------------------------------------------------------");async function f(e,n){const a=(await(0,o.default)(n,async n=>(await(0,r.lstat)(t.default.join(e,n))).isDirectory())).map(async n=>{const a=t.default.join(e,n,"changes.json"),[i,o]=await Promise.all([(0,r.readFile)(t.default.join(e,n,"changes.md"),"utf-8"),(0,r.readJson)(a)]);return{releases:o.releases,summary:i,id:n}});return Promise.all(a)}async function p(e,r){let t=await f(e,r);return 0===t.length?[]:((0,s.warn)(u),(0,s.warn)("There were old changesets from version 1 found"),(0,s.warn)("Theses are being applied now but the dependents graph may have changed"),(0,s.warn)("Make sure you validate all your dependencies"),(0,s.warn)("In a future major version, we will no longer apply these old changesets, and will instead throw here"),(0,s.warn)(d),t)}function h(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}function w(r){for(var t=1;te.split("/")[1]);return e.filter(e=>n.includes(e))}async function g(e,a){let i,o=t.default.join(e,".changeset");try{i=await r.default.readdir(o)}catch(c){if("ENOENT"===c.code)throw new Error("There is no .changeset directory in this project");throw c}void 0!==a&&(i=await y(i,o,a));let s=p(o,i);const l=i.filter(e=>e.endsWith(".md")&&"README.md"!==e).map(async e=>{const a=await r.default.readFile(t.default.join(o,e),"utf-8");return w({},(0,n.default)(a),{id:e.replace(".md","")})});return[...await s,...await Promise.all(l)]}var O=g;exports.default=O; },{"@babel/runtime/helpers/esm/defineProperty":"9iDM","fs-extra":"rdZu","@changesets/parse":"boSt","@changesets/git":"It5m","chalk":"ug4C","p-filter":"PNks","@changesets/logger":"cocj"}],"7QCb":[function(require,module,exports) { -"use strict";function e(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,n)}return a}function t(t){for(var n=1;n{let e=process.env.GITHUB_TOKEN;if(!e)return void o.setFailed("Please add the GITHUB_TOKEN to the changesets action");let a=`${s.context.repo.owner}/${s.context.repo.repo}`,n=s.context.ref.replace("refs/heads/",""),i=await h.readPreState(process.cwd()),f=void 0!==i&&"pre"===i.mode;const b=new s.GitHub(e);console.log("setting git user"),await r.exec("git",["config","--global","user.name",'"github-actions[bot]"']),await r.exec("git",["config","--global","user.email",'"github-actions[bot]@users.noreply.github.com"']),console.log("setting GitHub credentials"),await l.default.writeFile(`${process.env.HOME}/.netrc`,`machine github.com\nlogin github-actions[bot]\npassword ${e}`);let w=await d.default(process.cwd());if(f){let e=new Set(i.changesets);w=w.filter(t=>!e.has(t.id))}let m=0!==w.length,y=o.getInput("publish"),v=o.getInput("version");if(m||y)if(m||!y){if(m){let e=`changeset-release/${n}`,{stderr:o}=await g.execWithOutput("git",["checkout",e],{ignoreReturnCode:!0});if(!o.toString().includes(`Switched to a new branch '${e}'`)&&await r.exec("git",["checkout","-b",e]),await r.exec("git",["reset","--hard",s.context.sha]),v){let[e,...t]=v.split(/\s+/);await r.exec(e,t)}else{let e=await l.default.readJson(u.default.join("node_modules","@changesets","cli","package.json")),t=p.lt(e.version,"2.0.0")?"bump":"version";await r.exec("node",["./node_modules/@changesets/cli/bin.js",t])}let c=`repo:${a}+state:open+head:${e}+base:${n}`,h=b.search.issuesAndPullRequests({q:c}),d=await g.getChangedPackages(process.cwd()),w=(async()=>`This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and ${y?"the packages will be published to npm automatically":"publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing)"}. If you're not ready to do a release yet, that's fine, whenever you add more changesets to ${n}, this PR will be updated.\n${f?`\n⚠️⚠️⚠️⚠️⚠️⚠️\n\n\`${n}\` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run \`changeset pre exit\` on \`${n}\`.\n\n⚠️⚠️⚠️⚠️⚠️⚠️\n`:""}\n# Releases\n`+(await Promise.all(d.map(async e=>{let t=await l.default.readFile(u.default.join(e.dir,"CHANGELOG.md"),"utf8"),a=g.getChangelogEntry(t,e.config.version);return{highestLevel:a.highestLevel,private:!!e.config.private,content:`## ${e.name}@${e.config.version}\n\n`+a.content}}))).filter(e=>e).sort(g.sortTheThings).map(e=>e.content).join("\n "))();const m=`Version Packages${f?` (${i.tag})`:""}`,O=`ci(changeset): generate PR with changelog &${f?` (${i.tag})`:""} version updates`;await r.exec("git",["add","."]),await r.exec("git",["commit","-m",O]),await r.exec("git",["push","origin",e,"--force"]);let $=await h;console.log(JSON.stringify($.data,null,2)),0===$.data.items.length?(console.log("creating pull request"),await b.pulls.create(t({base:n,head:e,title:m,body:await w},s.context.repo))):(b.pulls.update(t({pull_number:$.data.items[0].number,title:m,body:await w},s.context.repo)),console.log("pull request found"))}}else{console.log("No changesets found, attempting to publish any unpublished packages to npm");let e=await c.default({tools:["yarn","bolt","pnpm","root"]});if(!e)return o.setFailed("Could not find workspaces");let a=new Map(e.map(e=>[e.name,e]));l.default.writeFileSync(`${process.env.HOME}/.npmrc`,`//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`);let[i,...p]=y.split(/\s+/),h=await g.execWithOutput(i,p);await r.exec("git",["pull","origin",n]),await r.exec("git",["push","origin",`HEAD:${n}`,"--tags"]);let d=/New tag:\s+(@[^/]+\/[^@]+|[^/]+)@([^\s]+)/,f=[];for(let t of h.stdout.split("\n")){let e=t.match(d);if(null===e)continue;let n=e[1],i=a.get(n);if(void 0===i)return o.setFailed("Workspace not found for "+n+". This is probably a bug in the action, please open an issue");f.push(i)}await Promise.all(f.map(async e=>{try{let n=u.default.join(e.dir,"CHANGELOG.md"),i=await l.default.readFile(n,"utf8"),r=g.getChangelogEntry(i,e.config.version);if(!r)return o.setFailed(`Could not find changelog entry for ${e.name}@${e.config.version}`);await b.repos.createRelease(t({tag_name:`${e.name}@${e.config.version}`,body:r.content,prerelease:e.config.version.includes("-")},s.context.repo))}catch(a){if("ENOENT"!==a.code)throw a}}))}else console.log("No changesets found")})().catch(e=>{console.error(e),o.setFailed(e.message)}); +"use strict";function e(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,n)}return a}function t(t){for(var n=1;n{let e=process.env.GITHUB_TOKEN;if(!e)return void o.setFailed("Please add the GITHUB_TOKEN to the changesets action");let a=`${s.context.repo.owner}/${s.context.repo.repo}`,n=s.context.ref.replace("refs/heads/",""),i=await h.readPreState(process.cwd()),f=void 0!==i&&"pre"===i.mode;const b=new s.GitHub(e);console.log("setting git user"),await r.exec("git",["config","--global","user.name",'"github-actions[bot]"']),await r.exec("git",["config","--global","user.email",'"github-actions[bot]@users.noreply.github.com"']),console.log("setting GitHub credentials"),await l.default.writeFile(`${process.env.HOME}/.netrc`,`machine github.com\nlogin github-actions[bot]\npassword ${e}`);let w=await d.default(process.cwd());if(f){let e=new Set(i.changesets);w=w.filter(t=>!e.has(t.id))}let m=0!==w.length,y=o.getInput("publish"),v=o.getInput("version");if(o.setOutput("published","false"),o.setOutput("publishedPackages","[]"),m||y){if(!m&&y){console.log("No changesets found, attempting to publish any unpublished packages to npm");let e=await c.default({tools:["yarn","bolt","pnpm","root"]});if(!e)return o.setFailed("Could not find workspaces");let a=new Map(e.map(e=>[e.name,e]));l.default.writeFileSync(`${process.env.HOME}/.npmrc`,`//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}`);let[i,...p]=y.split(/\s+/),h=await g.execWithOutput(i,p);await r.exec("git",["pull","origin",n]),await r.exec("git",["push","origin",`HEAD:${n}`,"--tags"]);let d=/New tag:\s+(@[^/]+\/[^@]+|[^/]+)@([^\s]+)/,f=[];for(let t of h.stdout.split("\n")){let e=t.match(d);if(null===e)continue;let n=e[1],i=a.get(n);if(void 0===i)return o.setFailed("Workspace not found for "+n+". This is probably a bug in the action, please open an issue");f.push(i)}return await Promise.all(f.map(async e=>{try{let n=u.default.join(e.dir,"CHANGELOG.md"),i=await l.default.readFile(n,"utf8"),r=g.getChangelogEntry(i,e.config.version);if(!r)return o.setFailed(`Could not find changelog entry for ${e.name}@${e.config.version}`);await b.repos.createRelease(t({tag_name:`${e.name}@${e.config.version}`,body:r.content,prerelease:e.config.version.includes("-")},s.context.repo))}catch(a){if("ENOENT"!==a.code)throw a}})),void(f.length&&(o.setOutput("published","true"),o.setOutput("publishedPackages",JSON.stringify(f.map(e=>({name:e.name,version:e.config.version}))))))}if(m){let e=`changeset-release/${n}`,{stderr:o}=await g.execWithOutput("git",["checkout",e],{ignoreReturnCode:!0});if(!o.toString().includes(`Switched to a new branch '${e}'`)&&await r.exec("git",["checkout","-b",e]),await r.exec("git",["reset","--hard",s.context.sha]),v){let[e,...t]=v.split(/\s+/);await r.exec(e,t)}else{let e=await l.default.readJson(u.default.join("node_modules","@changesets","cli","package.json")),t=p.lt(e.version,"2.0.0")?"bump":"version";await r.exec("node",["./node_modules/@changesets/cli/bin.js",t])}let c=`repo:${a}+state:open+head:${e}+base:${n}`,h=b.search.issuesAndPullRequests({q:c}),d=await g.getChangedPackages(process.cwd()),w=(async()=>`This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and ${y?"the packages will be published to npm automatically":"publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing)"}. If you're not ready to do a release yet, that's fine, whenever you add more changesets to ${n}, this PR will be updated.\n${f?`\n⚠️⚠️⚠️⚠️⚠️⚠️\n\n\`${n}\` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run \`changeset pre exit\` on \`${n}\`.\n\n⚠️⚠️⚠️⚠️⚠️⚠️\n`:""}\n# Releases\n`+(await Promise.all(d.map(async e=>{let t=await l.default.readFile(u.default.join(e.dir,"CHANGELOG.md"),"utf8"),a=g.getChangelogEntry(t,e.config.version);return{highestLevel:a.highestLevel,private:!!e.config.private,content:`## ${e.name}@${e.config.version}\n\n`+a.content}}))).filter(e=>e).sort(g.sortTheThings).map(e=>e.content).join("\n "))();const m=`Version Packages${f?` (${i.tag})`:""}`,O=`ci(changeset): generate PR with changelog &${f?` (${i.tag})`:""} version updates`;await r.exec("git",["add","."]),await r.exec("git",["commit","-m",O]),await r.exec("git",["push","origin",e,"--force"]);let $=await h;console.log(JSON.stringify($.data,null,2)),0===$.data.items.length?(console.log("creating pull request"),await b.pulls.create(t({base:n,head:e,title:m,body:await w},s.context.repo))):(b.pulls.update(t({pull_number:$.data.items[0].number,title:m,body:await w},s.context.repo)),console.log("pull request found"))}}else console.log("No changesets found")})().catch(e=>{console.error(e),o.setFailed(e.message)}); },{"@actions/core":"4FTV","@actions/exec":"utFe","@actions/github":"8Dol","fs-extra":"JTJ9","get-workspaces":"kAcF","./utils":"UnXq","semver":"aric","@changesets/pre":"jEAA","@changesets/read":"PCsh"}]},{},["7QCb"], null) \ No newline at end of file diff --git a/index.ts b/index.ts index 47ff8f9..fa7ba58 100644 --- a/index.ts +++ b/index.ts @@ -60,6 +60,8 @@ import readChangesets from "@changesets/read"; let publishScript = core.getInput("publish"); let versionScript = core.getInput("version"); + core.setOutput('published', 'false'); + core.setOutput('publishedPackages', '[]'); if (!hasChangesets && !publishScript) { console.log("No changesets found"); @@ -90,6 +92,7 @@ import readChangesets from "@changesets/read"; publishCommand, publishArgs ); + await exec("git", ["pull", "origin", branch]); await exec("git", ["push", "origin", `HEAD:${branch}`, "--tags"]); @@ -149,6 +152,13 @@ import readChangesets from "@changesets/read"; }) ); + if (releasedWorkspaces.length) { + core.setOutput('published', 'true'); + core.setOutput('publishedPackages', JSON.stringify(releasedWorkspaces.map( + workspace => ({name: workspace.name, version: workspace.config.version}) + ))); + } + return; } @@ -165,7 +175,7 @@ import readChangesets from "@changesets/read"; } await exec("git", ["reset", "--hard", github.context.sha]); - + if (versionScript) { let [versionCommand, ...versionArgs] = versionScript.split(/\s+/); await exec(versionCommand, versionArgs);