chore: bump version to 0.4.1 for GRANDPA consensus fix #65
This file contains hidden or 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: Create and publish a Docker image | |
| # Configures this workflow to run every time a change is pushed to the branch called `main`. | |
| on: | |
| push: | |
| branches: ['main'] | |
| # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| # NOTE: Bootnode configurations are now dynamically generated from GitHub secrets | |
| # to prevent peer ID collisions and follow external-only bootnode architecture | |
| # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. | |
| jobs: | |
| build-and-push-image: | |
| runs-on: ubuntu-latest | |
| # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. | |
| permissions: | |
| contents: write # Changed from read to write to allow pushing commits | |
| packages: write | |
| # | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| # Free up additional disk space on GitHub runner (~20-25 GB) | |
| # Enhanced cleanup for Polkadot SDK builds without cache | |
| - name: Free Disk Space (Ubuntu) | |
| uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # 1.3.1 | |
| with: | |
| android: true # 12 GB save | |
| dotnet: true # 3 GB save | |
| haskell: true # 2 GB save | |
| large-packages: true # 4 GB save | |
| swap-storage: false # Keep swap for large builds | |
| # Set up Docker Buildx for efficient layer caching | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| # ------------------------------------------------------------ | |
| # SECURITY: Derive peer IDs from GitHub secrets | |
| # Private keys are decoded temporarily in memory, never logged | |
| # ------------------------------------------------------------ | |
| - name: Derive bootnode peer IDs from secrets | |
| run: | | |
| set -euo pipefail | |
| echo "🔐 Deriving bootnode peer IDs from GitHub secrets..." | |
| # Install polkadot binary from official releases (most reliable) | |
| echo "📥 Installing polkadot binary..." | |
| POLKADOT_VERSION="v1.9.0" | |
| wget -q "https://github.com/paritytech/polkadot-sdk/releases/download/polkadot-${POLKADOT_VERSION}/polkadot" -O polkadot | |
| chmod +x polkadot | |
| # Verify installation | |
| ./polkadot --version | |
| # Helper: derive peer-id from a key file using polkadot | |
| # Parse only last line (PeerID) to avoid logging sensitive data | |
| derive_peer () { | |
| ./polkadot key inspect-node-key --file "$1" 2>/dev/null | tail -1 | |
| } | |
| # Decode secrets to tmpfs (runner's /tmp is already tmpfs), derive IDs | |
| BOOT1=$(mktemp) | |
| BOOT2=$(mktemp) | |
| trap 'rm -f "$BOOT1" "$BOOT2"' EXIT # always wipe | |
| echo "${{ secrets.BOOTNODE1_KEY_B64 }}" | base64 -d > "$BOOT1" | |
| echo "${{ secrets.BOOTNODE2_KEY_B64 }}" | base64 -d > "$BOOT2" | |
| PEER1="$(derive_peer "$BOOT1")" | |
| PEER2="$(derive_peer "$BOOT2")" | |
| # Mask *right now* so nothing else can leak it | |
| echo "::add-mask::$PEER1" | |
| echo "::add-mask::$PEER2" | |
| # Build JSON array (still invisible in logs because masked) | |
| BOOTNODES_JSON=$(jq -cn --arg id1 "$PEER1" --arg id2 "$PEER2" ' | |
| [ | |
| "/dns4/bootnode1.fennel.network/tcp/30333/p2p/\($id1)", | |
| "/dns4/bootnode2.fennel.network/tcp/30333/p2p/\($id2)" | |
| ]') | |
| # Set environment variables for subsequent steps (use base64 for safety) | |
| echo "EXTERNAL_BOOTNODES_B64=$(printf %s "$BOOTNODES_JSON" | base64 -w0)" >> $GITHUB_ENV | |
| echo "BOOTNODE1_PEER_ID=$PEER1" >> $GITHUB_ENV | |
| echo "BOOTNODE2_PEER_ID=$PEER2" >> $GITHUB_ENV | |
| # Log success (peer IDs are masked) | |
| echo "✅ Successfully derived peer IDs from secrets using official Parity container" | |
| echo "🌐 Using external-only bootnode architecture (following Parity best practices)" | |
| echo "📋 Bootnode configuration: [MASKED - using derived peer IDs]" | |
| # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. | |
| - name: Log in to the Container registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. | |
| - name: Extract metadata (tags, labels) for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=sha,format=long | |
| # ------------------------------------------------------------ | |
| # Build the runtime deterministically with srtool and capture | |
| # its SHA-256 so we can inject it as an OCI label. | |
| # ------------------------------------------------------------ | |
| - name: Build runtime with srtool & extract Wasm hash | |
| id: wasm | |
| run: | | |
| set -euo pipefail | |
| echo "🛠️ Running srtool to build compact runtime…" | |
| # Build runtime inside srtool container (outputs verbose log to console) | |
| docker run --rm \ | |
| -v "${PWD}":/build \ | |
| -e RUNTIME_DIR=runtime/fennel \ | |
| -e PACKAGE=fennel-node-runtime \ | |
| --workdir /build \ | |
| paritytech/srtool:1.84.1 | |
| # After the container exits the compiled Wasm lives in the mounted volume | |
| HASH=$(sha256sum runtime/fennel/target/srtool/release/wbuild/fennel-node-runtime/fennel_node_runtime.compact.wasm | awk '{print "0x"$1}') | |
| echo "WASM_HASH=$HASH" >> $GITHUB_ENV | |
| echo "hash=$HASH" >> $GITHUB_OUTPUT | |
| echo "✅ Deterministic Wasm hash: $HASH" | |
| # Clean up srtool build artifacts to free disk space | |
| - name: Clean up srtool artifacts | |
| run: | | |
| echo "=== Cleaning up srtool build artifacts ===" | |
| # Remove intermediate build files but keep the final WASM | |
| find runtime/fennel/target/srtool -type f -name "*.rlib" -delete || true | |
| find runtime/fennel/target/srtool -type f -name "*.rmeta" -delete || true | |
| find runtime/fennel/target/srtool -type d -name "deps" -exec rm -rf {} + || true | |
| find runtime/fennel/target/srtool -type d -name "build" -exec rm -rf {} + || true | |
| # Additional aggressive cleanup | |
| echo "=== Additional cleanup ===" | |
| # Remove Docker build cache and unused images | |
| docker system prune -af --volumes || true | |
| # Remove temporary files | |
| sudo rm -rf /tmp/* || true | |
| # Remove apt cache | |
| sudo apt-get clean || true | |
| echo "=== Disk usage after cleanup ===" | |
| df -h | |
| # ------------------------------------------------------------ | |
| # Generate chain specifications using chain-spec-builder | |
| # ------------------------------------------------------------ | |
| - name: Install jq for JSON processing | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y jq | |
| echo "✅ Installed jq" | |
| - name: Install chain-spec-builder | |
| run: | | |
| # Create directory for chain-spec-builder | |
| mkdir -p "${HOME}/.cargo/bin" | |
| # Use Parity's prebuilt container that has Rust, protoc, and all dependencies | |
| docker run --rm \ | |
| -v "${PWD}":/build \ | |
| -v "${HOME}/.cargo/bin":/cargo-bin \ | |
| --workdir /build \ | |
| paritytech/ci-unified:latest \ | |
| bash -c " | |
| cargo install staging-chain-spec-builder --locked --root /tmp/cargo-install && \ | |
| cp /tmp/cargo-install/bin/chain-spec-builder /cargo-bin/ | |
| " | |
| echo "✅ Installed chain-spec-builder" | |
| # Add cargo bin to PATH for subsequent steps | |
| echo "${HOME}/.cargo/bin" >> $GITHUB_PATH | |
| - name: Create development chain spec | |
| run: | | |
| set -euo pipefail | |
| # Create development directory in chainspecs if it doesn't exist | |
| mkdir -p chainspecs/development | |
| # Debug: Check chain-spec-builder version and help | |
| echo "Chain-spec-builder version:" | |
| chain-spec-builder --version || echo "No version flag available" | |
| echo -e "\nChain-spec-builder help:" | |
| chain-spec-builder --help || echo "No help available" | |
| echo -e "\nChain-spec-builder create help:" | |
| chain-spec-builder create --help || echo "No create help available" | |
| # Check if the runtime has a development preset | |
| echo "Checking available presets..." | |
| chain-spec-builder list-presets \ | |
| --runtime runtime/fennel/target/srtool/release/wbuild/fennel-node-runtime/fennel_node_runtime.compact.wasm || true | |
| # Check if runtime exists | |
| echo "Checking if runtime WASM exists..." | |
| ls -la runtime/fennel/target/srtool/release/wbuild/fennel-node-runtime/fennel_node_runtime.compact.wasm || echo "Runtime WASM not found!" | |
| # Generate development chain spec | |
| echo "Creating development chain spec..." | |
| chain-spec-builder \ | |
| -c chainspecs/development/development.json \ | |
| create \ | |
| -r runtime/fennel/target/srtool/release/wbuild/fennel-node-runtime/fennel_node_runtime.compact.wasm \ | |
| named-preset development | |
| # Convert to raw format | |
| echo "Converting to raw format..." | |
| chain-spec-builder \ | |
| -c chainspecs/development/development-raw.json \ | |
| convert-to-raw \ | |
| chainspecs/development/development.json | |
| # Verify the specs were created | |
| echo "✅ Generated chain specifications:" | |
| ls -l chainspecs/development/ | |
| # Quick verification of content | |
| echo "Verifying development.json content:" | |
| jq '.name' chainspecs/development/development.json || echo "Failed to parse JSON" | |
| # Comprehensive verification | |
| echo -e "\n📋 Verification of generated files:" | |
| ls -l chainspecs/development/development.json chainspecs/development/development-raw.json | |
| echo -e "\n📄 Chain spec structure (first 5 lines):" | |
| jq . chainspecs/development/development.json 2>/dev/null | head -n 5 || true | |
| echo -e "\n🔍 Checking file sizes:" | |
| stat -c "development.json: %s bytes" chainspecs/development/development.json | |
| stat -c "development-raw.json: %s bytes" chainspecs/development/development-raw.json | |
| # Verify raw spec is SCALE-encoded (not JSON) | |
| echo -e "\n🔬 Verifying raw spec format (first 200 bytes):" | |
| head -c 200 chainspecs/development/development-raw.json | xxd | head -n 5 || echo "Could not read raw spec" | |
| # Ensure files are not empty | |
| if [ ! -s chainspecs/development/development.json ]; then | |
| echo "❌ Error: development.json is empty!" | |
| exit 1 | |
| fi | |
| if [ ! -s chainspecs/development/development-raw.json ]; then | |
| echo "❌ Error: development-raw.json is empty!" | |
| exit 1 | |
| fi | |
| echo "✅ All development chain spec files are populated" | |
| - name: Inject bootnodes into development chain spec | |
| run: | | |
| set -euo pipefail | |
| echo "🔗 Injecting dynamically derived bootnodes into development chain spec..." | |
| TARGET="development" | |
| SPEC="chainspecs/${TARGET}/development.json" | |
| # Use external-only bootnodes (Parity's recommended approach) | |
| # Both internal and external nodes use the same public endpoints | |
| # Decode bootnodes from base64 (safe transport through GitHub Actions env) | |
| EXTERNAL_BOOTNODES=$(echo "$EXTERNAL_BOOTNODES_B64" | base64 -d) | |
| echo "📋 Using external-only bootnode architecture: [MASKED - derived peer IDs]" | |
| # Only update if there are changes (idempotent) | |
| CURRENT_BOOTNODES=$(jq -c '.bootNodes // []' "$SPEC") | |
| if [ "$CURRENT_BOOTNODES" != "$EXTERNAL_BOOTNODES" ]; then | |
| echo "📝 Updating bootNodes in ${TARGET} chain spec with derived peer IDs..." | |
| jq --argjson arr "$EXTERNAL_BOOTNODES" '.bootNodes = $arr' "$SPEC" > tmp.json && mv tmp.json "$SPEC" | |
| # Regenerate raw spec with bootnodes included | |
| echo "🔄 Regenerating raw ${TARGET} spec with derived bootnodes..." | |
| chain-spec-builder \ | |
| -c "chainspecs/${TARGET}/development-raw.json" \ | |
| convert-to-raw \ | |
| "chainspecs/${TARGET}/development.json" | |
| echo "✅ Bootnodes updated successfully with derived peer IDs" | |
| else | |
| echo "✅ No changes needed - bootnodes already up to date" | |
| fi | |
| # Verify bootnodes configuration | |
| echo "📊 Current bootNodes configuration:" | |
| jq '.bootNodes' "$SPEC" || echo "No bootNodes found" | |
| - name: Commit development chainspecs to repository | |
| run: | | |
| # Configure git | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| # Add the development chainspecs | |
| git add chainspecs/development/development.json chainspecs/development/development-raw.json | |
| # Check if there are changes to commit | |
| if git diff --staged --quiet; then | |
| echo "No changes to development chainspecs" | |
| else | |
| # Commit the changes with [ci skip] to prevent retriggering | |
| git commit -m "Update development chainspecs with derived bootnode peer IDs [ci skip] | |
| - Peer IDs derived from GitHub secrets (BOOTNODE1_KEY_B64, BOOTNODE2_KEY_B64) | |
| - Using external-only bootnode architecture (Parity best practice) | |
| - Bootnode 1: $BOOTNODE1_PEER_ID | |
| - Bootnode 2: $BOOTNODE2_PEER_ID" | |
| # Push the changes back to the repository | |
| git push origin ${GITHUB_REF#refs/heads/} | |
| echo "✅ Development chainspecs committed and pushed to repository on branch ${GITHUB_REF#refs/heads/}" | |
| fi | |
| - name: Create staging chain specs | |
| run: | | |
| set -euo pipefail | |
| # Create staging directory in chainspecs if it doesn't exist | |
| mkdir -p chainspecs/staging | |
| # Generate staging chain spec | |
| echo "Generating staging chain spec..." | |
| chain-spec-builder \ | |
| -c chainspecs/staging/staging-chainspec.json \ | |
| create \ | |
| -r runtime/fennel/target/srtool/release/wbuild/fennel-node-runtime/fennel_node_runtime.compact.wasm \ | |
| named-preset staging | |
| # Generate raw staging chain spec | |
| echo "Generating raw staging chain spec..." | |
| chain-spec-builder \ | |
| -c chainspecs/staging/staging-raw.json \ | |
| convert-to-raw \ | |
| chainspecs/staging/staging-chainspec.json | |
| # Verify the staging specs were created | |
| echo "✅ Generated staging chain specifications:" | |
| ls -la chainspecs/staging/ | |
| # Quick verification of content | |
| echo "Verifying staging-chainspec.json content:" | |
| jq '.name' chainspecs/staging/staging-chainspec.json || echo "Failed to parse JSON" | |
| # Comprehensive verification | |
| echo -e "\n📋 Verification of generated files:" | |
| ls -l chainspecs/staging/staging-chainspec.json chainspecs/staging/staging-raw.json | |
| echo -e "\n📄 Chain spec structure (first 5 lines):" | |
| jq . chainspecs/staging/staging-chainspec.json 2>/dev/null | head -n 5 || true | |
| echo -e "\n🔍 Checking file sizes:" | |
| stat -c "staging-chainspec.json: %s bytes" chainspecs/staging/staging-chainspec.json | |
| stat -c "staging-raw.json: %s bytes" chainspecs/staging/staging-raw.json | |
| # Verify raw spec is SCALE-encoded (not JSON) | |
| echo -e "\n🔬 Verifying raw spec format (first 200 bytes):" | |
| head -c 200 chainspecs/staging/staging-raw.json | xxd | head -n 5 || echo "Could not read raw spec" | |
| # Ensure files are not empty | |
| if [ ! -s chainspecs/staging/staging-chainspec.json ]; then | |
| echo "❌ Error: staging-chainspec.json is empty!" | |
| exit 1 | |
| fi | |
| if [ ! -s chainspecs/staging/staging-raw.json ]; then | |
| echo "❌ Error: staging-raw.json is empty!" | |
| exit 1 | |
| fi | |
| echo "✅ All staging chain spec files are populated" | |
| - name: Inject bootnodes into staging chain spec | |
| run: | | |
| set -euo pipefail | |
| echo "🔗 Injecting dynamically derived bootnodes into staging chain spec..." | |
| TARGET="staging" | |
| SPEC="chainspecs/${TARGET}/staging-chainspec.json" | |
| # Use external-only bootnodes (Parity's recommended approach) | |
| # Both internal and external nodes use the same public endpoints | |
| # Decode bootnodes from base64 (safe transport through GitHub Actions env) | |
| EXTERNAL_BOOTNODES=$(echo "$EXTERNAL_BOOTNODES_B64" | base64 -d) | |
| echo "📋 Using external-only bootnode architecture: [MASKED - derived peer IDs]" | |
| # Only update if there are changes (idempotent) | |
| CURRENT_BOOTNODES=$(jq -c '.bootNodes // []' "$SPEC") | |
| if [ "$CURRENT_BOOTNODES" != "$EXTERNAL_BOOTNODES" ]; then | |
| echo "📝 Updating bootNodes in ${TARGET} chain spec with derived peer IDs..." | |
| jq --argjson arr "$EXTERNAL_BOOTNODES" '.bootNodes = $arr' "$SPEC" > tmp.json && mv tmp.json "$SPEC" | |
| # Regenerate raw spec with bootnodes included | |
| echo "🔄 Regenerating raw ${TARGET} spec with derived bootnodes..." | |
| chain-spec-builder \ | |
| -c "chainspecs/${TARGET}/staging-raw.json" \ | |
| convert-to-raw \ | |
| "chainspecs/${TARGET}/staging-chainspec.json" | |
| echo "✅ Bootnodes updated successfully with derived peer IDs" | |
| else | |
| echo "✅ No changes needed - bootnodes already up to date" | |
| fi | |
| # Verify bootnodes configuration | |
| echo "📊 Current bootNodes configuration:" | |
| jq '.bootNodes' "$SPEC" || echo "No bootNodes found" | |
| - name: Commit staging chainspecs to repository | |
| run: | | |
| # Configure git | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| # Add the staging chainspecs | |
| git add chainspecs/staging/staging-chainspec.json chainspecs/staging/staging-raw.json | |
| # Check if there are changes to commit | |
| if git diff --staged --quiet; then | |
| echo "No changes to staging chainspecs" | |
| else | |
| # Commit the changes with [ci skip] to prevent retriggering | |
| git commit -m "Update staging chainspecs with derived bootnode peer IDs [ci skip] | |
| - Peer IDs derived from GitHub secrets (BOOTNODE1_KEY_B64, BOOTNODE2_KEY_B64) | |
| - Using external-only bootnode architecture (Parity best practice) | |
| - Bootnode 1: $BOOTNODE1_PEER_ID | |
| - Bootnode 2: $BOOTNODE2_PEER_ID" | |
| # Push the changes back to the repository | |
| git push origin ${GITHUB_REF#refs/heads/} | |
| echo "✅ Staging chainspecs committed and pushed to repository on branch ${GITHUB_REF#refs/heads/}" | |
| fi | |
| - name: Upload chain specs as artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fennel-chainspecs | |
| path: | | |
| chainspecs/development/development.json | |
| chainspecs/development/development-raw.json | |
| chainspecs/staging/staging-chainspec.json | |
| chainspecs/staging/staging-raw.json | |
| # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. | |
| # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. | |
| # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. | |
| - name: Build and push Docker image | |
| id: build | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| WASM_HASH=${{ env.WASM_HASH }} | |
| # Remove problematic cache settings that are causing the blob error | |
| # cache-from: type=gha | |
| # cache-to: type=gha,mode=max | |
| provenance: false | |
| # Create and upload artifact containing image info | |
| - name: Output image info to artifact | |
| run: | | |
| mkdir -p ./artifacts | |
| echo "Image name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" > ./artifacts/image-info.txt | |
| echo "Tags: ${{ steps.meta.outputs.tags }}" >> ./artifacts/image-info.txt | |
| echo "Wasm hash: ${{ env.WASM_HASH }}" >> ./artifacts/image-info.txt | |
| echo "Digest: ${{ steps.build.outputs.digest }}" >> ./artifacts/image-info.txt | |
| echo "Created: $(date -u +\"%Y-%m-%dT%H:%M:%SZ\")" >> ./artifacts/image-info.txt | |
| - name: Upload Docker image info artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fennel-node-image-info | |
| path: ./artifacts/image-info.txt | |
| # ------------------------------------------------------------ | |
| # Package and publish Helm chart with updated values | |
| # ------------------------------------------------------------ | |
| - name: Install Helm | |
| uses: azure/setup-helm@v3 | |
| with: | |
| version: 'v3.13.0' | |
| - name: Add Parity Helm repo | |
| run: | | |
| helm repo add parity https://paritytech.github.io/helm-charts | |
| helm repo update | |
| - name: Update Helm dependencies | |
| run: | | |
| cd Charts/fennel-node | |
| helm dependency update | |
| - name: Extract image tag from metadata | |
| id: extract-tag | |
| run: | | |
| # Extract the sha-prefixed tag from the metadata | |
| SHA_TAG=$(echo "${{ steps.meta.outputs.tags }}" | grep -oE 'sha-[a-f0-9]+' | head -1) | |
| echo "tag=${SHA_TAG}" >> $GITHUB_OUTPUT | |
| echo "✅ Extracted image tag: ${SHA_TAG}" | |
| - name: Update base values.yaml | |
| uses: fjogeleit/yaml-update-action@v0.13.2 | |
| with: | |
| valueFile: 'Charts/fennel-node/values.yaml' | |
| propertyPath: 'image.tag' | |
| value: ${{ steps.extract-tag.outputs.tag }} | |
| commitChange: false | |
| - name: Update staging values.yaml | |
| uses: fjogeleit/yaml-update-action@v0.13.2 | |
| with: | |
| valueFile: 'Charts/fennel-node/values-staging.yaml' | |
| propertyPath: 'image.tag' | |
| value: ${{ steps.extract-tag.outputs.tag }} | |
| commitChange: false | |
| - name: Lint Helm chart | |
| run: | | |
| echo "🔍 Linting base chart..." | |
| helm lint Charts/fennel-node | |
| echo "🔍 Linting with staging values..." | |
| helm lint Charts/fennel-node -f Charts/fennel-node/values-staging.yaml | |
| - name: Package Helm chart | |
| run: | | |
| mkdir -p release | |
| helm package Charts/fennel-node --destination release | |
| echo "📦 Packaged chart:" | |
| ls -la release/ | |
| - name: Configure Git for chart release | |
| run: | | |
| git config user.name "$GITHUB_ACTOR" | |
| git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | |
| - name: Publish Helm chart to GitHub Pages | |
| run: | | |
| set -euo pipefail | |
| echo "🚀 Publishing Helm chart to GitHub Pages..." | |
| # Store current chart version | |
| CHART_VERSION=$(grep '^version:' Charts/fennel-node/Chart.yaml | awk '{print $2}') | |
| echo "Chart version: $CHART_VERSION" | |
| # Create a temporary directory for gh-pages content | |
| TEMP_DIR=$(mktemp -d) | |
| echo "Working in temporary directory: $TEMP_DIR" | |
| # Initialize git in temp directory | |
| cd "$TEMP_DIR" | |
| git init | |
| git config user.name "$GITHUB_ACTOR" | |
| git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | |
| # Add remote | |
| git remote add origin "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" | |
| # Try to fetch existing gh-pages branch | |
| if git ls-remote --heads origin gh-pages | grep -q gh-pages; then | |
| echo "📥 Fetching existing gh-pages branch..." | |
| git fetch origin gh-pages | |
| git checkout gh-pages | |
| else | |
| echo "🆕 Creating new gh-pages branch..." | |
| git checkout --orphan gh-pages | |
| # Remove any files that might exist | |
| git rm -rf . 2>/dev/null || true | |
| fi | |
| # Create directory structure for Helm repository | |
| mkdir -p charts | |
| # Copy the packaged chart | |
| cp "${GITHUB_WORKSPACE}/release"/*.tgz charts/ | |
| # Generate Helm repository index | |
| helm repo index charts --url "https://corruptedaesthetic.github.io/fennel-solonet/charts" | |
| # Create a simple index.html for the repository | |
| cat > index.html << 'EOF' | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Fennel Node Helm Repository</title> | |
| <style> | |
| body { font-family: Arial, sans-serif; margin: 40px; } | |
| .header { color: #2c3e50; } | |
| .code { background-color: #f4f4f4; padding: 10px; border-radius: 5px; } | |
| .chart-list { margin-top: 20px; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1 class="header">🌿 Fennel Node Helm Repository</h1> | |
| <p>This repository contains Helm charts for the Fennel blockchain node.</p> | |
| <h2>Usage</h2> | |
| <div class="code"> | |
| <strong>Add this repository:</strong><br> | |
| <code>helm repo add fennel https://corruptedaesthetic.github.io/fennel-solonet</code><br><br> | |
| <strong>Update repositories:</strong><br> | |
| <code>helm repo update</code><br><br> | |
| <strong>Install Fennel node:</strong><br> | |
| <code>helm install fennel-node fennel/fennel-node</code> | |
| </div> | |
| <h2>Available Charts</h2> | |
| <div class="chart-list"> | |
| <ul> | |
| <li><strong>fennel-node</strong> - Fennel blockchain node deployment</li> | |
| </ul> | |
| </div> | |
| <h2>Repository Files</h2> | |
| <ul> | |
| <li><a href="charts/">charts/</a> - Chart packages and index</li> | |
| <li><a href="charts/index.yaml">charts/index.yaml</a> - Helm repository index</li> | |
| </ul> | |
| <hr> | |
| <p><small>Generated automatically by GitHub Actions</small></p> | |
| </body> | |
| </html> | |
| EOF | |
| # Create README for the repository | |
| cat > README.md << EOF | |
| # Fennel Node Helm Repository | |
| This is the Helm repository for Fennel blockchain node charts. | |
| ## Usage | |
| \`\`\`bash | |
| # Add the repository | |
| helm repo add fennel https://corruptedaesthetic.github.io/fennel-solonet | |
| # Update repositories | |
| helm repo update | |
| # Install Fennel node | |
| helm install fennel-node fennel/fennel-node | |
| \`\`\` | |
| ## Available Charts | |
| - **fennel-node** - Fennel blockchain node deployment chart | |
| ## Chart Version: $CHART_VERSION | |
| Generated automatically by GitHub Actions. | |
| EOF | |
| # Show what we're about to commit | |
| echo "📋 Repository structure:" | |
| find . -type f | sort | |
| echo "📄 Charts index content:" | |
| cat charts/index.yaml | |
| # Add all files | |
| git add . | |
| # Commit changes | |
| if git diff --staged --quiet; then | |
| echo "ℹ️ No changes to commit" | |
| else | |
| git commit -m "📦 Update Helm repository - fennel-node v$CHART_VERSION | |
| - Added fennel-node chart version $CHART_VERSION | |
| - Updated repository index | |
| - Generated: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" | |
| echo "📤 Pushing to gh-pages branch..." | |
| git push origin gh-pages --force | |
| echo "✅ Helm chart repository published successfully!" | |
| echo "🌐 Repository URL: https://corruptedaesthetic.github.io/fennel-solonet" | |
| echo "📊 Charts URL: https://corruptedaesthetic.github.io/fennel-solonet/charts" | |
| fi | |
| # Cleanup | |
| cd "$GITHUB_WORKSPACE" | |
| rm -rf "$TEMP_DIR" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| if: startsWith(github.ref, 'refs/tags/') | |
| with: | |
| files: | | |
| release/*.tgz | |
| ./artifacts/image-info.txt | |
| chainspecs/development/development.json | |
| chainspecs/development/development-raw.json | |
| chainspecs/staging/staging-chainspec.json | |
| chainspecs/staging/staging-raw.json | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Run chart-releaser | |
| uses: helm/chart-releaser-action@v1.6.0 | |
| with: | |
| charts_dir: Charts | |
| skip_existing: true | |
| env: | |
| CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | |
| - name: Upload Helm chart artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fennel-helm-chart | |
| path: release/*.tgz | |
| retention-days: 30 | |
| - name: Output workflow summary | |
| run: | | |
| echo "## 📊 Build Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🐳 Docker Image" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Image**: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Tag**: \`${{ steps.extract-tag.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Wasm Hash**: \`${{ env.WASM_HASH }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📋 Chain Specs" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Development chain spec generated" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Staging chain spec generated" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Helm Chart" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Chart packaged and published" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version**: \`$(helm show chart release/*.tgz | grep '^version:' | awk '{print $2}')\`" >> $GITHUB_STEP_SUMMARY |