207 lines
6.9 KiB
YAML
207 lines
6.9 KiB
YAML
name: vociferate/decorate-pr
|
|
description: >
|
|
Decorate pull requests with coverage badges, unreleased changelog entries,
|
|
and other useful review information. Updates existing comment or creates a
|
|
new one if it doesn't exist.
|
|
|
|
inputs:
|
|
coverage-percentage:
|
|
description: >
|
|
Computed coverage percentage (0-100). Typically from coverage-badge
|
|
action outputs.
|
|
required: true
|
|
badge-url:
|
|
description: >
|
|
Browser-facing URL for the coverage badge image (SVG). Typically from
|
|
coverage-badge action outputs.
|
|
required: true
|
|
changelog:
|
|
description: Path to changelog file relative to repository root.
|
|
required: false
|
|
default: CHANGELOG.md
|
|
comment-title:
|
|
description: >
|
|
Title/identifier for the PR comment. Used to locate existing comment
|
|
for updates. Defaults to 'Vociferate Review'.
|
|
required: false
|
|
default: 'Vociferate Review'
|
|
token:
|
|
description: >
|
|
GitHub or Gitea token for posting PR comments. Defaults to the
|
|
workflow token.
|
|
required: false
|
|
default: ''
|
|
|
|
outputs:
|
|
comment-id:
|
|
description: Numeric ID of the posted or updated PR comment.
|
|
value: ${{ steps.post-comment.outputs.comment_id }}
|
|
comment-url:
|
|
description: URL to the posted or updated PR comment.
|
|
value: ${{ steps.post-comment.outputs.comment_url }}
|
|
|
|
runs:
|
|
using: composite
|
|
steps:
|
|
- name: Validate PR context
|
|
id: validate
|
|
shell: bash
|
|
env:
|
|
GITHUB_EVENT_NAME: ${{ github.event_name }}
|
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ "$GITHUB_EVENT_NAME" != "pull_request" ]]; then
|
|
echo "This action only works on pull_request events" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "$PR_NUMBER" ]]; then
|
|
echo "Could not determine PR number from context" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf 'pr_number=%s\n' "$PR_NUMBER" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Extract changelog unreleased entries
|
|
id: extract-changelog
|
|
shell: bash
|
|
env:
|
|
CHANGELOG: ${{ inputs.changelog }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ ! -f "$CHANGELOG" ]]; then
|
|
printf 'unreleased_entries=%s\n' "" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
# Extract everything between [Unreleased] header and the next [X.Y.Z] header
|
|
unreleased="$(awk '
|
|
/^## \[Unreleased\]/ { in_unreleased=1; next }
|
|
/^## \[[0-9]+\.[0-9]+\.[0-9]+\]/ { if (in_unreleased) exit }
|
|
in_unreleased && NF { print }
|
|
' "$CHANGELOG")"
|
|
|
|
# Use a temporary file to handle multiline content
|
|
tmp_file=$(mktemp)
|
|
printf '%s' "$unreleased" > "$tmp_file"
|
|
|
|
# Read it back and set as output
|
|
delimiter="EOF_CHANGELOG"
|
|
printf '%s<<%s\n' "unreleased_entries<<$delimiter" "$delimiter" >> "$GITHUB_OUTPUT"
|
|
cat "$tmp_file" >> "$GITHUB_OUTPUT"
|
|
printf '%s\n' "$delimiter" >> "$GITHUB_OUTPUT"
|
|
|
|
rm -f "$tmp_file"
|
|
|
|
- name: Build PR comment markdown
|
|
id: build-comment
|
|
shell: bash
|
|
env:
|
|
COMMENT_TITLE: ${{ inputs.comment-title }}
|
|
COVERAGE_PCT: ${{ inputs.coverage-percentage }}
|
|
BADGE_URL: ${{ inputs.badge-url }}
|
|
UNRELEASED: ${{ steps.extract-changelog.outputs.unreleased_entries }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
# Start building the comment
|
|
tmp_file=$(mktemp)
|
|
|
|
# Add title and coverage section
|
|
cat > "$tmp_file" << 'EOF'
|
|
<!-- vociferate-pr-review -->
|
|
EOF
|
|
|
|
printf '## %s\n\n' "$COMMENT_TITLE" >> "$tmp_file"
|
|
|
|
# Coverage badge section
|
|
cat >> "$tmp_file" << EOF
|
|
### Coverage
|
|

|
|
|
|
**Coverage:** $COVERAGE_PCT%
|
|
|
|
EOF
|
|
|
|
# Changelog section
|
|
if [[ -n "$UNRELEASED" ]]; then
|
|
cat >> "$tmp_file" << 'EOF'
|
|
### Unreleased Changes
|
|
|
|
EOF
|
|
printf '%s\n' "$UNRELEASED" >> "$tmp_file"
|
|
printf '\n' >> "$tmp_file"
|
|
fi
|
|
|
|
# Add footer
|
|
cat >> "$tmp_file" << 'EOF'
|
|
---
|
|
*This comment was automatically generated by [vociferate/decorate-pr](https://git.hrafn.xyz/aether/vociferate).*
|
|
EOF
|
|
|
|
# Store as output using delimiter
|
|
delimiter="EOF_COMMENT"
|
|
printf '%s<<%s\n' "comment_body<<$delimiter" "$delimiter" >> "$GITHUB_OUTPUT"
|
|
cat "$tmp_file" >> "$GITHUB_OUTPUT"
|
|
printf '%s\n' "$delimiter" >> "$GITHUB_OUTPUT"
|
|
|
|
rm -f "$tmp_file"
|
|
|
|
- name: Find and update/post PR comment
|
|
id: post-comment
|
|
shell: bash
|
|
env:
|
|
GITHUB_TOKEN: ${{ inputs.token != '' && inputs.token || github.token }}
|
|
PR_NUMBER: ${{ steps.validate.outputs.pr_number }}
|
|
COMMENT_BODY: ${{ steps.build-comment.outputs.comment_body }}
|
|
SERVER_URL: ${{ github.server_url }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
API_URL="${SERVER_URL}/api/v1"
|
|
if [[ "$SERVER_URL" == *"github.com"* ]]; then
|
|
API_URL="https://api.github.com"
|
|
fi
|
|
|
|
# List existing comments to find vociferate comment
|
|
comments_url="${API_URL}/repos/${REPOSITORY}/issues/${PR_NUMBER}/comments"
|
|
|
|
response=$(curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" "$comments_url")
|
|
|
|
# Find existing vociferate comment by checking for the marker
|
|
existing_comment_id=$(printf '%s' "$response" | \
|
|
jq -r '.[] | select(.body | contains("vociferate-pr-review")) | .id' 2>/dev/null | \
|
|
head -1 || echo "")
|
|
|
|
if [[ -n "$existing_comment_id" ]]; then
|
|
# Update existing comment
|
|
update_url="${API_URL}/repos/${REPOSITORY}/issues/comments/${existing_comment_id}"
|
|
curl -s -X PATCH \
|
|
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$(printf '{"body": %s}' "$(printf '%s' "$COMMENT_BODY" | jq -Rs .)")" \
|
|
"$update_url" > /dev/null
|
|
|
|
printf 'comment_id=%s\n' "$existing_comment_id" >> "$GITHUB_OUTPUT"
|
|
printf 'comment_url=%s/repos/%s/issues/%s#issuecomment-%s\n' \
|
|
"$SERVER_URL" "$REPOSITORY" "$PR_NUMBER" "$existing_comment_id" >> "$GITHUB_OUTPUT"
|
|
else
|
|
# Create new comment
|
|
create_url="${API_URL}/repos/${REPOSITORY}/issues/${PR_NUMBER}/comments"
|
|
response=$(curl -s -X POST \
|
|
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$(printf '{"body": %s}' "$(printf '%s' "$COMMENT_BODY" | jq -Rs .)")" \
|
|
"$create_url")
|
|
|
|
comment_id=$(printf '%s' "$response" | jq -r '.id' 2>/dev/null)
|
|
|
|
printf 'comment_id=%s\n' "$comment_id" >> "$GITHUB_OUTPUT"
|
|
printf 'comment_url=%s/repos/%s/issues/%s#issuecomment-%s\n' \
|
|
"$SERVER_URL" "$REPOSITORY" "$PR_NUMBER" "$comment_id" >> "$GITHUB_OUTPUT"
|
|
fi
|