Skip to content

chore(release): router crates and artifacts #177

chore(release): router crates and artifacts

chore(release): router crates and artifacts #177

name: apollo-router-fork
on:
# For PRs, this pipeline will use the commit ID as Docker image tag and R2 artifact prefix.
pull_request:
branches:
- main
paths:
- "apollo-router-workspace/**"
- ".github/workflows/apollo-router-fork.yaml"
- ".github/workflows/apollo-router-updater.yaml"
# For `main` changes, this pipeline will look for changes in Rust crates or plugin versioning, and
# publish them only if changes are found and image does not exists in GH Packages.
push:
paths:
- "apollo-router-workspace/**"
- ".github/workflows/apollo-router-fork.yaml"
- ".github/workflows/apollo-router-updater.yaml"
branches:
- main
defaults:
run:
working-directory: ./apollo-router-workspace
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# This script is doing the following:
# 1. Get the version of the apollo-router and the plugin from the Cargo.toml file
# 2. Check if there are changes in the Cargo.toml file in the current commit
# 3. If there are changes, check if the image tag exists in the GitHub Container Registry
find-changes:
name: evaluate changes
runs-on: ubuntu-22.04
if: ${{ !github.event.pull_request.head.repo.fork }}
outputs:
should_release: ${{ steps.find_changes.outputs.should_release }}
release_version: ${{ steps.find_changes.outputs.release_version }}
release_latest: ${{ steps.find_changes.outputs.release_latest }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 2
- name: find changes in versions
id: find_changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
echo "Running in a PR, using commit ID as tag"
echo "should_release=true" >> $GITHUB_OUTPUT
echo "release_latest=false" >> $GITHUB_OUTPUT
echo "release_version=$GITHUB_SHA" >> $GITHUB_OUTPUT
exit 0
fi
echo "Running on push event, looking for changes in Rust crates or plugin versioning"
image_name="apollo-router"
github_org="graphql-hive"
router_version=$(cargo tree -i apollo-router --quiet | head -n 1 | awk -F" v" '{print $2}')
plugin_version=$(grep '^version' ./bin/router/Cargo.toml | sed 's/version *= *"\(.*\)"/\1/')
has_changes=$(git diff HEAD~ HEAD --name-only -- './bin/router/Cargo.toml' 'Cargo.lock')
echo "router_version: $router_version"
echo "plugin_version: $plugin_version"
echo "has_changes: $has_changes"
if [ "$has_changes" ]; then
image_tag_version="router${router_version}-plugin${plugin_version}"
echo "found changes, image_tag_version: $image_tag_version"
response=$(curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-s \
https://api.github.com/orgs/${github_org}/packages/container/${image_name}/versions)
echo "tag check response: $response"
tag_exists=$(echo "$response" | jq -r ".[] | .metadata.container.tags[] | select(. | contains(\"${image_tag_version}\"))")
echo "tag_exists: $tag_exists"
if [ ! "$tag_exists" ]; then
echo "Found changes in version $version_to_publish , and tag does not existing"
echo "release_version=$image_tag_version" >> $GITHUB_OUTPUT
echo "should_release=true" >> $GITHUB_OUTPUT
echo "release_latest=true" >> $GITHUB_OUTPUT
else
echo "Tag $image_tag_version already exists, skipping release"
echo "should_release=false" >> $GITHUB_OUTPUT
echo "release_latest=false" >> $GITHUB_OUTPUT
fi
fi
# Builds Rust crates, and creates Docker images
dockerize:
name: dockerize (${{ matrix.platform }})
needs: find-changes
if: ${{ needs.find-changes.outputs.should_release == 'true' }}
strategy:
fail-fast: false
matrix:
include:
- builder: ubuntu-22.04
platform: linux/amd64
suffix: "-amd64"
cache_key: Linux
rust_target: x86_64-unknown-linux-gnu
- builder: hive-linux-arm64-ubuntu2204
platform: linux/arm64
suffix: "-arm64"
rust_target: aarch64-unknown-linux-gnu
runs-on: ${{ matrix.builder }}
permissions:
contents: read
packages: write
pull-requests: write
steps:
- name: checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 2
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.17.0 # v1
with:
target: ${{ matrix.rust_target }}
rust-src-dir: ./apollo-router-workspace
- name: Build
run: cargo build --release --target ${{ matrix.rust_target }}
- name: Strip binary from debug symbols
if: ${{ runner.os == 'Linux' }}
run: strip ./target/${{ matrix.rust_target }}/release/router
- name: configure docker buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: login to docker registry
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: frabert/replace-string-action@b6828c5a4cb6371753ff873b0d1c4c4fbd9a63cb # v2.5
id: branch_name_fix
name: sanitize branch name
with:
pattern: '[+\/><@|-]'
flags: "g"
string: ${{ github.head_ref || github.ref_name }}
replace-with: "_"
- uses: frabert/replace-string-action@b6828c5a4cb6371753ff873b0d1c4c4fbd9a63cb # v2.5
id: docker_cache_key
name: build cache key
with:
pattern: '[\/,]'
flags: "g"
string: ${{ github.ref }}-apollo-router-hive-build-${{ matrix.platform }}
replace-with: "_"
- name: build docker images
timeout-minutes: 60
id: docker-bake
uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0
env:
DOCKER_REGISTRY: ghcr.io/${{ github.repository_owner }}/
COMMIT_SHA: ${{ needs.find-changes.outputs.release_version }}
RELEASE: ${{ needs.find-changes.outputs.release_version }}
BRANCH_NAME: ${{ steps.branch_name_fix.outputs.replaced }}
BUILD_TYPE: "publish"
PWD: ${{ github.workspace }}/apollo-router-workspace
BUILD_STABLE: ${{ needs.find-changes.outputs.release_latest == 'true' && '1' || '' }}
BUILD_PLATFORM: ${{ matrix.platform }}
IMAGE_SUFFIX: ${{ matrix.suffix }}
ROUTER_BINARY_DIR: ${{ github.workspace }}/apollo-router-workspace/target/${{ matrix.rust_target }}/release
with:
# See https://github.com/docker/buildx/issues/1533
provenance: false
push: true
files: ./apollo-router-workspace/docker/docker.hcl
targets: apollo-router-hive-build
source: .
set: |
*.cache-from=type=gha,ignore-error=true,scope=${{ steps.docker_cache_key.outputs.replaced }}
*.cache-from=type=gha,ignore-error=true,scope=refs_heads_main-apollo-router-hive-build-${{ matrix.platform == 'linux/amd64' && 'linux_amd64' || 'linux_arm64' }}
*.cache-to=type=gha,mode=max,ignore-error=true,scope=${{ steps.docker_cache_key.outputs.replaced }}
- name: docker details pr comment
uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v2
if: ${{ github.event_name == 'pull_request' }}
with:
header: ${{ github.workflow }}
message: |
🐋 This PR was built and pushed to the following [Docker images](https://github.com/graphql-hive?ecosystem=container&tab=packages&visibility=public):
**Targets**: `apollo-router-hive-build`
**Platform**: `${{ matrix.platform }}`
**Image Tag**: `${{ needs.find-changes.outputs.release_version }}`
publish_docker_manifest:
needs:
- dockerize
- find-changes
runs-on: ubuntu-22.04
name: publish multiarch manifest
permissions:
contents: read
packages: write
steps:
- name: checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 2
- name: configure docker buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: login to docker registry
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: "publish docker multiarch manifest (tag: ${{ needs.find-changes.outputs.release_version }})"
env:
IMAGE_TAG: ${{ needs.find-changes.outputs.release_version }}
run: |
image_name="ghcr.io/graphql-hive/apollo-router:$IMAGE_TAG"
docker manifest create $image_name --amend "$image_name-arm64" --amend "$image_name-amd64"
docker manifest push $image_name
- name: "publish docker multiarch manifest (tag: latest)"
if: ${{ needs.find-changes.outputs.release_latest == 'true' }}
run: |
image_name="ghcr.io/graphql-hive/apollo-router:latest"
docker manifest create $image_name --amend "$image_name-arm64" --amend "$image_name-amd64"
docker manifest push $image_name
# Test the Docker image, if it was published
test-docker-image:
name: test apollo-router docker image
needs:
- find-changes
- dockerize
runs-on: ubuntu-22.04
env:
HIVE_TOKEN: ${{ secrets.HIVE_TOKEN }}
steps:
- name: checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 2
- name: Run Docker image
run: |
# Create router.yaml
cat << EOF > router.yaml
supergraph:
listen: 0.0.0.0:4000
health_check:
listen: 0.0.0.0:8088
enabled: true
path: /health
plugins:
hive.usage:
enabled: false
EOF
# Download supergraph
curl -sSL https://supergraph.demo.starstuff.dev/ > ./supergraph.graphql
# Run Docker image
docker run -p 4000:4000 -p 8088:8088 --name apollo_router_test -d \
--env HIVE_TOKEN="fake" \
--mount "type=bind,source=/$(pwd)/router.yaml,target=/dist/config/router.yaml" \
--mount "type=bind,source=/$(pwd)/supergraph.graphql,target=/dist/config/supergraph.graphql" \
ghcr.io/graphql-hive/apollo-router:${{ needs.find-changes.outputs.release_version }}-amd64 \
--log debug \
--supergraph /dist/config/supergraph.graphql \
--config /dist/config/router.yaml
# Wait for the container to be ready
echo "Waiting for the container to be ready..."
sleep 20
HTTP_RESPONSE=$(curl -v --retry 5 --retry-delay 5 --max-time 30 --write-out "%{http_code}" --output /dev/null "http://127.0.0.1:8088/health")
# Check if the HTTP response code is 200 (OK)
if [ $HTTP_RESPONSE -eq 200 ]; then
echo "Health check successful."
exit 0
else
echo "Health check failed with HTTP status code $HTTP_RESPONSE."
exit 1
fi
- name: troubleshoot container
if: ${{ failure() }}
run: |
docker --version
docker ps --format json | jq .
docker logs apollo_router_test
# Build and publish Rust crates and binaries
test-rust:
name: test
if: ${{ needs.find-changes.outputs.should_release == 'true' }}
needs: find-changes
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 2
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.17.0 # v1
with:
rust-src-dir: ./apollo-router-workspace
- name: Run tests
run: cargo test
publish-binary:
needs: find-changes
if: ${{ needs.find-changes.outputs.should_release == 'true' }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
file: router
target: x86_64-unknown-linux-gnu
binary_name: linux
cache_key: Linux
- os: windows-latest
file: router.exe
target: x86_64-pc-windows-msvc
binary_name: win
cache_key: Windows
- os: macos-latest
file: router
target: x86_64-apple-darwin
binary_name: macos
cache_key: macOS
name: binary (${{ matrix.target }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 2
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.17.0 # v1
with:
target: ${{ matrix.target }}
rust-src-dir: ./apollo-router-workspace
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Strip binary from debug symbols
if: ${{ runner.os == 'Linux' }}
run: strip ./target/${{ matrix.target }}/release/${{ matrix.file }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
name: upload router artifact
with:
name: apollo_router_${{ matrix.binary_name }}
path: |
./apollo-router-workspace/target/${{ matrix.target }}/release/${{ matrix.file }}
if-no-files-found: error
- name: Compress
run: tar -czvf ./router.tar.gz -C ./target/${{ matrix.target }}/release ${{ matrix.file }}
- name: Upload to R2 (${{ needs.find-changes.outputs.release_version }})
uses: randomairborne/r2-release@9cbc35a2039ee2ef453a6988cd2a85bb2d7ba8af # v1.0.2
with:
endpoint: https://6d5bc18cd8d13babe7ed321adba3d8ae.r2.cloudflarestorage.com
accesskeyid: ${{ secrets.R2_ACCESS_KEY_ID }}
secretaccesskey: ${{ secrets.R2_SECRET_ACCESS_KEY }}
bucket: apollo-router
file: ./apollo-router-workspace/router.tar.gz
destination: ${{ needs.find-changes.outputs.release_version }}/${{ matrix.binary_name }}/router.tar.gz
- name: Upload to R2 (latest)
if: ${{ needs.find-changes.outputs.release_latest == 'true' }}
uses: randomairborne/r2-release@9cbc35a2039ee2ef453a6988cd2a85bb2d7ba8af # v1.0.2
with:
endpoint: https://6d5bc18cd8d13babe7ed321adba3d8ae.r2.cloudflarestorage.com
accesskeyid: ${{ secrets.R2_ACCESS_KEY_ID }}
secretaccesskey: ${{ secrets.R2_SECRET_ACCESS_KEY }}
bucket: apollo-router
file: ./apollo-router-workspace/router.tar.gz
destination: latest/${{ matrix.binary_name }}/router.tar.gz