This Codebase Smells #739
Workflow file for this run
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: This Codebase Smells | |
| on: | |
| workflow_dispatch: {} | |
| schedule: | |
| # Hourly on Sundays (UTC); we gate to run only at 16:00 Europe/Zurich | |
| - cron: '0 * * * 0' | |
| permissions: | |
| contents: read | |
| discussions: write | |
| env: | |
| TZ: Europe/Zurich | |
| COPILOT_MODEL: 'gpt-5.4' | |
| COPILOT_REASONING_EFFORT: 'xhigh' | |
| jobs: | |
| analyze: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Time gate (run only at 16:00 Europe/Zurich) | |
| id: gate | |
| if: ${{ github.event_name == 'schedule' }} | |
| run: | | |
| hour=$(TZ=Europe/Zurich date +%H) | |
| if [ "$hour" = "16" ]; then | |
| echo "run=true" >> "$GITHUB_OUTPUT" | |
| echo "It's 16:00 Europe/Zurich; proceeding." | |
| else | |
| echo "run=false" >> "$GITHUB_OUTPUT" | |
| echo "Not 16:00 Europe/Zurich; skipping subsequent steps." | |
| fi | |
| - uses: actions/checkout@v4 | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| - uses: actions/setup-node@v4 | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - name: Install GitHub Copilot CLI | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| run: | | |
| npm install -g @github/copilot | |
| copilot --version | |
| - name: Run GitHub Copilot CLI analysis | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.COPILOT_CLI_TOKEN }} | |
| run: | | |
| set -o pipefail | |
| mkdir -p "$RUNNER_TEMP" | |
| # Read the prompt and run Copilot CLI in programmatic mode | |
| copilot_args=( | |
| -p "$(cat .github/workflows/this-codebase-smells/prompt.md)" | |
| --allow-tool 'shell(*)' | |
| --allow-tool 'read_file(*)' | |
| --allow-tool 'glob(*)' | |
| ) | |
| if [ -n "${COPILOT_MODEL:-}" ]; then | |
| echo "Using requested Copilot model: $COPILOT_MODEL" | |
| copilot_args+=(--model "$COPILOT_MODEL") | |
| else | |
| echo "Using Copilot CLI default model" | |
| fi | |
| if [ -n "${COPILOT_REASONING_EFFORT:-}" ]; then | |
| echo "Using requested reasoning effort: $COPILOT_REASONING_EFFORT" | |
| copilot_args+=(--effort "$COPILOT_REASONING_EFFORT") | |
| fi | |
| copilot "${copilot_args[@]}" 2>&1 | tee "$RUNNER_TEMP/raw_report.md" | |
| # Extract only the content between our markers for the Discussion body | |
| awk '/^---BEGIN REPORT---$/ {flag=1; next} /^---END REPORT---$/ {flag=0} flag' "$RUNNER_TEMP/raw_report.md" > "$RUNNER_TEMP/report.md" | |
| if [ ! -s "$RUNNER_TEMP/report.md" ]; then | |
| echo "Report markers not found or empty report produced" | |
| echo "First 200 lines of raw output for debugging:" | |
| head -n 200 "$RUNNER_TEMP/raw_report.md" || true | |
| echo "Full raw output:" | |
| cat "$RUNNER_TEMP/raw_report.md" || true | |
| exit 1 | |
| fi | |
| - name: Resolve Discussion category ID | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| id: cat | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| owner="intellectronica" | |
| repo="ruler" | |
| gh api graphql -f query=' | |
| query($owner:String!,$repo:String!){ | |
| repository(owner:$owner,name:$repo){ | |
| discussionCategories(first:100){ | |
| nodes{ id name } | |
| } | |
| } | |
| }' -F owner="$owner" -F repo="$repo" > cat.json | |
| cat_id=$(jq -r '.data.repository.discussionCategories.nodes[] | select(.name=="Workflow") | .id' cat.json) | |
| if [ -z "$cat_id" ]; then echo "Workflow discussion category not found"; exit 1; fi | |
| echo "id=$cat_id" >> "$GITHUB_OUTPUT" | |
| - name: Create Discussion | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| owner="intellectronica" | |
| repo="ruler" | |
| repo_id=$(gh api "repos/$owner/$repo" --jq .node_id) | |
| if [ -z "$repo_id" ]; then echo "Failed to get repository node_id"; exit 1; fi | |
| title="This Codebase Smells! [$(TZ=Europe/Zurich date +%F)]" | |
| # JSON-escape the report body safely | |
| body_json=$(jq -Rs . < "$RUNNER_TEMP/report.md") | |
| # Build GraphQL payload | |
| jq -n --arg repoId "$repo_id" \ | |
| --arg catId "${{ steps.cat.outputs.id }}" \ | |
| --arg title "$title" \ | |
| --argjson body "$body_json" \ | |
| '{ | |
| query: "mutation($repoId:ID!,$categoryId:ID!,$title:String!,$body:String!){ createDiscussion(input:{repositoryId:$repoId, categoryId:$categoryId, title:$title, body:$body}){ discussion{ url } } }", | |
| variables: { repoId: $repoId, categoryId: $catId, title: $title, body: $body } | |
| }' > payload.json | |
| gh api graphql --input payload.json -q '.data.createDiscussion.discussion.url' | tee discussion_url.txt | |
| - name: Show Discussion URL | |
| if: ${{ steps.gate.outputs.run != 'false' }} | |
| run: | | |
| echo "Discussion created:" | |
| cat discussion_url.txt |