---
name: 📦 Build Linux binary
on: # yamllint disable-line rule:truthy
release:
types:
- published
jobs:
build-linux:
runs-on: ubuntu-latest
name: 📦 Build Linux Executables
strategy:
fail-fast: false
matrix:
platform:
- os: linux
arch: amd64
- os: linux
arch: arm64
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64,amd64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Extract version from tag
id: get_version
run: |
if [[ "$GITHUB_REF_NAME" == refs/pull/* ]]; then
# For pull requests, use "dev" as version
VERSION="dev"
else
# For releases, extract version from tag (remove 'v' prefix if present)
VERSION=${GITHUB_REF_NAME#v}
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "{\"version\": \"$VERSION\", \"type\":\"bin\"}" > version.json
- name: Build Docker image for ${{ matrix.platform.os }}-${{ matrix.platform.arch }}
uses: docker/build-push-action@v4
with:
context: .
push: false
load: true
tags: ctx-builder-${{ matrix.platform.os }}-${{ matrix.platform.arch }}:latest
platforms: linux/${{ matrix.platform.arch }}
build-args: |
TARGET_OS=${{ matrix.platform.os }}
TARGET_ARCH=${{ matrix.platform.arch }}
VERSION=${{ env.VERSION }}
cache-from: type=gha,scope=${{ matrix.platform.os }}-${{ matrix.platform.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.platform.os }}-${{ matrix.platform.arch }}
- name: Extract executable
run: |
mkdir -p dist
container_id=$(docker create ctx-builder-${{ matrix.platform.os }}-${{ matrix.platform.arch }}:latest)
docker cp $container_id:/.output/ctx ./dist/ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
docker rm $container_id
- name: 📤 Upload build artifact
uses: actions/upload-artifact@v4
with:
name: ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
path: dist/ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
- name: 📤 Upload release assets
uses: softprops/action-gh-release@v2.2.1
if: startsWith(github.ref, 'refs/tags/')
with:
token: "${{ secrets.RELEASE_TOKEN }}"
files: |
./dist/ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
build-alpine-docker:
needs: [ build-linux ]
runs-on: ubuntu-latest
name: 📦 Build Alpine Docker Container
strategy:
fail-fast: false
matrix:
platform:
- os: linux
arch: amd64
- os: linux
arch: arm64
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract version from tag
id: get_version
run: |
if [[ "$GITHUB_REF_NAME" == refs/pull/* ]]; then
# For pull requests, use "dev" as version
VERSION="dev"
else
# For releases, extract version from tag (remove 'v' prefix if present)
VERSION=${GITHUB_REF_NAME#v}
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Download Linux ${{ matrix.platform.arch }} binary
uses: actions/download-artifact@v4
with:
name: ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
path: ./tmp
- name: Make binary executable
run: |
chmod +x ./tmp/ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}
- name: Create Docker context directory
run: |
mkdir -p ./docker
cp ./tmp/ctx-${{ env.VERSION }}-${{ matrix.platform.os }}-${{ matrix.platform.arch }} ./docker/ctx
# Create Dockerfile for Alpine
cat > ./docker/Dockerfile << 'EOF'
FROM alpine:3.21
# Install dependencies
RUN apk add --no-cache libstdc++ libgcc
WORKDIR /app
COPY ctx /usr/local/bin/ctx
RUN chmod +x /usr/local/bin/ctx
ENTRYPOINT ["ctx"]
EOF
- name: Extract metadata for Docker Image
id: docker-metadata
uses: docker/metadata-action@v5
with:
images: ghcr.io/context-hub/ctx
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_LOGIN }}
password: ${{ secrets.GHCR_PASSWORD }}
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v6
with:
context: ./docker
push: true
tags: ghcr.io/context-hub/ctx
labels: ${{ steps.docker-metadata.outputs.labels }}
platforms: linux/${{ matrix.platform.arch }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ matrix.platform.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
runs-on: ubuntu-latest
needs:
- build-alpine-docker
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_LOGIN }}
password: ${{ secrets.GHCR_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/context-hub/ctx
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ !github.event.release.prerelease }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf 'ghcr.io/context-hub/ctx@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ghcr.io/context-hub/ctx:${{ steps.meta.outputs.version }}