Build #370
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
on: | |
push: | |
branches: | |
# for bors r+ | |
- staging | |
# for bors try | |
- trying | |
workflow_dispatch: | |
inputs: | |
no_cache: | |
description: Disable Docker cache, yes/no | |
default: 'no' | |
required: false | |
toolchain: | |
description: Rust toolchain to install | |
default: 'stable' | |
required: false | |
arch: | |
description: Architectures to build for | |
default: '' | |
required: false | |
schedule: | |
- cron: '0 0 1 */2 *' | |
name: Build | |
jobs: | |
setup: | |
name: Setup | |
runs-on: ubuntu-latest | |
outputs: | |
arch: ${{ steps.generate-matrix.outputs.arch }} | |
target: ${{ steps.generate-matrix.outputs.target }} | |
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 archMatrix = yaml.load(process.env.ARCH_MATRIX) | |
const targetMatrix = yaml.load(process.env.TARGET_MATRIX) | |
if (context.eventName == 'schedule') { | |
// Always run on schedule | |
core.setOutput('arch', JSON.stringify(archMatrix)) | |
core.setOutput('target', JSON.stringify(targetMatrix)) | |
} else if (context.eventName == 'workflow_dispatch') { | |
let outputArchMatrix = [] | |
let outputTargetMatrix = [] | |
const dockerArch = context.payload.inputs.arch.split(',') | |
if (dockerArch.length > 0) { | |
for (const arch of dockerArch) { | |
outputArchMatrix.push(...archMatrix.filter(item => item.arch == arch)) | |
} | |
} else { | |
outputArchMatrix = archMatrix | |
} | |
const toolchain = context.payload.inputs.toolchain | |
for (const target of targetMatrix) { | |
if (target.TOOLCHAIN == 'nightly' && toolchain != 'nightly') { | |
outputTargetMatrix.push(target) | |
} else { | |
outputTargetMatrix.push({...target, TOOLCHAIN: toolchain}) | |
} | |
} | |
core.setOutput('arch', JSON.stringify(outputArchMatrix)) | |
core.setOutput('target', JSON.stringify(outputTargetMatrix)) | |
core.setOutput('fail-fast', 'false') | |
} else if (context.eventName == 'push') { | |
const commitMessage = process.env.COMMIT_MESSAGE.trim() | |
if (commitMessage.length > 0) { | |
let outputArchMatrix = [] | |
let outputTargetMatrix = [] | |
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 --target aarch64 | |
// | |
// Co-authored-by: messense <messense@icloud.com> | |
// | |
borsArgs = commitMessage | |
.split('\n') | |
.filter(item => item.trim().startsWith('bors:')) | |
.join('\n') | |
.trim() | |
} | |
const targetIndex = borsArgs.indexOf('--target') | |
let dockerArch = [] | |
let targets = [] | |
if (targetIndex === -1) { | |
dockerArch = borsArgs.trim().split(' ').filter(x => x.length > 0) | |
targets = [] | |
} else { | |
dockerArch = borsArgs.substring(0, targetIndex).trim().split(' ').filter(x => x.length > 0) | |
targets = borsArgs.substring(targetIndex + '--target'.length).trim().split(' ') | |
} | |
if (dockerArch.length === 0) { | |
// Defaults to all arches | |
outputArchMatrix = archMatrix | |
} else { | |
for (const arch of dockerArch) { | |
outputArchMatrix.push(...archMatrix.filter(item => item.arch == arch)) | |
} | |
} | |
if (targets.length === 0) { | |
// Defaults to all targets | |
outputTargetMatrix = targetMatrix | |
} else { | |
for (const target of targets) { | |
outputTargetMatrix.push(...targetMatrix.filter(item => item.TARGET.startsWith(target))) | |
} | |
} | |
core.setOutput('arch', JSON.stringify(outputArchMatrix)) | |
core.setOutput('target', JSON.stringify(outputTargetMatrix)) | |
} else { | |
core.setOutput('arch', JSON.stringify(archMatrix)) | |
core.setOutput('target', JSON.stringify(targetMatrix)) | |
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('arch', JSON.stringify(archMatrix)) | |
core.setOutput('target', JSON.stringify(targetMatrix)) | |
core.setOutput('run-build', 'false') | |
} | |
- name: Show build matrix | |
run: | | |
echo '${{ toJson(steps.generate-matrix.outputs.arch) }}' | |
echo '${{ toJson(steps.generate-matrix.outputs.target) }}' | |
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) || '' | |
}} | |
ARCH_MATRIX: | | |
- arch: amd64 | |
runner: [ubuntu-latest] | |
- arch: arm64 | |
runner: [self-hosted, ARM64] | |
- arch: armv7 | |
runner: [self-hosted, ARM64] | |
docker_arch: arm/v7 | |
TARGET_MATRIX: | | |
- IMAGE_TAG: aarch64-musl | |
TARGET: aarch64-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak.aarch64 | |
TOOLCHAIN: stable | |
- IMAGE_TAG: arm-musleabi | |
TARGET: arm-unknown-linux-musleabi | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: arm-musleabihf | |
TARGET: arm-unknown-linux-musleabihf | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: armv5te-musleabi | |
TARGET: armv5te-unknown-linux-musleabi | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: armv7-musleabi | |
TARGET: armv7-unknown-linux-musleabi | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: armv7-musleabihf | |
TARGET: armv7-unknown-linux-musleabihf | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: i586-musl | |
TARGET: i586-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: i686-musl | |
TARGET: i686-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
- IMAGE_TAG: mips-musl | |
TARGET: mips-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: nightly | |
- IMAGE_TAG: mips64-muslabi64 | |
TARGET: mips64-unknown-linux-muslabi64 | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: nightly | |
- IMAGE_TAG: mips64el-muslabi64 | |
TARGET: mips64el-unknown-linux-muslabi64 | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: nightly | |
- IMAGE_TAG: mipsel-musl | |
TARGET: mipsel-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: nightly | |
- IMAGE_TAG: powerpc64le-musl | |
TARGET: powerpc64le-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: nightly | |
- IMAGE_TAG: s390x-musl | |
TARGET: s390x-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: nightly | |
- IMAGE_TAG: x86_64-musl | |
TARGET: x86_64-unknown-linux-musl | |
RUST_MUSL_MAKE_CONFIG: config.mak | |
TOOLCHAIN: stable | |
build: | |
name: Build - ${{ matrix.os.arch }} - ${{ matrix.env.IMAGE_TAG }} | |
runs-on: ${{ matrix.os.runner }} | |
if: ${{ needs.setup.outputs.run-build != 'false' }} | |
needs: setup | |
strategy: | |
fail-fast: ${{ needs.setup.outputs.fail-fast != 'false' }} | |
matrix: | |
os: ${{ fromJson(needs.setup.outputs.arch) }} | |
env: ${{ fromJson(needs.setup.outputs.target) }} | |
env: ${{ matrix.env }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Setup QEMU | |
uses: dbhi/qus/action@main | |
if: ${{ contains(matrix.os.runner, 'ubuntu-latest') }} | |
- name: Setup Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Login to DockerHub | |
if: ${{ github.repository_owner == 'rust-cross' }} | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_TOKEN }} | |
- name: Login to GitHub Container Registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: docker build | |
uses: docker/build-push-action@v6 | |
with: | |
platforms: linux/${{ matrix.os.docker_arch || matrix.os.arch }} | |
build-args: | | |
TARGET=${{ matrix.env.TARGET }} | |
RUST_MUSL_MAKE_CONFIG=${{ matrix.env.RUST_MUSL_MAKE_CONFIG }} | |
TOOLCHAIN=${{ matrix.env.TOOLCHAIN }} | |
tags: ghcr.io/${{ github.repository_owner }}/rust-musl-cross:${{ matrix.env.IMAGE_TAG }}-${{ matrix.os.arch }} | |
no-cache: ${{ github.event.inputs.no_cache == 'yes' }} | |
context: . | |
load: true | |
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/rust-musl-cross:buildcache-${{ matrix.env.IMAGE_TAG }}-${{ matrix.os.arch }} | |
cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/rust-musl-cross:buildcache-${{ matrix.env.IMAGE_TAG }}-${{ matrix.os.arch }},mode=max | |
- name: Test Docker cargo build | |
if: ${{ matrix.os.arch == 'amd64' && !startsWith(matrix.env.TARGET, 'armv5te') && !startsWith(matrix.env.TARGET, 's390x') }} | |
run: | | |
docker run --rm \ | |
-v "$(pwd)/tests":/home/rust/src \ | |
ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-${{ matrix.os.arch }} bash -c "cargo build" | |
- name: Build and push multiarch image | |
env: | |
DOCKER_CLI_EXPERIMENTAL: enabled | |
run: | | |
set -e | |
docker push ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-${{ 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 }}/rust-musl-cross:$IMAGE_TAG | |
manifests:" > ghcr-manifest.yaml | |
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-amd64 > /dev/null; then | |
echo " - image: ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-amd64 | |
platform: | |
architecture: amd64 | |
os: linux" >> ghcr-manifest.yaml | |
fi | |
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-arm64 > /dev/null; then | |
echo " - image: ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-arm64 | |
platform: | |
architecture: arm64 | |
os: linux" >> ghcr-manifest.yaml | |
fi | |
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-armv7 > /dev/null; then | |
echo " - image: ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-armv7 | |
platform: | |
architecture: arm | |
variant: v7 | |
os: linux" >> ghcr-manifest.yaml | |
fi | |
cat ghcr-manifest.yaml | |
./manifest-tool push from-spec ghcr-manifest.yaml | |
echo "image: ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$TARGET" > ghcr-manifest-target.yaml | |
sed -n '1d;p' ghcr-manifest.yaml >> ghcr-manifest-target.yaml | |
./manifest-tool push from-spec ghcr-manifest-target.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 }}/rust-musl-cross:$IMAGE_TAG | |
manifests:" > dockerhub-manifest.yaml | |
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-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 }}/rust-musl-cross:$IMAGE_TAG-amd64 docker://${{ secrets.DOCKER_USERNAME }}/rust-musl-cross:$IMAGE_TAG-amd64 | |
echo " - image: ${{ secrets.DOCKER_USERNAME }}/rust-musl-cross:$IMAGE_TAG-amd64 | |
platform: | |
architecture: amd64 | |
os: linux" >> dockerhub-manifest.yaml | |
fi | |
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-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 }}/rust-musl-cross:$IMAGE_TAG-arm64 docker://${{ secrets.DOCKER_USERNAME }}/rust-musl-cross:$IMAGE_TAG-arm64 | |
echo " - image: ${{ secrets.DOCKER_USERNAME }}/rust-musl-cross:$IMAGE_TAG-arm64 | |
platform: | |
architecture: arm64 | |
os: linux" >> dockerhub-manifest.yaml | |
fi | |
if docker manifest inspect ghcr.io/${{ github.repository_owner }}/rust-musl-cross:$IMAGE_TAG-armv7 > /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 }}/rust-musl-cross:$IMAGE_TAG-armv7 docker://${{ secrets.DOCKER_USERNAME }}/rust-musl-cross:$IMAGE_TAG-armv7 | |
echo " - image: ${{ secrets.DOCKER_USERNAME }}/rust-musl-cross:$IMAGE_TAG-armv7 | |
platform: | |
architecture: arm | |
variant: v7 | |
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) }} |