Skip to content

This Codebase Smells #709

This Codebase Smells

This Codebase Smells #709

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
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 -p "$(cat .github/workflows/this-codebase-smells/prompt.md)" \
--model gpt-5 \
--allow-tool 'shell(*)' \
--allow-tool 'read_file(*)' \
--allow-tool 'glob(*)' \
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