1+ # Copyright 2026 Google LLC
2+ #
3+ # Licensed under the Apache License, Version 2.0 (the "License");
4+ # you may not use this file except in compliance with the License.
5+ # You may obtain a copy of the License at
6+ #
7+ # https://www.apache.org/licenses/LICENSE-2.0
8+ #
9+ # Unless required by applicable law or agreed to in writing, software
10+ # distributed under the License is distributed on an "AS IS" BASIS,
11+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ # See the License for the specific language governing permissions and
13+ # limitations under the License.
14+
15+ name : Add Pull Ready Label
16+
17+ on :
18+ workflow_run :
19+ workflows : [Unit Test, Linter]
20+ types :
21+ - completed
22+ pull_request_review :
23+ pull_request_review_comment :
24+ workflow_dispatch :
25+
26+ jobs :
27+ AddPullReady :
28+ permissions :
29+ checks : read
30+ pull-requests : write
31+ runs-on : ubuntu-latest
32+
33+ steps :
34+ - uses : actions/github-script@v7
35+ with :
36+ script : |
37+ const owner = "google"
38+ const repo = "maxdiffusion"
39+ let pull_number = -1
40+ if (context.payload.pull_request !== undefined) {
41+ pull_number = context.payload.pull_request.number
42+ } else if (context.payload.workflow_run !== undefined) {
43+ if (context.payload.workflow_run.pull_requests.length === 0) {
44+ console.log("This workflow is NOT running within a PR's context")
45+ process.exit()
46+ }
47+ console.log(context.payload.workflow_run.pull_requests)
48+ pull_number = context.payload.workflow_run.pull_requests[0].number
49+ } else {
50+ console.log("This workflow is running within an invalid context")
51+ process.exit(1)
52+ }
53+ const reviews = await github.rest.pulls.listReviews({
54+ owner,
55+ repo,
56+ pull_number,
57+ })
58+ const decision_query = `
59+ query($owner: String!, $repo: String!, $pull_number: Int!) {
60+ repository(owner: $owner, name: $repo) {
61+ pullRequest(number: $pull_number) {
62+ reviewDecision # Fetches the overall review status
63+ }
64+ }
65+ }
66+ `;
67+ const decision_result = await github.graphql(decision_query, { owner, repo, pull_number });
68+
69+ if (reviews.data.length === 0) {
70+ console.log("Not adding pull ready because the PR is not approved yet.")
71+ process.exit()
72+ }
73+ let is_approved = false
74+ if (decision_result.repository.pullRequest.reviewDecision === "APPROVED") {
75+ is_approved = true
76+ }
77+ if (!is_approved) {
78+ console.log("Not adding pull ready because the PR is not approved yet by sufficient code owners.")
79+ process.exit()
80+ }
81+
82+ const commits = await github.rest.pulls.listCommits({
83+ owner,
84+ repo,
85+ pull_number,
86+ per_page: 100,
87+ })
88+ // Check that the number of commits in the PR is 1.
89+ if (commits.data.length !== 1) {
90+ console.log("Not adding pull ready because the PR has more than one commit. Please squash your commits.")
91+ process.exit(1)
92+ }
93+ const ref = commits.data.slice(-1)[0].sha
94+ const checkRuns = await github.rest.checks.listForRef({
95+ owner,
96+ repo,
97+ ref,
98+ })
99+ if (checkRuns.data.check_runs.length === 0) {
100+ console.log("Not adding pull ready because no check runs are associated with the last commit: " + ref)
101+ process.exit()
102+ }
103+ for (const checkRun of checkRuns.data.check_runs) {
104+ if (checkRun.name.endsWith(context.job)) continue
105+ if (checkRun.conclusion !== "success") {
106+ console.log("Not adding pull ready because " + checkRun.name + " has not passed yet: " + checkRun.html_url)
107+ process.exit()
108+ }
109+ }
110+ console.log("Adding pull ready label because the PR is approved AND all the check runs have passed")
111+ await github.rest.issues.addLabels({
112+ issue_number: pull_number,
113+ labels: ["pull ready"],
114+ owner,
115+ repo,
116+ })
0 commit comments