Skip to content

Commit 4efd81b

Browse files
feat(github-actions): add auto labeling by path to github labeler action
This adds the ability to add additional labels automatically if a specific path is matched in the pull request commits.
1 parent e126086 commit 4efd81b

File tree

13 files changed

+17020
-3834
lines changed

13 files changed

+17020
-3834
lines changed

.github/local-actions/branch-manager/main.js

Lines changed: 7 additions & 1 deletion
Large diffs are not rendered by default.

.github/local-actions/labels-sync/main.js

Lines changed: 7 additions & 1 deletion
Large diffs are not rendered by default.

github-actions/branch-manager/main.js

Lines changed: 7 additions & 1 deletion
Large diffs are not rendered by default.

github-actions/pull-request-labeling/BUILD.bazel

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ ts_project(
1313
":node_modules/@actions/core",
1414
":node_modules/@actions/github",
1515
":node_modules/@octokit/rest",
16+
":node_modules/@types/micromatch",
1617
":node_modules/@types/node",
18+
":node_modules/micromatch",
1719
":node_modules/undici",
1820
"//github-actions:utils",
1921
"//ng-dev/commit-message",
2022
"//ng-dev/pr/common/labels",
23+
"//ng-dev/pr/config",
24+
"//ng-dev/utils",
2125
],
2226
)
2327

@@ -27,6 +31,9 @@ esbuild_checked_in(
2731
":lib",
2832
],
2933
entry_point = "lib/main.ts",
34+
external = [
35+
"pnpapi",
36+
],
3037
format = "esm",
3138
platform = "node",
3239
target = "node22",

github-actions/pull-request-labeling/lib/main.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import {context} from '@actions/github';
33
import {Octokit, RestEndpointMethodTypes} from '@octokit/rest';
44
import {Commit, parseCommitMessage} from '../../../ng-dev/commit-message/parse.js';
55
import {actionLabels, managedLabels, targetLabels} from '../../../ng-dev/pr/common/labels/index.js';
6+
import {assertValidPullRequestConfig, PullRequestConfig} from '../../../ng-dev/pr/config/index.js';
67
import {ANGULAR_ROBOT, getAuthTokenFor, revokeActiveInstallationToken} from '../../utils.js';
78
import {ManagedRepositories} from '../../../ng-dev/pr/common/labels/base.js';
9+
import {getConfig, NgDevConfig} from '../../../ng-dev/utils/config.js';
10+
import micromatch from 'micromatch';
811

912
/** The type of the response data for a the pull request get method on from octokit. */
1013
type PullRequestGetData = RestEndpointMethodTypes['pulls']['get']['response']['data'];
@@ -17,7 +20,9 @@ class PullRequestLabeling {
1720
const token = await getAuthTokenFor(ANGULAR_ROBOT);
1821
const git = new Octokit({auth: token});
1922
try {
20-
const inst = new this(git);
23+
const config = await getConfig();
24+
assertValidPullRequestConfig(config);
25+
const inst = new this(git, config);
2126
await inst.run();
2227
} finally {
2328
await revokeActiveInstallationToken(git);
@@ -32,8 +37,13 @@ class PullRequestLabeling {
3237
commits: Commit[] = [];
3338
/** The pull request information from the github API. */
3439
pullRequestMetadata?: PullRequestGetData;
40+
/** The files changed in the pull request */
41+
pullRequestFilePaths?: string[];
3542

36-
private constructor(private git: Octokit) {}
43+
private constructor(
44+
private git: Octokit,
45+
private config: NgDevConfig<{pullRequest: PullRequestConfig}>,
46+
) {}
3747

3848
/** Run the action, and revoke the installation token on completion. */
3949
async run() {
@@ -43,6 +53,7 @@ class PullRequestLabeling {
4353

4454
await this.commitMessageBasedLabeling();
4555
await this.pullRequestMetadataLabeling();
56+
await this.pathBasedLabeling();
4657
}
4758

4859
/**
@@ -107,6 +118,27 @@ class PullRequestLabeling {
107118
}
108119
}
109120

121+
/**
122+
* Perform labeling based on the paths of the files in the pull request.
123+
*/
124+
async pathBasedLabeling() {
125+
const managedLabelByPath = this.config.pullRequest.managedLabelByPath;
126+
if (managedLabelByPath === undefined || this.pullRequestFilePaths === undefined) {
127+
return;
128+
}
129+
130+
for (const [path, labels] of Object.entries(managedLabelByPath)) {
131+
const files = micromatch(this.pullRequestFilePaths, path);
132+
if (files.length > 0) {
133+
for (const label of labels) {
134+
if (!this.labels.has(label)) {
135+
await this.addLabel(label);
136+
}
137+
}
138+
}
139+
}
140+
}
141+
110142
/** Remove the provided label to the pull request. */
111143
async removeLabel(label: string) {
112144
const {number: issue_number, owner, repo} = context.issue;
@@ -159,6 +191,13 @@ class PullRequestLabeling {
159191
await this.git.pulls.get({owner, repo, pull_number: number}).then(({data}) => {
160192
this.pullRequestMetadata = data;
161193
});
194+
195+
if (this.config.pullRequest.managedLabelByPath) {
196+
this.pullRequestFilePaths = [];
197+
await this.git
198+
.paginate(this.git.pulls.listFiles, {owner, pull_number: number, repo})
199+
.then((files) => this.pullRequestFilePaths?.push(...files.map((file) => file.filename)));
200+
}
162201
}
163202
}
164203

0 commit comments

Comments
 (0)