name: Label PR Intent on: pull_request: types: [opened, synchronize, reopened, edited, ready_for_review] permissions: pull-requests: read jobs: compute-labels: runs-on: ubuntu-latest if: >- github.actor != 'dependabot[bot]' && github.actor != 'github-actions[bot]' steps: - name: Compute desired intent labels uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const fs = require('fs'); const path = require('path'); const managedLabels = { 'skills': true, 'plugin': true, 'agent': true, 'instructions': true, 'new-submission': true, 'website-update': true, 'external-plugin': true, 'hooks': true, 'workflow': true, 'canvas-extension': true }; const matchesAny = (filename, patterns) => patterns.some((pattern) => pattern.test(filename)); async function listAllFiles() { const files = []; let page = 1; while (true) { const response = await github.rest.pulls.listFiles({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, per_page: 100, page }); files.push(...response.data); if (response.data.length < 100) { return files; } page += 1; } } const files = await listAllFiles(); const filenames = files.map((file) => file.filename); const patterns = { skills: [ /^skills\// ], plugin: [ /^plugins\// ], agent: [ /^agents\/.+\.agent\.md$/ ], instructions: [ /^instructions\/.+\.instructions\.md$/ ], websiteUpdate: [ /^website\// ], externalPlugin: [ /^plugins\/external\.json$/ ], hooks: [ /^hooks\// ], workflow: [ /^workflows\/.+\.md$/, /^\.github\/workflows\/.+\.(?:ya?ml|md)$/ ], canvasExtension: [ /^extensions\/[^/]+\// ], newSubmission: [ /^agents\/.+\.agent\.md$/, /^instructions\/.+\.instructions\.md$/, /^skills\/[^/]+\/SKILL\.md$/, /^hooks\/[^/]+\/(?:README\.md|hooks\.json)$/, /^plugins\/[^/]+\/\.github\/plugin\/plugin\.json$/, /^extensions\/[^/]+\/extension\.mjs$/, /^workflows\/.+\.md$/, /^\.github\/workflows\/.+\.(?:ya?ml|md)$/, /^website\// ] }; const hasNewSubmission = files.some( (file) => file.status === 'added' && matchesAny(file.filename, patterns.newSubmission) ); const desiredLabels = new Set(); if (filenames.some((filename) => matchesAny(filename, patterns.externalPlugin))) { desiredLabels.add('external-plugin'); } if (filenames.some((filename) => matchesAny(filename, patterns.skills))) { desiredLabels.add('skills'); } if (filenames.some((filename) => matchesAny(filename, patterns.plugin))) { desiredLabels.add('plugin'); } if (filenames.some((filename) => matchesAny(filename, patterns.agent))) { desiredLabels.add('agent'); } if (filenames.some((filename) => matchesAny(filename, patterns.instructions))) { desiredLabels.add('instructions'); } if (filenames.some((filename) => matchesAny(filename, patterns.websiteUpdate))) { desiredLabels.add('website-update'); } if (filenames.some((filename) => matchesAny(filename, patterns.hooks))) { desiredLabels.add('hooks'); } if (filenames.some((filename) => matchesAny(filename, patterns.workflow))) { desiredLabels.add('workflow'); } if (filenames.some((filename) => matchesAny(filename, patterns.canvasExtension))) { desiredLabels.add('canvas-extension'); } if (hasNewSubmission) { desiredLabels.add('new-submission'); } const outDir = path.join(process.env.RUNNER_TEMP, 'label-pr-intent-result'); fs.mkdirSync(outDir, { recursive: true }); fs.writeFileSync(path.join(outDir, 'result.json'), `${JSON.stringify({ schema_version: 'label-pr-intent-result/v1', event: 'pull_request', pr_number: context.payload.pull_request.number, head_sha: context.payload.pull_request.head.sha, managed_labels: Object.keys(managedLabels).sort(), desired_labels: [...desiredLabels].sort(), run_id: process.env.GITHUB_RUN_ID, }, null, 2)}\n`); core.info(`Desired managed labels: ${[...desiredLabels].sort().join(', ') || 'none'}`); - name: Upload desired label artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: label-pr-intent-result path: ${{ runner.temp }}/label-pr-intent-result/result.json if-no-files-found: error retention-days: 3