Mergin Maps delivery #1714
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: Mergin Maps delivery | |
| on: | |
| workflow_run: | |
| types: | |
| - "completed" | |
| workflows: | |
| - "win64 Build" | |
| - "macOS Build" | |
| - "linux Build" | |
| - "Android Build" | |
| - "iOS Build" | |
| permissions: | |
| actions: read | |
| pull-requests: write | |
| jobs: | |
| comment_on_pr: | |
| if: github.event.workflow_run.conclusion == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check all builds completed and find artifacts | |
| id: artifact_finder | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const buildWorkflowNames = ['macOS Build', 'linux Build', 'win64 Build', 'Android Build', 'iOS Build']; | |
| const headSha = context.payload.workflow_run.head_sha; | |
| // 1. Fetch all runs for this commit | |
| const runsResponse = await github.rest.actions.listWorkflowRunsForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| head_sha: headSha, | |
| per_page: 50 | |
| }); | |
| const allRuns = runsResponse.data.workflow_runs; | |
| // 2. Check that every required workflow has a completed run on this commit. | |
| // If any is still in progress (or missing), bail out — another workflow_run | |
| // event will re-trigger this job once that workflow finishes. | |
| for (const name of buildWorkflowNames) { | |
| const run = allRuns.find(r => r.name === name); | |
| if (!run || run.status !== 'completed') { | |
| console.log(`Workflow "${name}" is not yet completed. Skipping comment until all builds are done.`); | |
| core.setOutput('pr_number', ''); | |
| return; | |
| } | |
| } | |
| console.log('All required workflows are completed. Building comment...'); | |
| // 3. Helper: find the check run created by the Android job for this commit | |
| // and read the Play Store link from its output.summary field. | |
| async function fetchPlayStoreLink(headSha) { | |
| try { | |
| const checkRuns = await github.rest.checks.listForRef({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: headSha, | |
| }); | |
| // There may be multiple check runs with the same name (e.g. matrix builds); | |
| // find the one whose summary contains a URL (written by the deploy step). | |
| let linkDict = []; | |
| for (const run of checkRuns.data.check_runs) { | |
| if (run.name.includes("android")) { | |
| const buildType = run.output?.title.split(" ")[1]; | |
| const summary = run.output?.summary ?? ''; | |
| const match = summary.match(/https:\/\/[^\s)>\]"]+/); | |
| if (match) { | |
| linkDict.push({ | |
| type: buildType, | |
| link: summary | |
| }); | |
| } | |
| } | |
| } | |
| if (linkDict.length > 0) return linkDict; | |
| console.log('No Play Store link found in Android check run output.'); | |
| return []; | |
| } catch (e) { | |
| console.log(`Could not fetch Play Store link from check run: ${e.message}`); | |
| return []; | |
| } | |
| } | |
| // 4. Build the comment | |
| let commentBody = '## 📦 Build Artifacts Ready\n\n|OS|Status|Build|Info|Workflow run|\n|-----|-----|-----|-----|-----|\n'; | |
| let artifactsFound = false; | |
| for (const workflowName of buildWorkflowNames) { | |
| const latestRun = allRuns.find(run => run.name === workflowName); | |
| if (!latestRun || latestRun.conclusion !== 'success') { | |
| commentBody += `|**${workflowName}**| ❌ | Build failed or not found. | | ${latestRun ? `[#${latestRun.run_number}](${latestRun.html_url})` : ''} |\n`; | |
| continue; | |
| } | |
| if (workflowName !== 'iOS Build') { | |
| const artifactsResponse = await github.rest.actions.listWorkflowRunArtifacts({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: latestRun.id, | |
| }); | |
| let artifacts = []; | |
| let playStoreLinksDict = []; | |
| if (workflowName === 'Android Build') { | |
| artifacts = artifactsResponse.data.artifacts.filter(artifact => artifact.name.includes(' APK ')); | |
| // also let's fetch links to play store | |
| playStoreLinksDict = await fetchPlayStoreLink(headSha); | |
| } else { | |
| artifacts = artifactsResponse.data.artifacts; | |
| } | |
| if (artifacts.length > 0) { | |
| for (const artifact of artifacts) { | |
| commentBody += `|**${workflowName}**| 📬 | [**${artifact.name}**](${artifact.archive_download_url}) | Expires: ${new Date(artifact.expires_at).toLocaleDateString('en-GB')} | [#${latestRun.run_number}](${latestRun.html_url}) |\n`; | |
| artifactsFound = true; | |
| if (workflowName === 'Android Build' && playStoreLinksDict.length > 0) { | |
| const playStoreArtifact = playStoreLinksDict.find(playStoreLink => artifact.name.includes(playStoreLink.type)); | |
| commentBody += `|| 📬 | [**${artifact.name}**](${playStoreArtifact.link}) | Google Play Store | [#${latestRun.run_number}](${latestRun.html_url}) |\n`; | |
| } | |
| } | |
| } else { | |
| commentBody += `|**${workflowName}**| 📭 | | | [#${latestRun.run_number}](${latestRun.html_url}) |\n`; | |
| } | |
| } else { | |
| const currentYear = String(new Date().getFullYear()).slice(-2); | |
| const currentMonth = (new Date().getMonth() + 1).toLocaleString('en-US', { minimumIntegerDigits: 2, useGrouping: false }); | |
| const buildId = `${latestRun.run_number}1${latestRun.run_attempt}`; | |
| commentBody += `|**${workflowName}**| 📬 | | Build number: ${currentYear}.${currentMonth}.${buildId} | [#${latestRun.run_number}](${latestRun.html_url}) |\n`; | |
| artifactsFound = true; | |
| } | |
| } | |
| core.setOutput('comment_body', artifactsFound ? commentBody : 'No artifacts found for this PR commit.'); | |
| // 5. Resolve PR number | |
| const prsResponse = await github.rest.pulls.list({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`, | |
| per_page: 5 | |
| }); | |
| const pullRequest = prsResponse.data.find(pr => pr.head.sha === headSha); | |
| if (!pullRequest) { | |
| console.log(`No open Pull Request found for commit SHA: ${headSha}`); | |
| core.setOutput('pr_number', ''); | |
| } else { | |
| core.setOutput('pr_number', pullRequest.number); | |
| } | |
| - name: Update Comment | |
| if: steps.artifact_finder.outputs.pr_number != '' | |
| uses: peter-evans/create-or-update-comment@v5 | |
| with: | |
| issue-number: ${{ steps.artifact_finder.outputs.pr_number }} | |
| body: ${{ steps.artifact_finder.outputs.comment_body }} |