Skip to content

Build

Build #370

Workflow file for this run

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) }}