push-new-version #35
This file contains 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: Push_new_version | |
# this workflow is triggered by another repository | |
# WARN : need write main protection rule | |
# repository settings requirement : Allow GitHub Actions to create and approve pull requests | |
permissions: | |
contents: write | |
pull-requests: write | |
## Actions > Secrets | |
# BYPASS_USER_PAT - fine-grained PAT with content+pullrequest write from user that can review | |
on: | |
repository_dispatch: | |
types: [push-new-version] | |
jobs: | |
handle-dispatch: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ | |
node-version: [ 20.x ] | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
- name: Use Node.js ${{ matrix.node-version }} | |
uses: actions/setup-node@v3 | |
with: | |
node-version: ${{ matrix.node-version }} | |
# inputs github.event.client_payload : version,label,label_fr,description,description_fr,note,download | |
- name: Read input variables from client_payload as env variables | |
run: | | |
# Function to write a variable to $GITHUB_ENV handling newlines and quotes | |
write_env_var() { | |
local var_name="$1" | |
local payload_value="$2" | |
# Handle newlines and quotes to avoid issues in the environment file | |
echo -n "${var_name}=" >> $GITHUB_ENV | |
echo -e "${payload_value}" | sed ':a;N;$!ba;s/\n/\\n/g; s/'\''/’/g' >> $GITHUB_ENV | |
} | |
# Extract fields from payload and process for multiline handling | |
write_env_var "VERSION" "${{ github.event.client_payload.version }}" | |
write_env_var "LABEL" "${{ github.event.client_payload.label }}" | |
write_env_var "LABEL_FR" "${{ github.event.client_payload.label_fr }}" | |
write_env_var "DESCRIPTION" "${{ github.event.client_payload.description }}" | |
write_env_var "DESCRIPTION_FR" "${{ github.event.client_payload.description_fr }}" | |
write_env_var "NOTE" "${{ github.event.client_payload.note }}" | |
write_env_var "DOWNLOAD" "${{ github.event.client_payload.download }}" | |
# craft a new branch name | |
echo "BRANCH_NAME=update-version-${{ github.sha }}" >> $GITHUB_ENV | |
- name: Run push_new_version script | |
run: | | |
node scripts/push_new_version.mjs \ | |
--commitAndPush "false" \ | |
--version "$VERSION" \ | |
--label "$LABEL" \ | |
--label_fr "$LABEL_FR" \ | |
--description "$DESCRIPTION" \ | |
--description_fr "$DESCRIPTION_FR" \ | |
--note "$NOTE" \ | |
--download "$DOWNLOAD" | |
- name: Create a pull request | |
id: cpr | |
uses: peter-evans/create-pull-request@v7 | |
with: | |
token: ${{ secrets.BYPASS_USER_PAT }} | |
# base: main | |
branch: ${{ env.BRANCH_NAME}} | |
commit-message: Add version ${{ env.VERSION }} | |
title: Automated version update to ${{ env.VERSION }} | |
body: This PR updates the version file automatically. Generated from `push_new_version.yml`. | |
author: ChickArmy[bot] <github-actions[bot][email protected]> | |
- name: Create Pull request outputs | |
if: ${{ steps.cpr.outputs.pull-request-number }} | |
run: | | |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" | |
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" | |
# WARN this step expects at least 1 check in success to pass ! (0 check results in timeout error) | |
- name: Wait for PR related Checks to Pass | |
if: ${{ steps.cpr.outputs.pull-request-number }} | |
uses: actions/github-script@v7 | |
with: | |
github-token: ${{ secrets.BYPASS_USER_PAT }} | |
script: | | |
const prNumber = ${{ steps.cpr.outputs.pull-request-number }}; | |
let allChecksCompleted = false; | |
const checkInterval = 30 * 1000; // 30 seconds | |
const maxAttempts = 20; // Total wait time = maxAttempts * checkInterval | |
let attempt = 0; | |
let checks = []; | |
while (attempt < maxAttempts) { | |
console.log(`Checking status of CI/CD checks (Attempt ${attempt + 1}/${maxAttempts})...`); | |
try { | |
// Get PR details to retrieve PR SHA | |
const { data: { head: { sha } } } = await github.rest.pulls.get({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number: prNumber, | |
}); | |
console.log(`ℹ️ PR #${prNumber} ref is ${sha}`); | |
// Get PR checks | |
const { data } = await github.rest.checks.listForRef({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
ref: sha, | |
}); | |
checks = data.check_runs; | |
if (checks.length < 1) { | |
console.log('⌛ Await until CI/CD at least one check_run appears.'); | |
} else { | |
console.log("checks :\n" + JSON.stringify(checks, null, 2)); | |
allChecksCompleted = checks.every(check => check.status === 'completed'); | |
if (allChecksCompleted) { | |
console.log(`ℹ️ ${checks.length} CI/CD checks have completed.`); | |
break; | |
} else { | |
console.log(`⌛ Not all ${checks.length} checks are complete yet. Waiting...`); | |
} | |
} | |
} catch (error) { | |
if (error.status === 404) { | |
console.log('⌛ Pull request not yet available, waiting...'); | |
} else { | |
throw error; // Rethrow if it's a different error | |
} | |
} | |
await new Promise(resolve => setTimeout(resolve, checkInterval)); | |
attempt++; | |
} | |
if (!allChecksCompleted) { | |
throw new Error(`🔴 Some of ${checks.length} CI/CD checks did not complete within the expected timeframe.`); | |
} | |
// Check if all completed checks passed | |
const failedChecks = []; | |
allChecksPassed = checks.every(check => { | |
const passed = check.conclusion === 'success'; | |
if (!passed) { | |
// Gather details for failed checks | |
failedChecks.push({ | |
name: check.name, | |
conclusion: check.conclusion, | |
completed_at: check.completed_at, | |
html_url: check.html_url | |
}); | |
} | |
return passed; | |
}); | |
if (!allChecksPassed) { | |
console.log('Some checks failed:'); | |
failedChecks.forEach(check => { | |
console.log(`- Name: ${check.name}`); | |
console.log(` Conclusion: ${check.conclusion}`); | |
console.log(` Completed at: ${check.completed_at}`); | |
console.log(` Details: ${check.html_url}`); | |
}); | |
throw new Error('🔴 Some CI/CD checks did not pass successfully.'); | |
} else { | |
console.log(`✅ ${checks.length} CI/CD checks in SUCCESS 🥇`); | |
} | |
- name: Merge Pull Request using authorized user to bypass rule | |
if: ${{ steps.cpr.outputs.pull-request-number }} | |
uses: actions/github-script@v7 | |
with: | |
github-token: ${{ secrets.BYPASS_USER_PAT }} | |
script: | | |
const pull_number = ${{ steps.cpr.outputs.pull-request-number }}; | |
console.log(`Merging pull request: #${pull_number}`); | |
await github.rest.pulls.merge({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number, | |
merge_method: 'rebase' // or 'squash' or 'merge' | |
}); | |
console.log(`✅ Pull request #${pull_number} merged successfully. 🥳`); |