mirror of
https://github.com/changesets/action
synced 2026-10-26 16:39:56 +08:00
* Migrate to ESM * just use `require.resolve` * reuse setup action * checkout PR head for a sec * ls things * try a thing * the dirname had a trailing whitespace, lol
130 lines
3.4 KiB
TypeScript
130 lines
3.4 KiB
TypeScript
import * as core from "@actions/core";
|
|
import { exec, getExecOutput } from "@actions/exec";
|
|
import * as github from "@actions/github";
|
|
import { commitChangesFromRepo } from "@changesets/ghcommit/git";
|
|
import type { Octokit } from "./octokit.ts";
|
|
|
|
type GitOptions = {
|
|
cwd: string;
|
|
};
|
|
|
|
const push = async (branch: string, options: GitOptions) => {
|
|
await exec("git", ["push", "origin", `HEAD:${branch}`, "--force"], options);
|
|
};
|
|
|
|
const switchToMaybeExistingBranch = async (
|
|
branch: string,
|
|
options: GitOptions
|
|
) => {
|
|
let { stderr } = await getExecOutput("git", ["checkout", branch], {
|
|
ignoreReturnCode: true,
|
|
...options,
|
|
});
|
|
let isCreatingBranch = !stderr
|
|
.toString()
|
|
.includes(`Switched to a new branch '${branch}'`);
|
|
if (isCreatingBranch) {
|
|
await exec("git", ["checkout", "-b", branch], options);
|
|
}
|
|
};
|
|
|
|
const reset = async (pathSpec: string, options: GitOptions) => {
|
|
await exec("git", ["reset", `--hard`, pathSpec], options);
|
|
};
|
|
|
|
const commitAll = async (message: string, options: GitOptions) => {
|
|
await exec("git", ["add", "."], options);
|
|
await exec("git", ["commit", "-m", message], options);
|
|
};
|
|
|
|
const checkIfClean = async (options: GitOptions): Promise<boolean> => {
|
|
const { stdout } = await getExecOutput(
|
|
"git",
|
|
["status", "--porcelain"],
|
|
options
|
|
);
|
|
return !stdout.length;
|
|
};
|
|
|
|
export class Git {
|
|
readonly octokit: Octokit | null;
|
|
readonly cwd: string;
|
|
|
|
constructor(args: { octokit?: Octokit; cwd: string }) {
|
|
this.octokit = args.octokit ?? null;
|
|
this.cwd = args.cwd;
|
|
}
|
|
|
|
async setupUser() {
|
|
if (this.octokit) {
|
|
return;
|
|
}
|
|
await exec("git", ["config", "user.name", `"github-actions[bot]"`], {
|
|
cwd: this.cwd,
|
|
});
|
|
await exec(
|
|
"git",
|
|
[
|
|
"config",
|
|
"user.email",
|
|
`"41898282+github-actions[bot]@users.noreply.github.com"`,
|
|
],
|
|
{
|
|
cwd: this.cwd,
|
|
}
|
|
);
|
|
}
|
|
|
|
async pushTag(tag: string) {
|
|
if (this.octokit) {
|
|
return this.octokit.rest.git
|
|
.createRef({
|
|
...github.context.repo,
|
|
ref: `refs/tags/${tag}`,
|
|
sha: github.context.sha,
|
|
})
|
|
.catch((err) => {
|
|
// Assuming tag was manually pushed in custom publish script
|
|
core.warning(`Failed to create tag ${tag}: ${err.message}`);
|
|
});
|
|
}
|
|
await exec("git", ["push", "origin", tag], { cwd: this.cwd });
|
|
}
|
|
|
|
async prepareBranch(branch: string) {
|
|
if (this.octokit) {
|
|
// Preparing a new local branch is not necessary when using the API
|
|
return;
|
|
}
|
|
await switchToMaybeExistingBranch(branch, { cwd: this.cwd });
|
|
await reset(github.context.sha, { cwd: this.cwd });
|
|
}
|
|
|
|
async pushChanges({ branch, message }: { branch: string; message: string }) {
|
|
if (this.octokit) {
|
|
/**
|
|
* Only add files form the current working directory
|
|
*
|
|
* This will emulate the behavior of `git add .`,
|
|
* used in {@link commitAll}.
|
|
*/
|
|
const addFromDirectory = this.cwd;
|
|
return commitChangesFromRepo({
|
|
octokit: this.octokit,
|
|
...github.context.repo,
|
|
branch,
|
|
message,
|
|
base: {
|
|
commit: github.context.sha,
|
|
},
|
|
cwd: this.cwd,
|
|
force: true,
|
|
});
|
|
}
|
|
if (!(await checkIfClean({ cwd: this.cwd }))) {
|
|
await commitAll(message, { cwd: this.cwd });
|
|
}
|
|
await push(branch, { cwd: this.cwd });
|
|
}
|
|
}
|