-
-
Notifications
You must be signed in to change notification settings - Fork 29
Updated posting of coverage comments to replace existing comments. #2380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,69 @@ | ||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||||||||||||||
| ## | ||||||||||||||||||||||||||||||||||||||||
| ## Post code coverage summary as a PR comment on GitHub. | ||||||||||||||||||||||||||||||||||||||||
| ## | ||||||||||||||||||||||||||||||||||||||||
| ## Minimizes previous coverage comments before posting a new one. | ||||||||||||||||||||||||||||||||||||||||
| ## | ||||||||||||||||||||||||||||||||||||||||
| ## Environment variables: | ||||||||||||||||||||||||||||||||||||||||
| ## CIRCLE_PULL_REQUEST - CircleCI PR URL. | ||||||||||||||||||||||||||||||||||||||||
| ## GITHUB_TOKEN - GitHub token for API access. | ||||||||||||||||||||||||||||||||||||||||
| ## CIRCLE_PROJECT_USERNAME - GitHub org/user. | ||||||||||||||||||||||||||||||||||||||||
| ## CIRCLE_PROJECT_REPONAME - GitHub repo name. | ||||||||||||||||||||||||||||||||||||||||
| ## | ||||||||||||||||||||||||||||||||||||||||
| ## Usage: | ||||||||||||||||||||||||||||||||||||||||
| ## .circleci/post-coverage-comment.sh /path/to/coverage.txt | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| COVERAGE_FILE="${1:-}" | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if [ -z "${COVERAGE_FILE}" ] || [ ! -f "${COVERAGE_FILE}" ]; then | ||||||||||||||||||||||||||||||||||||||||
| echo "ERROR: Coverage file not found: ${COVERAGE_FILE}" >&2 | ||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if [ -z "${CIRCLE_PULL_REQUEST:-}" ]; then | ||||||||||||||||||||||||||||||||||||||||
| echo "Not a pull request. Skipping." | ||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if [ -z "${GITHUB_TOKEN:-}" ]; then | ||||||||||||||||||||||||||||||||||||||||
| echo "GITHUB_TOKEN is not set. Skipping." | ||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| COVERAGE_CONTENT=$(sed '/./,$!d' "${COVERAGE_FILE}") | ||||||||||||||||||||||||||||||||||||||||
| PR_NUMBER=$(echo "${CIRCLE_PULL_REQUEST}" | cut -d'/' -f 7) | ||||||||||||||||||||||||||||||||||||||||
| REPO_SLUG="${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| MARKER="<!-- coverage-circleci -->" | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| BODY=$(jq -n --arg body "**Code coverage (CircleCI)** | ||||||||||||||||||||||||||||||||||||||||
| \`\`\` | ||||||||||||||||||||||||||||||||||||||||
| ${COVERAGE_CONTENT} | ||||||||||||||||||||||||||||||||||||||||
| \`\`\` | ||||||||||||||||||||||||||||||||||||||||
| ${MARKER}" '{body: $body}') | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| # Minimize previous coverage comments. | ||||||||||||||||||||||||||||||||||||||||
| COMMENTS_JSON=$(curl -s \ | ||||||||||||||||||||||||||||||||||||||||
| -H "Authorization: token ${GITHUB_TOKEN}" \ | ||||||||||||||||||||||||||||||||||||||||
| -H "Accept: application/vnd.github.v3+json" \ | ||||||||||||||||||||||||||||||||||||||||
| "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments?per_page=100") | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| EXISTING_IDS=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("<!-- coverage-circleci -->")) | .node_id') | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add validation for the GET comments API response. If the API returns an error (e.g., rate limiting, 404, auth failure), 🛡️ Proposed fix to validate GET response # Minimize previous coverage comments.
COMMENTS_JSON=$(curl -s \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments?per_page=100")
+# Validate response is a JSON array (not an error object).
+if ! echo "${COMMENTS_JSON}" | jq -e 'type == "array"' >/dev/null 2>&1; then
+ echo "WARNING: Failed to fetch existing comments. Proceeding without minimization." >&2
+ EXISTING_IDS=""
+else
-EXISTING_IDS=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("<!-- coverage-circleci -->")) | .node_id')
+ EXISTING_IDS=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("<!-- coverage-circleci -->")) | .node_id')
+fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| for NODE_ID in ${EXISTING_IDS}; do | ||||||||||||||||||||||||||||||||||||||||
| GRAPHQL_BODY=$(jq -n --arg id "${NODE_ID}" '{query: "mutation($id:ID!){minimizeComment(input:{subjectId:$id,classifier:OUTDATED}){minimizedComment{isMinimized}}}", variables: {id: $id}}') | ||||||||||||||||||||||||||||||||||||||||
| curl -s -X POST \ | ||||||||||||||||||||||||||||||||||||||||
| -H "Authorization: bearer ${GITHUB_TOKEN}" \ | ||||||||||||||||||||||||||||||||||||||||
| -H "Content-Type: application/json" \ | ||||||||||||||||||||||||||||||||||||||||
| "https://api.github.com/graphql" \ | ||||||||||||||||||||||||||||||||||||||||
| -d "${GRAPHQL_BODY}" | ||||||||||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+55
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider logging GraphQL minimize failures. The GraphQL minimize calls fail silently. While not critical (the new comment still posts), logging failures would help debug issues when stale comments aren't being minimized. 🔍 Proposed enhancement for visibility for NODE_ID in ${EXISTING_IDS}; do
GRAPHQL_BODY=$(jq -n --arg id "${NODE_ID}" '{query: "mutation($id:ID!){minimizeComment(input:{subjectId:$id,classifier:OUTDATED}){minimizedComment{isMinimized}}}", variables: {id: $id}}')
- curl -s -X POST \
+ MINIMIZE_RESPONSE=$(curl -s -X POST \
-H "Authorization: bearer ${GITHUB_TOKEN}" \
-H "Content-Type: application/json" \
"https://api.github.com/graphql" \
- -d "${GRAPHQL_BODY}"
+ -d "${GRAPHQL_BODY}")
+ if echo "${MINIMIZE_RESPONSE}" | jq -e '.errors' >/dev/null 2>&1; then
+ echo "WARNING: Failed to minimize comment ${NODE_ID}" >&2
+ fi
done📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| # Post new coverage comment. | ||||||||||||||||||||||||||||||||||||||||
| curl -s -X POST \ | ||||||||||||||||||||||||||||||||||||||||
| -H "Authorization: token ${GITHUB_TOKEN}" \ | ||||||||||||||||||||||||||||||||||||||||
| -H "Accept: application/vnd.github.v3+json" \ | ||||||||||||||||||||||||||||||||||||||||
| "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments" \ | ||||||||||||||||||||||||||||||||||||||||
| -d "${BODY}" | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider adding error handling for the final POST request. The script exits successfully regardless of whether the comment was actually posted. A failed POST (e.g., rate limiting, permission issues) would silently fail since 🛡️ Proposed fix to add response validation # Post new coverage comment.
-curl -s -X POST \
+RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments" \
- -d "${BODY}"
+ -d "${BODY}")
+
+HTTP_CODE=$(echo "${RESPONSE}" | tail -n1)
+if [ "${HTTP_CODE}" -lt 200 ] || [ "${HTTP_CODE}" -ge 300 ]; then
+ echo "ERROR: Failed to post comment. HTTP ${HTTP_CODE}" >&2
+ exit 1
+fi🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #!/usr/bin/env bash | ||
| ## | ||
| ## Post code coverage summary as a PR comment on GitHub. | ||
| ## | ||
| ## Minimizes previous coverage comments before posting a new one. | ||
| ## | ||
| ## Environment variables: | ||
| ## CIRCLE_PULL_REQUEST - CircleCI PR URL. | ||
| ## GITHUB_TOKEN - GitHub token for API access. | ||
| ## CIRCLE_PROJECT_USERNAME - GitHub org/user. | ||
| ## CIRCLE_PROJECT_REPONAME - GitHub repo name. | ||
| ## | ||
| ## Usage: | ||
| ## .circleci/post-coverage-comment.sh /path/to/coverage.txt | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| COVERAGE_FILE="${1:-}" | ||
|
|
||
| if [ -z "${COVERAGE_FILE}" ] || [ ! -f "${COVERAGE_FILE}" ]; then | ||
| echo "ERROR: Coverage file not found: ${COVERAGE_FILE}" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ -z "${CIRCLE_PULL_REQUEST:-}" ]; then | ||
| echo "Not a pull request. Skipping." | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [ -z "${GITHUB_TOKEN:-}" ]; then | ||
| echo "GITHUB_TOKEN is not set. Skipping." | ||
| exit 0 | ||
| fi | ||
|
|
||
| COVERAGE_CONTENT=$(sed '/./,$!d' "${COVERAGE_FILE}") | ||
| PR_NUMBER=$(echo "${CIRCLE_PULL_REQUEST}" | cut -d'/' -f 7) | ||
| REPO_SLUG="${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" | ||
|
|
||
| MARKER="<!-- coverage-circleci -->" | ||
|
|
||
| BODY=$(jq -n --arg body "**Code coverage (CircleCI)** | ||
| \`\`\` | ||
| ${COVERAGE_CONTENT} | ||
| \`\`\` | ||
| ${MARKER}" '{body: $body}') | ||
|
|
||
| # Minimize previous coverage comments. | ||
| COMMENTS_JSON=$(curl -s \ | ||
| -H "Authorization: token ${GITHUB_TOKEN}" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments?per_page=100") | ||
|
|
||
| EXISTING_IDS=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("<!-- coverage-circleci -->")) | .node_id') | ||
|
|
||
| for NODE_ID in ${EXISTING_IDS}; do | ||
| GRAPHQL_BODY=$(jq -n --arg id "${NODE_ID}" '{query: "mutation($id:ID!){minimizeComment(input:{subjectId:$id,classifier:OUTDATED}){minimizedComment{isMinimized}}}", variables: {id: $id}}') | ||
| curl -s -X POST \ | ||
| -H "Authorization: bearer ${GITHUB_TOKEN}" \ | ||
| -H "Content-Type: application/json" \ | ||
| "https://api.github.com/graphql" \ | ||
| -d "${GRAPHQL_BODY}" | ||
| done | ||
|
|
||
| # Post new coverage comment. | ||
| curl -s -X POST \ | ||
| -H "Authorization: token ${GITHUB_TOKEN}" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments" \ | ||
| -d "${BODY}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #!/usr/bin/env bash | ||
| ## | ||
| ## Post code coverage summary as a PR comment on GitHub. | ||
| ## | ||
| ## Minimizes previous coverage comments before posting a new one. | ||
| ## | ||
| ## Environment variables: | ||
| ## CIRCLE_PULL_REQUEST - CircleCI PR URL. | ||
| ## GITHUB_TOKEN - GitHub token for API access. | ||
| ## CIRCLE_PROJECT_USERNAME - GitHub org/user. | ||
| ## CIRCLE_PROJECT_REPONAME - GitHub repo name. | ||
| ## | ||
| ## Usage: | ||
| ## .circleci/post-coverage-comment.sh /path/to/coverage.txt | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| COVERAGE_FILE="${1:-}" | ||
|
|
||
| if [ -z "${COVERAGE_FILE}" ] || [ ! -f "${COVERAGE_FILE}" ]; then | ||
| echo "ERROR: Coverage file not found: ${COVERAGE_FILE}" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ -z "${CIRCLE_PULL_REQUEST:-}" ]; then | ||
| echo "Not a pull request. Skipping." | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [ -z "${GITHUB_TOKEN:-}" ]; then | ||
| echo "GITHUB_TOKEN is not set. Skipping." | ||
| exit 0 | ||
| fi | ||
|
|
||
| COVERAGE_CONTENT=$(sed '/./,$!d' "${COVERAGE_FILE}") | ||
| PR_NUMBER=$(echo "${CIRCLE_PULL_REQUEST}" | cut -d'/' -f 7) | ||
| REPO_SLUG="${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" | ||
|
|
||
| MARKER="<!-- coverage-circleci -->" | ||
|
|
||
| BODY=$(jq -n --arg body "**Code coverage (CircleCI)** | ||
| \`\`\` | ||
| ${COVERAGE_CONTENT} | ||
| \`\`\` | ||
| ${MARKER}" '{body: $body}') | ||
|
|
||
| # Minimize previous coverage comments. | ||
| COMMENTS_JSON=$(curl -s \ | ||
| -H "Authorization: token ${GITHUB_TOKEN}" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments?per_page=100") | ||
|
|
||
| EXISTING_IDS=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("<!-- coverage-circleci -->")) | .node_id') | ||
|
|
||
| for NODE_ID in ${EXISTING_IDS}; do | ||
| GRAPHQL_BODY=$(jq -n --arg id "${NODE_ID}" '{query: "mutation($id:ID!){minimizeComment(input:{subjectId:$id,classifier:OUTDATED}){minimizedComment{isMinimized}}}", variables: {id: $id}}') | ||
| curl -s -X POST \ | ||
| -H "Authorization: bearer ${GITHUB_TOKEN}" \ | ||
| -H "Content-Type: application/json" \ | ||
| "https://api.github.com/graphql" \ | ||
| -d "${GRAPHQL_BODY}" | ||
| done | ||
|
|
||
| # Post new coverage comment. | ||
| curl -s -X POST \ | ||
| -H "Authorization: token ${GITHUB_TOKEN}" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments" \ | ||
| -d "${BODY}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
PR number extraction may fail for non-standard URL formats.
The extraction using
cut -d'/' -f 7assumes the URL always followshttps://github.com/org/repo/pull/123format. Consider adding validation.🛡️ Proposed fix to add validation
PR_NUMBER=$(echo "${CIRCLE_PULL_REQUEST}" | cut -d'/' -f 7) +if ! [[ "${PR_NUMBER}" =~ ^[0-9]+$ ]]; then + echo "ERROR: Could not extract PR number from CIRCLE_PULL_REQUEST: ${CIRCLE_PULL_REQUEST}" >&2 + exit 1 +fi REPO_SLUG="${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}"📝 Committable suggestion
🤖 Prompt for AI Agents