Skip to content

Commit 10a6975

Browse files
committed
build: add script to squash and merge PRs
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent fe60f20 commit 10a6975

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

.github/workflows/scripts/merge_pr

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/bin/bash
2+
#/
3+
# @license Apache-2.0
4+
#
5+
# Copyright (c) 2025 The Stdlib Authors.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
#/
19+
20+
# Script to merge a pull request.
21+
#
22+
# Usage: merge_pr PR_NUMBER
23+
#
24+
# Arguments:
25+
#
26+
# PR_NUMBER Pull request number.
27+
#
28+
# Environment variables:
29+
#
30+
# GITHUB_TOKEN GitHub token for authentication.
31+
32+
# Ensure that the exit status of pipelines is non-zero in the event that at least one of the commands in a pipeline fails:
33+
set -o pipefail
34+
35+
36+
# VARIABLES #
37+
38+
# Get the pull request number:
39+
pr_number="$1"
40+
41+
# GitHub API base URL:
42+
GITHUB_API_URL="https://api.github.com"
43+
44+
# Repository owner and name:
45+
REPO_OWNER="stdlib-js"
46+
REPO_NAME="stdlib"
47+
48+
# Exit codes:
49+
SUCCESS=0
50+
ERROR=1
51+
52+
# Identifier for PR commit message comments:
53+
COMMENT_IDENTIFIER="<!-- PR_COMMIT_MESSAGE -->"
54+
55+
56+
# FUNCTIONS #
57+
58+
# Error handler.
59+
on_error() {
60+
echo "ERROR: $1" >&2
61+
exit $ERROR
62+
}
63+
64+
# Makes GitHub API requests.
65+
github_api() {
66+
local method="$1"
67+
local endpoint="$2"
68+
local data="$3"
69+
70+
# Initialize an array to hold curl headers:
71+
local headers=()
72+
73+
# If GITHUB_TOKEN is set, add the Authorization header:
74+
if [ -n "$GITHUB_TOKEN" ]; then
75+
headers+=("-H" "Authorization: token $GITHUB_TOKEN")
76+
fi
77+
78+
# Determine the HTTP method and construct the curl command accordingly:
79+
case "$method" in
80+
GET)
81+
curl -s "${headers[@]}" "$GITHUB_API_URL$endpoint"
82+
;;
83+
POST)
84+
# For POST requests, always set the Content-Type header:
85+
headers+=("-H" "Content-Type: application/json")
86+
87+
# If data is provided, include it in the request:
88+
if [ -n "$data" ]; then
89+
curl -s -X POST "${headers[@]}" -d "$data" "$GITHUB_API_URL$endpoint"
90+
else
91+
# Handle cases where POST data is required but not provided:
92+
echo "POST request requires data."
93+
on_error "POST request requires data"
94+
fi
95+
;;
96+
*)
97+
on_error "Invalid HTTP method: $method"
98+
;;
99+
esac
100+
}
101+
102+
# Main execution sequence.
103+
main() {
104+
# Check if PR number is provided:
105+
if [ -z "$pr_number" ]; then
106+
on_error "PR number is required"
107+
fi
108+
109+
# Fetch PR comments to look for commit message comment:
110+
comments=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/issues/$pr_number/comments")
111+
112+
# Look for the PR commit message comment with the identifier:
113+
commit_message_comment=$(echo "$comments" | jq -r --arg id "$COMMENT_IDENTIFIER" '.[] | select(.body | contains($id)) | .body')
114+
115+
if [ -z "$commit_message_comment" ]; then
116+
on_error "No PR commit message comment found for PR #$pr_number"
117+
fi
118+
119+
# Extract commit message from the Markdown code block in the comment:
120+
commit_message=$(echo "$commit_message_comment" | awk '/```text/{flag=1;next}/```/{flag=0}flag')
121+
122+
if [ -z "$commit_message" ]; then
123+
on_error "Couldn't extract commit message from PR comment"
124+
fi
125+
126+
# Extract subject (first line) and body (everything after the first line):
127+
commit_subject=$(echo "$commit_message" | head -n 1)
128+
commit_body=$(echo "$commit_message" | tail -n +2)
129+
commit_body=$(echo "$commit_body" | awk 'NF {p=1} p') # Trim leading empty lines
130+
131+
if [ -z "$commit_subject" ]; then
132+
on_error "Couldn't extract commit subject from PR commit message"
133+
fi
134+
if [ -z "$commit_body" ]; then
135+
on_error "Couldn't extract commit body from PR commit message"
136+
fi
137+
138+
# Squash and merge the PR with the extracted subject and body:
139+
if ! gh pr merge "$pr_number" --admin --squash --subject "$commit_subject" --body "$commit_body"; then
140+
on_error "Failed to merge PR #$pr_number"
141+
fi
142+
143+
echo "Successfully merged PR #$pr_number"
144+
exit $SUCCESS
145+
}
146+
147+
# Call main with all command-line arguments:
148+
main "$@"

0 commit comments

Comments
 (0)