feat(ui): add OrganizationProfileApiKeysPanel mosaic component #133490
Workflow file for this run
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: Major Version Check | |
| on: | |
| pull_request: | |
| types: [opened, edited, synchronize, reopened] | |
| issue_comment: | |
| types: [created, edited, deleted] | |
| permissions: | |
| contents: read | |
| issues: read | |
| pull-requests: read | |
| statuses: write | |
| jobs: | |
| check-major-bump: | |
| if: ${{ github.event_name == 'pull_request' || github.event.issue.pull_request }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check for unapproved major changesets | |
| uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 | |
| with: | |
| script: | | |
| const STATUS_CONTEXT = 'Major Version Check'; | |
| const prNumber = context.payload?.pull_request?.number || context.payload?.issue?.number; | |
| // Resolve the PR so we have its head SHA. issue_comment runs are tied to the | |
| // default branch, so the implicit job check-run lands on main rather than the PR | |
| // head. We post an explicit commit status to the PR head instead, so the required | |
| // context updates correctly no matter which event triggered the run (e.g. the | |
| // re-run after an "!allow-major" comment). | |
| let pullRequest = context.payload.pull_request; | |
| if (!pullRequest) { | |
| const { data } = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: prNumber, | |
| }); | |
| pullRequest = data; | |
| } | |
| const headSha = pullRequest.head.sha; | |
| const setStatus = async (state, description) => { | |
| try { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: headSha, | |
| context: STATUS_CONTEXT, | |
| state, | |
| description, | |
| target_url: `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, | |
| }); | |
| } catch (error) { | |
| // Fork PRs get a read-only token and can't post statuses; don't fail the job over it | |
| // (such PRs need an internal re-run or admin bypass). Re-throw anything else. | |
| if (error.status === 403) { | |
| core.warning(`Could not post the "${STATUS_CONTEXT}" status (read-only token, likely a fork PR): ${error.message}`); | |
| return; | |
| } | |
| throw error; | |
| } | |
| }; | |
| // Check if any changeset files indicate a major bump. | |
| const files = await github.paginate(github.rest.pulls.listFiles, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: prNumber, | |
| per_page: 100, | |
| }); | |
| let hasMajorChangeset = false; | |
| for (const file of files) { | |
| if (file.filename.startsWith('.changeset/') && file.status !== 'removed') { | |
| const { data: changesetContent } = await github.rest.repos.getContent({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| path: file.filename, | |
| ref: headSha, | |
| }); | |
| const content = Buffer.from(changesetContent.content, changesetContent.encoding).toString(); | |
| // Only check for "major" in the YAML frontmatter section (between --- markers) | |
| // This avoids false positives from descriptive text mentioning "major" | |
| const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\s*$/m); | |
| if (frontmatterMatch && /:\s*["']?major["']?/.test(frontmatterMatch[1])) { | |
| hasMajorChangeset = true; | |
| break; | |
| } | |
| } | |
| } | |
| if (!hasMajorChangeset) { | |
| await setStatus('success', 'No major version bump detected.'); | |
| console.log('No major changeset detected.'); | |
| return; | |
| } | |
| // A major bump is present: require an "!allow-major" comment from an org member. | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| per_page: 100, | |
| }); | |
| // The GITHUB_TOKEN (github-actions[bot]) isn't an org member, so checkMembershipForUser | |
| // only confirms PUBLIC members; approvers must have public "clerk" org membership. | |
| let approvalFound = false; | |
| for (const comment of comments) { | |
| if (comment.body?.trim().toLowerCase() === '!allow-major') { | |
| try { | |
| const { status } = await github.rest.orgs.checkMembershipForUser({ | |
| org: context.repo.owner, | |
| username: comment.user.login, | |
| }); | |
| if (status === 204) { | |
| approvalFound = true; | |
| break; | |
| } | |
| } catch (error) { | |
| // 404 = not a public org member; rethrow transient 403/5xx so a hiccup can't drop a valid approval. | |
| if (error?.status === 404) continue; | |
| throw error; | |
| } | |
| } | |
| } | |
| if (approvalFound) { | |
| await setStatus('success', 'Major version bump approved by an organization member.'); | |
| console.log('Major version bump approved by an organization member.'); | |
| } else { | |
| // The red "Major Version Check" commit status on the PR head is the gate. We keep | |
| // the job itself green so that the success status posted by a later "!allow-major" | |
| // re-run (an issue_comment run, whose implicit check-run lands on main, not the PR | |
| // head) isn't shadowed by a stale red job check-run that never clears. | |
| await setStatus('failure', 'Major bump needs an "!allow-major" comment from an org member.'); | |
| core.warning('Major version bump requires approval from an organization member by commenting "!allow-major" on the PR.'); | |
| } |