Skip to content

Build

Build #144

Workflow file for this run

on:
push:
branches:
# for bors r+
- staging
# for bors try
- trying
workflow_dispatch:
name: Build
jobs:
setup:
name: Setup
runs-on: ubuntu-latest
outputs:
os: ${{ steps.generate-matrix.outputs.os }}
platform: ${{ steps.generate-matrix.outputs.platform }}
run-build: ${{ steps.generate-matrix.outputs.run-build }}
fail-fast: ${{ steps.generate-matrix.outputs.fail-fast }}
steps:
- uses: actions/setup-node@v4
with:
node-version: 16
- run: npm install js-yaml
- name: Generate matrix
id: generate-matrix
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const yaml = require('js-yaml')
const osMatrix = yaml.load(process.env.OS_MATRIX)
const platformMatrix = yaml.load(process.env.PLATFORM_MATRIX)
if (context.eventName == 'schedule' || context.eventName == 'workflow_dispatch') {
// Always run on schedule
core.setOutput('os', JSON.stringify(osMatrix))
core.setOutput('platform', JSON.stringify(platformMatrix))
core.setOutput('fail-fast', 'false')
} else if (context.eventName == 'push') {
const commitMessage = process.env.COMMIT_MESSAGE.trim()
if (commitMessage.length > 0) {
let outputOsMatrix = []
let outputPlatformMatrix = []
let borsArgs
if (commitMessage.startsWith('Try #')) {
borsArgs = commitMessage.replace(/Try #[0-9]+:/i, '').trim()
} else {
// Merge example commit message:
// Merge #64
//
// 64: Refine bors command r=messense a=messense
//
// bors: amd64 --platform manylinux2014
//
// Co-authored-by: messense <[email protected]>
//
borsArgs = commitMessage
.split('\n')
.filter(item => item.trim().startsWith('bors:'))
.map(item => item.substring('bors:'.length))
.join('\n')
.trim()
}
const platformIndex = borsArgs.indexOf('--platform')
let dockerArch = []
let platforms = []
if (platformIndex === -1) {
if (borsArgs.length > 0) {
dockerArch = borsArgs.split(' ')
}
platforms = []
} else {
const dockerArchArg = borsArgs.substring(0, platformIndex).trim()
if (dockerArchArg.length > 0) {
dockerArch = dockerArchArg.split(' ')
}
const platformArg = borsArgs.substring(platformIndex + '--platform'.length).trim()
if (platformArg.length > 0) {
platforms = platformArg.split(' ')
}
}
if (dockerArch.length === 0) {
// Defaults to all arches
outputOsMatrix = osMatrix
} else {
for (const arch of dockerArch) {
outputOsMatrix.push(...osMatrix.filter(item => item.arch == arch))
}
}
if (platforms.length === 0) {
// Defaults to all platforms
outputPlatformMatrix = platformMatrix
} else {
for (const platform of platforms) {
outputPlatformMatrix.push(...platformMatrix.filter(item => item.manylinux.startsWith(platform)))
}
}
core.setOutput('os', JSON.stringify(outputOsMatrix))
core.setOutput('platform', JSON.stringify(outputPlatformMatrix))
} else {
core.setOutput('os', JSON.stringify(osMatrix))
core.setOutput('platform', JSON.stringify(platformMatrix))
core.setOutput('run-build', 'false')
}
const matches = commitMessage.match(/(Try|Merge) #([0-9]+):/)
if (matches) {
const prNumber = matches[2]
const { data: { labels: labels } } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
})
const labelNames = labels.map(label => label.name)
if (labelNames.includes('CI-no-fail-fast')) {
core.setOutput('fail-fast', 'false')
}
}
} else {
core.setOutput('os', JSON.stringify(osMatrix))
core.setOutput('platform', JSON.stringify(platformMatrix))
core.setOutput('run-build', 'false')
}
- name: Show build matrix
run: |
echo '${{ toJson(steps.generate-matrix.outputs.os) }}'
echo '${{ toJson(steps.generate-matrix.outputs.platform) }}'
echo run build: ${{ steps.generate-matrix.outputs.run-build || 'true' }}
echo fail fast: ${{ steps.generate-matrix.outputs.fail-fast || 'true' }}
env:
COMMIT_MESSAGE: >
${{
((
(startsWith(github.event.head_commit.message, 'Try #') || startsWith(github.event.head_commit.message, 'Merge #')) &&
github.event.head_commit.author.username == 'bors[bot]'
) && github.event.head_commit.message) || ''
}}
OS_MATRIX: |
- arch: amd64
label: [ubuntu-latest]
- arch: arm64
label: [self-hosted, ARM64]
PLATFORM_MATRIX: |
- arch: x86_64
manylinux: manylinux2014
- arch: i686
manylinux: manylinux2014
- arch: aarch64
manylinux: manylinux2014
- arch: armv7l
manylinux: manylinux2014
- arch: s390x
manylinux: manylinux2014
- arch: ppc64le
manylinux: manylinux2014
- arch: ppc64
manylinux: manylinux2014
- arch: x86_64
manylinux: manylinux_2_28
- arch: aarch64
manylinux: manylinux_2_28
- arch: armv7l
manylinux: manylinux_2_28
- arch: s390x
manylinux: manylinux_2_28
- arch: ppc64le
manylinux: manylinux_2_28
- arch: x86_64
manylinux: musllinux_1_2
- arch: i686
manylinux: musllinux_1_2
- arch: aarch64
manylinux: musllinux_1_2
- arch: armv7l
manylinux: musllinux_1_2
build:
name: Build - ${{ matrix.os.arch }} - ${{ matrix.platform.manylinux }}_${{ matrix.platform.arch }}
if: ${{ needs.setup.outputs.run-build != 'false' }}
needs: [setup]
runs-on: ${{ matrix.os.label }}
strategy:
fail-fast: ${{ needs.setup.outputs.fail-fast != 'false' }}
matrix:
os: ${{ fromJson(needs.setup.outputs.os) }}
platform: ${{ fromJson(needs.setup.outputs.platform) }}
steps:
- uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image
uses: docker/build-push-action@v6
with:
platforms: linux/${{ matrix.os.arch }}
context: ${{ matrix.platform.manylinux }}/${{ matrix.platform.arch }}
file: ${{ matrix.platform.manylinux }}/${{ matrix.platform.arch }}/Dockerfile
tags: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }}
load: true
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }}-buildcache
cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }}-buildcache,mode=max
- name: Verify Image
run: |
set -ex
docker run --rm ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }} \
bash -c 'pip3 --version'
docker run --rm ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }} \
bash -c 'for VER in 3.7 3.8 3.9 3.10 3.11 3.12; do "python$VER" -m pip --version || exit 1; done'
docker run --rm ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }} \
bash -c 'for VER in 3.7 3.8 3.9; do "pypy$VER" -m pip --version || exit 1; done'
- name: Build and push multiarch image
env:
DOCKER_CLI_EXPERIMENTAL: enabled
run: |
set -e
docker push ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-${{ matrix.os.arch }}
curl -sqL -o manifest-tool https://github.com/estesp/manifest-tool/releases/download/v1.0.3/manifest-tool-linux-${{ matrix.os.arch }}
chmod +x manifest-tool
echo "image: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch}}
manifests:" > ghcr-manifest.yaml
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64 > /dev/null; then
echo " - image: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64
platform:
architecture: amd64
os: linux" >> ghcr-manifest.yaml
fi
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64 > /dev/null; then
echo " - image: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64
platform:
architecture: arm64
os: linux" >> ghcr-manifest.yaml
fi
cat ghcr-manifest.yaml
./manifest-tool push from-spec ghcr-manifest.yaml
- name: Sync images to Docker Hub
if: ${{ github.repository_owner == 'rust-cross' }}
env:
DOCKER_CLI_EXPERIMENTAL: enabled
run: |
set -e
echo "image: ${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}
manifests:" > dockerhub-manifest.yaml
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64 > /dev/null; then
docker run --rm quay.io/skopeo/stable:latest copy --src-creds ${{ github.repository_owner }}:${{ secrets.GITHUB_TOKEN }} --dest-creds ${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }} --retry-times 3 docker://ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64 docker://${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64
echo " - image: ${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64
platform:
architecture: amd64
os: linux" >> dockerhub-manifest.yaml
fi
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64 > /dev/null; then
docker run --rm quay.io/skopeo/stable:latest copy --src-creds ${{ github.repository_owner }}:${{ secrets.GITHUB_TOKEN }} --dest-creds ${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }} --retry-times 3 docker://ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64 docker://${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64
echo " - image: ${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64
platform:
architecture: arm64
os: linux" >> dockerhub-manifest.yaml
fi
cat dockerhub-manifest.yaml
./manifest-tool push from-spec dockerhub-manifest.yaml
- name: Alias armv7l to armv7
if: matrix.platform.arch == 'armv7l'
env:
DOCKER_CLI_EXPERIMENTAL: enabled
run: |
set -e
echo "image: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:armv7
manifests:" > ghcr-manifest.yaml
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64 > /dev/null; then
echo " - image: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64
platform:
architecture: amd64
os: linux" >> ghcr-manifest.yaml
fi
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64 > /dev/null; then
echo " - image: ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64
platform:
architecture: arm64
os: linux" >> ghcr-manifest.yaml
fi
cat ghcr-manifest.yaml
./manifest-tool push from-spec ghcr-manifest.yaml
echo "image: ${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:armv7
manifests:" > dockerhub-manifest.yaml
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64 > /dev/null; then
echo " - image: ${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-amd64
platform:
architecture: amd64
os: linux" >> dockerhub-manifest.yaml
fi
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64 > /dev/null; then
echo " - image: ${{ secrets.DOCKER_USERNAME }}/${{ matrix.platform.manylinux }}-cross:${{ matrix.platform.arch }}-arm64
platform:
architecture: arm64
os: linux" >> dockerhub-manifest.yaml
fi
cat dockerhub-manifest.yaml
./manifest-tool push from-spec dockerhub-manifest.yaml
conclusion:
needs: [setup, build]
if: always()
runs-on: ubuntu-latest
steps:
- name: Result
run: |
jq -C <<< "${needs}"
# Check if all needs were successful or skipped.
"$(jq -r 'all(.result as $result | (["success", "skipped"] | contains([$result])))' <<< "${needs}")"
env:
needs: ${{ toJson(needs) }}