Skip to content

Commit 5c5c9f8

Browse files
Planeshifterkgryte
andauthored
build: bring first-time greeting script in-house
PR-URL: #5833 Closes: stdlib-js/metr-issue-tracker#47 Co-authored-by: Athan Reines <[email protected]> Reviewed-by: Athan Reines <[email protected]> Signed-off-by: Athan Reines <[email protected]>
1 parent c9cacbf commit 5c5c9f8

File tree

2 files changed

+234
-11
lines changed

2 files changed

+234
-11
lines changed

.github/workflows/first_time_greeting.yml

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,21 @@ jobs:
4242
# Define the sequence of job steps...
4343
steps:
4444

45-
# Greet first-time contributors:
46-
- name: 'Greet first-time contributors'
45+
# Checkout the repository:
46+
- name: 'Checkout repository'
4747
# Pin action to full length commit SHA
48-
uses: actions/first-interaction@34f15e814fe48ac9312ccf29db4e74fa767cbab7 # v1.3.0
48+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
4949
with:
50-
repo-token: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
51-
issue-message: |
52-
:wave: Hi there! :wave:
53-
54-
And thank you for opening your first issue! We will get back to you shortly. :runner: :dash:
55-
pr-message: |
56-
:wave: Hi there! :wave:
50+
# Ensure we have access to the scripts directory:
51+
sparse-checkout: |
52+
.github/workflows/scripts
53+
sparse-checkout-cone-mode: false
54+
timeout-minutes: 10
5755

58-
And thank you for opening your first pull request! We will review it shortly. :runner: :dash:
56+
# Greet first-time contributors:
57+
- name: 'Greet first-time contributors'
58+
env:
59+
ISSUE_NUMBER: ${{ github.event.issue.number }}
60+
GITHUB_TOKEN: ${{ secrets.STDLIB_BOT_PAT_REPO_WRITE }}
61+
run: |
62+
. "$GITHUB_WORKSPACE/.github/workflows/scripts/first_time_greeting" $ISSUE_NUMBER
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
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 greet first-time contributors.
20+
#
21+
# Usage: first_time_greeting <issue_number>
22+
#
23+
# Arguments:
24+
#
25+
# issue_number Issue or 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 issue or pull request number:
38+
issue_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 user_issues
109+
local user_login
110+
local user_prs
111+
local details
112+
local is_pr
113+
114+
if [ -z "${issue_number}" ]; then
115+
echo "ERROR: Issue or pull request number is required." >&2
116+
on_error 1
117+
fi
118+
119+
# Fetch details:
120+
details=$(github_api "GET" "/repos/${repo_owner}/${repo_name}/issues/${issue_number}")
121+
user_login=$(echo "${details}" | jq -r '.user.login')
122+
123+
is_pr=$(echo "$details" | jq -r 'has("pull_request")')
124+
125+
if [ "${is_pr}" = "true" ]; then
126+
# Fetch PRs opened by the user:
127+
user_prs=$(github_api "GET" "/search/issues?q=repo%3A${repo_owner}%2F${repo_name}+author%3A${user_login}+type%3Apr")
128+
129+
# Extract number of PRs by the user:
130+
num_prs=$(echo "${user_prs}" | jq -r '.total_count')
131+
132+
if [ "${num_prs}" = "1" ]; then
133+
# Post a comment on the PR:
134+
comment=":wave: Hi there! :wave:
135+
136+
And thank you for opening your first pull request! We will review it shortly. :runner: :dash:
137+
138+
## Getting Started
139+
140+
- Please read our [contributing guidelines][stdlib-contributing] if you haven't already.
141+
- For development guidance, refer to the [development guide][stdlib-development].
142+
143+
## Next Steps
144+
145+
1. A project maintainer will approve GitHub Actions workflows for your PR.
146+
2. All CI checks must pass before your submission can be fully reviewed.
147+
3. You'll need to address any failures in linting or unit tests.
148+
149+
## Running Tests Locally
150+
151+
You can use \`make\` to run any of the CI commands locally from the **root directory** of the stdlib repository:
152+
153+
\`\`\`bash
154+
# Run tests for all packages in the math namespace:
155+
make test TESTS_FILTER=\".*/@stdlib/math/.*\"
156+
157+
# Run benchmarks for a specific package:
158+
make benchmark BENCHMARKS_FILTER=\".*/@stdlib/math/base/special/sin/.*\"
159+
\`\`\`
160+
161+
If you haven't heard back from us within two weeks, please ping us by tagging the \"reviewers\" team in a comment on this PR.
162+
163+
If you have any further questions while waiting for a response, please join our [Gitter channel][stdlib-gitter] to chat with project maintainers and other community members.
164+
165+
We appreciate your contribution!
166+
167+
## Documentation Links
168+
169+
- [Contributing Guidelines][stdlib-contributing]
170+
- [Developtment Guide][stdlib-development]
171+
- [Gitter channel][stdlib-gitter]
172+
- [make rules for running examples][make-docs-examples]
173+
- [make rules for running unit tests][make-docs-test]
174+
- [make rules for running benchmarks][make-docs-benchmark]
175+
176+
[stdlib-contributing]: https://github.com/stdlib-js/stdlib/blob/develop/CONTRIBUTING.md
177+
[stdlib-development]: https://github.com/stdlib-js/stdlib/blob/develop/docs/contributing/development.md
178+
[stdlib-gitter]: https://gitter.im/stdlib-js/stdlib
179+
180+
[make-docs-examples]: https://github.com/stdlib-js/stdlib/blob/develop/tools/make/lib/examples/README.md
181+
[make-docs-test]: https://github.com/stdlib-js/stdlib/blob/develop/tools/make/lib/test/README.md
182+
[make-docs-benchmark]: https://github.com/stdlib-js/stdlib/blob/develop/tools/make/lib/benchmark/README.md"
183+
if ! github_api "POST" "/repos/${repo_owner}/${repo_name}/issues/${issue_number}/comments" "{\"body\":$(echo "${comment}" | jq -R -s -c .)}"; then
184+
echo "Failed to post comment on PR."
185+
on_error 1
186+
fi
187+
else
188+
echo "PR is not the first contribution from the respective user."
189+
fi
190+
else
191+
# Fetch issues opened by the user:
192+
user_issues=$(github_api "GET" "/search/issues?q=repo%3A${repo_owner}%2F${repo_name}+author%3A${user_login}+type%3Aissue")
193+
194+
# Extract number of issues by the user:
195+
num_issues=$(echo "${user_issues}" | jq -r '.total_count')
196+
197+
if [ "${num_issues}" = "1" ]; then
198+
# Post a comment on the issue:
199+
comment="wave: Hi there! :wave:
200+
201+
And thank you for opening your first issue! We will get back to you shortly. :runner: :dash:
202+
203+
If you have any further questions while waiting for a response, please join our [Gitter channel][stdlib-gitter] to chat with project maintainers and other community members.
204+
205+
[stdlib-gitter]: https://gitter.im/stdlib-js/stdlib"
206+
if ! github_api "POST" "/repos/${repo_owner}/${repo_name}/issues/${issue_number}/comments" "{\"body\":$(echo "${comment}" | jq -R -s -c .)}"; then
207+
echo "Failed to post comment on issue."
208+
on_error 1
209+
fi
210+
else
211+
echo "Issue is not the first contribution from the respective user."
212+
fi
213+
fi
214+
215+
print_success
216+
exit 0
217+
}
218+
219+
main

0 commit comments

Comments
 (0)