-
-
Notifications
You must be signed in to change notification settings - Fork 398
Add select-mode, version, pack and publish sub-actions
#656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0595e1b
26f6f8c
40c95bc
9fc1981
10ef577
d5aac8f
7c58248
3723a6a
ae062ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@changesets/action": minor | ||
| --- | ||
|
|
||
| Add new `/select-mode`, `/version`, and `/publish` sub-actions to better control version and publish steps |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # changesets/action/pack | ||
|
|
||
| TODO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| name: Changesets - Pack | ||
| description: Pack publishable packages into tarballs | ||
| runs: | ||
| using: node24 | ||
| main: ../dist/pack.js | ||
| inputs: | ||
| publish-plan-artifact-id: | ||
| description: "Artifact id for a publish plan generated by the select-mode subaction" | ||
| required: false | ||
| outputs: | ||
| packed-artifact-id: | ||
| description: "Artifact id for the packed output directory" | ||
| branding: | ||
| icon: package | ||
| color: blue |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # changesets/action/publish | ||
|
|
||
| TODO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| name: Changesets - Publish | ||
| description: Publish packages to npm | ||
| runs: | ||
| using: node24 | ||
| main: ../dist/publish.js | ||
| inputs: | ||
| github-token: | ||
| description: "The GitHub token to use for authentication. Defaults to the GitHub-provided token." | ||
| required: false | ||
| default: ${{ github.token }} | ||
| script: | ||
| description: "The command to use to publish packages" | ||
| required: false | ||
| packed-artifact-id: | ||
| description: "Artifact id for packed publish output generated by the pack subaction" | ||
| required: false | ||
| create-github-releases: | ||
| description: "Whether to create Github releases after publish" | ||
| required: false | ||
| default: true | ||
| outputs: | ||
| published: | ||
| description: "A boolean value to indicate whether a publishing has happened or not" | ||
| published-packages: | ||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # changesets/action/select-mode | ||
|
|
||
| TODO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| name: Changesets - Select Mode | ||
| description: Whether to version or publish in the current repo state | ||
| runs: | ||
| using: node24 | ||
| main: ../dist/select-mode.js | ||
| inputs: {} | ||
| outputs: | ||
| mode: | ||
| description: "The mode to use for the current repo state: 'version', 'publish', or 'none'." | ||
| publish-plan-artifact-id: | ||
| description: "Artifact id for the generated publish plan when mode is `publish`" | ||
| branding: | ||
| icon: package | ||
| color: blue |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import fs from "node:fs/promises"; | ||
| import os from "node:os"; | ||
| import path from "node:path"; | ||
| import artifact from "@actions/artifact"; | ||
| import * as core from "@actions/core"; | ||
| import { downloadArtifact, execChangesetsCli } from "../utils.ts"; | ||
|
|
||
| try { | ||
| await main(); | ||
| } catch (err) { | ||
| core.setFailed((err as Error).message); | ||
| } | ||
|
|
||
| async function main() { | ||
| const publishPlanArtifactId = core.getInput("publish-plan-artifact-id"); | ||
|
|
||
| // If the user needs to change the cwd, set `working-directory` in the step instead | ||
| const cwd = process.cwd(); | ||
| const tmpDir = process.env.RUNNER_TEMP ?? (await fs.realpath(os.tmpdir())); | ||
| const outDir = path.join(tmpDir, `changeset-pack-${Date.now()}`); | ||
|
|
||
| await pack(cwd, { | ||
| outDir, | ||
| publishPlanPath: publishPlanArtifactId | ||
| ? await downloadPublishPlanArtifact(tmpDir, Number(publishPlanArtifactId)) | ||
| : undefined, | ||
| }); | ||
|
|
||
| const packedArtifact = await artifact.uploadArtifact( | ||
| `changeset-pack-${Date.now()}`, | ||
| await getFiles(outDir), | ||
| outDir, | ||
| ); | ||
| if (packedArtifact.id === undefined) { | ||
| throw new Error("Packed artifact upload did not return an artifact id"); | ||
| } | ||
| core.setOutput("packed-artifact-id", String(packedArtifact.id)); | ||
| } | ||
|
|
||
| async function pack( | ||
| cwd: string, | ||
| args: { | ||
| outDir: string; | ||
| publishPlanPath?: string; | ||
| }, | ||
| ) { | ||
| const cliArgs = ["pack", "--out-dir", args.outDir]; | ||
| if (args.publishPlanPath) { | ||
| cliArgs.push("--from-plan", args.publishPlanPath); | ||
| } | ||
|
|
||
| await execChangesetsCli(cliArgs, { | ||
| cwd, | ||
| env: process.env, | ||
| }); | ||
| } | ||
|
|
||
| async function downloadPublishPlanArtifact(tmpDir: string, artifactId: number) { | ||
| const downloadPath = await downloadArtifact( | ||
| tmpDir, | ||
| artifactId, | ||
| "changeset-publish-plan", | ||
| ); | ||
| return path.join(downloadPath, "publish-plan.json"); | ||
| } | ||
|
|
||
| async function getFiles(dir: string): Promise<string[]> { | ||
| const entries = await fs.readdir(dir, { withFileTypes: true }); | ||
| const files = await Promise.all( | ||
| entries.map(async (entry) => { | ||
| const entryPath = path.join(dir, entry.name); | ||
| if (entry.isDirectory()) { | ||
| return getFiles(entryPath); | ||
| } | ||
| return [entryPath]; | ||
| }), | ||
| ); | ||
| return files.flat(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| import fs from "node:fs/promises"; | ||
| import os from "node:os"; | ||
| import * as core from "@actions/core"; | ||
| import { Git } from "../git.ts"; | ||
| import { setupOctokit } from "../octokit.ts"; | ||
| import { runPublish } from "../run.ts"; | ||
| import { downloadArtifact } from "../utils.ts"; | ||
|
|
||
| try { | ||
| await main(); | ||
| } catch (err) { | ||
| core.setFailed((err as Error).message); | ||
| } | ||
|
|
||
| async function main() { | ||
| const githubToken = core.getInput("github-token", { required: true }); | ||
| const script = core.getInput("script"); | ||
| const packedArtifactId = core.getInput("packed-artifact-id"); | ||
| const createGithubReleases = core.getBooleanInput("create-github-releases"); | ||
|
|
||
| // If the user needs to change the cwd, set `working-directory` in the step instead | ||
| const cwd = process.cwd(); | ||
|
|
||
| const octokit = setupOctokit(githubToken); | ||
| // NOTE: Always pass octokit here as publish does not need a commit-mode | ||
| const git = new Git({ octokit, cwd }); | ||
|
|
||
| const fromPackDir = packedArtifactId | ||
| ? await downloadArtifact( | ||
| process.env.RUNNER_TEMP ?? (await fs.realpath(os.tmpdir())), | ||
| Number(packedArtifactId), | ||
| "changeset-pack", | ||
| ) | ||
| : undefined; | ||
|
|
||
| const result = await runPublish({ | ||
| script, | ||
| githubToken, | ||
| git, | ||
| octokit, | ||
| createGithubReleases, | ||
| cwd, | ||
| fromPackDir, | ||
| }); | ||
|
|
||
| if (result.published) { | ||
| core.setOutput("published", "true"); | ||
| core.setOutput( | ||
| "published-packages", | ||
| JSON.stringify(result.publishedPackages), | ||
| ); | ||
| } else { | ||
| core.setOutput("published", "false"); | ||
| } | ||
|
|
||
| if (result.exitCode !== 0) { | ||
| throw new Error( | ||
| `Publish command exited with code ${result.exitCode}${ | ||
| result.published | ||
| ? `, but some packages were published: ${result.publishedPackages | ||
| .map((p) => `${p.name}@${p.version}`) | ||
| .join(", ")}` | ||
| : "" | ||
| }`, | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,28 @@ | ||
| import fs from "node:fs/promises"; | ||
| import { createRequire } from "node:module"; | ||
| import path from "node:path"; | ||
| import * as core from "@actions/core"; | ||
| import { exec, getExecOutput } from "@actions/exec"; | ||
| import { | ||
| exec, | ||
| getExecOutput, | ||
| type ExecOptions, | ||
| type ExecOutput, | ||
| } from "@actions/exec"; | ||
| import * as github from "@actions/github"; | ||
| import type { PreState } from "@changesets/types"; | ||
| import { type Package, getPackages } from "@manypkg/get-packages"; | ||
| import { Git } from "./git.ts"; | ||
| import type { Octokit } from "./octokit.ts"; | ||
| import readChangesetState from "./readChangesetState.ts"; | ||
| import { | ||
| execChangesetsCli, | ||
| getChangedPackages, | ||
| getChangelogEntry, | ||
| getExecOutputChangesetsCli, | ||
| getVersionsByDirectory, | ||
| isErrorWithCode, | ||
| sortTheThings, | ||
| } from "./utils.ts"; | ||
|
|
||
| const require = createRequire(import.meta.url); | ||
|
|
||
| // GitHub Issues/PRs messages have a max size limit on the | ||
| // message body payload. | ||
| // `body is too long (maximum is 65536 characters)`. | ||
|
|
@@ -58,7 +62,8 @@ const createRelease = async ( | |
| }; | ||
|
|
||
| type PublishOptions = { | ||
| script: string; | ||
| script?: string; | ||
| fromPackDir?: string; | ||
| githubToken: string; | ||
| octokit: Octokit; | ||
| createGithubReleases: boolean; | ||
|
|
@@ -81,17 +86,36 @@ type PublishResult = | |
|
|
||
| export async function runPublish({ | ||
| script, | ||
| fromPackDir, | ||
| githubToken, | ||
| git, | ||
| octokit, | ||
| createGithubReleases, | ||
| cwd, | ||
| }: PublishOptions): Promise<PublishResult> { | ||
| let changesetPublishOutput = await getExecOutput(script, undefined, { | ||
| let changesetPublishOutput: ExecOutput; | ||
| const execOptions: ExecOptions = { | ||
| cwd, | ||
| ignoreReturnCode: true, | ||
| env: { ...process.env, GITHUB_TOKEN: githubToken }, | ||
| }); | ||
| }; | ||
|
|
||
| if (script) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note how with a custom publish |
||
| changesetPublishOutput = await getExecOutput( | ||
| script, | ||
| undefined, | ||
| execOptions, | ||
| ); | ||
| } else { | ||
| const args = ["publish"]; | ||
| if (fromPackDir) { | ||
| args.push("--from-pack-dir", fromPackDir); | ||
| } | ||
| changesetPublishOutput = await getExecOutputChangesetsCli( | ||
| args, | ||
| execOptions, | ||
| ); | ||
| } | ||
|
|
||
| let { packages, tool } = await getPackages(cwd); | ||
| let releasedPackages: Package[] = []; | ||
|
|
@@ -277,19 +301,7 @@ export async function runVersion({ | |
| if (script) { | ||
| await exec(script, undefined, { cwd, env }); | ||
| } else { | ||
| await exec( | ||
| "node", | ||
| [ | ||
| require.resolve("@changesets/cli/bin.js", { | ||
| paths: [cwd], | ||
| }), | ||
| "version", | ||
| ], | ||
| { | ||
| cwd, | ||
| env, | ||
| }, | ||
| ); | ||
| await execChangesetsCli(["version"], { cwd, env }); | ||
| } | ||
|
|
||
| let changedPackages = await getChangedPackages(cwd, versionsByDirectory); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a good input name? maybe
pack-dir-artifact-idwould be better?