Skip to content

Weekly OpenCHAMI Digest → Website PR #41

Weekly OpenCHAMI Digest → Website PR

Weekly OpenCHAMI Digest → Website PR #41

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 }}