name: contrib on: issue_comment: types: [created, edited] # zizmor: ignore[dangerous-triggers] We explicitly want to run on pull_request_target. pull_request_target: types: - opened - closed - synchronize - labeled - unlabeled - reopened - edited # For jobs that don't run on draft PRs. - ready_for_review permissions: contents: read # Only run one instance per PR to ensure in-order execution. concurrency: pr-${{ github.ref }} jobs: cla: runs-on: ubuntu-latest permissions: pull-requests: write steps: - name: cla if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # the below token should have repo scope and must be manually added by you in the repository's secret PERSONAL_ACCESS_TOKEN: ${{ secrets.CDRCI2_GITHUB_TOKEN }} with: remote-organization-name: "coder" remote-repository-name: "cla" path-to-signatures: "v2022-09-04/signatures.json" path-to-document: "https://github.com/coder/cla/blob/main/README.md" # branch should not be protected branch: "main" # Some users have signed a corporate CLA with Coder so are exempt from signing our community one. allowlist: "coryb,aaronlehmann,dependabot*,blink-so*,blinkagent*" release-labels: runs-on: ubuntu-latest permissions: pull-requests: write # Skip tagging for draft PRs. if: ${{ github.event_name == 'pull_request_target' && !github.event.pull_request.draft }} steps: - name: release-labels uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: # This script ensures PR title and labels are in sync: # # When release/breaking label is: # - Added, rename PR title to include ! (e.g. feat!:) # - Removed, rename PR title to strip ! (e.g. feat:) # # When title is: # - Renamed (+!), add the release/breaking label # - Renamed (-!), remove the release/breaking label script: | const releaseLabels = { breaking: "release/breaking", } const { action, changes, label, pull_request } = context.payload const { title } = pull_request const labels = pull_request.labels.map((label) => label.name) const isBreakingTitle = isBreaking(title) // Debug information. console.log("Action: %s", action) console.log("Title: %s", title) console.log("Labels: %s", labels.join(", ")) const params = { issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, } if (action === "opened" || action === "reopened" || action === "ready_for_review") { if (isBreakingTitle && !labels.includes(releaseLabels.breaking)) { console.log('Add "%s" label', releaseLabels.breaking) await github.rest.issues.addLabels({ ...params, labels: [releaseLabels.breaking], }) } } if (action === "edited" && changes.title) { if (isBreakingTitle && !labels.includes(releaseLabels.breaking)) { console.log('Add "%s" label', releaseLabels.breaking) await github.rest.issues.addLabels({ ...params, labels: [releaseLabels.breaking], }) } if (!isBreakingTitle && labels.includes(releaseLabels.breaking)) { const wasBreakingTitle = isBreaking(changes.title.from) if (wasBreakingTitle) { console.log('Remove "%s" label', releaseLabels.breaking) await github.rest.issues.removeLabel({ ...params, name: releaseLabels.breaking, }) } else { console.log('Rename title from "%s" to "%s"', title, toBreaking(title)) await github.rest.issues.update({ ...params, title: toBreaking(title), }) } } } if (action === "labeled") { if (label.name === releaseLabels.breaking && !isBreakingTitle) { console.log('Rename title from "%s" to "%s"', title, toBreaking(title)) await github.rest.issues.update({ ...params, title: toBreaking(title), }) } } if (action === "unlabeled") { if (label.name === releaseLabels.breaking && isBreakingTitle) { console.log('Rename title from "%s" to "%s"', title, fromBreaking(title)) await github.rest.issues.update({ ...params, title: fromBreaking(title), }) } } function isBreaking(t) { return t.split(" ")[0].endsWith("!:") } function toBreaking(t) { const parts = t.split(" ") return [parts[0].replace(/:$/, "!:"), ...parts.slice(1)].join(" ") } function fromBreaking(t) { const parts = t.split(" ") return [parts[0].replace(/!:$/, ":"), ...parts.slice(1)].join(" ") }