ci/split-prd-deploys #1502
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
name: CI | |
on: | |
push: | |
branches: | |
- main | |
- develop | |
paths-ignore: | |
- '**/CHANGELOG.md' | |
pull_request: | |
workflow_dispatch: | |
concurrency: | |
group: ${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }} | |
cancel-in-progress: true | |
jobs: | |
get_release_info: | |
name: Get Release Info | |
runs-on: ubuntu-latest | |
outputs: | |
tag: ${{ steps.new_release_tag.outputs.TAG }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Get latest release | |
if: startsWith(github.ref, 'refs/heads/main') | |
id: release | |
uses: pozetroninc/github-action-get-latest-release@master | |
with: | |
repository: ${{ github.repository }} | |
excludes: prerelease, draft | |
- name: Determine if release build | |
if: startsWith(github.ref, 'refs/heads/main') | |
id: new_release_tag | |
env: | |
LATEST_RELEASE: ${{ steps.release.outputs.release }} | |
run: | | |
CARGO_VERSION=v$(grep "version" components/chainhook-cli/Cargo.toml | head -n 1 | cut -d\" -f2) | |
if [[ "${CARGO_VERSION}" != "${LATEST_RELEASE}" ]]; then | |
echo "::set-output name=TAG::${CARGO_VERSION}" | |
echo "::warning::Will create release for version: ${CARGO_VERSION}" | |
else | |
echo "::warning::Will not create a release" | |
fi | |
test: | |
name: Generate test coverage | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
with: | |
persist-credentials: false | |
- name: Install Rust toolchain | |
run: | | |
rustup toolchain install stable --profile minimal | |
echo "RUST_VERSION_HASH=$(rustc --version | sha256sum | awk '{print $1}')" >> $GITHUB_ENV | |
- name: Install redis | |
run: sudo apt-get install -y redis-server | |
- name: Cache cargo | |
uses: actions/cache@v3 | |
with: | |
path: | | |
~/.cargo/bin/ | |
~/.cargo/registry/index/ | |
~/.cargo/registry/cache/ | |
~/.cargo/git/db/ | |
# Cache crates.toml & crates2.json to allow `cargo install` | |
~/.cargo/.crates.toml | |
~/.cargo/.crates2.json | |
target/ | |
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
- name: Install and run cargo-tarpaulin | |
run: | | |
cargo install cargo-tarpaulin | |
cargo --version | |
cargo tarpaulin --out lcov --features redis_tests -- --test-threads=1 | |
- name: Upload coverage reports to Codecov | |
uses: codecov/codecov-action@v4 | |
env: | |
token: ${{ secrets.CODECOV_TOKEN }} | |
codecov_yml_path: .github/codecov.yml | |
dist_chainhook: | |
name: Build Chainhook Distributions | |
runs-on: ${{ matrix.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- os: ubuntu-latest | |
platform: linux | |
target: x86_64-unknown-linux-gnu | |
architecture: x64 | |
libc: glibc | |
- os: windows-latest | |
platform: windows | |
target: x86_64-pc-windows-msvc | |
architecture: x64 | |
- os: macos-latest | |
platform: darwin | |
target: x86_64-apple-darwin | |
architecture: x64 | |
- os: macos-latest | |
platform: darwin | |
target: aarch64-apple-darwin | |
architecture: arm64 | |
steps: | |
- name: Configure git to use LF (Windows) | |
if: matrix.os == 'windows-latest' | |
run: | | |
git config --global core.autocrlf false | |
git config --global core.eol lf | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
- name: Install Rust toolchain | |
run: rustup toolchain install stable --profile minimal --target ${{ matrix.target }} | |
- name: Install Rust Target | |
run: rustup target add ${{ matrix.target }} | |
- name: List rust targets | |
run: rustup target list | |
- name: "Get Rust version (unix)" | |
if: matrix.os != 'windows-latest' | |
run: echo "RUST_VERSION_HASH=$(rustc --version | shasum -a 256 | awk '{print $1}')" >> $GITHUB_ENV | |
- name: "Get Rust version (windows)" | |
if: matrix.os == 'windows-latest' | |
shell: bash | |
run: echo "RUST_VERSION_HASH=$(rustc --version | sha256sum | awk '{print $1}')" >> $GITHUB_ENV | |
- name: Cache cargo | |
uses: actions/cache@v3 | |
with: | |
path: | | |
~/.cargo/ | |
./target/${{ matrix.target }}/release/ | |
key: ${{ runner.os }}-rust-${{ env.RUST_VERSION_HASH }}-cargo-${{ hashFiles('./Cargo.lock') }} | |
- name: Install wix (Windows) | |
if: matrix.os == 'windows-latest' && steps.cache-cargo.outputs.cache-hit != 'true' | |
run: cargo install cargo-wix | |
# Set environment variables required from cross compiling from macos-x86_64 to macos-arm64 | |
- name: Configure macos-arm64 cross compile config | |
if: matrix.target == 'aarch64-apple-darwin' | |
run: | | |
echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV | |
echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV | |
- name: Configure artifact names (libc) | |
if: ${{ matrix.libc }} | |
shell: bash | |
run: | | |
echo "SHORT_TARGET_NAME=${{ matrix.platform }}-${{ matrix.architecture }}-${{ matrix.libc }}" >> $GITHUB_ENV | |
echo "PRE_GYP_TARGET_NAME=${{ matrix.platform }}-${{ matrix.architecture }}-${{ matrix.libc }}" >> $GITHUB_ENV | |
- name: Configure artifact names (not libc) | |
if: ${{ ! matrix.libc }} | |
shell: bash | |
run: | | |
echo "SHORT_TARGET_NAME=${{ matrix.platform }}-${{ matrix.architecture }}" >> $GITHUB_ENV | |
echo "PRE_GYP_TARGET_NAME=${{ matrix.platform }}-${{ matrix.architecture }}-unknown" >> $GITHUB_ENV | |
- name: Build - Cargo | |
if: matrix.target != 'x86_64-unknown-linux-musl' | |
run: cargo build --release --features cli --features debug --no-default-features --target ${{ matrix.target }} | |
# Steps for Windows Code Signing with DigiCert | |
- name: Windows - Setup Certificate | |
if: startsWith(github.ref, 'refs/heads/main') && matrix.os == 'windows-latest' | |
run: | | |
echo "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12 | |
cat /d/Certificate_pkcs12.p12 | |
shell: bash | |
- name: Windows - Set variables | |
if: startsWith(github.ref, 'refs/heads/main') && matrix.os == 'windows-latest' | |
id: variables | |
run: | | |
dir | |
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}" | |
echo "::set-output name=KEYPAIR_NAME::gt-standard-keypair" | |
echo "::set-output name=CERTIFICATE_NAME::gt-certificate" | |
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV" | |
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV" | |
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV" | |
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV" | |
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH | |
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH | |
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH | |
shell: bash | |
- name: Windows - Setup Keylocker KSP | |
if: startsWith(github.ref, 'refs/heads/main') && matrix.os == 'windows-latest' | |
run: | | |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o Keylockertools-windows-x64.msi | |
msiexec /i Keylockertools-windows-x64.msi /quiet /qn | |
smksp_registrar.exe list | |
smctl.exe keypair ls | |
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user | |
shell: cmd | |
- name: Windows - Certificates Sync | |
if: startsWith(github.ref, 'refs/heads/main') && matrix.os == 'windows-latest' | |
run: | | |
smctl windows certsync | |
shell: cmd | |
- name: Code sign bin (Windows) | |
if: startsWith(github.ref, 'refs/heads/main') && matrix.os == 'windows-latest' | |
run: | | |
$signtool_path = ((Resolve-Path -Path "${env:ProgramFiles(x86)}/Windows Kits/10/bin/10*/x86").Path[-1]) + "/signtool.exe" | |
$bin_path = (Resolve-Path -Path "target/${{ matrix.target }}/release/chainhook.exe").Path | |
& ${signtool_path} sign ` | |
/d "Chainhook is a reorg-aware indexing engine for the Stacks & Bitcoin blockchains." ` | |
/du "https://github.com/hirosystems/chainhook" ` | |
/tr http://timestamp.digicert.com ` | |
/sha1 "${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}" ` | |
/td sha256 ` | |
/fd sha256 ` | |
"${bin_path}" | |
& ${signtool_path} verify /v /pa "${bin_path}" | |
- name: Build Installer (Windows) | |
if: matrix.os == 'windows-latest' | |
run: cargo wix -v --no-build --nocapture -p chainhook | |
- name: Code sign installed (Windows) | |
if: startsWith(github.ref, 'refs/heads/main') && matrix.os == 'windows-latest' | |
run: | | |
$signtool_path = ((Resolve-Path -Path "${env:ProgramFiles(x86)}/Windows Kits/10/bin/10*/x86").Path[-1]) + "/signtool.exe" | |
$msi_path = (Resolve-Path -Path "target/wix/*.msi").Path | |
& ${signtool_path} sign ` | |
/d "Chainhook is a reorg-aware indexing engine for the Stacks & Bitcoin blockchains." ` | |
/du "https://github.com/hirosystems/chainhook" ` | |
/tr http://timestamp.digicert.com ` | |
/sha1 "${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}" ` | |
/td sha256 ` | |
/fd sha256 ` | |
"${msi_path}" | |
& ${signtool_path} verify /v /pa "${msi_path}" | |
# Don't compress for Windows because winget can't yet unzip files | |
- name: Compress cargo artifact (Linux) | |
if: matrix.os != 'windows-latest' | |
run: tar -C target/${{ matrix.target }}/release -zcvf chainhook-${{ env.SHORT_TARGET_NAME }}.tar.gz chainhook | |
- name: Rename cargo artifact (Windows) | |
if: matrix.os == 'windows-latest' | |
shell: bash | |
run: mv target/wix/*.msi chainhook-${{ env.SHORT_TARGET_NAME }}.msi | |
# Separate uploads to prevent paths from being preserved | |
- name: Upload cargo artifacts (Linux) | |
if: matrix.os != 'windows-latest' | |
uses: actions/upload-artifact@v2 | |
with: | |
name: chainhook-${{ env.SHORT_TARGET_NAME }} | |
path: chainhook-${{ env.SHORT_TARGET_NAME }}.tar.gz | |
- name: Upload cargo artifact (Windows) | |
if: matrix.os == 'windows-latest' | |
uses: actions/upload-artifact@v2 | |
with: | |
name: chainhook-${{ env.SHORT_TARGET_NAME }} | |
path: chainhook-${{ env.SHORT_TARGET_NAME }}.msi | |
release: | |
name: Release | |
runs-on: ubuntu-latest | |
if: startsWith(github.ref, 'refs/heads/main') && needs.get_release_info.outputs.tag != '' | |
needs: | |
- test | |
- dist_chainhook | |
- get_release_info | |
permissions: | |
actions: write | |
contents: write | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Download pre-built dists | |
uses: actions/download-artifact@v3 | |
- name: Tag and Release | |
uses: ncipollo/release-action@v1 | |
with: | |
artifacts: "**/*.tar.gz,**/*.msi" | |
tag: ${{ needs.get_release_info.outputs.tag }} | |
commit: ${{ env.GITHUB_SHA }} | |
- name: Trigger pkg-version-bump workflow | |
uses: peter-evans/repository-dispatch@v1 | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
event-type: released | |
client-payload: '{"tag": "${{ needs.get_release_info.outputs.tag }}"}' | |
build-publish: | |
runs-on: ubuntu-latest | |
needs: | |
- test | |
- dist_chainhook | |
- get_release_info | |
outputs: | |
docker_image_digest: ${{ steps.docker_push.outputs.digest }} | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- name: Chainhook | |
description: Chainhook is a reorg-aware indexing engine for the Stacks & Bitcoin blockchains. | |
image: ${{ github.repository }} | |
artifact: chainhook-linux-x64-glibc | |
dockerfile: dockerfiles/components/chainhook-node.dockerfile | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
persist-credentials: false | |
- name: Checkout tag | |
if: needs.get_release_info.outputs.tag != '' | |
uses: actions/checkout@v4 | |
with: | |
persist-credentials: false | |
ref: ${{ needs.get_release_info.outputs.tag }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Docker Meta | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
hirosystems/${{ github.event.repository.name }} | |
tags: | | |
type=ref,event=branch | |
type=ref,event=pr | |
type=semver,pattern={{version}},value=${{ needs.get_release_info.outputs.tag }},enable=${{ needs.get_release_info.outputs.tag != '' }} | |
type=semver,pattern={{major}}.{{minor}},value=${{ needs.get_release_info.outputs.tag }},enable=${{ needs.get_release_info.outputs.tag != '' }} | |
type=raw,value=latest,enable={{is_default_branch}} | |
- name: Log in to DockerHub | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_PASSWORD }} | |
- name: Download pre-built dist | |
uses: actions/download-artifact@v3 | |
with: | |
name: ${{ matrix.artifact }} | |
- name: Untar pre-built dist | |
run: tar zxvf *.tar.gz | |
- name: Build/Push Image | |
uses: docker/build-push-action@v5 | |
id: docker_push | |
with: | |
context: . | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
file: ${{ matrix.dockerfile }} | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
# Only push if (there's a new release on main branch, or if building a non-main branch) and (Only run on non-PR events or only PRs that aren't from forks) | |
push: ${{ (github.ref != 'refs/heads/main' || needs.get_release_info.outputs.tag != '') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} | |
deploy-dev: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
k8s-env: [mainnet,testnet] | |
needs: build-publish | |
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | |
env: | |
DEPLOY_ENV: dev | |
environment: | |
name: Development-${{ matrix.k8s-env }} | |
url: https://platform.dev.hiro.so/ | |
steps: | |
- name: Checkout actions repo | |
uses: actions/checkout@v4 | |
with: | |
ref: main | |
token: ${{ secrets.GH_TOKEN }} | |
repository: ${{ secrets.DEVOPS_ACTIONS_REPO }} | |
- name: Deploy Chainhook build to Dev ${{ matrix.k8s-env }} | |
uses: ./actions/deploy | |
with: | |
docker_image_tag_or_digest: ${{ needs.build-publish.outputs.docker_image_digest }} | |
file_pattern: manifests/chainhooks/${{ matrix.k8s-env }}/chainhook-node/${{ env.DEPLOY_ENV }}/base/kustomization.yaml | |
gh_token: ${{ secrets.GH_TOKEN }} | |
auto-approve-dev: | |
runs-on: ubuntu-latest | |
if: startsWith(github.ref, 'refs/heads/main') && needs.get_release_info.outputs.tag != '' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) | |
needs: | |
- build-publish | |
- get_release_info | |
steps: | |
- name: Approve pending deployments | |
run: | | |
sleep 5 | |
ENV_IDS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/hirosystems/chainhook/actions/runs/${{ github.run_id }}/pending_deployments" | jq -r '[.[].environment.id // empty]') | |
if [[ "${ENV_IDS}" != "[]" ]]; then | |
curl -s -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/hirosystems/chainhook/actions/runs/${{ github.run_id }}/pending_deployments" -d "{\"environment_ids\":${ENV_IDS},\"state\":\"approved\",\"comment\":\"auto approve\"}" | |
fi | |
deploy-staging: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
k8s-env: [mainnet,testnet] | |
needs: | |
- build-publish | |
- deploy-dev | |
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository | |
env: | |
DEPLOY_ENV: stg | |
environment: | |
name: Staging-${{ matrix.k8s-env }} | |
url: https://platform.stg.hiro.so/ | |
steps: | |
- name: Checkout actions repo | |
uses: actions/checkout@v4 | |
with: | |
ref: main | |
token: ${{ secrets.GH_TOKEN }} | |
repository: ${{ secrets.DEVOPS_ACTIONS_REPO }} | |
- name: Deploy Chainhook build to Stg ${{ matrix.k8s-env }} | |
uses: ./actions/deploy | |
with: | |
docker_image_tag_or_digest: ${{ needs.build-publish.outputs.docker_image_digest }} | |
file_pattern: manifests/chainhooks/${{ matrix.k8s-env }}/chainhook-node/${{ env.DEPLOY_ENV }}/base/kustomization.yaml | |
gh_token: ${{ secrets.GH_TOKEN }} | |
auto-approve-stg: | |
runs-on: ubuntu-latest | |
if: startsWith(github.ref, 'refs/heads/main') && needs.get_release_info.outputs.tag != '' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) | |
needs: | |
- build-publish | |
- deploy-dev | |
- get_release_info | |
steps: | |
- name: Approve pending deployments | |
run: | | |
sleep 5 | |
ENV_IDS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/hirosystems/chainhook/actions/runs/${{ github.run_id }}/pending_deployments" | jq -r '[.[].environment.id // empty]') | |
if [[ "${ENV_IDS}" != "[]" ]]; then | |
curl -s -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/hirosystems/chainhook/actions/runs/${{ github.run_id }}/pending_deployments" -d "{\"environment_ids\":${ENV_IDS},\"state\":\"approved\",\"comment\":\"auto approve\"}" | |
fi | |
deploy-prod: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
include: | |
- k8s-env: mainnet | |
k8s-subenv: blue | |
- k8s-env: mainnet | |
k8s-subenv: green | |
- k8s-env: testnet | |
k8s-subenv: blue | |
needs: | |
- build-publish | |
- deploy-staging | |
- get_release_info | |
if: startsWith(github.ref, 'refs/heads/main') && needs.get_release_info.outputs.tag != '' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) | |
env: | |
DEPLOY_ENV: prd | |
environment: | |
name: Production-${{ matrix.k8s-env }}-${{ matrix.k8s-subenv }} | |
url: https://platform.hiro.so/ | |
steps: | |
- name: Checkout actions repo | |
uses: actions/checkout@v4 | |
with: | |
ref: main | |
token: ${{ secrets.GH_TOKEN }} | |
repository: ${{ secrets.DEVOPS_ACTIONS_REPO }} | |
- name: Deploy Chainhook build to Prd ${{ matrix.k8s-env }}-${{ matrix.k8s-subenv }} | |
uses: ./actions/deploy | |
with: | |
docker_image_tag_or_digest: ${{ needs.build-publish.outputs.docker_image_digest }} | |
file_pattern: manifests/chainhooks/${{ matrix.k8s-env }}/chainhook-node/${{ env.DEPLOY_ENV }}/base/kustomization.yaml | |
subenv: ${{ matrix.k8s-subenv }} | |
gh_token: ${{ secrets.GH_TOKEN }} |