Scheduled Fragment Updates #11
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: Scheduled Fragment Updates | |
| on: | |
| schedule: | |
| - cron: '0 0 * * 0' # Run weekly on Sunday | |
| workflow_dispatch: | |
| inputs: | |
| force_copilot: | |
| description: 'Force creation of the Copilot update issue even if no image changes are detected' | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| update-fragments: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Update Docker Tags | |
| run: node scripts/update-tags.js | |
| - name: Check for changes | |
| id: check_changes | |
| run: | | |
| if [[ -n $(git status --porcelain) ]]; then | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "changed=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create Copilot Update Issue | |
| id: create_issue | |
| if: steps.check_changes.outputs.changed == 'true' || github.event.inputs.force_copilot == 'true' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const issue = await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: "Update fragment image versions and docs", | |
| body: "The scheduled job has detected updated Docker image tags. Please update stale image versions across all fragments.\n\n## Instructions\n\n**Do NOT use web search for version lookups. Use the MCP tools below instead.**\n\n### Step 1: Find fragments to update\nCheck each `.json` file in `fragments/compose/` and note the current image tag in the `variables` field (e.g. `POSTGRES_VERSION`, `REDIS_TAG`).\n\n### Step 2: Look up the best tag using Docker Hub MCP\nFor each image, call the Docker Hub MCP tool `list_repository_tags` to identify the best tag using this priority order:\n- Prefer major-version tags with the image variant suffix (e.g. `4-management-alpine`, `16-alpine`).\n- Fall back to minor-version only if no major-version tag exists for the variant (e.g. `16.3`).\n- Only use full semver (e.g. `4.2.5-management-alpine`) as a last resort.\n- Never use `latest`, `edge`, `nightly`, `beta`, or `rc`.\n```\nlist_repository_tags({ namespace: \"library\", repository: \"postgres\" })\n```\nUse `check_repository_tag` to verify the chosen tag exists before updating.\n\n### Step 3: Look up documentation using Context7 MCP (optional)\nIf you need to understand configuration options for a service, use Context7 MCP:\n```\nresolve-library-id({ libraryName: \"postgres\" })\nquery-docs({ context7CompatibleLibraryId: \"...\" })\n```\n\n### Step 4: Update the files\n- Update the tag value in the fragment `.json` file\n- Update any hardcoded tag references in the corresponding `.yml` file\n- Update the `docs/fragments/<name>.md` frontmatter if it has a version field\n\n### Step 5: Run validation\n```\nnpm run validate\n```\n\n### Step 6: Submit a pull request with all changes.", | |
| labels: ["automated-update"], | |
| headers: { | |
| 'X-GitHub-Api-Version': '2022-11-28' | |
| } | |
| }); | |
| console.log(`Created issue ${issue.data.number}`); | |
| return issue.data.number; | |
| - name: Assign @copilot to issue | |
| if: steps.create_issue.outputs.result | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.RELEASE_PLEASE_TOKEN }} | |
| script: | | |
| const issueNumber = Number(${{ steps.create_issue.outputs.result }}); | |
| // Use GraphQL to assign the Copilot bot (BOT_kgDOC9w8XQ) as the authenticated user (PAT) | |
| const issue = await github.rest.issues.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issueNumber, | |
| }); | |
| const mutation = ` | |
| mutation($id: ID!, $actorIds: [ID!]!) { | |
| replaceActorsForAssignable(input: { assignableId: $id, actorIds: $actorIds }) { | |
| assignable { ... on Issue { id } } | |
| } | |
| } | |
| `; | |
| try { | |
| await github.graphql(mutation, { | |
| id: issue.data.node_id, | |
| actorIds: ["BOT_kgDOC9w8XQ"] | |
| }); | |
| console.log(`Successfully assigned Copilot to issue ${issueNumber}`); | |
| } catch (e) { | |
| // Fallback: post a comment as the PAT user to trigger @copilot | |
| console.log(`GraphQL assignment failed: ${e.message}. Posting comment as PAT user.`); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issueNumber, | |
| body: "@copilot review these changes, update any stale image versions in fragment `.yml` and `.json` files, update the docs, and submit a pull request." | |
| }); | |
| } | |