diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml index 95c05e7fd29..8e44c718271 100644 --- a/.github/workflows/agentics-maintenance.yml +++ b/.github/workflows/agentics-maintenance.yml @@ -359,19 +359,20 @@ jobs: restore-keys: | ${{ runner.os }}-activity-report-logs-${{ github.repository }}- ${{ runner.os }}-activity-report-logs- - - name: Generate agentic workflow activity report - uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + - name: Download activity report logs + timeout-minutes: 20 + shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_AW_CMD_PREFIX: ./gh-aw - GH_AW_ACTIVITY_REPORT_OUTPUT_DIR: ./.cache/gh-aw/activity-report-logs - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/run_activity_report.cjs'); - await main(); + run: | + ${GH_AW_CMD_PREFIX} logs \ + --repo "${{ github.repository }}" \ + --start-date -1w \ + --count 100 \ + --output ./.cache/gh-aw/activity-report-logs \ + --format markdown \ + > ./.cache/gh-aw/activity-report-logs/report.md - name: Save activity report logs cache if: ${{ always() }} @@ -380,6 +381,46 @@ jobs: path: ./.cache/gh-aw/activity-report-logs key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }} + - name: Generate activity report issue + uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('node:fs'); + const reportPath = './.cache/gh-aw/activity-report-logs/report.md'; + if (!fs.existsSync(reportPath)) { + core.warning(`Activity report markdown not found at ${reportPath}; skipping issue creation.`); + return; + } + let reportBody = ''; + try { + reportBody = fs.readFileSync(reportPath, 'utf8').trim(); + } catch (error) { + core.warning(`Failed to read activity report markdown at ${reportPath}: ${error.message}`); + return; + } + if (!reportBody) { + core.warning(`Activity report markdown is empty at ${reportPath}; skipping issue creation.`); + return; + } + const repoSlug = `${context.repo.owner}/${context.repo.repo}`; + const body = [ + '### Agentic workflow activity report', + '', + `Repository: ${repoSlug}`, + `Generated at: ${new Date().toISOString()}`, + '', + reportBody, + ].join('\n'); + const createdIssue = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: '[aw] agentic status report', + body, + labels: ['agentic-workflows'], + }); + core.info(`Created issue #${createdIssue.data.number}: ${createdIssue.data.html_url}`); + close_agentic_workflows_issues: if: ${{ (github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && inputs.operation == 'close_agentic_workflows_issues' && (!(github.event.repository.fork)) }} runs-on: ubuntu-slim diff --git a/pkg/workflow/maintenance_workflow_test.go b/pkg/workflow/maintenance_workflow_test.go index 0ec6a3cb3ca..852f3fd78d3 100644 --- a/pkg/workflow/maintenance_workflow_test.go +++ b/pkg/workflow/maintenance_workflow_test.go @@ -400,8 +400,32 @@ func TestGenerateMaintenanceWorkflow_OperationJobConditions(t *testing.T) { t.Errorf("Job activity_report cache key should include run_id for latest-cache resolution in:\n%s", yaml) } - if !strings.Contains(yaml, "GH_AW_ACTIVITY_REPORT_OUTPUT_DIR: ./.cache/gh-aw/activity-report-logs") { - t.Errorf("Job activity_report should set GH_AW_ACTIVITY_REPORT_OUTPUT_DIR in:\n%s", yaml) + if !strings.Contains(yaml, "Download activity report logs") { + t.Errorf("Job activity_report should include direct logs download step in:\n%s", yaml) + } + if !strings.Contains(yaml, "timeout-minutes: 20") { + t.Errorf("Job activity_report logs download step should set timeout-minutes: 20 in:\n%s", yaml) + } + if !strings.Contains(yaml, "${GH_AW_CMD_PREFIX} logs") { + t.Errorf("Job activity_report should run gh aw logs directly in:\n%s", yaml) + } + if !strings.Contains(yaml, "--start-date -1w") { + t.Errorf("Job activity_report gh aw logs command should include --start-date -1w in:\n%s", yaml) + } + if !strings.Contains(yaml, "--count 100") { + t.Errorf("Job activity_report gh aw logs command should include --count 100 in:\n%s", yaml) + } + if !strings.Contains(yaml, "--format markdown") { + t.Errorf("Job activity_report gh aw logs command should include --format markdown in:\n%s", yaml) + } + if !strings.Contains(yaml, "./.cache/gh-aw/activity-report-logs/report.md") { + t.Errorf("Job activity_report gh aw logs command should write report markdown output to report.md in:\n%s", yaml) + } + if !strings.Contains(yaml, "Generate activity report issue") { + t.Errorf("Job activity_report should include issue generation step after cache save in:\n%s", yaml) + } + if !strings.Contains(yaml, "title: '[aw] agentic status report'") { + t.Errorf("Job activity_report issue generation step should create the activity report issue title in:\n%s", yaml) } // close_agentic_workflows_issues job should be triggered when operation == 'close_agentic_workflows_issues' diff --git a/pkg/workflow/maintenance_workflow_yaml.go b/pkg/workflow/maintenance_workflow_yaml.go index dd55cc3ffec..3dd0362056d 100644 --- a/pkg/workflow/maintenance_workflow_yaml.go +++ b/pkg/workflow/maintenance_workflow_yaml.go @@ -394,19 +394,20 @@ jobs: ${{ runner.os }}-activity-report-logs-${{ github.repository }}- ${{ runner.os }}-activity-report-logs- `) - yaml.WriteString(` - name: Generate agentic workflow activity report - uses: ` + getCachedActionPinFromResolver("actions/github-script", resolver) + ` + yaml.WriteString(` - name: Download activity report logs + timeout-minutes: 20 + shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_AW_CMD_PREFIX: ` + getCLICmdPrefix(actionMode) + ` - GH_AW_ACTIVITY_REPORT_OUTPUT_DIR: ./.cache/gh-aw/activity-report-logs - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/run_activity_report.cjs'); - await main(); + run: | + ${GH_AW_CMD_PREFIX} logs \ + --repo "${{ github.repository }}" \ + --start-date -1w \ + --count 100 \ + --output ./.cache/gh-aw/activity-report-logs \ + --format markdown \ + > ./.cache/gh-aw/activity-report-logs/report.md - name: Save activity report logs cache if: ${{ always() }} @@ -414,6 +415,46 @@ jobs: with: path: ./.cache/gh-aw/activity-report-logs key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }} + + - name: Generate activity report issue + uses: ` + getCachedActionPinFromResolver("actions/github-script", resolver) + ` + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('node:fs'); + const reportPath = './.cache/gh-aw/activity-report-logs/report.md'; + if (!fs.existsSync(reportPath)) { + core.warning('Activity report markdown not found at ' + reportPath + '; skipping issue creation.'); + return; + } + let reportBody = ''; + try { + reportBody = fs.readFileSync(reportPath, 'utf8').trim(); + } catch (error) { + core.warning('Failed to read activity report markdown at ' + reportPath + ': ' + error.message); + return; + } + if (!reportBody) { + core.warning('Activity report markdown is empty at ' + reportPath + '; skipping issue creation.'); + return; + } + const repoSlug = context.repo.owner + '/' + context.repo.repo; + const body = [ + '### Agentic workflow activity report', + '', + 'Repository: ' + repoSlug, + 'Generated at: ' + new Date().toISOString(), + '', + reportBody, + ].join('\n'); + const createdIssue = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: '[aw] agentic status report', + body, + labels: ['agentic-workflows'], + }); + core.info('Created issue #' + createdIssue.data.number + ': ' + createdIssue.data.html_url); `) // Add close_agentic_workflows_issues job for workflow_dispatch with operation == 'close_agentic_workflows_issues' diff --git a/pkg/workflow/side_repo_maintenance.go b/pkg/workflow/side_repo_maintenance.go index add1c5d87e5..c33233082ab 100644 --- a/pkg/workflow/side_repo_maintenance.go +++ b/pkg/workflow/side_repo_maintenance.go @@ -469,20 +469,21 @@ jobs: ${{ runner.os }}-activity-report-logs-` + repoSlug + `- ${{ runner.os }}-activity-report-logs- `) - yaml.WriteString(` - name: Generate agentic workflow activity report in target repository - uses: ` + getCachedActionPinFromResolver("actions/github-script", resolver) + ` + yaml.WriteString(` - name: Download activity report logs in target repository + timeout-minutes: 20 + shell: bash env: GH_TOKEN: ` + token + ` GH_AW_CMD_PREFIX: ` + getCLICmdPrefix(actionMode) + ` GH_AW_TARGET_REPO_SLUG: "` + repoSlug + `" - GH_AW_ACTIVITY_REPORT_OUTPUT_DIR: ./.cache/gh-aw/activity-report-logs - with: - github-token: ` + token + ` - script: | - const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io, getOctokit); - const { main } = require('${{ runner.temp }}/gh-aw/actions/run_activity_report.cjs'); - await main(); + run: | + ${GH_AW_CMD_PREFIX} logs \ + --repo "${GH_AW_TARGET_REPO_SLUG}" \ + --start-date -1w \ + --count 100 \ + --output ./.cache/gh-aw/activity-report-logs \ + --format markdown \ + > ./.cache/gh-aw/activity-report-logs/report.md - name: Save activity report logs cache if: ${{ always() }} @@ -490,6 +491,51 @@ jobs: with: path: ./.cache/gh-aw/activity-report-logs key: ${{ steps.activity_report_logs_cache.outputs.cache-primary-key }} + + - name: Generate activity report issue in target repository + uses: ` + getCachedActionPinFromResolver("actions/github-script", resolver) + ` + with: + github-token: ` + token + ` + script: | + const fs = require('node:fs'); + const reportPath = './.cache/gh-aw/activity-report-logs/report.md'; + if (!fs.existsSync(reportPath)) { + core.warning('Activity report markdown not found at ' + reportPath + '; skipping issue creation.'); + return; + } + let reportBody = ''; + try { + reportBody = fs.readFileSync(reportPath, 'utf8').trim(); + } catch (error) { + core.warning('Failed to read activity report markdown at ' + reportPath + ': ' + error.message); + return; + } + if (!reportBody) { + core.warning('Activity report markdown is empty at ' + reportPath + '; skipping issue creation.'); + return; + } + const repoSlug = process.env.GH_AW_TARGET_REPO_SLUG || ''; + const [owner, repo] = repoSlug.split('/'); + if (!owner || !repo) { + core.setFailed('Invalid GH_AW_TARGET_REPO_SLUG: ' + repoSlug); + return; + } + const body = [ + '### Agentic workflow activity report', + '', + 'Repository: ' + repoSlug, + 'Generated at: ' + new Date().toISOString(), + '', + reportBody, + ].join('\n'); + const createdIssue = await github.rest.issues.create({ + owner, + repo, + title: '[aw] agentic status report', + body, + labels: ['agentic-workflows'], + }); + core.info('Created issue #' + createdIssue.data.number + ': ' + createdIssue.data.html_url); `) // Add validate_workflows job for workflow_dispatch/workflow_call with operation == 'validate' diff --git a/pkg/workflow/side_repo_maintenance_integration_test.go b/pkg/workflow/side_repo_maintenance_integration_test.go index fe9ff6905fe..7e0080ee35b 100644 --- a/pkg/workflow/side_repo_maintenance_integration_test.go +++ b/pkg/workflow/side_repo_maintenance_integration_test.go @@ -98,8 +98,24 @@ This workflow operates on a separate repository. "generated workflow should save activity_report logs cache even if report generation fails") assert.Contains(t, contentStr, "steps.activity_report_logs_cache.outputs.cache-primary-key", "generated workflow should save activity_report logs using the cache primary key") - assert.Contains(t, contentStr, "GH_AW_ACTIVITY_REPORT_OUTPUT_DIR: ./.cache/gh-aw/activity-report-logs", - "generated workflow should set GH_AW_ACTIVITY_REPORT_OUTPUT_DIR for activity_report logs") + assert.Contains(t, contentStr, "Download activity report logs in target repository", + "generated workflow should include direct logs download step for activity_report") + assert.Contains(t, contentStr, "timeout-minutes: 20", + "generated workflow should set a 20-minute timeout for the activity_report logs download step") + assert.Contains(t, contentStr, "${GH_AW_CMD_PREFIX} logs", + "generated workflow should run gh aw logs directly") + assert.Contains(t, contentStr, "--start-date -1w", + "generated workflow should download 7 days of logs for activity_report") + assert.Contains(t, contentStr, "--count 100", + "generated workflow should limit activity_report log downloads to at most 100 runs") + assert.Contains(t, contentStr, "--format markdown", + "generated workflow should request markdown report output from gh aw logs") + assert.Contains(t, contentStr, "./.cache/gh-aw/activity-report-logs/report.md", + "generated workflow should write activity_report markdown output to report.md") + assert.Contains(t, contentStr, "Generate activity report issue in target repository", + "generated workflow should include activity_report issue generation step after cache save") + assert.Contains(t, contentStr, "title: '[aw] agentic status report'", + "generated workflow should create the activity_report issue with the expected title") assert.Contains(t, contentStr, "actions: read\n contents: read\n issues: write", "activity_report job should include contents: read with explicit permissions") assert.Contains(t, contentStr, "timeout-minutes: 120",