Skip to content

Commit e5f23f4

Browse files
authored
Merge branch 'stdlib-js:develop' into ndarray-b-torvdims
2 parents d67fc28 + 6a15889 commit e5f23f4

529 files changed

Lines changed: 45523 additions & 1028 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/labeler.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,25 @@ jobs:
138138
console.log( 'Error removing label: %s', error.message );
139139
}
140140
141+
# Remove "Ready To Merge" label when PR is merged:
142+
- name: 'Remove "Ready To Merge" label if PR is merged'
143+
if: ${{ github.event.action == 'closed' && github.event.pull_request.merged == true }}
144+
# Pin action to full length commit SHA
145+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
146+
with:
147+
github-token: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
148+
script: |
149+
try {
150+
await github.rest.issues.removeLabel({
151+
'owner': context.repo.owner,
152+
'repo': context.repo.repo,
153+
'issue_number': context.payload.pull_request.number,
154+
'name': 'Ready To Merge'
155+
})
156+
} catch ( error ) {
157+
console.log( 'Error removing label: %s', error.message );
158+
}
159+
141160
# Remove "Needs Review" and "Needs Changes" labels when "Ready To Merge" is assigned:
142161
- name: 'Remove "Needs Review" and "Needs Changes" labels when "Ready To Merge" is assigned'
143162
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'Ready To Merge' }}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#/
2+
# @license Apache-2.0
3+
#
4+
# Copyright (c) 2025 The Stdlib Authors.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#/
18+
19+
# Workflow name:
20+
name: merge_ready_prs
21+
22+
# Workflow triggers:
23+
on:
24+
workflow_dispatch:
25+
inputs:
26+
dry-run:
27+
description: 'Dry run (only print PRs to be merged)'
28+
type: boolean
29+
default: false
30+
31+
# Workflow jobs:
32+
jobs:
33+
34+
# Define a job for merging PRs with Ready to Merge label:
35+
merge:
36+
37+
# Define a display name:
38+
name: 'Merge Ready PRs'
39+
40+
# Define the type of virtual host machine:
41+
runs-on: ubuntu-latest
42+
43+
# Define the job's steps:
44+
steps:
45+
46+
# Checkout the repository:
47+
- name: 'Checkout repository'
48+
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
49+
50+
# Import GPG key to sign commits:
51+
- name: 'Import GPG key to sign commits'
52+
uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0
53+
with:
54+
gpg_private_key: ${{ secrets.STDLIB_BOT_GPG_PRIVATE_KEY }}
55+
passphrase: ${{ secrets.STDLIB_BOT_GPG_PASSPHRASE }}
56+
git_user_signingkey: true
57+
git_commit_gpgsign: true
58+
59+
# Merge PRs with Ready to Merge label:
60+
- name: 'Merge PRs'
61+
env:
62+
GH_TOKEN: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
63+
GITHUB_TOKEN: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
64+
run: |
65+
if [ "${{ inputs.dry-run }}" == "true" ]; then
66+
. "$GITHUB_WORKSPACE/.github/workflows/scripts/merge_ready_prs" --dry-run
67+
else
68+
. "$GITHUB_WORKSPACE/.github/workflows/scripts/merge_ready_prs"
69+
fi

.github/workflows/namespace_declarations.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ jobs:
137137
# Commit changes:
138138
git commit -m "feat: update \`${display_namespace}\` TypeScript declarations" --signoff
139139
140-
# Push branch and create PR:
141-
git push origin "$branch_name"
140+
# Push branch and create PR (force push to handle stale remote branches from previously merged/closed PRs):
141+
git push --force origin "$branch_name"
142142
143143
gh pr create \
144144
--title "feat: update \`${display_namespace}\` TypeScript declarations" \

