Feature/toh #147
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: contributor automation | |
| on: | |
| schedule: | |
| - cron: '0 0 * * *' | |
| pull_request_target: | |
| types: [closed] | |
| branches: | |
| - main | |
| # Prevent multiple runs from overlapping and causing commit conflicts | |
| concurrency: | |
| group: contributor-automation | |
| cancel-in-progress: true | |
| permissions: | |
| contents: write | |
| jobs: | |
| update-readme: | |
| # Security: pull_request_target runs in the context of the base repo. | |
| # We only run if the event is a schedule or a merged PR. | |
| if: github.event_name == 'schedule' || (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Base Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| # Security: Explicitly checkout the base repository's default branch. | |
| # This ensures we are running trusted code from the main repo, not the fork. | |
| ref: ${{ github.event.repository.default_branch }} | |
| fetch-depth: 0 | |
| - name: Fetch Contributors (Paginated) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| echo "[]" > contributors.json | |
| PAGE=1 | |
| echo "Fetching contributors from GitHub API..." | |
| while true; do | |
| # Scaling: Handle pagination to fetch all contributors. | |
| # Security: Using standard GH API with Linux timeout utility. | |
| timeout 30s gh api "/repos/${{ github.repository }}/contributors?per_page=100&page=${PAGE}" > "response_${PAGE}.json" || { | |
| echo "API call failed or timed out. Retrying once..." | |
| sleep 5 | |
| timeout 60s gh api "/repos/${{ github.repository }}/contributors?per_page=100&page=${PAGE}" > "response_${PAGE}.json" | |
| } | |
| COUNT=$(jq '. | length' "response_${PAGE}.json") | |
| if [ "$COUNT" -eq 0 ]; then break; fi | |
| # Merge and filter out bots | |
| jq -s '.[0] + [.[1][] | select(.type != "Bot")]' contributors.json "response_${PAGE}.json" > tmp.json && mv tmp.json contributors.json | |
| if [ "$COUNT" -lt 100 ]; then break; fi | |
| PAGE=$((PAGE + 1)) | |
| done | |
| # Extract only unique logins | |
| jq -r '.[] | .login' contributors.json | sort -u > contributor_logins.txt | |
| - name: Build Professional Contributor Grid | |
| run: | | |
| set -euo pipefail | |
| # UI: Professional 6-column HTML grid with avatars | |
| echo "<table border=\"0\">" > gallery.html | |
| echo " <tr>" >> gallery.html | |
| COL=0 | |
| while IFS= read -r USERNAME; do | |
| if [ "$COL" -eq 6 ]; then | |
| echo " </tr>" >> gallery.html | |
| echo " <tr>" >> gallery.html | |
| COL=0 | |
| fi | |
| echo " <td align=\"center\" width=\"120\">" >> gallery.html | |
| echo " <a href=\"https://github.com/${USERNAME}\">" >> gallery.html | |
| echo " <img src=\"https://github.com/${USERNAME}.png?size=100\" width=\"100\" height=\"100\" style=\"border-radius:50%; border:2px solid #555;\" alt=\"${USERNAME}\" /><br />" >> gallery.html | |
| echo " <sub><b>@${USERNAME}</b></sub>" >> gallery.html | |
| echo " </a>" >> gallery.html | |
| echo " </td>" >> gallery.html | |
| COL=$((COL + 1)) | |
| done < contributor_logins.txt | |
| # Fill remaining empty cells to maintain grid structure | |
| while [ "$COL" -lt 6 ] && [ "$COL" -gt 0 ]; do | |
| echo " <td width=\"120\"></td>" >> gallery.html | |
| COL=$((COL + 1)) | |
| done | |
| echo " </tr>" >> gallery.html | |
| echo "</table>" >> gallery.html | |
| - name: Update README.md | |
| run: | | |
| set -euo pipefail | |
| # Verify markers exist before modification | |
| if ! grep -q "<!-- CONTRIBUTORS_START -->" README.md || ! grep -q "<!-- CONTRIBUTORS_END -->" README.md; then | |
| echo "Error: Markers missing in README.md" | |
| exit 1 | |
| fi | |
| # Surgical replacement using markers | |
| sed -n '1,/<!-- CONTRIBUTORS_START -->/p' README.md > README.new | |
| cat gallery.html >> README.new | |
| sed -n '/<!-- CONTRIBUTORS_END -->/,$p' README.md >> README.new | |
| mv README.new README.md | |
| - name: Commit and Push | |
| run: | | |
| git config --global user.name "github-actions[bot]" | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| git add README.md | |
| if git diff --staged --quiet; then | |
| echo "No changes to README." | |
| else | |
| # Permissions: Using the GITHUB_TOKEN's write authority | |
| git commit -m "docs: update contributor gallery [skip ci]" | |
| git push origin HEAD:${{ github.event.repository.default_branch }} | |
| fi |