mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-02 01:00:46 +00:00
The GitHub-hosted runner image rolled out on ~2026-09-14 ships cmdline-tools 12.0, whose sdkmanager no longer resolves the obsolete 'tools' (legacy Android SDK Tools) package. The android-actions/setup-android step inherits the action default packages 'tools platform-tools' and thus failed with "Failed to find package 'tools'" (exit code 1) before the build script even ran. The same request in buildAndUpdateProduct.sh would fail the same way once reached. Override the action's packages input to 'platform-tools' and drop the trailing 'tools' argument from the sdkmanager call in buildAndUpdateProduct.sh. build-tools, platform-tools and the platform are still installed by the script. The cmdline-tools-version pin is left unchanged. Assisted-By: Claude (claude-4.8-opus)
431 lines
23 KiB
YAML
431 lines
23 KiB
YAML
name: release
|
|
on:
|
|
push:
|
|
# NOTE: introducing a "tags:" filter makes GitHub treat any Git ref kind that
|
|
# is NOT filtered as "undefined", and the workflow then stops running for it.
|
|
# So branches MUST be listed explicitly here; without "branches: ['**']" the
|
|
# tag filter below would silently disable all branch-push builds. '**' (not
|
|
# '*') is required to match branch names containing slashes (e.g. releases/x).
|
|
branches:
|
|
- '**'
|
|
# Reviewed-fork-PR tags. A maintainer fetches a fork PR head, reviews the
|
|
# exact SHA, then pushes one of these tags at that SHA. Because a tag push is
|
|
# a push event in this (base) repo, the run executes in trusted context WITH
|
|
# secrets — the only way to run secret-bearing validation on fork-authored
|
|
# code. '*-reviewed-for-compile' runs a compile-only build with NO secrets
|
|
# (cheap sanity check); '*-reviewed-for-build' runs the full build with tests
|
|
# and secrets. Safety rests on the maintainer having read that exact SHA
|
|
# before pushing the tag. See the "Determine build mode" step below.
|
|
tags:
|
|
- '*-reviewed-for-compile'
|
|
- '*-reviewed-for-build'
|
|
# paths-ignore is not evaluated for tag pushes (GitHub rule), so it only
|
|
# scopes branch pushes, exactly as before.
|
|
paths-ignore:
|
|
- 'wiki/**'
|
|
- '.github/workflows/*'
|
|
- '**/*.md'
|
|
- 'README.md'
|
|
- 'docs/**'
|
|
# Auto-build submitted PRs. A same-repo PR (branch pushed by a committer) runs
|
|
# the full build with tests and secrets — same trust as a direct branch push.
|
|
# A fork PR runs compile-only with NO secrets (GitHub withholds secrets from
|
|
# fork pull_request runs at the event level); the secret-bearing full build of
|
|
# fork code stays gated behind a maintainer pushing a *-reviewed-for-build tag.
|
|
# No branches: filter here — for pull_request that would filter by BASE branch;
|
|
# omitting it targets PRs into any branch. Draft PRs are excluded by the build
|
|
# job's if:. See the "Determine build mode" step for the fork/same-repo split.
|
|
pull_request:
|
|
types: [opened, synchronize, reopened, ready_for_review]
|
|
paths-ignore:
|
|
- 'wiki/**'
|
|
- '.github/workflows/*'
|
|
- '**/*.md'
|
|
- 'README.md'
|
|
- 'docs/**'
|
|
workflow_dispatch:
|
|
inputs:
|
|
skip_tests:
|
|
description: Skip tests (set to "true" to skip all tests)
|
|
default: 'false'
|
|
local_target_platform:
|
|
description: Build with a local target platform (set to "true" to use local target platform)
|
|
default: 'false'
|
|
runner_cpus:
|
|
description: Empty means ubuntu-latest, usually 4 CPUs with little disk/memory, but if you have runners named ubuntu-latest-Xcpu, it can be 4, 8, 16, and 64 as well, using, e.g., ubuntu-latest-16cpu; default is ubuntu-latest
|
|
default: ''
|
|
firefox_version:
|
|
description: Version to use for Selenium tests; default is "latest", but could, e.g., be "141.0" or a specific pin like "140.0"
|
|
default: 'latest'
|
|
|
|
jobs:
|
|
# The "changes" job will cause the "build" job to get skipped for trivial changes
|
|
changes:
|
|
permissions: {}
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
# On workflow_dispatch there is no 'before' field in the event payload, so
|
|
# paths-filter cannot compute a meaningful diff (it would warn and fall back
|
|
# to the last commit only). A manual dispatch is an explicit request to build,
|
|
# so we skip the filter step entirely and force should_run=true. On push/PR the
|
|
# filter runs and its 'code' output decides. (The build job also short-circuits
|
|
# its own if-condition on workflow_dispatch, so this keeps both in agreement.)
|
|
should_run: ${{ github.event_name == 'workflow_dispatch' && 'true' || steps.filter.outputs.code }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
- id: filter
|
|
if: github.event_name != 'workflow_dispatch'
|
|
uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
|
|
with:
|
|
# Under the default 'some' quantifier a negated rule still counts as a
|
|
# match (picomatch treats '!README.md' as "anything but README.md"),
|
|
# so a changed README.md would set code=true. 'some-with-excludes'
|
|
# (v4+) makes the '!' rules act as real exclusions: code is true only
|
|
# when a changed file matches the positive '**' rule AND none of the
|
|
# excludes.
|
|
predicate-quantifier: 'some-with-excludes'
|
|
filters: |
|
|
code:
|
|
- '**'
|
|
- '!wiki/**'
|
|
- '!.github/workflows/*'
|
|
- '!**/*.md'
|
|
- '!README.md'
|
|
- '!docs/**'
|
|
|
|
build:
|
|
needs: changes
|
|
if: >-
|
|
${{ (needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch')
|
|
&& (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
|
|
permissions:
|
|
contents: write
|
|
checks: write
|
|
actions: read
|
|
runs-on: ${{ github.event.inputs.runner_cpus != '' && format('ubuntu-latest-{0}cpu', github.event.inputs.runner_cpus) || 'ubuntu-latest' }}
|
|
outputs:
|
|
skip_tests: ${{ steps.mode.outputs.skip_tests }}
|
|
steps:
|
|
- name: Determine build mode
|
|
id: mode
|
|
shell: bash
|
|
# skip_tests=true means "compile only, no tests, no secrets". It is true
|
|
# for a workflow_dispatch with skip_tests=true, for a push of a
|
|
# *-reviewed-for-compile tag, OR for a fork-originated pull_request (fork
|
|
# runs get no secrets, so we compile without tests; the secret-bearing
|
|
# full build of fork code is gated behind a *-reviewed-for-build tag).
|
|
# Everything else (branches, same-repo PRs, *-reviewed-for-build tags)
|
|
# runs the full build with tests and secrets.
|
|
run: |
|
|
skip=false
|
|
if [[ "${{ github.event.inputs.skip_tests }}" == "true" ]]; then skip=true; fi
|
|
if [[ "${{ github.ref }}" == refs/tags/*-reviewed-for-compile ]]; then skip=true; fi
|
|
if [[ "${{ github.event_name }}" == "pull_request" \
|
|
&& "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
|
|
skip=true
|
|
fi
|
|
echo "skip_tests=$skip" >> "$GITHUB_OUTPUT"
|
|
- name: Free Disk Space (Ubuntu)
|
|
uses: jlumbroso/free-disk-space@v1.3.1
|
|
with:
|
|
# this might remove tools that are actually needed,
|
|
# if set to "true" but frees about 6 GB
|
|
tool-cache: false
|
|
# all of these default to true, but feel free to set to
|
|
# "false" if necessary for your workflow
|
|
android: false
|
|
dotnet: true
|
|
haskell: true
|
|
large-packages: true
|
|
docker-images: false
|
|
swap-storage: true
|
|
- name: Allocate swap space
|
|
shell: bash
|
|
run: |
|
|
sudo dd if=/dev/zero of=/mnt/large-swapfile bs=1G count=30
|
|
sudo chmod 600 /mnt/large-swapfile
|
|
sudo mkswap /mnt/large-swapfile
|
|
sudo chown root:root /mnt/large-swapfile
|
|
sudo swapon /mnt/large-swapfile
|
|
- name: Create TMP space under /mnt/tmp
|
|
shell: bash
|
|
run: |
|
|
sudo mkdir /mnt/tmp
|
|
sudo chmod 777 /mnt/tmp
|
|
- name: Collect Workflow Telemetry
|
|
uses: ycfreeman/workflow-telemetry-action@72ec425db8a31670fdc4419966940a6d980a0b49 # v3.0.2
|
|
with:
|
|
comment_on_pr: false
|
|
proc_trace_min_duration: 5000 # only chart processes running >= 5s
|
|
proc_trace_chart_max_count: 40 # cap Gantt bars to keep mermaid source under 50k
|
|
metric_frequency: 30 # ~3h+ builds: coarser sampling so the per-sample CPU/memory xychart source stays well under mermaid's 50k maxTextSize (~390 points/3h15m)
|
|
- name: Setup firefox
|
|
id: setup-firefox
|
|
uses: browser-actions/setup-firefox@0bc507ddf224827e3b1af68e014d5e42ab93e795 # v1.7.2
|
|
with:
|
|
firefox-version: ${{ github.event.inputs.firefox_version == '' && 'latest' || github.event.inputs.firefox_version }}
|
|
- run: |
|
|
echo Installed firefox versions: ${{ steps.setup-firefox.outputs.firefox-version }}
|
|
${{ steps.setup-firefox.outputs.firefox-path }} --version
|
|
- name: Check out the repository to the runner
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
fetch-depth: '500'
|
|
- name: Install JDK 8
|
|
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
|
with:
|
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
|
java-version: '8'
|
|
mvn-toolchain-id: 'JavaSE-1.8'
|
|
- name: Install JDK 17
|
|
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
|
with:
|
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
|
java-version: '17'
|
|
mvn-toolchain-id: 'JavaSE-17'
|
|
- name: Install JDK 25
|
|
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
|
|
with:
|
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
|
java-version: '25'
|
|
mvn-toolchain-id: 'JavaSE-25'
|
|
- name: Setup Android SDK
|
|
uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
|
with:
|
|
log-accepted-android-sdk-licenses: 'false'
|
|
cmdline-tools-version: 9123335 # This corresponds to human-friendly version number 8.0
|
|
# The action's default 'packages' is "tools platform-tools". The legacy "tools"
|
|
# package was removed from Google's SDK repository; as of the ~2026-09-14 runner
|
|
# image (cmdline-tools 12.0 preinstalled) sdkmanager no longer resolves it and the
|
|
# step fails with "Failed to find package 'tools'". We only need the action to
|
|
# bootstrap cmdline-tools here; buildAndUpdateProduct.sh installs build-tools,
|
|
# platform-tools and the platform itself. So request just platform-tools.
|
|
packages: 'platform-tools'
|
|
- name: Start MongoDB
|
|
uses: supercharge/mongodb-github-action@315db7fe45ac2880b7758f1933e6e5d59afd5e94 #v1.12.1
|
|
with:
|
|
mongodb-version: 7.0
|
|
- name: Start RabbitMQ
|
|
uses: Namoshek/rabbitmq-github-action@80a182e44c7f60bc3417a8689d6a24fe9d08b27b #v1.2.0
|
|
with:
|
|
version: '3.8.9'
|
|
ports: '5672:5672'
|
|
- shell: bash
|
|
env: # Or as an environment variable
|
|
TMP: /mnt/tmp
|
|
# These five are consumed only at TEST runtime. For a compile-only run
|
|
# (skip_tests) they resolve to '' so the real secret values are never
|
|
# placed in the process environment where reviewed-but-fork-authored
|
|
# code could read them. The full build (skip_tests false) gets them all.
|
|
AWS_S3_TEST_S3ACCESSID: ${{ steps.mode.outputs.skip_tests == 'true' && '' || secrets.AWS_S3_TEST_S3ACCESSID }}
|
|
AWS_S3_TEST_S3ACCESSKEY: ${{ steps.mode.outputs.skip_tests == 'true' && '' || secrets.AWS_S3_TEST_S3ACCESSKEY }}
|
|
GEONAMES_ORG_USERNAMES: ${{ steps.mode.outputs.skip_tests == 'true' && '' || secrets.GEONAMES_ORG_USERNAMES }}
|
|
GOOGLE_MAPS_AUTHENTICATION_PARAMS: ${{ steps.mode.outputs.skip_tests == 'true' && '' || secrets.GOOGLE_MAPS_AUTHENTICATION_PARAMS }}
|
|
POLAR_DATA_BASE_URL: ${{ vars.POLAR_DATA_BASE_URL }}
|
|
POLAR_DATA_BEARER_TOKEN: ${{ steps.mode.outputs.skip_tests == 'true' && '' || secrets.POLAR_DATA_BEARER_TOKEN }}
|
|
APP_PARAMETERS: "-Daws.region=eu-west-1"
|
|
JAVA8_HOME: ${{env.JAVA_HOME_8_X64}}
|
|
JAVA17_HOME: ${{env.JAVA_HOME_17_X64}}
|
|
run: |
|
|
./configuration/buildAndUpdateProduct.sh -x ${{ github.event.inputs.runner_cpus == '' && '4' || github.event.inputs.runner_cpus }} ${{ steps.mode.outputs.skip_tests == 'true' && '-t' || '' }} ${{ github.event.inputs.local_target_platform == 'true' && '-v' || '' }} build 2>&1
|
|
- name: show disk stats
|
|
if: always()
|
|
run: df -h
|
|
- name: Upload build log
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: build.log
|
|
path: build.log
|
|
retention-days: 90
|
|
- name: Collect Test Reports
|
|
uses: dorny/test-reporter@a6ddd83ac95ff4586f5d3aceeb314d9a1841db95 # v3.0.0
|
|
# Skip for compile-only runs: no tests ran, so there are no TEST-*.xml
|
|
# and fail-on-error would otherwise error on zero matches.
|
|
if: ${{ always() && steps.mode.outputs.skip_tests != 'true' }}
|
|
with:
|
|
name: Maven Tests
|
|
path: '**/TEST-*.xml'
|
|
max-annotations: '1'
|
|
list-suites: failed
|
|
list-tests: failed
|
|
reporter: java-junit
|
|
fail-on-error: true
|
|
- name: Build Release
|
|
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-24' || github.ref == 'refs/heads/docker-25' || startsWith(github.ref, 'refs/heads/releases/') }}
|
|
shell: bash
|
|
run: |
|
|
./configuration/buildAndUpdateProduct.sh -u -L ${{ github.event.inputs.skip_tests == 'true' && '-n untested' || '' }} release
|
|
- name: Determine release name
|
|
run: |
|
|
echo "SIMPLE_VERSION_INFO=$( basename dist/* )" >>${GITHUB_ENV}
|
|
- name: Upload test results
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: always()
|
|
with:
|
|
name: test-results
|
|
path: |
|
|
**/surefire-reports/**
|
|
retention-days: 90
|
|
- name: Upload distribution artifact
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-24' || github.ref == 'refs/heads/docker-25' || startsWith(github.ref, 'refs/heads/releases/') }}
|
|
with:
|
|
name: ${{ env.SIMPLE_VERSION_INFO }}
|
|
path: dist/**/*
|
|
retention-days: 90
|
|
- name: Create Release
|
|
id: create_release
|
|
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-24' || github.ref == 'refs/heads/docker-25' || startsWith(github.ref, 'refs/heads/releases/') }}
|
|
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
|
with:
|
|
tag_name: ${{ env.SIMPLE_VERSION_INFO }}
|
|
target_commitish: ${{ github.ref_name }}
|
|
name: ${{ env.SIMPLE_VERSION_INFO }}
|
|
draft: false
|
|
prerelease: false
|
|
- name: Upload Release Asset tar.gz
|
|
id: upload-release-asset-tar-gz
|
|
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-24' || github.ref == 'refs/heads/docker-25' || startsWith(github.ref, 'refs/heads/releases/') }}
|
|
uses: actions/upload-release-asset@v1
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
with:
|
|
# Do NOT fold this into action-gh-release's files: input: that action derives the
|
|
# content type via the mime-types library, which maps .tar.gz to application/gzip.
|
|
# Production installers (refreshInstance.sh, github-download-release-assets.sh) select
|
|
# the tarball with select(.content_type=="application/x-tar"), so the type must be set
|
|
# explicitly here.
|
|
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
|
asset_path: ./dist/${{ env.SIMPLE_VERSION_INFO }}/${{ env.SIMPLE_VERSION_INFO }}.tar.gz
|
|
asset_name: ${{ env.SIMPLE_VERSION_INFO }}.tar.gz
|
|
asset_content_type: application/x-tar
|
|
- name: Upload Release Asset release_notes.txt
|
|
id: upload-release-asset-release-notes-txt
|
|
if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker-24' || github.ref == 'refs/heads/docker-25' || startsWith(github.ref, 'refs/heads/releases/') }}
|
|
uses: actions/upload-release-asset@v1
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
with:
|
|
upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
|
asset_path: ./dist/${{ env.SIMPLE_VERSION_INFO }}/release-notes.txt
|
|
asset_name: release-notes.txt
|
|
asset_content_type: text/plain
|
|
- name: Trigger CI job
|
|
env:
|
|
CI_JOB_USERNAME: ${{ vars.CI_JOB_USERNAME }}
|
|
CI_JOB_PASSWORD: ${{ secrets.CI_JOB_PASSWORD }}
|
|
CI_JOB_TOKEN: ${{ secrets.CI_JOB_TOKEN }}
|
|
if: ${{ always() && env.CI_JOB_USERNAME != '' && env.CI_JOB_PASSWORD != '' && env.CI_JOB_TOKEN != '' }}
|
|
shell: bash
|
|
run: |
|
|
if [[ "${{ github.ref }}" =~ refs/heads/releases/.* ]]; then
|
|
JOB=$( echo "${{ github.ref }}" | sed -e 's/^refs\/heads\/releases\///' )
|
|
else
|
|
JOB=$( echo "${{ github.ref }}" | sed -e 's/^refs\/heads\///' )
|
|
fi
|
|
echo "Identified CI job: ${JOB}"
|
|
curl -u "${{ vars.CI_JOB_USERNAME }}:${{ secrets.CI_JOB_PASSWORD}}" ${{ vars.CI_BASE_URL }}/job/${JOB}/build?token=${{ secrets.CI_JOB_TOKEN }}
|
|
|
|
# build-gate is the REQUIRED status check in the branch ruleset (context
|
|
# "build-gate"). It must be SATISFIED only for a genuine full build (tests
|
|
# actually ran and passed) or a legitimate trivial-change skip; every other
|
|
# case — most importantly a compile-only fork PR — must leave the PR
|
|
# un-mergeable WITHOUT a red X.
|
|
#
|
|
# WHY THIS IS A POSTED COMMIT STATUS, NOT A JOB NAMED build-gate:
|
|
# GitHub Actions auto-creates a check-run for every JOB, and fills its
|
|
# conclusion from the job's fate — including "skipped" when the job's if: is
|
|
# false. A rule set / branch protection treats a "skipped" required check as
|
|
# SATISFIED (mergeable). So a job named build-gate can NEVER represent "absent"
|
|
# — a skipped job still materializes a skipped=passed check-run. That is the
|
|
# exact bug that let compile-only fork PRs #53/#54 merge without tests.
|
|
#
|
|
# A COMMIT STATUS (legacy Statuses API) is different: it exists only if we
|
|
# explicitly POST it. A skipped STEP posts nothing (steps are not check-runs).
|
|
# The ruleset matches the required context "build-gate" by NAME across both
|
|
# APIs, so a posted commit status with context=build-gate satisfies it exactly
|
|
# as the old check-run did — no ruleset change needed.
|
|
#
|
|
# Hence: this job is named post-build-gate-status (NOT build-gate) so its own
|
|
# auto check-run carries a context the ruleset ignores. Its single step POSTs a
|
|
# commit status context=build-gate ONLY when: the change was trivial (build
|
|
# skipped, no relevant changes) OR a full build ran WITH tests and succeeded
|
|
# -> state=success; OR a full build ran WITH tests and FAILED
|
|
# (build.result==failure, skip_tests==false) -> state=failure (red X, so a
|
|
# committer's own broken build is loud). In every OTHER case it posts NOTHING,
|
|
# so no build-gate context exists for the head SHA and the PR stays blocked at
|
|
# "Expected" with no red X. That "nothing" covers: any compile-only run,
|
|
# succeeded OR failed (fork PR, *-reviewed-for-compile, workflow_dispatch
|
|
# skip_tests) — no tests ran, so there is nothing meaningful to fail on; AND a
|
|
# CANCELLED trusted build — cancellation is indeterminate (tests might have
|
|
# passed had it finished), so "failure" would be misleading; re-run to get a
|
|
# real verdict. Merge qualification for fork code comes only from a maintainer
|
|
# pushing a *-reviewed-for-build tag (full trusted build with tests), which
|
|
# posts success/failure. compile-gate (advisory) still shows compile pass/fail.
|
|
#
|
|
# The status is posted against the PR HEAD sha on pull_request events
|
|
# (github.sha there is the ephemeral refs/pull/N/merge commit, which the
|
|
# ruleset does not evaluate) and github.sha otherwise. needs:[changes, build]
|
|
# + if: always() so the trivial-change path (build skipped) is still evaluated.
|
|
post-build-gate-status:
|
|
permissions:
|
|
statuses: write
|
|
needs: [changes, build]
|
|
if: always()
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Post build-gate commit status
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
BUILD_RESULT: ${{ needs.build.result }}
|
|
SKIP_TESTS: ${{ needs.build.outputs.skip_tests }}
|
|
SHOULD_RUN: ${{ needs.changes.outputs.should_run }}
|
|
GATE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
run: |
|
|
STATE=""
|
|
if [[ "$BUILD_RESULT" == "success" && "$SKIP_TESTS" != "true" ]]; then
|
|
STATE=success; REASON="Full build with tests passed."
|
|
elif [[ "$BUILD_RESULT" == "skipped" && "$SHOULD_RUN" == "false" ]]; then
|
|
STATE=success; REASON="No relevant changes — nothing to build."
|
|
elif [[ "$BUILD_RESULT" == "failure" && "$SKIP_TESTS" != "true" ]]; then
|
|
STATE=failure; REASON="Full build with tests failed."
|
|
fi
|
|
if [[ -n "$STATE" ]]; then
|
|
echo "Posting build-gate=$STATE on $GATE_SHA: $REASON"
|
|
gh api "repos/${GITHUB_REPOSITORY}/statuses/${GATE_SHA}" \
|
|
-f state="$STATE" \
|
|
-f context=build-gate \
|
|
-f description="$REASON" \
|
|
-f target_url="$RUN_URL"
|
|
else
|
|
echo "Not posting build-gate: build.result=$BUILD_RESULT skip_tests=$SKIP_TESTS should_run=$SHOULD_RUN"
|
|
echo "The build-gate context stays absent, so the PR remains un-mergeable"
|
|
echo "at 'Expected' without a red X — this covers a successful OR failed"
|
|
echo "compile-only run (e.g. a fork PR, where no tests ran so there is"
|
|
echo "nothing to fail on). A *-reviewed-for-build tag runs the full build"
|
|
echo "with tests and posts success (or failure) to the build-gate context."
|
|
fi
|
|
|
|
# compile-gate is an ADVISORY (non-required) check. It reflects only whether
|
|
# the build job compiled successfully, regardless of whether tests ran — a full
|
|
# build implies compilation succeeded. It gives *-reviewed-for-compile runs a
|
|
# distinct green/red on the PR without touching the required build-gate check.
|
|
compile-gate:
|
|
permissions: {}
|
|
needs: [changes, build]
|
|
if: always()
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- run: |
|
|
if [[ "${{ needs.build.result }}" == "success" ]]; then
|
|
echo "Compilation succeeded."
|
|
elif [[ "${{ needs.build.result }}" == "skipped" && "${{ needs.changes.outputs.should_run }}" == "false" ]]; then
|
|
echo "No relevant changes — nothing to compile."
|
|
else
|
|
echo "Compilation failed or was cancelled."
|
|
exit 1
|
|
fi
|
|
|