branch-created.yml 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. name: Branch Created
  2. on:
  3. create:
  4. permissions: {}
  5. jobs:
  6. release-branch-created:
  7. name: Release Branch Created
  8. if: ${{ github.event.ref_type == 'branch' && endsWith(github.event.ref, '-x-y') }}
  9. permissions:
  10. contents: read
  11. pull-requests: write
  12. repository-projects: write # Required for labels
  13. runs-on: ubuntu-latest
  14. steps:
  15. - name: Determine Major Version
  16. id: check-major-version
  17. run: |
  18. if [[ ${{ github.event.ref }} =~ ^([0-9]+)-x-y$ ]]; then
  19. echo "MAJOR=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT"
  20. else
  21. echo "Not a release branch: ${{ github.event.ref }}"
  22. fi
  23. - name: New Release Branch Tasks
  24. if: ${{ steps.check-major-version.outputs.MAJOR }}
  25. env:
  26. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  27. GH_REPO: electron/electron
  28. MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
  29. NUM_SUPPORTED_VERSIONS: 3
  30. run: |
  31. PREVIOUS_MAJOR=$((MAJOR - 1))
  32. UNSUPPORTED_MAJOR=$((MAJOR - NUM_SUPPORTED_VERSIONS - 1))
  33. # Create new labels
  34. gh label create $MAJOR-x-y --color 8d9ee8 || true
  35. gh label create target/$MAJOR-x-y --color ad244f --description "PR should also be added to the \"${MAJOR}-x-y\" branch." || true
  36. gh label create merged/$MAJOR-x-y --color 61a3c6 --description "PR was merged to the \"${MAJOR}-x-y\" branch." || true
  37. gh label create in-flight/$MAJOR-x-y --color db69a6 || true
  38. gh label create needs-manual-bp/$MAJOR-x-y --color 8b5dba || true
  39. # Change color of old labels
  40. gh label edit $UNSUPPORTED_MAJOR-x-y --color ededed || true
  41. gh label edit target/$UNSUPPORTED_MAJOR-x-y --color ededed || true
  42. gh label edit merged/$UNSUPPORTED_MAJOR-x-y --color ededed || true
  43. gh label edit in-flight/$UNSUPPORTED_MAJOR-x-y --color ededed || true
  44. gh label edit needs-manual-bp/$UNSUPPORTED_MAJOR-x-y --color ededed || true
  45. # Add the new target label to any PRs which:
  46. # * target the previous major
  47. # * are in-flight for the previous major
  48. # * need manual backport for the previous major
  49. for PREVIOUS_MAJOR_LABEL in target/$PREVIOUS_MAJOR-x-y in-flight/$PREVIOUS_MAJOR-x-y needs-manual-bp/$PREVIOUS_MAJOR-x-y; do
  50. PULL_REQUESTS=$(gh pr list --label $PREVIOUS_MAJOR_LABEL --jq .[].number --json number --limit 500)
  51. if [[ $PULL_REQUESTS ]]; then
  52. echo $PULL_REQUESTS | xargs -n 1 gh pr edit --add-label target/$MAJOR-x-y || true
  53. fi
  54. done
  55. - name: Generate GitHub App token
  56. if: ${{ steps.check-major-version.outputs.MAJOR }}
  57. id: generate-token
  58. env:
  59. RELEASE_BOARD_GH_APP_CREDS: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
  60. run: |
  61. TOKEN=$(npx @electron/github-app-auth --creds=$RELEASE_BOARD_GH_APP_CREDS --org=electron)
  62. echo "TOKEN=$TOKEN" >> "$GITHUB_OUTPUT"
  63. - name: Create Release Project Board
  64. if: ${{ steps.check-major-version.outputs.MAJOR }}
  65. env:
  66. GITHUB_TOKEN: ${{ steps.generate-token.outputs.TOKEN }}
  67. MAJOR: ${{ steps.check-major-version.outputs.MAJOR }}
  68. ELECTRON_ORG_ID: "O_kgDOAMybxg"
  69. ELECTRON_REPO_ID: "R_kgDOAI8xSw"
  70. TEMPLATE_PROJECT_ID: "PVT_kwDOAMybxs4AQvib"
  71. run: |
  72. # Copy template to create new project board
  73. PROJECT_ID=$(gh api graphql -f query='mutation ($ownerId: ID!, $projectId: ID!, $title: String!) {
  74. copyProjectV2(input: {
  75. includeDraftIssues: true,
  76. ownerId: $ownerId,
  77. projectId: $projectId,
  78. title: $title
  79. }) {
  80. projectV2 {
  81. id
  82. }
  83. }
  84. }' -f ownerId=$ELECTRON_ORG_ID -f projectId=$TEMPLATE_PROJECT_ID -f title="${MAJOR}-x-y" | jq -r '.data.copyProjectV2.projectV2.id')
  85. # Make the new project public
  86. gh api graphql -f query='mutation ($projectId: ID!) {
  87. updateProjectV2(input: {
  88. projectId: $projectId,
  89. public: true,
  90. }) {
  91. projectV2 {
  92. id
  93. }
  94. }
  95. }' -f projectId=$PROJECT_ID
  96. # Link the new project to the Electron repository
  97. gh api graphql -f query='mutation ($projectId: ID!, $repositoryId: ID!) {
  98. linkProjectV2ToRepository(input: {
  99. projectId: $projectId,
  100. repositoryId: $repositoryId
  101. }) {
  102. clientMutationId
  103. }
  104. }' -f projectId=$PROJECT_ID -f repositoryId=$ELECTRON_REPO_ID
  105. # Get all draft issues on the new project board
  106. gh api graphql -f query='query ($id: ID!) {
  107. node(id: $id) {
  108. ... on ProjectV2 {
  109. items(first: 100) {
  110. nodes {
  111. ... on ProjectV2Item {
  112. id
  113. content {
  114. ... on DraftIssue { id title
  115. body
  116. }
  117. }
  118. }
  119. }
  120. }
  121. }
  122. }
  123. }' -f id=$PROJECT_ID > issues.json
  124. PROJECT_ITEMS=$(jq '.data.node.items.nodes[] | select(.content.id != null) | .id' issues.json)
  125. #
  126. # Do template replacement for draft issues
  127. #
  128. echo "{\"major\": $MAJOR, \"next-major\": $((MAJOR + 1))}" > variables.json
  129. # npx mustache is annoyingly slow, so install mustache directly
  130. yarn add -D mustache
  131. for PROJECT_ITEM_ID in $PROJECT_ITEMS; do
  132. # These are done with the raw output flag and sent to file to better retain formatting
  133. jq -r ".data.node.items.nodes[] | select(.id == $PROJECT_ITEM_ID) | .content.title" issues.json > title.txt
  134. jq -r ".data.node.items.nodes[] | select(.id == $PROJECT_ITEM_ID) | .content.body" issues.json > body.txt
  135. ./node_modules/.bin/mustache variables.json title.txt new_title.txt
  136. ./node_modules/.bin/mustache variables.json body.txt new_body.txt
  137. # Only update draft issues which had content change when interpolated
  138. if ! cmp --silent -- new_title.txt title.txt || ! cmp --silent -- new_body.txt body.txt; then
  139. DRAFT_ISSUE_ID=$(jq ".data.node.items.nodes[] | select(.id == $PROJECT_ITEM_ID) | .content.id" issues.json)
  140. gh api graphql -f query='mutation ($draftIssueId: ID!, $title: String!, $body: String!) {
  141. updateProjectV2DraftIssue(input: {
  142. draftIssueId: $draftIssueId,
  143. title: $title,
  144. body: $body
  145. }) {
  146. draftIssue {
  147. id
  148. }
  149. }
  150. }' -f draftIssueId=$DRAFT_ISSUE_ID -f title="$(cat new_title.txt)" -f body="$(cat new_body.txt)"
  151. fi
  152. done