Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/itchy-eyes-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@changesets/action": patch
---

Make git add work consistently with subdirectories

Ensure that when running the action from a subdirectory of a repository,
only the files from that directory are added, regardless of `commitMode`.
91 changes: 57 additions & 34 deletions src/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,75 @@ import * as github from "@actions/github";
import { commitChangesFromRepo } from "@changesets/ghcommit/git";
import { Octokit } from "./octokit";

const push = async (branch: string, { force }: { force?: boolean } = {}) => {
await exec(
"git",
["push", "origin", `HEAD:${branch}`, force && "--force"].filter<string>(
Boolean as any
)
);
type GitOptions = {
cwd: string;
};

const switchToMaybeExistingBranch = async (branch: 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]);
await exec("git", ["checkout", "-b", branch], options);
}
};

const reset = async (
pathSpec: string,
mode: "hard" | "soft" | "mixed" = "hard"
) => {
await exec("git", ["reset", `--${mode}`, pathSpec]);
const reset = async (pathSpec: string, options: GitOptions) => {
await exec("git", ["reset", `--hard`, pathSpec], options);
};

const commitAll = async (message: string) => {
await exec("git", ["add", "."]);
await exec("git", ["commit", "-m", message]);
const commitAll = async (message: string, options: GitOptions) => {
await exec("git", ["add", "."], options);
await exec("git", ["commit", "-m", message], options);
};

const checkIfClean = async (): Promise<boolean> => {
const { stdout } = await getExecOutput("git", ["status", "--porcelain"]);
const checkIfClean = async (options: GitOptions): Promise<boolean> => {
const { stdout } = await getExecOutput(
"git",
["status", "--porcelain"],
options
);
return !stdout.length;
};

export class Git {
octokit;
constructor(octokit?: Octokit) {
this.octokit = octokit;
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]"`]);
await exec("git", [
"config",
"user.email",
`"41898282+github-actions[bot]@users.noreply.github.com"`,
]);
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) {
Expand All @@ -73,20 +88,27 @@ export class Git {
core.warning(`Failed to create tag ${tag}: ${err.message}`);
});
}
await exec("git", ["push", "origin", tag]);
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);
await reset(github.context.sha);
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,
Expand All @@ -95,12 +117,13 @@ export class Git {
base: {
commit: github.context.sha,
},
addFromDirectory,
force: true,
});
}
if (!(await checkIfClean())) {
await commitAll(message);
if (!(await checkIfClean({ cwd: this.cwd }))) {
await commitAll(message, { cwd: this.cwd });
}
await push(branch, { force: true });
await push(branch, { cwd: this.cwd });
}
}
9 changes: 7 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,23 @@ const getOptionalInput = (name: string) => core.getInput(name) || undefined;
return;
}

const inputCwd = core.getInput("cwd");
const inputCwd = getOptionalInput("cwd");
if (inputCwd) {
core.info("changing directory to the one given as the input");
process.chdir(inputCwd);
}
const cwd = inputCwd || process.cwd();

const octokit = setupOctokit(githubToken);
const commitMode = getOptionalInput("commitMode") ?? "git-cli";
if (commitMode !== "git-cli" && commitMode !== "github-api") {
core.setFailed(`Invalid commit mode: ${commitMode}`);
return;
}
const git = new Git(commitMode === "github-api" ? octokit : undefined);
const git = new Git({
octokit: commitMode === "github-api" ? octokit : undefined,
cwd
});

let setupGitUser = core.getBooleanInput("setupGitUser");

Expand Down Expand Up @@ -100,6 +104,7 @@ const getOptionalInput = (name: string) => core.getInput(name) || undefined;
git,
octokit,
createGithubReleases: core.getBooleanInput("createGithubReleases"),
cwd,
});

if (result.published) {
Expand Down
4 changes: 2 additions & 2 deletions src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ type PublishOptions = {
octokit: Octokit;
createGithubReleases: boolean;
git: Git;
cwd?: string;
cwd: string;
};

type PublishedPackage = { name: string; version: string };
Expand All @@ -85,7 +85,7 @@ export async function runPublish({
git,
octokit,
createGithubReleases,
cwd = process.cwd(),
cwd,
}: PublishOptions): Promise<PublishResult> {
let [publishCommand, ...publishArgs] = script.split(/\s+/);

Expand Down