Files
container/.github/workflows/common.yml
T
Noah Thornton d12d64d488 Change PR build to generate coverage and comment it (#1474)
This extends the github actions to by default run the coverage
generation targets. The targets will generate the coverage artifacts,
which will then be used by a seprate github action to comment on the PR
the coverage numbers.

This is a sanity check for testing information for new features and
refactors alike. It will allow reviewers to quickly identify if there
are major issues with new tests, or large changes to coverage percentage
that indicate a problem.
2026-05-04 11:10:02 -07:00

215 lines
7.3 KiB
YAML

name: container project - common jobs
permissions:
contents: read
on:
workflow_call:
inputs:
release:
type: boolean
description: "Publish this build for release"
default: false
coverage:
type: boolean
description: "Run tests with code coverage enabled"
default: false
pr_number:
type: string
description: "PR number for coverage artifact naming (required when coverage is true)"
default: ""
jobs:
buildAndTest:
name: Build and test the project
if: github.repository == 'apple/container'
timeout-minutes: 60
runs-on: [self-hosted, macos, tahoe, ARM64]
permissions:
contents: read
packages: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Check formatting
run: |
./scripts/install-hawkeye.sh
make fmt
if ! git diff --quiet -- . ; then
echo "❌ The following files require formatting or license header updates:"
git diff --name-only -- .
false
fi
- name: Check protobuf
run: |
make protos
if ! git diff --quiet -- . ; then
echo "❌ The following files require formatting or license header updates:"
git diff --name-only -- .
false
fi
env:
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
- name: Set build configuration
env:
RELEASE: ${{ inputs.release }}
run: |
echo "BUILD_CONFIGURATION=debug" >> $GITHUB_ENV
if [[ "${RELEASE}" == "true" ]]; then
echo "BUILD_CONFIGURATION=release" >> $GITHUB_ENV
fi
- name: Make the container project and docs
run: |
make container dsym docs
tar cfz _site.tgz _site
env:
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
- name: Validate coverage inputs
if: ${{ inputs.coverage }}
env:
PR_NUMBER: ${{ inputs.pr_number }}
run: |
if [ -z "${PR_NUMBER}" ]; then
echo "::error::pr_number input is required when coverage is true"
exit 1
fi
- name: Create package
run: |
mkdir -p outputs
mv "bin/${BUILD_CONFIGURATION}/container-installer-unsigned.pkg" outputs
mv "bin/${BUILD_CONFIGURATION}/bundle/container-dSYM.zip" outputs
- name: Set up test environment
run: |
APP_ROOT=$(mktemp -d -p "${RUNNER_TEMP}")
LOG_ROOT="${APP_ROOT}/logs"
echo "created data directory: ${APP_ROOT}"
echo "hostname: $(hostname)"
export NO_PROXY="${NO_PROXY},192.168.0.0/16,fe80::/10"
echo NO_PROXY=${NO_PROXY}
export no_proxy="${no_proxy},192.168.0.0/16,fe80::/10"
echo no_proxy=${no_proxy}
echo "APP_ROOT=${APP_ROOT}" >> $GITHUB_ENV
echo "LOG_ROOT=${LOG_ROOT}" >> $GITHUB_ENV
- name: Test the container project
if: ${{ !inputs.coverage }}
run: make APP_ROOT="${APP_ROOT}" LOG_ROOT="${LOG_ROOT}" test install-kernel integration
env:
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
- name: Test the container project with coverage
if: ${{ inputs.coverage }}
run: make APP_ROOT="${APP_ROOT}" LOG_ROOT="${LOG_ROOT}" install-kernel coverage
env:
DEVELOPER_DIR: "/Applications/Xcode-latest.app/Contents/Developer"
- name: Extract coverage percentages
if: ${{ inputs.coverage }}
env:
PR_NUMBER: ${{ inputs.pr_number }}
run: |
mkdir -p pr-coverage
jq -r '.data[0].totals.lines.percent | . * 100 | round | . / 100' coverage-reports/unit/coverage-summary.json > pr-coverage/unit-line-coverage.txt
jq -r '.data[0].totals.lines.percent | . * 100 | round | . / 100' coverage-reports/integration/coverage-summary.json > pr-coverage/integration-line-coverage.txt
jq -r '.data[0].totals.lines.percent | . * 100 | round | . / 100' coverage-reports/combined/coverage-summary.json > pr-coverage/combined-line-coverage.txt
echo "${PR_NUMBER}" > pr-coverage/pr-number.txt
echo "Coverage data:"
cat pr-coverage/*.txt
- name: Upload coverage data
if: ${{ inputs.coverage }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pr-coverage-${{ inputs.pr_number }}
path: pr-coverage/
retention-days: 1
if-no-files-found: warn
- name: Upload coverage HTML reports
if: ${{ inputs.coverage }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-html-reports
path: |
coverage-reports/unit/html/
coverage-reports/integration/html/
coverage-reports/combined/html/
retention-days: 14
if-no-files-found: ignore
- name: Archive test logs
if: always()
run: |
if [ -d "${APP_ROOT}/containers" ] && [ -n "${LOG_ROOT}" ]; then
rsync -a --include='*/' --include='*.log' --exclude='*' \
"${APP_ROOT}/containers/" \
"${LOG_ROOT}/containers/"
fi
if [ -n "${LOG_ROOT}" ] && [ -d "${LOG_ROOT}" ] ; then
echo "Collecting logs from ${LOG_ROOT}..."
tar czf container-logs.tar.gz -C "$(dirname "${LOG_ROOT}")" "$(basename "${LOG_ROOT}")"
echo "Log archive created: container-logs.tar.gz"
fi
if [ -n "${APP_ROOT}" ] ; then
rm -rf "${APP_ROOT}"
echo "Removed data directory ${APP_ROOT}"
fi
rm -rf coverage-reports pr-coverage
- name: Upload logs if present
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: container-test-logs
path: container-logs.tar.gz
retention-days: 14
if-no-files-found: ignore
- name: Save documentation artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: api-docs
path: "./_site.tgz"
retention-days: 14
- name: Save package artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: container-package
path: ${{ github.workspace }}/outputs
uploadPages:
# Separate upload step required because upload-pages-artifact needs
# gtar which is not on the macOS runner.
name: Upload artifact for GitHub Pages
needs: buildAndTest
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- name: Setup Pages
uses: actions/configure-pages@v6
- name: Download a single artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: api-docs
- name: Add API docs to documentation
run: |
tar xfz _site.tgz
- name: Upload Artifact
uses: actions/upload-pages-artifact@v5
with:
path: "./_site"