Skip to content

Commit 37235de

Browse files
committed
build: add workflow and script to leave comment with make instructions
--- 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: missing_dependencies - task: lint_typescript_declarations status: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- type: pre_push_report description: Results of running various checks prior to pushing changes. report: - task: run_javascript_examples status: na - task: run_c_examples status: na - task: run_cpp_examples status: na - task: run_javascript_readme_examples status: na - task: run_c_benchmarks status: na - task: run_cpp_benchmarks status: na - task: run_fortran_benchmarks status: na - task: run_javascript_benchmarks status: na - task: run_julia_benchmarks status: na - task: run_python_benchmarks status: na - task: run_r_benchmarks status: na - task: run_javascript_tests status: na ---
1 parent a62261a commit 37235de

File tree

3 files changed

+315
-2
lines changed

3 files changed

+315
-2
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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: pr_commands_comment
21+
22+
# Workflow triggers:
23+
on:
24+
# Allow the workflow to be triggered by other workflows
25+
workflow_call:
26+
# Define the input parameters for the workflow:
27+
inputs:
28+
pull_request_number:
29+
description: 'Pull request number'
30+
required: true
31+
type: number
32+
33+
# Define the secrets accessible by the workflow:
34+
secrets:
35+
STDLIB_BOT_GITHUB_TOKEN:
36+
description: 'stdlib-bot GitHub token to create pull request comments'
37+
required: true
38+
39+
# Allow the workflow to be manually triggered:
40+
workflow_dispatch:
41+
inputs:
42+
pull_request_number:
43+
description: 'Pull request number'
44+
required: true
45+
type: number
46+
47+
# Global permissions:
48+
permissions:
49+
# Allow read-only access to the repository contents:
50+
contents: read
51+
52+
# Workflow jobs:
53+
jobs:
54+
55+
# Define a job for leaving a comment on a PR with package make command instructions:
56+
pr_commands_comment:
57+
58+
# Define a display name:
59+
name: 'Leave comment with package make command instructions'
60+
61+
# Define the type of virtual host machine:
62+
runs-on: ubuntu-latest
63+
64+
# Define the sequence of job steps...
65+
steps:
66+
67+
# Leave comment with package make command instructions:
68+
- name: 'Leave comment with package make command instructions'
69+
env:
70+
PR_NUMBER: ${{ inputs.pull_request_number }}
71+
run: |
72+
. "$GITHUB_WORKSPACE/.github/workflows/scripts/package_commands_comment" "$PR_NUMBER"
73+
timeout-minutes: 30
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#!/usr/bin/env 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+
# Script to generate a command with relevant `make` commands tailored to package changed in a PR.
20+
#
21+
# Usage: package_commands_comment <pr_number>
22+
#
23+
# Arguments:
24+
#
25+
# pr_number Pull request number.
26+
#
27+
# Environment variables:
28+
#
29+
# GITHUB_TOKEN GitHub token for authentication.
30+
31+
# Ensure that the exit status of pipelines is non-zero in the event that at least one of the commands in a pipeline fails:
32+
set -o pipefail
33+
34+
35+
# VARIABLES #
36+
37+
# Resolve the pull request number:
38+
pr_number="$1"
39+
40+
# GitHub API base URL:
41+
github_api_url="https://api.github.com"
42+
43+
# Repository owner and name:
44+
repo_owner="stdlib-js"
45+
repo_name="stdlib"
46+
47+
48+
# FUNCTIONS #
49+
50+
# Error handler.
51+
#
52+
# $1 - error status
53+
on_error() {
54+
echo 'ERROR: An error was encountered during execution.' >&2
55+
exit "$1"
56+
}
57+
58+
# Prints a success message.
59+
print_success() {
60+
echo 'Success!' >&2
61+
}
62+
63+
# Performs a GitHub API request.
64+
#
65+
# $1 - HTTP method (GET or POST)
66+
# $2 - API endpoint
67+
# $3 - data for POST requests
68+
github_api() {
69+
local method="$1"
70+
local endpoint="$2"
71+
local data="$3"
72+
73+
# Initialize an array to hold curl headers:
74+
local headers=()
75+
76+
# If GITHUB_TOKEN is set, add the Authorization header:
77+
if [ -n "${GITHUB_TOKEN}" ]; then
78+
headers+=("-H" "Authorization: token ${GITHUB_TOKEN}")
79+
fi
80+
81+
# Determine the HTTP method and construct the curl command accordingly...
82+
case "${method}" in
83+
GET)
84+
curl -s "${headers[@]}" "${github_api_url}${endpoint}"
85+
;;
86+
POST)
87+
# For POST requests, always set the Content-Type header:
88+
headers+=("-H" "Content-Type: application/json")
89+
90+
# If data is provided, include it in the request:
91+
if [ -n "${data}" ]; then
92+
curl -s -X POST "${headers[@]}" -d "${data}" "${github_api_url}${endpoint}"
93+
else
94+
# Handle cases where POST data is required but not provided:
95+
echo "ERROR: POST request requires data."
96+
on_error 1
97+
fi
98+
;;
99+
*)
100+
echo "ERROR: Invalid HTTP method: ${method}."
101+
on_error 1
102+
;;
103+
esac
104+
}
105+
106+
# Main execution sequence.
107+
main() {
108+
local directories
109+
local packages
110+
local response
111+
local c_files
112+
local comment
113+
local files
114+
115+
if [ -z "${pr_number}" ]; then
116+
echo "ERROR: Pull request number is required." >&2
117+
on_error 1
118+
fi
119+
120+
# Fetch changed files in pull request (no need to paginate because skipping PRs affecting multiple packages anyway):
121+
response=$(github_api "GET" "/repos/${repo_owner}/${repo_name}/pulls/${pr_number}/files?per_page=100")
122+
files=$(echo $response | jq -r '.[] | .filename')
123+
124+
# Extract files associated with native add-ons:
125+
c_files=$(echo $files | grep -e '/benchmark/c' -e '/examples/c' -e '/binding.gyp' -e '/include.gypi' -e '/src/')
126+
127+
# Find unique package directories:
128+
directories=$(echo "${files}" | tr ' ' '\n' | \
129+
xargs dirname | \
130+
grep '^lib/node_modules/@stdlib' | \
131+
sed -E 's/\/(benchmark|bin|data|docs|etc|examples|include|lib|scripts|src|test)(\/.*)?$//' | \
132+
sort -u)
133+
134+
# Extract package names from changed package directories (e.g., @stdlib/math/base/special/sin) by removing the leading 'lib/node_modules/':
135+
packages=$(echo "${directories}" | sed -E 's/^lib\/node_modules\///')
136+
137+
case "$packages" in
138+
*)
139+
# Post a comment on the PR when only a single package is changed in PR:
140+
if [[ "${#c_files[@]}" -eq 0 ]]; then
141+
comment="Hello! 👋
142+
143+
Pro-tip: Use the below \`make\` commands during local development to ensure that all tests, examples, and benchmark files in your PR run successfully.
144+
145+
For each of the commands, please run them from the root stdlib repository directory (not the package folder!).
146+
147+
To run unit tests,
148+
149+
\`\`\`bash
150+
make test TESTS_FILTER=\".*/${packages}/.*\"
151+
\`\`\`
152+
153+
To run benchmarks,
154+
155+
\`\`\`bash
156+
make benchmark BENCHMARKS_FILTER=\".*/${packages}/.*\"
157+
\`\`\`
158+
159+
To run examples,
160+
161+
\`\`\`bash
162+
make examples EXAMPLES_FILTER=\".*/${packages}/.*\"
163+
\`\`\`
164+
"
165+
else
166+
comment="Hello! 👋
167+
168+
Pro-tip: Use the below \`make\` commands during local development to ensure that all tests, examples, and benchmark files in your PR run successfully.
169+
170+
For each of the commands, please run them from the root stdlib repository directory (not the package folder!).
171+
172+
To build the native add-on,
173+
174+
\`\`\`bash
175+
NODE_ADDONS_PATTERN="${packages}" make install-node-addons
176+
\`\`\`
177+
178+
To run unit tests,
179+
180+
\`\`\`bash
181+
make test TESTS_FILTER=\".*/${packages}/.*\"
182+
\`\`\`
183+
184+
To run benchmarks,
185+
186+
\`\`\`bash
187+
make benchmark BENCHMARKS_FILTER=\".*/${packages}/.*\"
188+
\`\`\`
189+
190+
\`\`\`bash
191+
make benchmark-c BENCHMARKS_FILTER=\".*/${packages}/.*\"
192+
\`\`\`
193+
194+
To run examples,
195+
196+
\`\`\`bash
197+
make examples EXAMPLES_FILTER=\".*/${packages}/.*\"
198+
\`\`\`
199+
200+
\`\`\`bash
201+
make examples-c EXAMPLES_FILTER=\".*/${packages}/.*\"
202+
\`\`\`
203+
"
204+
fi
205+
206+
if ! github_api "POST" "/repos/${repo_owner}/${repo_name}/issues/${pr_number}/comments" "{\"body\":$(echo "${comment}" | jq -R -s -c .)}"; then
207+
echo "Failed to post comment on PR."
208+
on_error 1
209+
fi
210+
211+
exit 0
212+
;;
213+
*\ * )
214+
echo "Skip leaving comment for PRs changing multiple packages."
215+
print_success
216+
exit 0
217+
;;
218+
esac
219+
}
220+
221+
main

.github/workflows/slash_commands.yml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ jobs:
6464
github-token: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
6565
script: |
6666
const commentBody = context.payload.comment.body.trim();
67-
const RE_COMMANDS = /^\/stdlib\s+(help|check-files|update-copyright-years|lint-autofix|merge|rebase)$/i;
67+
const RE_COMMANDS = /^\/stdlib\s+(help|check-files|update-copyright-years|lint-autofix|merge|rebase|commands-comment)$/i;
6868
const isRecognizedCommand = RE_COMMANDS.test( commentBody );
6969
7070
if ( isRecognizedCommand ) {
@@ -107,6 +107,24 @@ jobs:
107107
secrets:
108108
STDLIB_BOT_GITHUB_TOKEN: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
109109

110+
# Define a command for leaving a comment with make command instructions:
111+
commands-comment:
112+
# Define a display name:
113+
name: 'Post a comment with make command instructions'
114+
115+
# Ensure initial reaction job has completed before running this job:
116+
needs: [ add_initial_reaction ]
117+
118+
# Define the conditions under which the job should run:
119+
if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/stdlib commands-comment')
120+
121+
# Run reusable workflow:
122+
uses: ./.github/workflows/pr_commands_comment.yml
123+
with:
124+
pull_request_number: ${{ github.event.issue.number }}
125+
secrets:
126+
STDLIB_BOT_GITHUB_TOKEN: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
127+
110128
# Define a job for updating copyright header years:
111129
update_copyright_years:
112130

@@ -218,6 +236,7 @@ jobs:
218236
@${{ github.event.comment.user.login }}, available slash commands include:
219237
220238
- `/stdlib check-files` - Check for required files.
239+
- `/stdlib commands-comment` - Print `make` commands for package changed in PR.
221240
- `/stdlib update-copyright-years` - Update copyright header years.
222241
- `/stdlib lint-autofix` - Auto-fix lint errors.
223242
- `/stdlib merge` - Merge changes from develop branch into this PR.
@@ -236,7 +255,7 @@ jobs:
236255
runs-on: ubuntu-latest
237256

238257
# Ensure all previous jobs have completed before running this job:
239-
needs: [ add_initial_reaction, check_files, update_copyright_years, fix_lint_errors, merge_develop, rebase_develop, help ]
258+
needs: [ add_initial_reaction, check_files, commands-comment, update_copyright_years, fix_lint_errors, merge_develop, rebase_develop, help ]
240259

241260
# Define the conditions under which the job should run:
242261
if: |

0 commit comments

Comments
 (0)