Merge pull request #134 from improvgroup/copilot/update-to-tunit-dotn… #4
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: Maintain Copilot Instructions | |
| on: | |
| # Run automatically when solution structure or shared build config changes | |
| push: | |
| branches: [main] | |
| paths: | |
| - '**/*.csproj' | |
| - 'SharedCode.sln' | |
| - 'Directory.Build.props' | |
| - 'Directory.Packages.props' | |
| # Run on the first day of each month to catch any drift that slipped through | |
| schedule: | |
| - cron: '0 9 1 * *' | |
| # Allow a maintainer to trigger a review at any time | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| issues: write | |
| jobs: | |
| check-instructions: | |
| name: Check Copilot Instructions are Up-to-Date | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Detect projects not documented in copilot-instructions.md | |
| id: check | |
| shell: bash | |
| run: | | |
| instructions=".github/copilot-instructions.md" | |
| # Collect all SharedCode project names from the solution file. | |
| # The .sln format uses Windows paths: "SharedCode.<Name>\<Name>.csproj" | |
| # so we extract the folder name (everything between the opening quote | |
| # and the first backslash). | |
| projects=$(grep -oP '"SharedCode\.[^\\"]+(?=\\)' SharedCode.sln \ | |
| | tr -d '"' | sort -u) | |
| missing_list="" | |
| while IFS= read -r project; do | |
| if [[ -z "$project" ]]; then | |
| continue | |
| fi | |
| if ! grep -qF "$project" "$instructions"; then | |
| missing_list="${missing_list}\n- \`${project}\`" | |
| fi | |
| done <<< "$projects" | |
| # Check that required prompt files exist | |
| required_prompts=( | |
| ".github/prompts/add-extension-method.prompt.md" | |
| ".github/prompts/add-specification.prompt.md" | |
| ".github/prompts/add-test-class.prompt.md" | |
| ".github/prompts/create-module.prompt.md" | |
| ".github/prompts/fix-code-analysis.prompt.md" | |
| ".github/prompts/improve-coverage.prompt.md" | |
| ".github/prompts/maintain-copilot-instructions.prompt.md" | |
| ) | |
| for prompt in "${required_prompts[@]}"; do | |
| if [[ ! -f "$prompt" ]]; then | |
| missing_list="${missing_list}\n- Missing prompt: \`${prompt}\`" | |
| fi | |
| done | |
| if [[ -n "$missing_list" ]]; then | |
| echo "has_missing=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "has_missing=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| # Use a heredoc to safely pass multi-line content to GITHUB_OUTPUT | |
| { | |
| echo "missing_list<<EOF" | |
| printf '%b' "$missing_list" | |
| echo "" | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Open or update a GitHub Issue when instructions are outdated | |
| if: steps.check.outputs.has_missing == 'true' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const missing = `${{ steps.check.outputs.missing_list }}`; | |
| const body = [ | |
| '## Copilot Instructions May Be Outdated', | |
| '', | |
| 'The following projects or prompt files are missing from the Copilot configuration:', | |
| '', | |
| missing, | |
| '', | |
| '### What to do', | |
| '', | |
| '1. Open `.github/copilot-instructions.md` and add any missing projects to', | |
| ' the module table.', | |
| '2. Ensure all required prompt files exist under `.github/prompts/`.', | |
| '3. Use the prompt at `.github/prompts/maintain-copilot-instructions.prompt.md`', | |
| ' to guide a full review of all Copilot configuration files.', | |
| '4. Close this issue once the instructions are up to date.', | |
| ].join('\n'); | |
| const label = 'copilot-instructions'; | |
| // Ensure the label exists (create it if not) | |
| try { | |
| await github.rest.issues.getLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: label, | |
| }); | |
| } catch { | |
| await github.rest.issues.createLabel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| name: label, | |
| color: '0075ca', | |
| description: 'Tracks updates needed to .github/copilot-instructions.md', | |
| }); | |
| } | |
| // Update an existing open issue rather than creating duplicates | |
| const existing = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| labels: label, | |
| }); | |
| if (existing.data.length > 0) { | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: existing.data[0].number, | |
| body, | |
| }); | |
| core.info(`Updated existing issue #${existing.data[0].number}`); | |
| } else { | |
| const created = await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: 'Update Copilot Instructions', | |
| body, | |
| labels: [label, 'documentation'], | |
| }); | |
| core.info(`Created issue #${created.data.number}`); | |
| } |