.github/workflows/scripts/generate_pr_commit_message

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ main() {
153153
# Resolve the PR author's name and email using .mailmap:
154154
pr_author_resolved=$(resolve_user "$pr_author_login")
155155

156+
# Fetch commits in the PR:
157+
pr_commits=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/commits")
158+
156159
pr_author_id=$(echo "$pr_details" | jq -r '.user.id')
157160
pr_author_emails=$(
158161
{
@@ -181,9 +184,6 @@ main() {
181184
pr_reviews=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/reviews")
182185
reviewers=$(echo "$pr_reviews" | jq -r '.[] | select(.state == "APPROVED" ) | .user.login' | sort -u)
183186

184-
# Fetch commits in the PR:
185-
pr_commits=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/commits")
186-
187187
# Extract co-authors from commit messages:
188188
co_authors=$(echo "$pr_commits" | jq -r '.[].commit.message' | grep -Eio 'Co-authored-by:.*' | sort -u)
189189
processed_co_authors=""

.github/workflows/scripts/merge_pr

Lines changed: 91 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ set -o pipefail
3636
# VARIABLES #
3737

3838
# Get the pull request number:
39-
pr_number="$1"
39+
pr_number="${1}"
4040

4141
# GitHub API base URL:
4242
GITHUB_API_URL="https://api.github.com"
@@ -56,93 +56,105 @@ COMMENT_IDENTIFIER="<!-- PR_COMMIT_MESSAGE -->"
5656
# FUNCTIONS #
5757

5858
# Error handler.
59+
#
60+
# $1 - error message
5961
on_error() {
60-
echo "ERROR: $1" >&2
61-
exit $ERROR
62+
echo "ERROR: ${1}" >&2
63+
exit ${ERROR}
6264
}
6365

6466
# Makes GitHub API requests.
67+
#
68+
# $1 - HTTP method
69+
# $2 - API endpoint
70+
# $3 - request data (optional)
6571
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
72+
local method="${1}"
73+
local endpoint="${2}"
74+
local data="${3}"
75+
76+
# Initialize an array to hold curl headers:
77+
local headers=()
78+
79+
# If GITHUB_TOKEN is set, add the Authorization header:
80+
if [ -n "${GITHUB_TOKEN}" ]; then
81+
headers+=("-H" "Authorization: token ${GITHUB_TOKEN}")
82+
fi
83+
84+
# Determine the HTTP method and construct the curl command accordingly:
85+
case "${method}" in
86+
GET)
87+
curl -s "${headers[@]}" "${GITHUB_API_URL}${endpoint}"
88+
;;
89+
POST)
90+
# For POST requests, always set the Content-Type header:
91+
headers+=("-H" "Content-Type: application/json")
92+
93+
# If data is provided, include it in the request:
94+
if [ -n "${data}" ]; then
95+
curl -s -X POST "${headers[@]}" -d "${data}" "${GITHUB_API_URL}${endpoint}"
96+
else
97+
# Handle cases where POST data is required but not provided:
98+
echo "POST request requires data."
99+
on_error "POST request requires data"
100+
fi
101+
;;
102+
*)
103+
on_error "Invalid HTTP method: ${method}"
104+
;;
105+
esac
100106
}
101107

102108
# Main execution sequence.
103109
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
110+
local commit_message_comment
111+
local commit_message
112+
local commit_subject
113+
local commit_body
114+
local comments
115+
116+
# Check if PR number is provided:
117+
if [ -z "${pr_number}" ]; then
118+
on_error "PR number is required"
119+
fi
120+
121+
# Fetch PR comments to look for commit message comment:
122+
comments=$(github_api "GET" "/repos/${REPO_OWNER}/${REPO_NAME}/issues/${pr_number}/comments")
123+
124+
# Look for the PR commit message comment with the identifier:
125+
commit_message_comment=$(echo "${comments}" | jq -r --arg id "${COMMENT_IDENTIFIER}" '.[] | select(.body | contains($id)) | .body')
126+
127+
if [ -z "${commit_message_comment}" ]; then
128+
on_error "No PR commit message comment found for PR #${pr_number}"
129+
fi
130+
131+
# Extract commit message from the Markdown code block in the comment:
132+
commit_message=$(echo "${commit_message_comment}" | awk '/```text/{flag=1;next}/```/{flag=0}flag')
133+
134+
if [ -z "${commit_message}" ]; then
135+
on_error "Couldn't extract commit message from PR comment"
136+
fi
137+
138+
# Extract subject (first line) and body (everything after the first line):
139+
commit_subject=$(echo "${commit_message}" | head -n 1)
140+
commit_body=$(echo "${commit_message}" | tail -n +2)
141+
commit_body=$(echo "${commit_body}" | awk 'NF {p=1} p') # Trim leading empty lines
142+
143+
if [ -z "${commit_subject}" ]; then
144+
on_error "Couldn't extract commit subject from PR commit message"
145+
fi
146+
if [ -z "${commit_body}" ]; then
147+
on_error "Couldn't extract commit body from PR commit message"
148+
fi
149+
150+
# Squash and merge the PR with the extracted subject and body:
151+
if ! gh pr merge "${pr_number}" --admin --squash --subject "${commit_subject}" --body "${commit_body}"; then
152+
on_error "Failed to merge PR #${pr_number}"
153+
fi
154+
155+
echo "Successfully merged PR #${pr_number}"
156+
exit ${SUCCESS}
145157
}
146158

147159
# Call main with all command-line arguments:
148-
main "$@"
160+
main "${@}"

0 commit comments

Comments
 (0)