Skip to content
155 changes: 152 additions & 3 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,164 @@
name: Docker

on:
push:
branches: [main]
paths: [Dockerfile]
workflow_dispatch:
inputs:
ref:
description: "The git ref to build from (branch, tag, or commit SHA)."
type: string
required: true
default: main
release:
types: [published]

defaults:
run:
shell: bash

jobs:
docker:
build:
strategy:
matrix:
include:
- platform: linux/amd64
runs-on: ubuntu-latest
arch: amd64
- platform: linux/arm64
runs-on: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.runs-on }}
permissions:
contents: read
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}

- name: Install build dependencies
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libudev-dev libdbus-1-dev

- name: Cache Rust build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-

- name: Build binary
run: cargo build --package stellar-cli --release

- name: Copy binary for Docker context
run: cp target/release/stellar stellar

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Log in to Docker Hub
if: github.event_name != 'push'
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

# Validation only — build without pushing.
- name: Build
if: github.event_name == 'push'
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
push: false
cache-from: type=gha,scope=${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.arch }}

# Publish — push by digest so the merge job can assemble the manifest.
- name: Build and push by digest
if: github.event_name != 'push'
id: build
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
outputs: type=image,name=stellar/cli,push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.arch }}

- name: Upload digest
if: github.event_name != 'push'
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"

- name: Upload digest artifact
if: github.event_name != 'push'
uses: actions/upload-artifact@v4
with:
name: digest-${{ matrix.arch }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

merge:
needs: build
if: github.event_name != 'push'
runs-on: ubuntu-latest
permissions: {}
permissions:
contents: read
steps:
- run: echo "Building and pushing Docker image..."
- uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref }}
fetch-depth: 0

# Compute Docker tags from the ref.
# - Version tag (e.g. v1.2.3): push versioned + latest tags.
# - Any other ref: push a tag for the resolved commit SHA.
- name: Compute tags
run: |
ref="${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }}"

if [[ "$ref" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
version="${ref#v}"
echo "DOCKER_TAGS=stellar/cli:${version},stellar/cli:latest" >> $GITHUB_ENV
elif [[ "${{ github.event_name }}" == "release" ]]; then
echo "::error::Release tag '${ref}' is not a valid version tag (expected vX.Y.Z)."
exit 1
else
commit="$(git rev-parse HEAD)"
echo "DOCKER_TAGS=stellar/cli:${commit}" >> $GITHUB_ENV
fi

- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digest-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Create and push manifest
working-directory: /tmp/digests
run: |
tag_args=""
IFS=',' read -ra tag_list <<< "$DOCKER_TAGS"
for tag in "${tag_list[@]}"; do
tag_args+=" --tag ${tag}"
done

docker buildx imagetools create $tag_args \
$(printf 'stellar/cli@sha256:%s ' *)
17 changes: 1 addition & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
FROM rust:latest AS builder

ARG STELLAR_CLI_REF=main

RUN apt-get update && \
apt-get install -y --no-install-recommends libdbus-1-dev libudev-dev pkg-config git && \
rm -rf /var/lib/apt/lists/*

RUN git clone https://github.com/stellar/stellar-cli.git /tmp/stellar-cli && \
cd /tmp/stellar-cli && \
git fetch origin "${STELLAR_CLI_REF}" && \
git checkout "${STELLAR_CLI_REF}" && \
cargo install --locked --path cmd/stellar-cli && \
rm -rf /tmp/stellar-cli

FROM rust:latest

RUN rustup target add wasm32v1-none
Expand All @@ -21,7 +6,7 @@ RUN apt-get update && \
apt-get install -y --no-install-recommends dbus gnome-keyring libdbus-1-3 libudev1 libssl3 && \
rm -rf /var/lib/apt/lists/*

COPY --from=builder /usr/local/cargo/bin/stellar /usr/local/bin/stellar
COPY stellar /usr/local/bin/stellar

ENV STELLAR_CONFIG_HOME=/config
ENV STELLAR_DATA_HOME=/data
Expand Down
Loading