Weekly OpenCHAMI Digest → Website PR #41
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: Weekly OpenCHAMI Digest → Website PR | |
| on: | |
| schedule: | |
| # Mondays 09:00 America/Denver (16:00 UTC most of the year) | |
| - cron: "0 16 * * 1" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| models: read | |
| env: | |
| ORG: OpenCHAMI | |
| WEBSITE_REPO: OpenCHAMI/openchami.org | |
| POST_DIR: content/news/weekly | |
| LOCAL_TZ: America/Denver | |
| POST_TIME: "09:00:00" # local publish time in the Hugo front matter | |
| MODEL_ID: openai/gpt-4.1-mini | |
| jobs: | |
| weekly_digest: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout (community repo context) | |
| uses: actions/checkout@v4 | |
| - name: Install GitHub CLI + models extension | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y jq | |
| gh extension install github/gh-models | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Verify org-level token is available | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_READ_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "${GH_TOKEN:-}" ]]; then | |
| echo "ORG_READ_TOKEN is not available to this workflow." | |
| exit 1 | |
| fi | |
| # Lightweight call that should succeed with a fine-grained PAT that can read public repos | |
| gh api "/rate_limit" >/dev/null | |
| echo "ORG_READ_TOKEN present and usable." | |
| - name: Compute dates (Denver-local & UTC) | |
| id: dates | |
| run: | | |
| # Past 7 days window (UTC for queries) | |
| SINCE_UTC=$(date -u -d "7 days ago" +"%Y-%m-%d") | |
| NOW_UTC=$(date -u +"%Y-%m-%d") | |
| # Publication date/time in local tz for Hugo front matter & filenames | |
| export TZ="${LOCAL_TZ}" | |
| PUB_DATE=$(date +"%Y-%m-%d") | |
| PUB_YEAR=$(date +"%Y") | |
| PUB_MONTH=$(date +"%m") | |
| PUB_ISO_LOCAL="${PUB_DATE}T${POST_TIME}" | |
| # Pretty range for title | |
| RANGE_START_PRETTY=$(date -d "7 days ago" +"%b %d") | |
| RANGE_END_PRETTY=$(date +"%b %d, %Y") | |
| echo "since_utc=$SINCE_UTC" >> $GITHUB_OUTPUT | |
| echo "now_utc=$NOW_UTC" >> $GITHUB_OUTPUT | |
| echo "pub_date=$PUB_DATE" >> $GITHUB_OUTPUT | |
| echo "pub_year=$PUB_YEAR" >> $GITHUB_OUTPUT | |
| echo "pub_month=$PUB_MONTH" >> $GITHUB_OUTPUT | |
| echo "pub_iso_local=$PUB_ISO_LOCAL" >> $GITHUB_OUTPUT | |
| echo "range_start=$RANGE_START_PRETTY" >> $GITHUB_OUTPUT | |
| echo "range_end=$RANGE_END_PRETTY" >> $GITHUB_OUTPUT | |
| - name: Collect org activity → activity.json | |
| run: | | |
| set -e | |
| ORG="${ORG}" | |
| SINCE="${{ steps.dates.outputs.since_utc }}" | |
| # Issues updated in last 7 days | |
| gh search issues "org:$ORG" "is:public" "updated:>$SINCE" \ | |
| --json title,number,repository,author,createdAt,updatedAt,state,labels,url > issues.json | |
| # PRs updated/merged in last 7 days | |
| gh search prs "org:$ORG" "is:public" "updated:>$SINCE" \ | |
| --json title,number,repository,author,createdAt,updatedAt,state,labels,url > prs.json | |
| # Releases (enumerate repos and fetch via REST API) | |
| gh api "/orgs/$ORG/repos?per_page=100&type=public" > repos.json | |
| : > releases.jsonl | |
| jq -r '.[].name' repos.json | while read -r REPO; do | |
| gh api -H "Accept: application/vnd.github+json" "/repos/$ORG/$REPO/releases?per_page=100" \ | |
| | jq -c --arg SINCE "${SINCE}T00:00:00Z" '.[] | select(.created_at >= $SINCE) | {name, tag_name, created_at, html_url, repository:"'$ORG'/'$REPO'"}' \ | |
| >> releases.jsonl || true | |
| done | |
| jq -s '.' releases.jsonl > releases.json || echo '[]' > releases.json | |
| # Public org events (best effort) | |
| gh api "/orgs/$ORG/events" > events.json || echo '[]' > events.json | |
| jq -n \ | |
| --slurpfile issues issues.json \ | |
| --slurpfile prs prs.json \ | |
| --slurpfile releases releases.json \ | |
| --slurpfile events events.json \ | |
| '{issues:$issues[0], prs:$prs[0], releases:$releases[0], events:$events[0]}' \ | |
| > activity.json | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_READ_TOKEN }} | |
| ORG: ${{ env.ORG }} | |
| - name: Write prompt file | |
| run: | | |
| mkdir -p prompts | |
| cat > prompts/digest.prompt.yml <<'YML' | |
| name: Weekly Org Digest | |
| description: Summarize OpenCHAMI org activity for new users and contributors. | |
| messages: | |
| - role: system | |
| content: > | |
| You are a technical writer + developer marketer. | |
| Create a concise, skimmable weekly digest in Markdown. | |
| Sections: Highlights, New & Notable PRs, Issues to Watch, Releases, Contributor Thanks. | |
| Link to items. Prefer user-facing language. Avoid internal jargon. | |
| End with "What’s next" suggestions and 3–5 proposed blog titles. | |
| - role: user | |
| content: > | |
| Here is JSON of activity across the org for the last 7 days. | |
| Extract themes (user value), group by repo when helpful, | |
| and surface at most 10 bullets in Highlights. | |
| Data:\n{{input}} | |
| YML | |
| - name: Generate digest (Markdown) with GitHub Models → DIGEST.md | |
| run: | | |
| set -Eeuo pipefail | |
| # Keep all issues, PRs, and releases but strip verbose fields to fit token limits | |
| # Remove events entirely as they're redundant with issues/PRs and add significant size | |
| jq '{ | |
| issues: [.issues[] | {title, number, repository, author, state, url}], | |
| prs: [.prs[] | {title, number, repository, author, state, url}], | |
| releases: [.releases[] | {name, tag_name, repository, html_url}], | |
| events: [] | |
| }' activity.json > activity_subset.json | |
| ACTIVITY_DATA=$(cat activity_subset.json) | |
| gh models run "$MODEL_ID" --file prompts/digest.prompt.yml --var input="$ACTIVITY_DATA" > DIGEST.md | |
| if [ ! -f DIGEST.md ]; then | |
| echo "DIGEST.md not created; check model run and activity.json." | |
| exit 1 | |
| fi | |
| cat DIGEST.md | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| MODEL_ID: ${{ env.MODEL_ID }} | |
| - name: Build Hugo post content → POST.md | |
| id: post | |
| run: | | |
| set -e | |
| TITLE="OpenCHAMI Weekly Digest: ${{ steps.dates.outputs.range_start }}–${{ steps.dates.outputs.range_end }}" | |
| SLUG="weekly-digest-${{ steps.dates.outputs.pub_date }}" | |
| FRONTMATTER=$(cat <<EOF | |
| --- | |
| title: "${TITLE}" | |
| date: "${{ steps.dates.outputs.pub_iso_local }}" | |
| slug: "${SLUG}" | |
| tags: ["weekly", "updates", "openchami"] | |
| draft: false | |
| --- | |
| EOF | |
| ) | |
| echo "${FRONTMATTER}" > POST.md | |
| echo "" >> POST.md | |
| cat DIGEST.md >> POST.md | |
| # Output for later steps | |
| echo "title=${TITLE}" >> $GITHUB_OUTPUT | |
| echo "slug=${SLUG}" >> $GITHUB_OUTPUT | |
| - name: Clone website repo (openchami.org) | |
| run: | | |
| git clone "https://x-access-token:${WEBSITE_REPO_TOKEN}@github.com/${WEBSITE_REPO}.git" website | |
| env: | |
| WEBSITE_REPO_TOKEN: ${{ secrets.WEBSITE_REPO_TOKEN }} | |
| - name: Create post file, branch, commit, and push | |
| id: prprep | |
| run: | | |
| set -e | |
| BRANCH="weekly-digest/${{ steps.dates.outputs.pub_date }}" | |
| POST_FILENAME="${{ steps.dates.outputs.pub_date }}.md" | |
| # Path relative to repo root (for git operations inside website/) | |
| POST_PATH_RELATIVE="${POST_DIR}/${POST_FILENAME}" | |
| # Full path from current directory (for file operations) | |
| POST_PATH_FULL="website/${POST_PATH_RELATIVE}" | |
| mkdir -p "website/${POST_DIR}" | |
| if [ ! -f POST.md ]; then | |
| echo "POST.md is missing; check if previous steps failed." | |
| exit 1 | |
| fi | |
| cp POST.md "${POST_PATH_FULL}" | |
| cd website | |
| git config user.name "openchami-bot" | |
| git config user.email "bot@openchami.org" | |
| git checkout -b "$BRANCH" | |
| git add "${POST_PATH_RELATIVE}" | |
| git commit -s -m "feat(blog): add ${{ steps.post.outputs.title }}" | |
| git push --set-upstream origin "$BRANCH" | |
| echo "branch=$BRANCH" >> $GITHUB_OUTPUT | |
| echo "post_path=${POST_PATH_RELATIVE}" >> $GITHUB_OUTPUT | |
| - name: Open PR to website repo | |
| run: | | |
| gh pr create \ | |
| --repo "${WEBSITE_REPO}" \ | |
| --base main \ | |
| --head "${{ steps.prprep.outputs.branch }}" \ | |
| --title "${{ steps.post.outputs.title }}" \ | |
| --body "This PR adds the weekly digest post generated on ${{ steps.dates.outputs.pub_date }}. | |
| - Post path: \`${{ steps.prprep.outputs.post_path }}\` | |
| - Slug: \`${{ steps.post.outputs.slug }}\` | |
| Please review copy and publish. | |
| " | |
| env: | |
| GH_TOKEN: ${{ secrets.WEBSITE_REPO_TOKEN }} |