Skip to content

Weekly QuantEcon Report #34

Weekly QuantEcon Report

Weekly QuantEcon Report #34

Workflow file for this run

name: Weekly QuantEcon Report
on:
schedule:
# Run every Saturday at 9:00 AM UTC
- cron: '0 9 * * 6'
workflow_dispatch:
# Allow manual triggering
permissions:
contents: read
issues: write
jobs:
generate-report:
runs-on: ubuntu-latest
name: Generate Weekly Report
steps:
- name: Generate weekly report
id: report
uses: QuantEcon/action-weekly-report@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
organization: 'QuantEcon'
exclude-repos: 'lecture-.*\.notebooks,test-.*'
track-external-repos: 'executablebooks/sphinx-exercise,executablebooks/sphinx-proof'
highlights: 'true'
llm-summary: 'true'
env:
# Used by --llm-summary to draft 1-sentence theme narratives via Claude.
# If the secret is missing the step warns and still produces highlights
# without narratives (see action-weekly-report docs/highlights.md).
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- name: Create issue with report and post highlights as first comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Read the main report content
let reportContent = '';
try {
reportContent = fs.readFileSync('weekly-report.md', 'utf8');
console.log(`Read weekly-report.md (${reportContent.length} chars)`);
} catch (error) {
console.error('Failed to read weekly-report.md:', error);
reportContent = 'Error: Unable to load weekly report content.';
}
// Build the issue title
const now = new Date();
const weekEnding = now.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
const title = `Weekly Report - Week Ending ${weekEnding}`;
// Create the issue
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: title,
body: reportContent,
labels: ['weekly-report', 'automated']
});
console.log(`Created issue #${issue.data.number}: ${title}`);
// Post the curated highlights as the first comment, if produced.
// The action emits highlights.md when `highlights: true` is set above.
//
// Hardened against:
// - GitHub's 65,536-char comment body limit (truncate with a pointer
// to the uploaded artifact)
// - transient API failures (log + continue rather than fail the
// workflow — the issue itself has already been created above, so
// the report isn't lost even if the comment can't be posted)
const COMMENT_BODY_LIMIT = 65536;
if (fs.existsSync('highlights.md')) {
// Read + truncate inside its own try/catch — existsSync doesn't
// guarantee the read succeeds (permissions, IO), and we want any
// such failure to behave like "file not produced" rather than
// crash the workflow.
let highlights;
try {
highlights = fs.readFileSync('highlights.md', 'utf8');
} catch (readErr) {
console.error(`Failed to read highlights.md: ${readErr.message || readErr}`);
console.error('Skipping highlights comment. The report issue was still created.');
highlights = null;
}
if (highlights !== null) {
const originalLen = highlights.length;
if (highlights.length > COMMENT_BODY_LIMIT) {
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const footer = `\n\n---\n\n_Highlights truncated to fit GitHub's 65,536-char comment limit. Full content available in the workflow artifact: [weekly-report (run #${context.runId})](${runUrl})._\n`;
highlights = highlights.slice(0, COMMENT_BODY_LIMIT - footer.length) + footer;
console.log(`Truncated highlights from ${originalLen} to ${highlights.length} chars`);
}
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.data.number,
body: highlights,
});
console.log(`Posted highlights.md (${highlights.length} chars) as first comment`);
} catch (err) {
// Don't fail the run — the issue is created and the artifact is
// uploaded, so the highlights are recoverable manually.
// Octokit errors carry status + response.data; log them so
// future debugging isn't limited to err.message (which is
// often terse, e.g. "Validation Failed").
const status = err.status ? ` [HTTP ${err.status}]` : '';
const message = err.message || String(err);
const responseDetail = err.response?.data ? ` response=${JSON.stringify(err.response.data)}` : '';
console.error(`Failed to post highlights comment on issue #${issue.data.number}${status}: ${message}${responseDetail}`);
console.error('The report issue was still created. highlights.md is available in the workflow artifact.');
}
}
} else {
console.log('highlights.md not produced — skipping highlights comment');
}
- name: Upload report artifacts
uses: actions/upload-artifact@v4
with:
name: weekly-report
# Bundle every artifact the action produces so we can re-run
# tools/highlights.py against weekly-report-data.json offline if we
# ever want to retune themes or compare LLM models.
path: |
weekly-report.md
weekly-report-data.json
highlights.md
retention-days: 90