diff --git a/.github/workflows/commit-message-based-labels.yml b/.github/workflows/commit-message-based-labels.yml index 14dc49974..c9bb7445a 100644 --- a/.github/workflows/commit-message-based-labels.yml +++ b/.github/workflows/commit-message-based-labels.yml @@ -13,6 +13,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: ./github-actions/commit-message-based-labels + - uses: ./github-actions/pull-request-labeling with: angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }} diff --git a/.ng-dev/commit-message.mts b/.ng-dev/commit-message.mts index 2b3931041..dd64a13a2 100644 --- a/.ng-dev/commit-message.mts +++ b/.ng-dev/commit-message.mts @@ -26,7 +26,7 @@ export const commitMessage: CommitMessageConfig = { 'spec-bundling', ]), ...buildScopesFor('github-actions', [ - 'commit-message-based-labels', + 'pull-request-labeling', 'feature-request', 'lock-closed', 'rebase', diff --git a/.prettierignore b/.prettierignore index f48ea34d5..724c314b7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,7 +5,7 @@ github-actions/bazel/configure-remote/configure-remote.cjs github-actions/branch-manager/main.js github-actions/browserstack/set-browserstack-env.cjs -github-actions/commit-message-based-labels/main.js +github-actions/pull-request-labeling/main.js github-actions/feature-request/main.js github-actions/google-internal-tests/main.js github-actions/org-file-sync/main.js diff --git a/github-actions/commit-message-based-labels/BUILD.bazel b/github-actions/commit-message-based-labels/BUILD.bazel deleted file mode 100644 index 00818fa49..000000000 --- a/github-actions/commit-message-based-labels/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -load("//tools:defaults.bzl", "esbuild_checked_in") - -esbuild_checked_in( - name = "main", - entry_point = "//github-actions/commit-message-based-labels/lib:main.ts", - target = "node16", - deps = [ - "//github-actions/commit-message-based-labels/lib", - ], -) diff --git a/github-actions/pull-request-labeling/BUILD.bazel b/github-actions/pull-request-labeling/BUILD.bazel new file mode 100644 index 000000000..992f42b29 --- /dev/null +++ b/github-actions/pull-request-labeling/BUILD.bazel @@ -0,0 +1,10 @@ +load("//tools:defaults.bzl", "esbuild_checked_in") + +esbuild_checked_in( + name = "main", + entry_point = "//github-actions/pull-request-labeling/lib:main.ts", + target = "node16", + deps = [ + "//github-actions/pull-request-labeling/lib", + ], +) diff --git a/github-actions/commit-message-based-labels/action.yml b/github-actions/pull-request-labeling/action.yml similarity index 56% rename from github-actions/commit-message-based-labels/action.yml rename to github-actions/pull-request-labeling/action.yml index 5ce8b8705..0604d8026 100644 --- a/github-actions/commit-message-based-labels/action.yml +++ b/github-actions/pull-request-labeling/action.yml @@ -1,5 +1,5 @@ -name: 'Breaking Changes Labeling' -description: 'Automatically label pull requests with a breaking change with a breaking change label' +name: 'Pull Request Labeling' +description: 'Automatically label pull requests based on pull request metadata' author: 'Angular' inputs: angular-robot-key: diff --git a/github-actions/commit-message-based-labels/lib/BUILD.bazel b/github-actions/pull-request-labeling/lib/BUILD.bazel similarity index 82% rename from github-actions/commit-message-based-labels/lib/BUILD.bazel rename to github-actions/pull-request-labeling/lib/BUILD.bazel index 4d998ef3b..bbb1f07c1 100644 --- a/github-actions/commit-message-based-labels/lib/BUILD.bazel +++ b/github-actions/pull-request-labeling/lib/BUILD.bazel @@ -1,6 +1,6 @@ load("//tools:defaults.bzl", "ts_library") -package(default_visibility = ["//github-actions/commit-message-based-labels:__subpackages__"]) +package(default_visibility = ["//github-actions/pull-request-labeling:__subpackages__"]) exports_files([ "main.ts", diff --git a/github-actions/commit-message-based-labels/lib/main.ts b/github-actions/pull-request-labeling/lib/main.ts similarity index 68% rename from github-actions/commit-message-based-labels/lib/main.ts rename to github-actions/pull-request-labeling/lib/main.ts index 0e6e2f36a..5f495c47b 100644 --- a/github-actions/commit-message-based-labels/lib/main.ts +++ b/github-actions/pull-request-labeling/lib/main.ts @@ -1,12 +1,17 @@ import * as core from '@actions/core'; import {context} from '@actions/github'; -import {Octokit} from '@octokit/rest'; +import {Octokit, RestEndpointMethodTypes} from '@octokit/rest'; import {Commit, parseCommitMessage} from '../../../ng-dev/commit-message/parse.js'; -import {managedLabels} from '../../../ng-dev/pr/common/labels/index.js'; +import {managedLabels, targetLabels} from '../../../ng-dev/pr/common/labels/index.js'; import {ANGULAR_ROBOT, getAuthTokenFor, revokeActiveInstallationToken} from '../../utils.js'; import {ManagedRepositories} from '../../../ng-dev/pr/common/labels/base.js'; -class CommitMessageBasedLabelManager { +/** The type of the response data for a the pull request get method on from octokit. */ +type PullRequestGetData = RestEndpointMethodTypes['pulls']['get']['response']['data']; +/** A Regex matcher to match releasable branch patterns. */ +const releasableBranchMatcher = /(main|\d+\.\d+\.x)/; + +class PullRequestLabeling { /** Run the commit message based labelling process. */ static run = async () => { const token = await getAuthTokenFor(ANGULAR_ROBOT); @@ -26,6 +31,8 @@ class CommitMessageBasedLabelManager { labels = new Set(); /** All commits in the PR */ commits: Commit[] = []; + /** The pull request information from the github API. */ + pullRequestMetadata?: PullRequestGetData; private constructor(private git: Octokit) {} @@ -35,6 +42,14 @@ class CommitMessageBasedLabelManager { await this.initialize(); core.info(`PR #${context.issue.number}`); + await this.commitMessageBasedLabeling(); + await this.pullRequestMetadataLabeling(); + } + + /** + * Perform labeling based on the commit messages for the pull request. + */ + async commitMessageBasedLabeling() { // Add or Remove label as appropriate for each of the supported label and commit messaage // combinations. for (const {commitCheck, name, repositories} of Object.values(managedLabels)) { @@ -62,6 +77,31 @@ class CommitMessageBasedLabelManager { } } + /** + * Perform labeling based on the metadata for the pull request from the Github API. + */ + async pullRequestMetadataLabeling() { + // If we are unable to get pull request metadata, we can shortcut and exit early. + if (this.pullRequestMetadata === undefined) { + return; + } + /** The base reference string, or target branch of the pull request. */ + const baseRef = this.pullRequestMetadata.base.ref; + + if (!releasableBranchMatcher.test(baseRef)) { + if (this.labels.has(targetLabels.TARGET_FEATURE.name)) { + core.info( + `The target branch (${baseRef}) is not a releasable branch, already has "target: feature" label`, + ); + } else { + core.info( + `The target branch (${baseRef}) is not a releasable branch, adding "target: feature" label`, + ); + await this.addLabel(targetLabels.TARGET_FEATURE.name); + } + } + } + /** Add the provided label to the pull request. */ async addLabel(label: string) { const {number: issue_number, owner, repo} = context.issue; @@ -97,13 +137,17 @@ class CommitMessageBasedLabelManager { await this.git.issues .listLabelsOnIssue({issue_number: number, owner, repo}) .then((resp) => resp.data.forEach(({name}) => this.labels.add(name))); + + await this.git.pulls.get({owner, repo, pull_number: number}).then(({data}) => { + this.pullRequestMetadata = data; + }); } } // Only run if the action is executed in a repository within the Angular org. This is in place // to prevent the action from actually running in a fork of a repository with this action set up. if (context.repo.owner === 'angular') { - CommitMessageBasedLabelManager.run().catch((e: Error) => { + PullRequestLabeling.run().catch((e: Error) => { console.error(e); core.setFailed(e.message); }); diff --git a/github-actions/commit-message-based-labels/main.js b/github-actions/pull-request-labeling/main.js similarity index 99% rename from github-actions/commit-message-based-labels/main.js rename to github-actions/pull-request-labeling/main.js index 04750f45e..50da4362a 100644 --- a/github-actions/commit-message-based-labels/main.js +++ b/github-actions/pull-request-labeling/main.js @@ -43411,7 +43411,8 @@ async function revokeActiveInstallationToken(githubOrToken) { // var _a; -var CommitMessageBasedLabelManager = class { +var releasableBranchMatcher = /(main|\d+\.\d+\.x)/; +var PullRequestLabeling = class { constructor(git) { this.git = git; this.repoAreaLabels = /* @__PURE__ */ new Set(); @@ -43421,6 +43422,10 @@ var CommitMessageBasedLabelManager = class { async run() { await this.initialize(); core.info(`PR #${import_github2.context.issue.number}`); + await this.commitMessageBasedLabeling(); + await this.pullRequestMetadataLabeling(); + } + async commitMessageBasedLabeling() { for (const { commitCheck, name, repositories } of Object.values(managedLabels)) { if (!repositories.includes(import_github2.context.repo.repo)) { continue; @@ -43439,6 +43444,20 @@ var CommitMessageBasedLabelManager = class { } } } + async pullRequestMetadataLabeling() { + if (this.pullRequestMetadata === void 0) { + return; + } + const baseRef = this.pullRequestMetadata.base.ref; + if (!releasableBranchMatcher.test(baseRef)) { + if (this.labels.has(targetLabels.TARGET_FEATURE.name)) { + core.info(`The target branch (${baseRef}) is not a releasable branch, already has "target: feature" label`); + } else { + core.info(`The target branch (${baseRef}) is not a releasable branch, adding "target: feature" label`); + await this.addLabel(targetLabels.TARGET_FEATURE.name); + } + } + } async addLabel(label) { const { number: issue_number, owner, repo } = import_github2.context.issue; try { @@ -43455,10 +43474,13 @@ var CommitMessageBasedLabelManager = class { await this.git.paginate(this.git.issues.listLabelsForRepo, { owner, repo }).then((labels) => labels.filter((l) => l.name.startsWith("area: ")).forEach((l) => this.repoAreaLabels.add(l.name))); await this.git.paginate(this.git.pulls.listCommits, { owner, pull_number: number, repo }).then((commits) => this.commits = commits.map(({ commit }) => parseCommitMessage(commit.message))); await this.git.issues.listLabelsOnIssue({ issue_number: number, owner, repo }).then((resp) => resp.data.forEach(({ name }) => this.labels.add(name))); + await this.git.pulls.get({ owner, repo, pull_number: number }).then(({ data }) => { + this.pullRequestMetadata = data; + }); } }; -_a = CommitMessageBasedLabelManager; -CommitMessageBasedLabelManager.run = async () => { +_a = PullRequestLabeling; +PullRequestLabeling.run = async () => { const token = await getAuthTokenFor(ANGULAR_ROBOT); const git = new Octokit2({ auth: token }); try { @@ -43469,7 +43491,7 @@ CommitMessageBasedLabelManager.run = async () => { } }; if (import_github2.context.repo.owner === "angular") { - CommitMessageBasedLabelManager.run().catch((e) => { + PullRequestLabeling.run().catch((e) => { console.error(e); core.setFailed(e.message); }); diff --git a/ng-dev/commit-message/BUILD.bazel b/ng-dev/commit-message/BUILD.bazel index f3c4a4da0..16c121437 100644 --- a/ng-dev/commit-message/BUILD.bazel +++ b/ng-dev/commit-message/BUILD.bazel @@ -7,7 +7,7 @@ ts_library( exclude = ["**/*.spec.ts"], ), visibility = [ - "//github-actions/commit-message-based-labels:__subpackages__", + "//github-actions/pull-request-labeling:__subpackages__", "//ng-dev:__subpackages__", ], deps = [ diff --git a/ng-dev/pr/common/BUILD.bazel b/ng-dev/pr/common/BUILD.bazel index 483616106..def4f9368 100644 --- a/ng-dev/pr/common/BUILD.bazel +++ b/ng-dev/pr/common/BUILD.bazel @@ -12,7 +12,7 @@ ts_library( ), visibility = [ "//.github/local-actions/branch-manager:__subpackages__", - "//github-actions/commit-message-based-labels:__subpackages__", + "//github-actions/pull-request-labeling:__subpackages__", "//ng-dev:__subpackages__", ], deps = [