Skip to content

Daily Activity Report #201

Daily Activity Report

Daily Activity Report #201

Workflow file for this run

name: Daily Activity Report
permissions:
contents: write
on:
schedule:
- cron: "0 9 * * *" # Daily at 9 AM UTC
workflow_dispatch: # Manual trigger
# Configure these in your repo's Settings > Variables and Secrets:
# Variables (vars):
# SCAN_PATHS - Comma-separated paths to scan (e.g. "~/Projects,~/code")
# EXCLUDE_REPOS - Comma-separated repo name patterns to exclude (e.g. "archive,understanding-dana")
# GH_AUTHOR - GitHub username for PR fetching (default: @me)
# GIT_EMAIL - Email for git commits (default: activity-bot@users.noreply.github.com)
# GIT_NAME - Name for git commits (default: Activity Bot)
# SITE_CONFIG - JSON for dashboard branding (optional, see site-config.json.example)
# CATEGORIES_CONFIG - JSON for repo grouping (optional, see categories.json.example)
# Secrets:
# CLOUDFLARE_API_TOKEN - For Cloudflare Pages deploy (optional)
# CLOUDFLARE_ACCOUNT_ID - For Cloudflare Pages deploy (optional)
jobs:
generate:
runs-on: self-hosted # Uses your machine with access to local repos
env:
REPORT_SCAN_PATHS: ${{ vars.SCAN_PATHS || '~/Projects,~/Local Sites' }}
REPORT_EXCLUDE_REPOS: ${{ vars.EXCLUDE_REPOS || '' }}
REPORT_GH_AUTHOR: ${{ vars.GH_AUTHOR || '@me' }}
steps:
- name: Clean runner state
run: |
cd "$GITHUB_WORKSPACE" 2>/dev/null || true
# Abort any stuck rebase/merge from a previous failed run
git rebase --abort 2>/dev/null || true
git merge --abort 2>/dev/null || true
# Discard any uncommitted changes to generated files
git checkout -- . 2>/dev/null || true
git clean -fd 2>/dev/null || true
- uses: actions/checkout@v6
with:
clean: true
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: Write categories config
if: vars.CATEGORIES_CONFIG != ''
run: echo '${{ vars.CATEGORIES_CONFIG }}' > categories.json
- name: Generate report
shell: bash
run: |
EXTRA_ARGS=()
[ -n "${REPORT_EXCLUDE_REPOS}" ] && EXTRA_ARGS+=("--exclude=${REPORT_EXCLUDE_REPOS}")
node generate-rich-report.mjs "--paths=${REPORT_SCAN_PATHS}" --gh-author="${REPORT_GH_AUTHOR}" "${EXTRA_ARGS[@]}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CATEGORIES_CONFIG: ${{ vars.CATEGORIES_CONFIG }}
- name: Commit and push
id: commit
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config user.email "${{ vars.GIT_EMAIL || 'activity-bot@users.noreply.github.com' }}"
git config user.name "${{ vars.GIT_NAME || 'Activity Bot' }}"
git add -f activity-data.json
if git diff --cached --quiet; then
echo "No changes to commit"
echo "committed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m "chore: daily activity update"
echo "committed=true" >> "$GITHUB_OUTPUT"
# Push with retry + auto-resolve conflicts on generated files
for attempt in 1 2 3; do
if git push; then
echo "Push succeeded on attempt $attempt"
exit 0
fi
echo "Push failed (attempt $attempt), rebasing on latest..."
git fetch origin main
# Use -X theirs to prefer our freshly generated files on conflict
if git rebase -X theirs origin/main; then
echo "Rebase succeeded, retrying push..."
continue
fi
# If rebase still fails, abort and force-regenerate
echo "Rebase failed, regenerating from latest..."
git rebase --abort
git reset --soft HEAD~1
git checkout -- .
git pull origin main
EXTRA_ARGS=()
[ -n "${REPORT_EXCLUDE_REPOS}" ] && EXTRA_ARGS+=("--exclude=${REPORT_EXCLUDE_REPOS}")
node generate-rich-report.mjs "--paths=${REPORT_SCAN_PATHS}" --gh-author="${REPORT_GH_AUTHOR}" "${EXTRA_ARGS[@]}"
git add -f activity-data.json
git diff --cached --quiet || git commit -m "chore: daily activity update"
done
echo "::warning::All push attempts failed"
exit 1
- name: Prepare deploy directory
if: always() && vars.CLOUDFLARE_DEPLOY == 'true'
run: |
mkdir -p _deploy
cp index.html activity-data.json _deploy/
[ -n "$SITE_CONFIG" ] && echo "$SITE_CONFIG" > _deploy/site-config.json || true
[ -n "$CATEGORIES" ] && echo "$CATEGORIES" > _deploy/categories.json || true
env:
SITE_CONFIG: ${{ vars.SITE_CONFIG }}
CATEGORIES: ${{ vars.CATEGORIES_CONFIG }}
- name: Deploy to Cloudflare
if: always() && steps.commit.outcome != 'skipped' && vars.CLOUDFLARE_DEPLOY == 'true'
run: npx wrangler@4 pages deploy _deploy --project-name=${{ vars.CLOUDFLARE_PROJECT || 'activity-report' }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}