Skip to content

Commit 3c24abe

Browse files
s0Andarist
andauthored
Make git add work consistently with subdirectories (#473)
* Make git add work consistently with subdirectories Currently, depending on your `commitMode`, when running the action with `cwd` set to a subdirectory of a repo, the action will either: - `git-cli`: add the files changed in the subdirectory only - `github-api`: add files changed anywhere in the repository This commit brings github-api in line with git-cli, so that it only adds files in the current working directory. * Explicitly set `cwd` for all exec calls * Avoid using `ExecOptions` from `@actions/exec` * Rename type * remove redundant `filter` --------- Co-authored-by: Mateusz Burzyński <[email protected]>
1 parent 7f0270e commit 3c24abe

File tree

4 files changed

+74
-38
lines changed

4 files changed

+74
-38
lines changed

.changeset/itchy-eyes-look.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@changesets/action": patch
3+
---
4+
5+
Make git add work consistently with subdirectories
6+
7+
Ensure that when running the action from a subdirectory of a repository,
8+
only the files from that directory are added, regardless of `commitMode`.

src/git.ts

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,75 @@ import * as github from "@actions/github";
44
import { commitChangesFromRepo } from "@changesets/ghcommit/git";
55
import { Octokit } from "./octokit";
66

7-
const push = async (branch: string, { force }: { force?: boolean } = {}) => {
8-
await exec(
9-
"git",
10-
["push", "origin", `HEAD:${branch}`, force && "--force"].filter<string>(
11-
Boolean as any
12-
)
13-
);
7+
type GitOptions = {
8+
cwd: string;
149
};
1510

16-
const switchToMaybeExistingBranch = async (branch: string) => {
11+
const push = async (branch: string, options: GitOptions) => {
12+
await exec("git", ["push", "origin", `HEAD:${branch}`, "--force"], options);
13+
};
14+
15+
const switchToMaybeExistingBranch = async (
16+
branch: string,
17+
options: GitOptions
18+
) => {
1719
let { stderr } = await getExecOutput("git", ["checkout", branch], {
1820
ignoreReturnCode: true,
21+
...options,
1922
});
2023
let isCreatingBranch = !stderr
2124
.toString()
2225
.includes(`Switched to a new branch '${branch}'`);
2326
if (isCreatingBranch) {
24-
await exec("git", ["checkout", "-b", branch]);
27+
await exec("git", ["checkout", "-b", branch], options);
2528
}
2629
};
2730

28-
const reset = async (
29-
pathSpec: string,
30-
mode: "hard" | "soft" | "mixed" = "hard"
31-
) => {
32-
await exec("git", ["reset", `--${mode}`, pathSpec]);
31+
const reset = async (pathSpec: string, options: GitOptions) => {
32+
await exec("git", ["reset", `--hard`, pathSpec], options);
3333
};
3434

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

40-
const checkIfClean = async (): Promise<boolean> => {
41-
const { stdout } = await getExecOutput("git", ["status", "--porcelain"]);
40+
const checkIfClean = async (options: GitOptions): Promise<boolean> => {
41+
const { stdout } = await getExecOutput(
42+
"git",
43+
["status", "--porcelain"],
44+
options
45+
);
4246
return !stdout.length;
4347
};
4448

4549
export class Git {
46-
octokit;
47-
constructor(octokit?: Octokit) {
48-
this.octokit = octokit;
50+
readonly octokit: Octokit | null;
51+
readonly cwd: string;
52+
53+
constructor(args: { octokit?: Octokit; cwd: string }) {
54+
this.octokit = args.octokit ?? null;
55+
this.cwd = args.cwd;
4956
}
5057

5158
async setupUser() {
5259
if (this.octokit) {
5360
return;
5461
}
55-
await exec("git", ["config", "user.name", `"github-actions[bot]"`]);
56-
await exec("git", [
57-
"config",
58-
"user.email",
59-
`"41898282+github-actions[bot]@users.noreply.github.com"`,
60-
]);
62+
await exec("git", ["config", "user.name", `"github-actions[bot]"`], {
63+
cwd: this.cwd,
64+
});
65+
await exec(
66+
"git",
67+
[
68+
"config",
69+
"user.email",
70+
`"41898282+github-actions[bot]@users.noreply.github.com"`,
71+
],
72+
{
73+
cwd: this.cwd,
74+
}
75+
);
6176
}
6277

6378
async pushTag(tag: string) {
@@ -73,20 +88,27 @@ export class Git {
7388
core.warning(`Failed to create tag ${tag}: ${err.message}`);
7489
});
7590
}
76-
await exec("git", ["push", "origin", tag]);
91+
await exec("git", ["push", "origin", tag], { cwd: this.cwd });
7792
}
7893

7994
async prepareBranch(branch: string) {
8095
if (this.octokit) {
8196
// Preparing a new local branch is not necessary when using the API
8297
return;
8398
}
84-
await switchToMaybeExistingBranch(branch);
85-
await reset(github.context.sha);
99+
await switchToMaybeExistingBranch(branch, { cwd: this.cwd });
100+
await reset(github.context.sha, { cwd: this.cwd });
86101
}
87102

88103
async pushChanges({ branch, message }: { branch: string; message: string }) {
89104
if (this.octokit) {
105+
/**
106+
* Only add files form the current working directory
107+
*
108+
* This will emulate the behavior of `git add .`,
109+
* used in {@link commitAll}.
110+
*/
111+
const addFromDirectory = this.cwd;
90112
return commitChangesFromRepo({
91113
octokit: this.octokit,
92114
...github.context.repo,
@@ -95,12 +117,13 @@ export class Git {
95117
base: {
96118
commit: github.context.sha,
97119
},
120+
addFromDirectory,
98121
force: true,
99122
});
100123
}
101-
if (!(await checkIfClean())) {
102-
await commitAll(message);
124+
if (!(await checkIfClean({ cwd: this.cwd }))) {
125+
await commitAll(message, { cwd: this.cwd });
103126
}
104-
await push(branch, { force: true });
127+
await push(branch, { cwd: this.cwd });
105128
}
106129
}

src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,23 @@ const getOptionalInput = (name: string) => core.getInput(name) || undefined;
1515
return;
1616
}
1717

18-
const inputCwd = core.getInput("cwd");
18+
const inputCwd = getOptionalInput("cwd");
1919
if (inputCwd) {
2020
core.info("changing directory to the one given as the input");
2121
process.chdir(inputCwd);
2222
}
23+
const cwd = inputCwd || process.cwd();
2324

2425
const octokit = setupOctokit(githubToken);
2526
const commitMode = getOptionalInput("commitMode") ?? "git-cli";
2627
if (commitMode !== "git-cli" && commitMode !== "github-api") {
2728
core.setFailed(`Invalid commit mode: ${commitMode}`);
2829
return;
2930
}
30-
const git = new Git(commitMode === "github-api" ? octokit : undefined);
31+
const git = new Git({
32+
octokit: commitMode === "github-api" ? octokit : undefined,
33+
cwd
34+
});
3135

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

@@ -100,6 +104,7 @@ const getOptionalInput = (name: string) => core.getInput(name) || undefined;
100104
git,
101105
octokit,
102106
createGithubReleases: core.getBooleanInput("createGithubReleases"),
107+
cwd,
103108
});
104109

105110
if (result.published) {

src/run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type PublishOptions = {
6666
octokit: Octokit;
6767
createGithubReleases: boolean;
6868
git: Git;
69-
cwd?: string;
69+
cwd: string;
7070
};
7171

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

0 commit comments

Comments
 (0)