Update internal-dependencies #866
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: Build Docker Images | |
on: | |
pull_request: | |
branches: [ main ] | |
paths-ignore: | |
- '**.md' | |
- 'docs/**' | |
- '.gitignore' | |
- 'LICENSE' | |
- '.github/**' | |
- '!.github/workflows/**' | |
types: | |
- opened # PR is created | |
- synchronize # New commits pushed | |
- reopened # Closed PR is reopened | |
pull_request_target: | |
branches: [ main ] | |
paths-ignore: | |
- '**.md' | |
- 'docs/**' | |
- '.gitignore' | |
- 'LICENSE' | |
- '.github/**' | |
- '!.github/workflows/**' | |
types: | |
- closed # PR is merged or closed | |
permissions: | |
contents: read | |
packages: write | |
id-token: write | |
pull-requests: write | |
env: | |
HOME: /home/github-runner | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: true | |
jobs: | |
detect-changes: | |
runs-on: dev | |
if: | | |
github.event_name == 'pull_request' && | |
github.event.action != 'closed' | |
outputs: | |
base_matrix: ${{ steps.set-matrix.outputs.base_matrix }} | |
clients_matrix: ${{ steps.set-matrix.outputs.clients_matrix }} | |
protocols_matrix: ${{ steps.set-matrix.outputs.protocols_matrix }} | |
content_changes: ${{ steps.set-matrix.outputs.content_changes }} | |
all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }} | |
dockerfile_changes: ${{ steps.set-matrix.outputs.dockerfile_changes }} | |
dockerfile_matrix: ${{ steps.set-matrix.outputs.dockerfile_matrix }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
with: | |
fetch-depth: 0 # Fetch all history for all tags and branches | |
- name: Get changed files | |
id: changed-files | |
uses: tj-actions/changed-files@d6e91a2266cdb9d62096cebf1e8546899c6aa18f # v45 | |
with: | |
base_sha: ${{ github.event.pull_request.base.sha }} | |
fetch_depth: 0 | |
- name: List all changed files | |
env: | |
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} | |
run: | | |
for file in ${ALL_CHANGED_FILES}; do | |
echo "$file was changed" | |
done | |
- name: Debug changed files outputs | |
env: | |
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} | |
run: | | |
echo "Debug outputs from changed-files action:" | |
echo "Changed files:" | |
echo "$ALL_CHANGED_FILES" | |
- name: Generate build matrices | |
id: set-matrix | |
env: | |
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }} | |
run: | | |
# First find all Docker build contexts (directories containing Dockerfile) | |
DOCKER_DIRS=$(find . -name Dockerfile -exec dirname {} \; | sed 's|^./||' | sort) | |
echo "Found Docker directories:" | |
echo "$DOCKER_DIRS" | |
echo "Changed files in this commit:" | |
echo "$ALL_CHANGED_FILES" | |
# For each changed file, find which Docker directory it belongs to | |
CHANGED_DIRS=$(for file in ${ALL_CHANGED_FILES}; do | |
echo "Checking file: $file" | |
echo "$DOCKER_DIRS" | while read -r docker_dir; do | |
if [[ "$file" =~ ^"$docker_dir"(/|$) ]]; then | |
echo "$docker_dir" | |
fi | |
done | |
done | sort -u) | |
echo "Changed directories:" | |
echo "$CHANGED_DIRS" | |
# Filter by component | |
BASE=$(echo "$CHANGED_DIRS" | grep "^base-images/" || true) | |
CLIENTS=$(echo "$CHANGED_DIRS" | grep "^clients/" || true) | |
PROTOCOLS=$(echo "$CHANGED_DIRS" | grep "^protocols/[^/]\+/[^/]\+$" || true) | |
CONTENT_CHANGES=$(echo "$CHANGED_DIRS" | grep "^protocols/" || true) | |
DOCKERFILE_CHANGES=$(echo "$CHANGED_DIRS" | grep -E "^base-images/|^clients/|^protocols/" || true) | |
echo "Base dirs: $BASE" | |
echo "Client dirs: $CLIENTS" | |
echo "Protocol dirs: $PROTOCOLS" | |
echo "Content changes: $CONTENT_CHANGES" | |
echo "Dockerfile changes: $DOCKERFILE_CHANGES" | |
# Generate base image matrix from changed base-images directories | |
if [[ -n "$BASE" ]]; then | |
BASE_MATRIX=$(echo "$BASE" | jq -Rsc 'split("\n")[:-1] | {include: map({image_path: .})}') | |
else | |
BASE_MATRIX='{"include":[]}' | |
fi | |
echo "base_matrix=$BASE_MATRIX" >> $GITHUB_OUTPUT | |
if [[ -n "$CLIENTS" ]]; then | |
echo "clients_matrix=$(echo "$CLIENTS" | jq -Rsc 'split("\n")[:-1] | {include: map({image_path: .})}')" >> $GITHUB_OUTPUT | |
else | |
echo 'clients_matrix={"include":[]}' >> $GITHUB_OUTPUT | |
fi | |
if [[ -n "$PROTOCOLS" ]]; then | |
echo "protocols_matrix=$(echo "$PROTOCOLS" | jq -Rsc 'split("\n")[:-1] | {include: map({image_path: .})}')" >> $GITHUB_OUTPUT | |
else | |
echo 'protocols_matrix={"include":[]}' >> $GITHUB_OUTPUT | |
fi | |
if [[ -n "$CONTENT_CHANGES" ]]; then | |
echo "content_changes=$(echo "$CONTENT_CHANGES" | jq -Rsc 'split("\n")[:-1] | {include: map({image_path: .})}')" >> $GITHUB_OUTPUT | |
else | |
echo 'content_changes={"include":[]}' >> $GITHUB_OUTPUT | |
fi | |
if [[ -n "$DOCKERFILE_CHANGES" ]]; then | |
echo "dockerfile_changes=true" >> $GITHUB_OUTPUT | |
echo "dockerfile_matrix=$(echo "$DOCKERFILE_CHANGES" | jq -Rsc 'split("\n")[:-1] | {include: map({image_path: .})}')" >> $GITHUB_OUTPUT | |
else | |
echo 'dockerfile_changes=false' >> $GITHUB_OUTPUT | |
echo 'dockerfile_matrix={"include":[]}' >> $GITHUB_OUTPUT | |
fi | |
scan-dockerfiles: | |
needs: [detect-changes] | |
if: | | |
github.event_name == 'pull_request' && | |
github.event.action != 'closed' && | |
contains(needs.detect-changes.outputs.dockerfile_changes, 'true') | |
runs-on: dev | |
strategy: | |
matrix: ${{ fromJson(needs.detect-changes.outputs.dockerfile_matrix) }} | |
fail-fast: false | |
permissions: | |
contents: read | |
security-events: write | |
pull-requests: write | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Run Trivy Dockerfile scan | |
id: scan | |
uses: aquasecurity/trivy-action@master | |
with: | |
scan-type: 'config' | |
scan-ref: './${{ matrix.image_path }}/Dockerfile' | |
hide-progress: false | |
format: 'table' | |
severity: 'CRITICAL,HIGH' | |
exit-code: '0' | |
- name: Generate human-readable report | |
if: always() | |
run: | | |
set -x | |
trivy config \ | |
--severity CRITICAL,HIGH \ | |
--format table \ | |
--debug \ | |
./${{ matrix.image_path }}/Dockerfile | tee trivy-dockerfile-results.txt | |
cat trivy-dockerfile-results.txt | |
- name: Comment on PR | |
if: always() | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
set -x | |
if [ -s trivy-dockerfile-results.txt ]; then | |
echo "Vulnerabilities found, commenting on PR" | |
{ | |
echo "### 🔍 Trivy Dockerfile Scan Results for \`${{ matrix.image_path }}/Dockerfile\`" | |
echo "" | |
echo "<details>" | |
echo "<summary>Click to view findings</summary>" | |
echo "" | |
echo "\`\`\`" | |
cat trivy-dockerfile-results.txt | |
echo "\`\`\`" | |
echo "</details>" | |
echo "" | |
echo "Please review these findings and make necessary fixes to improve the security of your Dockerfile." | |
} > comment.md | |
gh pr comment ${{ github.event.pull_request.number }} --body-file comment.md | |
else | |
echo "No vulnerabilities found in Dockerfile" | |
gh pr comment ${{ github.event.pull_request.number }} --body "✅ No security issues found in \`${{ matrix.image_path }}/Dockerfile\`" | |
fi | |
check-protocols: | |
needs: [detect-changes] | |
if: | | |
github.event_name == 'pull_request' && | |
github.event.action != 'closed' && | |
fromJson(needs.detect-changes.outputs.content_changes).include[0] | |
runs-on: dev | |
outputs: | |
protocols_changed: ${{ steps.check-protocol.outputs.protocols_changed }} | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Check protocol keys in protocols.yaml | |
id: check-protocol | |
run: | | |
# Get all changed protocols from detect-changes | |
CHANGED_PROTOCOLS='${{ needs.detect-changes.outputs.content_changes }}' | |
# Check each protocol key | |
echo "$CHANGED_PROTOCOLS" | jq -r '.[] | .image_path' | while read -r IMAGE_PATH; do | |
echo "Checking protocol in $IMAGE_PATH" | |
# Get protocol key from babel.yaml | |
PROTOCOL_KEY=$(yq e '.protocol_key' "$IMAGE_PATH/babel.yaml") | |
echo "Checking for protocol key: $PROTOCOL_KEY" | |
# Check if key exists in protocols.yaml | |
if ! yq e '.[] | select(.key == "'$PROTOCOL_KEY'")' protocols/protocols.yaml > /dev/null 2>&1; then | |
echo " Protocol key '$PROTOCOL_KEY' not found in protocols/protocols.yaml" | |
exit 1 | |
fi | |
done | |
# Check if protocols.yaml has changed | |
if git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} | grep -q "^protocols/protocols.yaml$"; then | |
echo "protocols/protocols.yaml has changed, will push protocol updates" | |
echo "protocols_changed=true" >> $GITHUB_OUTPUT | |
else | |
echo "protocols/protocols.yaml unchanged" | |
echo "protocols_changed=false" >> $GITHUB_OUTPUT | |
fi | |
build-base-images: | |
name: build-base-images | |
needs: [detect-changes, scan-dockerfiles] | |
if: | | |
github.event_name == 'pull_request' && | |
fromJson(needs.detect-changes.outputs.base_matrix).include[0] && | |
github.event.action != 'closed' && | |
(needs.scan-dockerfiles.result == 'success' || needs.scan-dockerfiles.result == 'skipped') | |
runs-on: dev | |
permissions: | |
contents: read # Allows reading repository contents | |
packages: write # Allows pushing/pulling container images | |
security-events: write # For trivy scan results | |
pull-requests: write # For commenting on PRs | |
strategy: | |
matrix: ${{ fromJson(needs.detect-changes.outputs.base_matrix) }} | |
outputs: | |
image_name: ${{ steps.version.outputs.image_name }} | |
image_tag: ${{ steps.version.outputs.image_tag }} | |
version_tag: ${{ steps.version.outputs.version_tag }} | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Authenticate GitHub CLI | |
run: | | |
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | |
- name: Extract image name | |
id: version | |
run: | | |
set -x | |
# Extract image name from path - get the last part of the path | |
IMAGE_NAME=$(basename ${{ matrix.image_path }}) | |
echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT | |
# Generate version tag | |
SHA=$(git rev-parse --short HEAD) | |
DATE=$(date '+%Y%m%d') | |
# Try to get the current build number, default to 0 if API call fails | |
set +e | |
OUTPUT=$(gh api \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
"/orgs/blockjoy/packages/container/${IMAGE_NAME}/versions" 2>&1) | |
API_STATUS=$? | |
set -e | |
if echo "$OUTPUT" | grep -q "message.*Package not found" || \ | |
echo "$OUTPUT" | grep -q "status.*404" || \ | |
[ $API_STATUS -ne 0 ]; then | |
echo "Package $IMAGE_NAME not found in registry - this is expected for new images" | |
echo "Starting with build number 1" | |
BUILD_NUM=1 | |
else | |
echo "API call succeeded, parsing response" | |
LATEST_BUILD=$(echo "$OUTPUT" | \ | |
jq "[.[] | select(.metadata.container.tags[] | startswith(\"v${DATE}\"))] | length") | |
if [ -z "$LATEST_BUILD" ] || [ "$LATEST_BUILD" = "null" ]; then | |
echo "No existing versions found for today, starting at 0" | |
BUILD_NUM=0 | |
else | |
echo "Found $LATEST_BUILD existing versions today" | |
BUILD_NUM=$((LATEST_BUILD + 1)) | |
fi | |
fi | |
echo "Debug: Final build number: ${BUILD_NUM}" | |
# Format: v20250108.1, v20250108.2, etc | |
VERSION_TAG="v${DATE}.${BUILD_NUM}" | |
# Make sure we have a build number before continuing | |
if [ -z "$BUILD_NUM" ]; then | |
echo "Error: Build number is empty, defaulting to 0" | |
BUILD_NUM=0 | |
VERSION_TAG="v${DATE}.${BUILD_NUM}" | |
fi | |
echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT | |
echo "image_tag=${SHA}" >> $GITHUB_OUTPUT | |
echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT | |
echo "sha=${SHA}" >> $GITHUB_OUTPUT | |
- name: Generate build contexts | |
id: build-contexts | |
run: | | |
# First, find all directories containing Dockerfiles to build our valid image list | |
VALID_IMAGES=$(find . -name Dockerfile -exec dirname {} \; | while read dir; do | |
# Convert directory path to image name (e.g., ./ethereum/ethereum-erigon -> ethereum-erigon) | |
basename "$dir" | tr '[:upper:]' '[:lower:]' | |
# For protocol directories, also add the protocol-client format | |
if [[ "$dir" =~ ^./[^/]+/[^/]+ ]]; then | |
echo "$dir" | sed 's|^./\([^/]\+\)/\([^/]\+\)|\1-\2|' | tr '[:upper:]' '[:lower:]' | |
fi | |
done | sort -u) | |
# Now extract FROM directives and filter against our valid images | |
BUILD_CONTEXTS=$(grep -h "^FROM.*\${.*_IMAGE}" ./${{ matrix.image_path }}/Dockerfile | while read -r line; do | |
# Extract variable name from FROM line | |
var_name=$(echo "$line" | grep -o '\${[^}]*}' | tr -d '${}\n') | |
# Extract image name and remove any default tag | |
image=$(grep "^ARG ${var_name}=" ./${{ matrix.image_path }}/Dockerfile | cut -d'=' -f2 | cut -d':' -f1) | |
# Check if this image is in our valid image list | |
if echo "$VALID_IMAGES" | grep -q "^${image}$"; then | |
# Use short name for context key but specify it as a docker-image context with SHA tag | |
echo "${image}=docker-image://ghcr.io/blockjoy/${image}:${{ steps.version.outputs.sha }}" | |
fi | |
done | sort -u | tr '\n' ',' | sed 's/,$//') | |
echo "contexts=${BUILD_CONTEXTS}" >> $GITHUB_OUTPUT | |
echo "Generated build contexts: ${BUILD_CONTEXTS}" | |
echo "Valid images: ${VALID_IMAGES}" | |
echo "Current image path: '${{ matrix.image_path }}'" | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 | |
with: | |
buildkitd-flags: | | |
--debug | |
--allow-insecure-entitlement network.host | |
- name: Build base image | |
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6 | |
with: | |
context: ./${{ matrix.image_path }} | |
push: false | |
load: true | |
build-args: | | |
GRAFANA_LOKI_API_KEY=${{ secrets.GRAFANA_LOKI_API_KEY }} | |
GRAFANA_PROM_API_KEY=${{ secrets.GRAFANA_PROM_API_KEY }} | |
build-contexts: ${{ steps.build-contexts.outputs.contexts }} | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
tags: | | |
localhost/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }} | |
- name: Run Trivy vulnerability scanner | |
id: scan | |
uses: aquasecurity/trivy-action@master | |
with: | |
scan-type: 'image' | |
image-ref: 'localhost/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }}' | |
format: 'table' | |
severity: 'CRITICAL,HIGH' | |
timeout: '10m' | |
exit-code: '0' | |
- name: Generate human-readable report | |
if: always() | |
run: | | |
set -x | |
trivy image --severity CRITICAL,HIGH --format table localhost/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }} > trivy-image-results.txt | |
- name: Comment on PR | |
if: always() | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
set -x | |
if [ -s trivy-image-results.txt ]; then | |
{ | |
echo "### 🔍 Trivy Image Scan Results for \`${{ steps.version.outputs.image_name }}\`" | |
echo "" | |
echo "<details><summary>Click to show scan results</summary>" | |
echo "" | |
echo "\`\`\`" | |
cat trivy-image-results.txt | |
echo "\`\`\`" | |
echo "" | |
echo "</details>" | |
echo "" | |
echo "These vulnerabilities were found in the ${{ steps.version.outputs.image_name }} image. Since this is a base image, these vulnerabilities will affect all derived images. Please review and update dependencies to their latest secure versions where possible." | |
} > comment.md | |
gh pr comment ${{ github.event.pull_request.number }} --body-file comment.md | |
exit 0 | |
else | |
echo "No vulnerabilities found in image" | |
gh pr comment ${{ github.event.pull_request.number }} --body "✅ No vulnerabilities found in \`${{ steps.version.outputs.image_name }}\` image" | |
fi | |
- name: Log in to GitHub Container Registry | |
if: success() | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Push base image | |
if: success() | |
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6 | |
with: | |
context: ./${{ matrix.image_path }} | |
push: true | |
build-args: | | |
GRAFANA_LOKI_API_KEY=${{ secrets.GRAFANA_LOKI_API_KEY }} | |
GRAFANA_PROM_API_KEY=${{ secrets.GRAFANA_PROM_API_KEY }} | |
build-contexts: ${{ steps.build-contexts.outputs.contexts }} | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
tags: | | |
ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }} | |
ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.version_tag }} | |
build-clients: | |
needs: [detect-changes, scan-dockerfiles] | |
if: | | |
github.event_name == 'pull_request' && | |
fromJson(needs.detect-changes.outputs.clients_matrix).include[0] && | |
github.event.action != 'closed' && | |
(needs.scan-dockerfiles.result == 'success' || needs.scan-dockerfiles.result == 'skipped') | |
runs-on: dev | |
permissions: | |
contents: read # Allows reading repository contents | |
packages: write # Allows pushing/pulling container images | |
strategy: | |
matrix: ${{ fromJson(needs.detect-changes.outputs.clients_matrix) }} | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Authenticate GitHub CLI | |
run: | | |
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | |
- name: Log in to GitHub Container Registry | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Generate version | |
id: version | |
run: | | |
set -x # Enable debug mode to see commands being executed | |
set +e | |
SHA=$(git rev-parse --short HEAD) | |
DATE=$(date '+%Y%m%d') | |
CLIENT_NAME=$(basename ${{ matrix.image_path }}) | |
IMAGE_NAME="${CLIENT_NAME}" | |
# Extract version for any client under /clients/ | |
if [[ "${{ matrix.image_path }}" =~ ^clients/ ]]; then | |
CLIENT_UPPER=$(echo "${CLIENT_NAME}" | tr '[:lower:]' '[:upper:]') | |
CLIENT_VERSION=$(grep -E "ENV ${CLIENT_UPPER}_VERSION=[[:space:]]*v?[0-9]+\.[0-9]+\.[0-9]+[-.a-zA-Z0-9]*" "${{ matrix.image_path }}/Dockerfile" | grep -oE "v?[0-9]+\.[0-9]+\.[0-9]+[-.a-zA-Z0-9]*") | |
if [[ ! -z "$CLIENT_VERSION" ]]; then | |
# Remove 'v' prefix and ensure version is Docker-compatible (only alphanumeric and . - _) | |
CLIENT_VERSION=${CLIENT_VERSION#v} | |
CLIENT_VERSION=$(echo "$CLIENT_VERSION" | tr -cd '[:alnum:].-') | |
IMAGE_TAG="${CLIENT_VERSION}-${SHA}" | |
else | |
IMAGE_TAG="${SHA}" | |
fi | |
else | |
IMAGE_TAG="${SHA}" | |
fi | |
echo "Debug: matrix.image_path = ${{ matrix.image_path }}" | |
echo "Debug: IMAGE_NAME = ${IMAGE_NAME}" | |
echo "Debug: IMAGE_TAG = ${IMAGE_TAG}" | |
# Try to get the current build number, default to 0 if API call fails | |
echo "Debug: Querying GitHub API for package ${IMAGE_NAME}" | |
OUTPUT=$(gh api \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
"/orgs/blockjoy/packages/container/${IMAGE_NAME}/versions" 2>&1) | |
API_STATUS=$? | |
echo "Debug: Full command output:" | |
echo "$OUTPUT" | |
echo "Debug: API Status: $API_STATUS" | |
echo "Debug: Checking if output contains error message..." | |
# More detailed error checking | |
if echo "$OUTPUT" | grep -q "message.*Package not found" || \ | |
echo "$OUTPUT" | grep -q "status.*404" || \ | |
[ $API_STATUS -ne 0 ]; then | |
echo "Package $IMAGE_NAME not found in registry - this is expected for new images" | |
echo "Starting with build number 1" | |
BUILD_NUM=1 | |
else | |
echo "API call succeeded, parsing response" | |
LATEST_BUILD=$(echo "$OUTPUT" | \ | |
jq "[.[] | select(.metadata.container.tags[] | startswith(\"v${DATE}\"))] | length") | |
if [ -z "$LATEST_BUILD" ] || [ "$LATEST_BUILD" = "null" ]; then | |
echo "No existing versions found for today, starting at 1" | |
BUILD_NUM=1 | |
else | |
echo "Found $LATEST_BUILD existing versions today" | |
BUILD_NUM=$((LATEST_BUILD + 1)) | |
fi | |
fi | |
echo "Debug: Final build number: ${BUILD_NUM}" | |
# Format: v20250108.1, v20250108.2, etc | |
VERSION_TAG="v${DATE}.${BUILD_NUM}" | |
echo "Debug: Version tag: ${VERSION_TAG}" | |
# Make sure we have a build number before continuing | |
if [ -z "$BUILD_NUM" ]; then | |
echo "Error: Build number is empty, defaulting to 1" | |
BUILD_NUM=1 | |
VERSION_TAG="v${DATE}.${BUILD_NUM}" | |
fi | |
echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT | |
echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT | |
echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT | |
echo "sha=${SHA}" >> $GITHUB_OUTPUT | |
- name: Generate build contexts | |
id: build-contexts | |
run: | | |
# First, find all directories containing Dockerfiles to build our valid image list | |
VALID_IMAGES=$(find . -name Dockerfile -exec dirname {} \; | while read dir; do | |
# Convert directory path to image name (e.g., ./ethereum/ethereum-erigon -> ethereum-erigon) | |
basename "$dir" | tr '[:upper:]' '[:lower:]' | |
# For protocol directories, also add the protocol-client format | |
if [[ "$dir" =~ ^./[^/]+/[^/]+ ]]; then | |
echo "$dir" | sed 's|^./\([^/]\+\)/\([^/]\+\)|\1-\2|' | tr '[:upper:]' '[:lower:]' | |
fi | |
done | sort -u) | |
# Now extract FROM directives and filter against our valid images | |
BUILD_CONTEXTS=$(grep -h "^FROM.*\${.*_IMAGE}" ./${{ matrix.image_path }}/Dockerfile | while read -r line; do | |
# Extract variable name from FROM line | |
var_name=$(echo "$line" | grep -o '\${[^}]*}' | tr -d '${}\n') | |
# Extract image name and remove any default tag | |
image=$(grep "^ARG ${var_name}=" ./${{ matrix.image_path }}/Dockerfile | cut -d'=' -f2 | cut -d':' -f1) | |
# Check if this image is in our valid image list | |
if echo "$VALID_IMAGES" | grep -q "^${image}$"; then | |
# Use short name for context key but specify it as a docker-image context with SHA tag | |
echo "${image}=docker-image://ghcr.io/blockjoy/${image}:${{ steps.version.outputs.sha }}" | |
fi | |
done | sort -u | tr '\n' ',' | sed 's/,$//') | |
echo "contexts=${BUILD_CONTEXTS}" >> $GITHUB_OUTPUT | |
echo "Generated build contexts: ${BUILD_CONTEXTS}" | |
echo "Valid images: ${VALID_IMAGES}" | |
echo "Current image path: '${{ matrix.image_path }}'" | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 | |
with: | |
buildkitd-flags: | | |
--debug | |
--allow-insecure-entitlement network.host | |
- name: Build and push client images | |
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6 | |
with: | |
context: ./${{ matrix.image_path }} | |
push: true | |
build-args: | | |
GRAFANA_LOKI_BASICAUTH=${{ secrets.GRAFANA_LOKI_BASICAUTH }} | |
GRAFANA_PROM_BASICAUTH=${{ secrets.GRAFANA_PROM_BASICAUTH }} | |
CLOUDFLARE_API_KEY=${{ secrets.CLOUDFLARE_API_KEY }} | |
build-contexts: ${{ steps.build-contexts.outputs.contexts }} | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
tags: | | |
ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }} | |
ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.version_tag }} | |
build-protocols: | |
needs: [detect-changes, scan-dockerfiles] | |
environment: Dev | |
if: | | |
github.event_name == 'pull_request' && | |
fromJson(needs.detect-changes.outputs.protocols_matrix).include[0] && | |
github.event.action != 'closed' && | |
(needs.scan-dockerfiles.result == 'success' || needs.scan-dockerfiles.result == 'skipped') | |
runs-on: dev | |
outputs: | |
matrix: ${{ needs.detect-changes.outputs.protocols_matrix }} | |
image_name: ${{ steps.version.outputs.image_name }} | |
image_tag: ${{ steps.version.outputs.image_tag }} | |
runner_hostname: ${{ steps.get-hostname.outputs.hostname }} | |
strategy: | |
matrix: ${{ fromJson(needs.detect-changes.outputs.protocols_matrix) }} | |
fail-fast: false | |
permissions: | |
contents: read | |
packages: write | |
steps: | |
- name: Get runner hostname | |
id: get-hostname | |
run: echo "hostname=$(hostname)" >> $GITHUB_OUTPUT | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Authenticate GitHub CLI | |
run: | | |
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | |
- name: Setup NIB auth | |
run: | | |
echo '${{ secrets.NIB_AUTH }}' > ~/.nib.json | |
- name: Log in to GitHub Container Registry | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Generate version | |
id: version | |
run: | | |
set -x # Enable debug mode to see commands being executed | |
set +e | |
SHA=$(git rev-parse --short HEAD) | |
DATE=$(date '+%Y%m%d') | |
PROTOCOL_PATH=${{ matrix.image_path }} | |
# Extract just the protocol name without the parent directory | |
PROTOCOL=$(echo "${{ matrix.image_path }}" | cut -d'/' -f2) | |
IMAGE_NAME=$(echo "${{ matrix.image_path }}" | cut -d'/' -f3) | |
echo "Debug: matrix.image_path = ${{ matrix.image_path }}" | |
echo "Debug: IMAGE_NAME = ${IMAGE_NAME}" | |
# Try to get the current build number, default to 0 if API call fails | |
echo "Debug: Querying GitHub API for package ${IMAGE_NAME}" | |
OUTPUT=$(gh api \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
"/orgs/blockjoy/packages/container/${IMAGE_NAME}/versions" 2>&1) | |
API_STATUS=$? | |
set -e | |
# More detailed error checking | |
if echo "$OUTPUT" | grep -q "message.*Package not found" || \ | |
echo "$OUTPUT" | grep -q "status.*404" || \ | |
[ $API_STATUS -ne 0 ]; then | |
echo "Package $IMAGE_NAME not found in registry - this is expected for new images" | |
echo "Starting with build number 1" | |
BUILD_NUM=1 | |
else | |
echo "API call succeeded, parsing response" | |
# Get the highest build number for today's date | |
LATEST_BUILD=$(echo "$OUTPUT" | \ | |
jq -r "[.[] | select(.metadata.container.tags[] | select(startswith(\"v${DATE}\"))) | | |
.metadata.container.tags[] | select(startswith(\"v${DATE}\")) | | |
split(\".\")[1] | tonumber] | max // 0") | |
if [ -z "$LATEST_BUILD" ] || [ "$LATEST_BUILD" = "null" ]; then | |
echo "No existing versions found for today, starting at 1" | |
BUILD_NUM=1 | |
else | |
echo "Found highest build number $LATEST_BUILD for today" | |
BUILD_NUM=$((LATEST_BUILD + 1)) | |
fi | |
fi | |
echo "Debug: Final build number: ${BUILD_NUM}" | |
# Format: v20250108.1, v20250108.2, etc | |
VERSION_TAG="v${DATE}.${BUILD_NUM}" | |
echo "Debug: Version tag: ${VERSION_TAG}" | |
# Make sure we have a build number before continuing | |
if [ -z "$BUILD_NUM" ]; then | |
echo "Error: Build number is empty, defaulting to 1" | |
BUILD_NUM=1 | |
VERSION_TAG="v${DATE}.${BUILD_NUM}" | |
fi | |
echo "image_name=${IMAGE_NAME}" >> $GITHUB_OUTPUT | |
echo "image_tag=${SHA}" >> $GITHUB_OUTPUT | |
echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT | |
echo "sha=${SHA}" >> $GITHUB_OUTPUT | |
# Script should succeed even if API call failed | |
exit 0 | |
- name: Generate build contexts | |
id: build-contexts | |
run: | | |
# First, find all directories containing Dockerfiles to build our valid image list | |
VALID_IMAGES=$(find . -name Dockerfile -exec dirname {} \; | while read dir; do | |
# Convert directory path to image name (e.g., ./ethereum/ethereum-erigon -> ethereum-erigon) | |
basename "$dir" | tr '[:upper:]' '[:lower:]' | |
# For protocol directories, also add the protocol-client format | |
if [[ "$dir" =~ ^./[^/]+/[^/]+ ]]; then | |
echo "$dir" | sed 's|^./\([^/]\+\)/\([^/]\+\)|\1-\2|' | tr '[:upper:]' '[:lower:]' | |
fi | |
done | sort -u) | |
# Now extract FROM directives and filter against our valid images | |
BUILD_CONTEXTS=$(grep -h "^FROM.*\${.*_IMAGE}" ./${{ matrix.image_path }}/Dockerfile | while read -r line; do | |
# Extract variable name from FROM line | |
var_name=$(echo "$line" | grep -o '\${[^}]*}' | tr -d '${}\n') | |
# Extract image name and remove any default tag | |
image=$(grep "^ARG ${var_name}=" ./${{ matrix.image_path }}/Dockerfile | cut -d'=' -f2 | cut -d':' -f1) | |
# Check if this image is in our valid image list | |
if echo "$VALID_IMAGES" | grep -q "^${image}$"; then | |
# Use short name for context key but specify it as a docker-image context with SHA tag | |
echo "${image}=docker-image://ghcr.io/blockjoy/${image}:${{ steps.version.outputs.sha }}" | |
fi | |
done | sort -u | tr '\n' ',' | sed 's/,$//') | |
echo "contexts=${BUILD_CONTEXTS}" >> $GITHUB_OUTPUT | |
echo "Generated build contexts: ${BUILD_CONTEXTS}" | |
echo "Valid images: ${VALID_IMAGES}" | |
echo "Current image path: '${{ matrix.image_path }}'" | |
- name: Generate build args | |
id: build-args | |
run: | | |
# Extract all *_IMAGE args from Dockerfile with their specified tags | |
IMAGE_ARGS=$(grep "^ARG.*_IMAGE=" ./${{ matrix.image_path }}/Dockerfile | while read -r line; do | |
var_name=$(echo "$line" | cut -d'=' -f1 | cut -d' ' -f2) | |
# Use the full image reference from the Dockerfile, including its tag | |
image_ref=$(echo "$line" | cut -d'=' -f2) | |
echo "${var_name}=${image_ref}" | |
done | tr '\n' '\n') | |
echo "image_args<<EOF" >> $GITHUB_OUTPUT | |
echo "$IMAGE_ARGS" >> $GITHUB_OUTPUT | |
echo "EOF" >> $GITHUB_OUTPUT | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 | |
with: | |
buildkitd-flags: | | |
--debug | |
--allow-insecure-entitlement network.host | |
- name: Build and push protocol images | |
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6 | |
with: | |
context: ./${{ matrix.image_path }} | |
push: true | |
build-args: | | |
GRAFANA_LOKI_BASICAUTH=${{ secrets.GRAFANA_LOKI_BASICAUTH }} | |
GRAFANA_PROM_BASICAUTH=${{ secrets.GRAFANA_PROM_BASICAUTH }} | |
CLOUDFLARE_API_KEY=${{ secrets.CLOUDFLARE_API_KEY }} | |
${{ steps.build-args.outputs.image_args }} | |
build-contexts: ${{ steps.build-contexts.outputs.contexts }} | |
cache-from: | | |
type=registry,ref=ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:buildcache | |
cache-to: | | |
type=registry,ref=ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:buildcache,mode=max | |
platforms: linux/amd64 | |
tags: | | |
ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }} | |
ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.version_tag }} | |
- name: Get variants from babel.yaml | |
id: get-variants | |
run: | | |
variants=$(yq e '.variants[].key' ${{ matrix.image_path }}/babel.yaml | tr '\n' ' ') | |
if [ -z "$variants" ]; then | |
echo " No variants found in ${{ matrix.image_path }}/babel.yaml" | |
exit 1 | |
fi | |
echo "variants=$variants" >> $GITHUB_OUTPUT | |
- name: Check variants | |
id: check-variants | |
run: | | |
mkdir -p ~/temp | |
chmod 777 ~/temp | |
export TMPDIR=~/temp | |
echo "TMPDIR=~/temp" >> $GITHUB_ENV | |
echo "APPTAINER_TMPDIR=~/temp" >> $GITHUB_ENV | |
cp ${{ matrix.image_path }}/babel.yaml ${{ matrix.image_path }}/babel.yaml-test | |
# Update container_uri with newly built image | |
NEW_URI="docker://ghcr.io/blockjoy/${{ steps.version.outputs.image_name }}:${{ steps.version.outputs.image_tag }}" | |
TMPDIR=~/temp yq -i e ".container_uri = \"$NEW_URI\"" ${{ matrix.image_path }}/babel.yaml-test | |
echo "test_file=${{ matrix.image_path }}/babel.yaml-test" >> $GITHUB_OUTPUT | |
success_variants=() | |
failed_variants=() | |
for variant in ${{ steps.get-variants.outputs.variants }}; do | |
echo "Checking variant: $variant" | |
echo "Running: nib image check --lint-only --variant $variant --path ${{ matrix.image_path }}/babel.yaml-test" | |
if OUTPUT=$(nib image check --lint-only --variant $variant --path ${{ matrix.image_path }}/babel.yaml-test 2>&1); then | |
success_variants+=("$variant") | |
echo " Variant $variant check passed" | |
echo "Command output:" | |
echo "$OUTPUT" | |
else | |
echo " Variant $variant check failed" | |
echo "Command output:" | |
echo "$OUTPUT" | |
failed_variants+=("$variant") | |
fi | |
done | |
rm -rf ${{ matrix.image_path }}/babel.yaml-test | |
if [ ${#failed_variants[@]} -gt 0 ]; then | |
echo " The following variants failed checks: ${failed_variants[*]}" | |
exit 1 | |
fi | |
echo "success_variants=${success_variants[*]}" >> $GITHUB_OUTPUT | |
get-host: | |
runs-on: dev | |
outputs: | |
target_host: ${{ steps.get-host.outputs.target_host }} | |
steps: | |
- name: Get previous host | |
id: get-host | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
PREV_HOST=$(gh pr view ${{ github.event.pull_request.number }} --json comments --jq ' | |
.comments | |
| map(select(.author.login == "github-actions")) | |
| map(select(.body | test("All nodes have been cleaned up"))) | |
| sort_by(.createdAt) | |
| last | |
| if . == null then "" else | |
(.body | capture("The following nodes have been deployed on `(?<host>[^`]+)`:\\n").host) | |
end | |
') | |
if [ -z "$PREV_HOST" ]; then | |
echo "No previous host found, using default" | |
PREV_HOST="dev" | |
else | |
echo "Found previous host: $PREV_HOST" | |
fi | |
echo "target_host=$PREV_HOST" >> $GITHUB_OUTPUT | |
cleanup: | |
needs: [get-host] | |
runs-on: ${{ needs.get-host.outputs.target_host }} | |
steps: | |
- name: Cleanup nodes | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
echo "Finding nodes to clean up..." | |
# Find the latest cleanup comment timestamp | |
LAST_CLEANUP=$(gh pr view ${{ github.event.pull_request.number }} --json comments --jq ' | |
.comments | |
| map(select(.author.login == "github-actions")) | |
| map(select(.body | test("All nodes have been cleaned up"))) | |
| sort_by(.createdAt) | |
| last | |
| if . == null then "" else .createdAt end | |
') | |
echo "Last cleanup was at: $LAST_CLEANUP" | |
# Get list of nodes from PR comments after last cleanup | |
NODES=$(gh pr view ${{ github.event.pull_request.number }} --json comments | jq -r --arg last "$LAST_CLEANUP" ' | |
.comments | |
| map(select(.author.login == "github-actions")) | |
| map(select(.body | contains("following nodes have been deployed"))) | |
| map(select( | |
if $last == "" then true | |
else (.createdAt > $last) | |
end | |
)) | |
| map(.body | split("\n") | |
| map(select(contains("running variant"))) | |
| map(capture("- `(?<n>[a-z-]+-[a-z-]+-[a-z-]+)`, running variant `[^`]+`").n) | |
| join("\n") | |
) | |
| join("\n") | |
') | |
if [ ! -z "$NODES" ]; then | |
echo "Found nodes to clean up:" | |
echo "$NODES" | |
CLEANED_NODES=0 | |
while read -r node; do | |
if [ -z "$node" ]; then | |
echo "Skipping empty node name" | |
continue | |
fi | |
echo "Processing node: '$node'" | |
if bv n delete -y "$node"; then | |
CLEANED_NODES=$((CLEANED_NODES + 1)) | |
else | |
echo "Warning: Failed to delete node '$node'" | |
fi | |
done <<< "$NODES" | |
# Only post message if we actually cleaned up nodes | |
if [ $CLEANED_NODES -gt 0 ]; then | |
if [[ "${{ github.event.pull_request.merged }}" == "true" ]]; then | |
gh pr comment ${{ github.event.pull_request.number }} --body " All nodes have been cleaned up after merge" | |
elif [[ "${{ github.event.action }}" == "closed" ]]; then | |
gh pr comment ${{ github.event.pull_request.number }} --body " All nodes have been cleaned up after PR close" | |
elif [[ "${{ github.event.action }}" == "synchronize" ]]; then | |
gh pr comment ${{ github.event.pull_request.number }} --body " All nodes have been cleaned up after PR update" | |
else | |
gh pr comment ${{ github.event.pull_request.number }} --body " All nodes have been cleaned up" | |
fi | |
fi | |
else | |
echo "No nodes found to clean up, exiting cleanly" | |
fi | |
test-nodes: | |
needs: [build-protocols, get-host, cleanup] | |
if: | | |
github.event_name == 'pull_request' && | |
github.event.action != 'closed' | |
runs-on: ${{ needs.get-host.outputs.target_host }} | |
environment: Dev | |
strategy: | |
matrix: ${{ fromJson(needs.build-protocols.outputs.matrix) }} | |
outputs: | |
runner_host: ${{ steps.test-nodes.outputs.runner_host }} | |
node_names: ${{ steps.test-nodes.outputs.node_names }} | |
permissions: | |
contents: read | |
packages: write | |
statuses: write | |
pull-requests: write | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Authenticate GitHub CLI | |
run: | | |
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | |
- name: Setup NIB auth | |
run: | | |
echo '${{ secrets.NIB_AUTH }}' > ~/.nib.json | |
- name: Create test babel file | |
run: | | |
# Copy babel.yaml to test file | |
cp ${{ matrix.image_path }}/babel.yaml ${{ matrix.image_path }}/babel.yaml-test | |
# Extract image name the same way as build-protocols | |
IMAGE_NAME=$(echo "${{ matrix.image_path }}" | cut -d'/' -f3) | |
# Update container_uri with newly built image | |
NEW_URI="docker://ghcr.io/blockjoy/${IMAGE_NAME}:${{ needs.build-protocols.outputs.image_tag }}" | |
TMPDIR=~/temp yq -i e ".container_uri = \"$NEW_URI\"" ${{ matrix.image_path }}/babel.yaml-test | |
- name: Test nodes | |
id: test-nodes | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
# Store runner hostname | |
RUNNER_HOST=$(hostname) | |
echo "runner_host=${RUNNER_HOST}" >> $GITHUB_OUTPUT | |
# Get variants from babel.yaml | |
VARIANTS=$(yq e '.variants[].key' ${{ matrix.image_path }}/babel.yaml-test) | |
if [ $? -ne 0 ]; then | |
echo "Error: Failed to get variants from babel.yaml" | |
echo "Content of babel.yaml-test:" | |
cat ${{ matrix.image_path }}/babel.yaml-test | |
exit 1 | |
fi | |
# Initialize arrays for node info | |
declare -a NODE_NAMES=() | |
declare -a DEPLOYED_NODES=() | |
declare -i CHECK_FAILED=0 | |
START_FAILED=false | |
# For each variant, start a node and capture info | |
for variant in $VARIANTS; do | |
echo "Testing variant: $variant" | |
# Run nib image check and capture output | |
echo "Running: nib image check --variant $variant --path ${{ matrix.image_path }}/babel.yaml-test" | |
OUTPUT=$(nib image check --variant $variant --path ${{ matrix.image_path }}/babel.yaml-test 2>&1 || true) | |
NIB_EXIT=$? | |
echo "nib image check output:" | |
echo "$OUTPUT" | |
# Check if node was started regardless of final exit code | |
if echo "$OUTPUT" | grep -q "Node started"; then | |
# Extract node name from the 'Created ... dev_node' line | |
NODE_NAME=$(echo "$OUTPUT" | grep -o "'[^']*'" | head -1 | tr -d "'") | |
if [ -z "$NODE_NAME" ]; then | |
echo "Error: Failed to extract node name from output" | |
((CHECK_FAILED++)) | |
continue | |
fi | |
# Store for later use | |
NODE_NAMES+=("$NODE_NAME") | |
# Add to deployed nodes list before attempting start | |
DEPLOYED_NODES+=("- \`${NODE_NAME}\`, running variant \`${variant}\`") | |
# Start the node | |
echo "Starting node ${NODE_NAME}" | |
if ! START_OUTPUT=$(bv n start "$NODE_NAME" 2>&1); then | |
echo "Error: Failed to start node ${NODE_NAME}:" | |
echo "$START_OUTPUT" | |
((CHECK_FAILED++)) | |
else | |
echo "Successfully started node ${NODE_NAME}" | |
fi | |
fi | |
if [ $NIB_EXIT -ne 0 ]; then | |
echo "Error: nib image check failed with exit code $NIB_EXIT" | |
((CHECK_FAILED++)) | |
fi | |
done | |
# Post comment about all deployed nodes | |
if [ ${#DEPLOYED_NODES[@]} -gt 0 ]; then | |
COMMENT="The following nodes have been deployed on \`${RUNNER_HOST}\`:"$'\n' | |
for node in "${DEPLOYED_NODES[@]}"; do | |
COMMENT="${COMMENT}${node}"$'\n' | |
done | |
COMMENT="${COMMENT}"$'\n'"These nodes will be cleaned up on PR merge or close and replaced on PR update." | |
echo -e "$COMMENT" | gh pr comment ${{ github.event.pull_request.number }} --body-file - | |
fi | |
# Save node names for cleanup | |
echo "node_names=${NODE_NAMES[*]}" >> $GITHUB_OUTPUT | |
echo "start_failed=${START_FAILED}" >> $GITHUB_OUTPUT | |
# Exit with failure if any checks failed | |
if [ $CHECK_FAILED -gt 0 ]; then | |
echo "Error: $CHECK_FAILED node checks/starts failed" | |
exit 1 | |
fi | |
echo "status=success" >> $GITHUB_OUTPUT | |
exit 0 | |
workflow-status: | |
needs: [detect-changes, test-nodes, build-base-images, build-clients, build-protocols, scan-dockerfiles] | |
if: always() && github.event_name == 'pull_request' && github.event.action != 'closed' | |
runs-on: dev | |
permissions: | |
statuses: write | |
steps: | |
- name: Report Status | |
env: | |
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
if [[ "${{ needs.build-base-images.result }}" == "failure" ]] || \ | |
[[ "${{ needs.build-clients.result }}" == "failure" ]] || \ | |
[[ "${{ needs.build-protocols.result }}" == "failure" ]] || \ | |
[[ "${{ needs.test-nodes.result }}" == "failure" ]] || \ | |
[[ "${{ needs.scan-dockerfiles.result }}" == "failure" ]]; then | |
DESCRIPTION="Workflow failed" | |
[[ "${{ needs.test-nodes.result }}" == "failure" ]] && DESCRIPTION="Node testing failed" | |
[[ "${{ needs.scan-dockerfiles.result }}" == "failure" ]] && DESCRIPTION="Dockerfile scanning failed" | |
gh api \ | |
--method POST \ | |
-H "Accept: application/vnd.github+json" \ | |
"/repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ | |
-f state='failure' \ | |
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ | |
-f description="$DESCRIPTION" \ | |
-f context="workflow-status" | |
exit 1 | |
fi | |
# All jobs either succeeded or were skipped | |
if [[ "${{ needs.detect-changes.outputs.content_changes }}" == '{"include":[]}' ]]; then | |
DESCRIPTION="No protocol changes detected that require testing" | |
else | |
DESCRIPTION="All checks passed successfully" | |
fi | |
gh api \ | |
--method POST \ | |
-H "Accept: application/vnd.github+json" \ | |
"/repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ | |
-f state='success' \ | |
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ | |
-f description="$DESCRIPTION" \ | |
-f context="workflow-status" | |
push-protocols: | |
environment: Dev | |
needs: [check-protocols] | |
if: needs.check-protocols.outputs.protocols_changed == 'true' | |
runs-on: dev | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 | |
- name: Setup NIB auth | |
run: | | |
echo '${{ secrets.NIB_AUTH }}' > ~/.nib.json | |
- name: Push protocols to dev | |
run: | | |
echo "Pushing protocol updates to dev" | |
nib protocol push --path protocols/protocols.yaml |