Skip to content

Commit 097ea5e

Browse files
committed
build: create sub-issues upon encountering C lint errors
build: create sub-issues upon encountering C lint errors
1 parent 7bfeb06 commit 097ea5e

File tree

2 files changed

+253
-0
lines changed

2 files changed

+253
-0
lines changed

.github/workflows/lint_random_files.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,22 @@ jobs:
386386
make lint-c-files FILES="${files}" CPPCHECK_SUPPRESSIONS_LIST="${cppcheck_benchmarks_suppressions_list}"
387387
fi
388388
389+
# Create sub-issue for C linting failures:
390+
- name: 'Create sub-issue for C lint failures'
391+
if: ( github.event.inputs.c != 'false' ) && failure() && contains(steps.*.outcome, 'failure') && contains(job.steps.*.name, 'Lint C files')
392+
env:
393+
GITHUB_TOKEN: ${{ secrets.STDLIB_BOT_GITHUB_TOKEN }}
394+
run: |
395+
# Create a temporary file for storing lint error messages:
396+
ERROR_LOG=$(mktemp)
397+
grep -B 1 -A 2 "style:\|warning:\|error:" <<< "${{ steps.lint-c.outputs.stderr }}" > $ERROR_LOG
398+
399+
. "$GITHUB_WORKSPACE/.github/workflows/scripts/create_lint_sub_issue.sh" \
400+
"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
401+
"C" \
402+
"3235" \ # Number of C lint error tracking issue
403+
"$ERROR_LOG"
404+
389405
# Lint TypeScript declarations files:
390406
- name: 'Lint TypeScript declarations files'
391407
if: ( github.event.inputs.javascript != 'false' ) && ( success() || failure() )
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#!/usr/bin/env bash
2+
#
3+
# @license Apache-2.0
4+
#
5+
# Copyright (c) 2024 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 create a sub-issue for linting failures
20+
#
21+
# Usage: ./create_lint_sub_issue.sh <workflow-url> <lint-type> <parent-issue-number>
22+
#
23+
# Arguments:
24+
#
25+
# workflow-url URL of the workflow run.
26+
# lint-type Type of linting failure.
27+
# parent-issue-number Number of the parent issue.
28+
# error-log-file Path to the error log file.
29+
#
30+
#
31+
# Environment variables:
32+
#
33+
# GITHUB_TOKEN GitHub authentication token.
34+
#
35+
36+
# shellcheck disable=SC2153,SC2317
37+
38+
# Ensure that the exit status of pipelines is non-zero in the event that at least one of the commands in a pipeline fails:
39+
set -o pipefail
40+
41+
# VARIABLES #
42+
43+
# Assign command line arguments to variables:
44+
workflow_url="$1"
45+
lint_type="$2"
46+
parent_issue_number="$3"
47+
error_log_file="$4"
48+
49+
# Repository information:
50+
owner="stdlib-js"
51+
repo="stdlib"
52+
53+
# Get the GitHub authentication token:
54+
github_token="${GITHUB_TOKEN}"
55+
if [ -z "$github_token" ]; then
56+
echo -e "ERROR: GITHUB_TOKEN environment variable is not set."
57+
exit 1
58+
fi
59+
60+
# Read and format the error log
61+
if [ ! -f "$error_log_file" ]; then
62+
echo -e "Error log file not found: ${error_log_file}"
63+
exit 1
64+
fi
65+
error_log_content=$(cat "$error_log_file")
66+
67+
# Create issue body with formatted error log
68+
issue_body="## ${lint_type} Linting Failures
69+
70+
Linting failures were detected in the automated lint workflow run.
71+
72+
### Workflow Details
73+
- Run: ${workflow_url}
74+
- Type: ${lint_type} Linting
75+
- Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
76+
77+
### Error Details
78+
\`\`\`
79+
${error_log_content}
80+
\`\`\`
81+
"
82+
83+
# FUNCTIONS #
84+
85+
# Error handler.
86+
#
87+
# $1 - error status
88+
on_error() {
89+
echo -e "ERROR: An error was encountered during execution." >&2
90+
exit "$1"
91+
}
92+
93+
# Prints a success message.
94+
print_success() {
95+
echo -e "Success!" >&2
96+
}
97+
98+
# Fetches the repository node ID.
99+
fetch_repo_id() {
100+
local response
101+
response=$(curl -s -X POST 'https://api.github.com/graphql' \
102+
-H "Authorization: bearer ${github_token}" \
103+
-H "Content-Type: application/json" \
104+
--data @- << EOF
105+
{
106+
"query": "query(\$owner: String!, \$repo: String!) { repository(owner: \$owner, name: \$repo) { id } }",
107+
"variables": {
108+
"owner": "${owner}",
109+
"repo": "${repo}"
110+
}
111+
}
112+
EOF
113+
)
114+
echo "$response" | jq -r '.data.repository.id'
115+
}
116+
117+
# Creates a child issue.
118+
#
119+
# $1 - repository node ID
120+
# $2 - issue body
121+
create_child_issue() {
122+
local repo_id="$1"
123+
local issue_body="$2"
124+
local response
125+
response=$(curl -s -X POST 'https://api.github.com/graphql' \
126+
-H "Authorization: bearer ${github_token}" \
127+
-H "Content-Type: application/json" \
128+
--data @- << EOF
129+
{
130+
"query": "mutation CreateIssue(\$repositoryId: ID!, \$title: String!, \$body: String!) { createIssue(input: {repositoryId: \$repositoryId, title: \$title, body: \$body}) { issue { id number } } }",
131+
"variables": {
132+
"repositoryId": "${repo_id}",
133+
"title": "Fix ${lint_type} lint errors",
134+
"body": $(echo "$issue_body" | jq -R -s '.')
135+
}
136+
}
137+
EOF
138+
)
139+
echo "$response"
140+
}
141+
142+
# Fetches the parent issue ID.
143+
fetch_parent_issue_id() {
144+
local response
145+
response=$(curl -s -X POST 'https://api.github.com/graphql' \
146+
-H "Authorization: bearer ${github_token}" \
147+
-H "Content-Type: application/json" \
148+
--data @- << EOF
149+
{
150+
"query": "query(\$owner: String!, \$repo: String!, \$number: Int!) { repository(owner: \$owner, name: \$repo) { issue(number: \$number) { id } } }",
151+
"variables": {
152+
"owner": "${owner}",
153+
"repo": "${repo}",
154+
"number": ${parent_issue_number}
155+
}
156+
}
157+
EOF
158+
)
159+
echo "$response" | jq -r '.data.repository.issue.id'
160+
}
161+
162+
# Creates a sub-issue relationship.
163+
#
164+
# $1 - parent issue ID
165+
# $2 - child issue ID
166+
create_sub_issue_relationship() {
167+
local parent_issue_id="$1"
168+
local child_issue_id="$2"
169+
local response
170+
response=$(curl -s -X POST 'https://api.github.com/graphql' \
171+
-H "Authorization: bearer ${github_token}" \
172+
-H "GraphQL-Features: issue_types" \
173+
-H "GraphQL-Features: sub_issues" \
174+
-H "Content-Type: application/json" \
175+
--data @- << EOF
176+
{
177+
"query": "mutation(\$parentIssueId: ID!, \$childIssueId: ID!) { addSubIssue(input: { issueId: \$parentIssueId, subIssueId: \$childIssueId }) { issue { number } subIssue { number } } }",
178+
"variables": {
179+
"parentIssueId": "${parent_issue_id}",
180+
"childIssueId": "${child_issue_id}"
181+
}
182+
}
183+
EOF
184+
)
185+
echo "$response"
186+
}
187+
188+
# Main execution sequence.
189+
main() {
190+
echo "Fetching repository node ID..."
191+
repo_id=$(fetch_repo_id)
192+
if [ -z "$repo_id" ] || [ "$repo_id" = "null" ]; then
193+
echo -e "Failed to fetch repository ID."
194+
exit 1
195+
fi
196+
197+
echo "Creating child issue for ${lint_type} lint failures..."
198+
child_issue_response=$(create_child_issue "$repo_id" "$issue_body")
199+
200+
child_issue_id=$(echo "$child_issue_response" | jq -r '.data.createIssue.issue.id')
201+
child_issue_number=$(echo "$child_issue_response" | jq -r '.data.createIssue.issue.number')
202+
203+
if [ -z "$child_issue_id" ] || [ "$child_issue_id" = "null" ]; then
204+
echo -e "Failed to create child issue. Response: ${child_issue_response}"
205+
exit 1
206+
fi
207+
208+
echo -e "Created child issue #${child_issue_number}"
209+
210+
echo "Fetching parent issue #${parent_issue_number}..."
211+
parent_issue_id=$(fetch_parent_issue_id)
212+
213+
if [ -z "$parent_issue_id" ] || [ "$parent_issue_id" = "null" ]; then
214+
echo -e "Failed to fetch parent issue."
215+
exit 1
216+
fi
217+
218+
echo "Creating sub-issue relationship..."
219+
sub_issue_response=$(create_sub_issue_relationship "$parent_issue_id" "$child_issue_id")
220+
sub_issue_success=$(echo "$sub_issue_response" | jq -r '.data.addSubIssue.subIssue.number')
221+
222+
if [ -z "$sub_issue_success" ] || [ "$sub_issue_success" = "null" ]; then
223+
echo -e "Failed to create sub-issue relationship. Response: ${sub_issue_response}"
224+
exit 1
225+
fi
226+
227+
echo -e "Successfully created sub-issue relationship between #${parent_issue_number} and #${child_issue_number}"
228+
229+
print_success
230+
exit 0
231+
}
232+
233+
# Set an error handler to capture errors and perform any clean-up tasks:
234+
trap 'on_error $?' ERR
235+
236+
# Run main:
237+
main

0 commit comments

Comments
 (0)