From 39b7f6dfbd43acacf9500cd5ed02eb8d29662b46 Mon Sep 17 00:00:00 2001 From: daywalker90 Date: Thu, 23 Jul 2026 13:58:17 +0200 Subject: [PATCH] CI: restructure release workflows Binaries, docker images, and python packages are now separated into build and publish flows. First everything gets built and if every build step succeeds the publish step can continue. Also fan out the docker build into a matrix to speed up the workflow. Changelog-None --- .github/workflows/check-release-tag.yml | 56 ++++++ .github/workflows/docker-build.yml | 86 +++++++++ .github/workflows/docker-publish.yml | 67 +++++++ .github/workflows/docker-release.yml | 134 ------------- .github/workflows/pypi-build.yml | 48 +++++ .github/workflows/pypi-publish.yml | 58 ++++++ .github/workflows/pypi.yml | 96 ---------- .github/workflows/release-build.yml | 67 +++++++ .github/workflows/release-publish.yml | 69 +++++++ .github/workflows/release.yml | 245 ++++++++---------------- 10 files changed, 533 insertions(+), 393 deletions(-) create mode 100644 .github/workflows/check-release-tag.yml create mode 100644 .github/workflows/docker-build.yml create mode 100644 .github/workflows/docker-publish.yml delete mode 100644 .github/workflows/docker-release.yml create mode 100644 .github/workflows/pypi-build.yml create mode 100644 .github/workflows/pypi-publish.yml delete mode 100644 .github/workflows/pypi.yml create mode 100644 .github/workflows/release-build.yml create mode 100644 .github/workflows/release-publish.yml diff --git a/.github/workflows/check-release-tag.yml b/.github/workflows/check-release-tag.yml new file mode 100644 index 000000000..1b2b3aa1e --- /dev/null +++ b/.github/workflows/check-release-tag.yml @@ -0,0 +1,56 @@ +name: Check release tag + +on: + workflow_call: + inputs: + version: + type: string + required: false + skip_validation: + type: boolean + default: false + outputs: + version: + description: "Resolved release version" + value: ${{ jobs.check.outputs.version }} + +jobs: + check: + name: Validate tag against .version file and release content + runs-on: ubuntu-24.04 + outputs: + version: ${{ steps.resolve.outputs.version }} + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Validate tag matches .version file + id: resolve + run: | + if [[ "${{ github.ref_type }}" != "tag" ]]; then + echo "::notice::Not triggered by a tag push (ref_type=${{ github.ref_type }}); skipping .version check." + echo "version=${{ inputs.version }}" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [[ ! -f .version ]]; then + echo "::error::.version file not found in repository root." + exit 1 + fi + + FILE_VERSION="$(tr -d '[:space:]' < .version)" + TAG_VERSION="${{ github.ref_name }}" + + if [[ "$TAG_VERSION" != "$FILE_VERSION" ]]; then + echo "::error::Tag '$TAG_VERSION' does not match version in .version file ('$FILE_VERSION'). Refusing to release." + exit 1 + fi + + echo "Tag '$TAG_VERSION' matches .version file." + echo "version=$TAG_VERSION" >> "$GITHUB_OUTPUT" + + - name: Validate release + if: ${{ !inputs.skip_validation }} + run: tools/check-release.sh --version=${{ steps.resolve.outputs.version }} diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 000000000..6b2479309 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,86 @@ +name: Docker build + +on: + workflow_call: + inputs: + version: + type: string + required: true + dh-repository-owner: + type: string + required: true + platforms-to-build: + type: string + required: true + +jobs: + # Turn the comma-separated platforms-to-build input into a JSON matrix array, + # so we can fan out per-platform without hardcoding the list twice. + plan: + name: Plan platform matrix + runs-on: ubuntu-24.04 + outputs: + platforms: ${{ steps.plan.outputs.platforms }} + steps: + - id: plan + run: | + IFS=',' read -ra ARR <<< "${{ inputs.platforms-to-build }}" + JSON=$(printf '%s\n' "${ARR[@]}" | jq -R . | jq -sc .) + echo "platforms=$JSON" >> "$GITHUB_OUTPUT" + + build: + name: Build ${{ matrix.target == 'lightningd-vls-signer' && 'vls' || 'normal' }} / ${{ matrix.platform }} + needs: plan + strategy: + fail-fast: false + matrix: + target: + - lightningd + - lightningd-vls-signer + platform: ${{ fromJson(needs.plan.outputs.platforms) }} + runs-on: ${{ matrix.platform == 'linux/arm64' && 'ubuntu-22.04-arm' || 'ubuntu-22.04' }} + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up QEMU + if: matrix.platform == 'linux/arm/v7' + uses: docker/setup-qemu-action@v4 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build single-platform image, push by digest + id: build + uses: docker/build-push-action@v7 + with: + context: . + file: ./Dockerfile + target: ${{ matrix.target }} + platforms: ${{ matrix.platform }} + build-args: | + VERSION=${{ inputs.version }} + outputs: type=image,name=${{ inputs.dh-repository-owner }}/lightningd,push-by-digest=true,name-canonical=true,push=true + cache-from: type=gha,scope=${{ matrix.target }}-${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=${{ matrix.target }}-${{ matrix.platform }} + + - name: Save digest + run: | + mkdir -p /tmp/digests + echo "${{ steps.build.outputs.digest }}" > /tmp/digests/digest.txt + + - name: Upload digest + uses: actions/upload-artifact@v7 + with: + name: digest_${{ matrix.target }}_${{ strategy.job-index }} + path: /tmp/digests/digest.txt + if-no-files-found: error + retention-days: 1 diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 000000000..78bcaf64e --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,67 @@ +name: Docker publish + +on: + workflow_call: + inputs: + version: + type: string + required: true + dh-repository-owner: + type: string + required: true + push-latest: + type: string + required: true + +jobs: + publish: + name: Tag and publish ${{ matrix.target }} + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + include: + - target: lightningd + tag_suffix: '' + - target: lightningd-vls-signer + tag_suffix: '-vls' + steps: + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Download platform digests for this target + uses: actions/download-artifact@v8 + with: + pattern: digest_${{ matrix.target }}_* + path: /tmp/digests + merge-multiple: false + + - name: Set up values + run: | + DIGEST_REFS="" + for f in /tmp/digests/*/digest.txt; do + D=$(cat "$f") + DIGEST_REFS="$DIGEST_REFS ${{ inputs.dh-repository-owner }}/lightningd@${D}" + done + echo "DIGEST_REFS=$DIGEST_REFS" >> $GITHUB_ENV + + if [[ "${{ inputs.push-latest }}" == "true" ]] || + ([[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "${{ inputs.version }}" =~ rc ]]); then + echo "PUSHLATEST=true" >> $GITHUB_ENV + else + echo "PUSHLATEST=false" >> $GITHUB_ENV + fi + + - name: Create and push real tag(s) + run: | + TAG_ARGS=(-t "${{ inputs.dh-repository-owner }}/lightningd:${{ inputs.version }}${{ matrix.tag_suffix }}") + if [[ "$PUSHLATEST" == "true" ]]; then + TAG_ARGS+=(-t "${{ inputs.dh-repository-owner }}/lightningd:latest${{ matrix.tag_suffix }}") + fi + docker buildx imagetools create "${TAG_ARGS[@]}" $DIGEST_REFS diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml deleted file mode 100644 index 738634999..000000000 --- a/.github/workflows/docker-release.yml +++ /dev/null @@ -1,134 +0,0 @@ -name: Publish multi-platform docker images - -on: - push: - tags: - - 'v[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+[0-9a-z]+' - workflow_dispatch: - inputs: - version: - description: 'Release version' - required: true - - repository-name: - description: 'Docker repository name' - default: 'elementsproject' - required: false - - platforms-to-build: - description: 'List of platforms to build' - default: 'linux/amd64,linux/arm64,linux/arm/v7' - required: false - - push-latest: - description: 'Push the latest tag also?' - default: 'false' - required: false - -jobs: - build: - runs-on: ubuntu-22.04 - strategy: - fail-fast: false # Let each tag finish. - matrix: - include: - - target: lightningd - tag_suffix: '' - - target: lightningd-vls-signer - tag_suffix: '-vls' - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - ref: ${{ github.ref }} # Ensures the branch triggering the workflow is checked out - fetch-depth: 0 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Log in to Docker Hub - uses: docker/login-action@v4 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Set up values for ${{ matrix.target }} - id: set-values - run: | - if [[ "${{ github.event.inputs.version }}" != "" ]]; then - echo "Input version provided" - VERSION=${{ github.event.inputs.version }} - elif [[ ${{ github.ref_type }} == "tag" ]]; then - echo "This is a tag event" - VERSION=${{ github.ref_name }} - else - echo "No version provided and no tag found." - exit 1 - fi - echo "VERSION=$VERSION" >> $GITHUB_ENV - - if [[ "${{ github.event.inputs.repository-name }}" != "" ]]; then - REPONAME=${{ github.event.inputs.repository-name }} - else - REPONAME="elementsproject" - fi - echo "REPONAME=$REPONAME" >> $GITHUB_ENV - - if [[ "${{ github.event.inputs.platforms-to-build }}" != "" ]]; then - PLATFORMS=${{ github.event.inputs.platforms-to-build }} - else - PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7" - fi - echo "PLATFORMS=$PLATFORMS" >> $GITHUB_ENV - - if [[ "${{ github.event.inputs.push-latest }}" == "true" ]] || - ([[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "$VERSION" =~ rc ]]); then - echo "Latest true" - PUSHLATEST="true" - else - echo "Latest false" - PUSHLATEST="false" - fi - echo "PUSHLATEST=$PUSHLATEST" >> $GITHUB_ENV - - TAGS="$REPONAME/lightningd:$VERSION${{ matrix.tag_suffix }}" - if [[ "$PUSHLATEST" == "true" ]]; then - TAGS="$TAGS,$REPONAME/lightningd:latest${{ matrix.tag_suffix }}" - fi - echo "TAGS=$TAGS" >> $GITHUB_ENV - - - name: Print GitHub Ref Values - run: | - echo "TARGET: ${{ matrix.target }}" - echo "TAG SUFFIX: ${{ matrix.tag_suffix }}" - echo "GITHUB REF TYPE: ${{ github.ref_type }}" - echo "GITHUB REF NAME: ${{ github.ref_name }}" - echo "EVENT INPUT VERSION: ${{ github.event.inputs.version }}" - echo "EVENT INPUT REPO: ${{ github.event.inputs.repository-name }}" - echo "EVENT INPUT PLATFORMS: ${{ github.event.inputs.platforms-to-build }}" - echo "EVENT INPUT PUSH LATEST: ${{ github.event.inputs.push-latest }}" - echo "ENV VERSION: ${{ env.VERSION }}" - echo "ENV REPO NAME: ${{ env.REPONAME }}" - echo "ENV PLATFORMS: ${{ env.PLATFORMS }}" - echo "ENV PUSH LATEST: ${{ env.PUSHLATEST }}" - echo "ENV TAGS: ${{ env.TAGS }}" - - - name: Build and push Docker tag - ${{ env.TAGS }} - uses: docker/build-push-action@v7 - with: - context: . - file: ./Dockerfile - target: ${{ matrix.target }} - push: true - platforms: ${{ env.PLATFORMS }} - tags: ${{ env.TAGS }} - build-args: | - VERSION=${{ env.VERSION }} - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.github/workflows/pypi-build.yml b/.github/workflows/pypi-build.yml new file mode 100644 index 000000000..83f80eb7b --- /dev/null +++ b/.github/workflows/pypi-build.yml @@ -0,0 +1,48 @@ +name: PyPI build + +on: + workflow_call: + inputs: + version: + type: string + required: true + +jobs: + build: + name: Build ${{ matrix.PACKAGE }} 🐍 + runs-on: ubuntu-22.04 + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + include: + - PACKAGE: pyln-client + - PACKAGE: pyln-testing + - PACKAGE: pyln-proto + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.10' + + - name: Install uv + uses: astral-sh/setup-uv@v8.1.0 + + - name: Update pyln versions + run: | + make update-pyln-versions NEW_VERSION=${{ inputs.version }} + + - name: Build distribution 📦 + run: uv build --package ${{ matrix.PACKAGE }} + + - name: Upload distribution artifact + uses: actions/upload-artifact@v7 + with: + name: dist-${{ matrix.PACKAGE }} + path: dist/ + if-no-files-found: error diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml new file mode 100644 index 000000000..6244891c7 --- /dev/null +++ b/.github/workflows/pypi-publish.yml @@ -0,0 +1,58 @@ +name: PyPI publish + +on: + workflow_call: + inputs: + version: + type: string + required: true + dist-location: + type: string + required: true + +jobs: + publish: + name: Publish ${{ matrix.PACKAGE }} 🐍 + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + include: + - PACKAGE: pyln-client + - PACKAGE: pyln-testing + - PACKAGE: pyln-proto + steps: + - name: Download built distribution + uses: actions/download-artifact@v8 + with: + name: dist-${{ matrix.PACKAGE }} + path: dist/ + + - name: Determine PyPI distribution location + id: set-values + run: | + if [[ "${{ inputs.dist-location }}" != "" ]]; then + DISTLOCATION="${{ inputs.dist-location }}" + elif [[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "${{ inputs.version }}" =~ rc ]]; then + DISTLOCATION="prod" + else + DISTLOCATION="test" + fi + echo "DISTLOCATION=$DISTLOCATION" >> "$GITHUB_OUTPUT" + echo "EVENT DISTLOCATION: ${{ github.event.inputs.dist-location }}" + echo "Resolved dist-location: $DISTLOCATION" + + - name: Install uv + uses: astral-sh/setup-uv@v8.1.0 + + - name: Publish distribution 📦 to Test PyPI + if: github.repository == 'ElementsProject/lightning' && steps.set-values.outputs.DISTLOCATION == 'test' + env: + UV_PUBLISH_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} + run: uv publish --publish-url https://test.pypi.org/legacy/ --check-url https://test.pypi.org/simple/ dist/* + + - name: Publish distribution 📦 to PyPI + if: github.repository == 'ElementsProject/lightning' && steps.set-values.outputs.DISTLOCATION == 'prod' + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + run: uv publish dist/* diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml deleted file mode 100644 index 346c413f3..000000000 --- a/.github/workflows/pypi.yml +++ /dev/null @@ -1,96 +0,0 @@ -name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI - -on: - push: - tags: - - 'v[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+[0-9a-z]+' - workflow_dispatch: - inputs: - dist-location: - description: 'Distribution location (test/prod)' - default: 'test' - required: false - -jobs: - deploy: - name: Build and publish ${{ matrix.package }} 🐍 - runs-on: ubuntu-22.04 - timeout-minutes: 120 - strategy: - fail-fast: true - matrix: - include: - - PACKAGE: pyln-client - WORKDIR: contrib/pyln-client - - PACKAGE: pyln-testing - WORKDIR: contrib/pyln-testing - - PACKAGE: pyln-proto - WORKDIR: contrib/pyln-proto - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - # Need to fetch entire history in order to locate the version tag - fetch-depth: 0 - - - name: Check version tag - run: >- - git describe --tags --always --dirty=-modded --abbrev=7 - - - name: Setup Version - env: - WORKDIR: ${{ matrix.WORKDIR }} - run: | - echo "VERSION=$(git describe --tags --abbrev=0).post$(git describe --tags --abbrev=1 | awk -F "-" '{print $2}')" >> $GITHUB_ENV - - - name: Set up values - id: set-values - run: | - if [[ "${{ github.event.inputs.dist-location }}" != "" ]]; then - DISTLOCATION=${{ github.event.inputs.dist-location }} - elif [[ "${{ github.ref_type }}" == "tag" ]] && [[ ! "${{ github.ref_name }}" =~ rc ]]; then - DISTLOCATION="prod" - else - DISTLOCATION="test" - fi - echo "DISTLOCATION=$DISTLOCATION" >> $GITHUB_OUTPUT - echo "EVENT DISTLOCATION: ${{ github.event.inputs.dist-location }}" - echo "DISTRIBUTION LOCATION: $DISTLOCATION" - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: '3.10' - - - name: Install uv - uses: astral-sh/setup-uv@v8.1.0 - - - name: Update pyln versions - id: update-versions - run: | - export VERSION=$(git describe --tags --abbrev=0) - echo "Pyln VERSION: $VERSION" - make update-pyln-versions NEW_VERSION=$VERSION - - - name: Publish distribution 📦 to Test PyPI - if: github.repository == 'ElementsProject/lightning' && steps.set-values.outputs.DISTLOCATION == 'test' - env: - UV_PUBLISH_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} - WORKDIR: ${{ matrix.WORKDIR }} - run: | - echo "Pyln VERSION: $VERSION" - uv build --package ${{ matrix.PACKAGE }} - uv publish --publish-url https://test.pypi.org/legacy/ --check-url https://test.pypi.org/simple/ - - - name: Publish distribution 📦 to PyPI - if: github.repository == 'ElementsProject/lightning' && steps.set-values.outputs.DISTLOCATION == 'prod' - env: - UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - WORKDIR: ${{ matrix.WORKDIR }} - run: | - echo "UV VERSION PUBLISH: $(uv --version)" - echo "Pyln VERSION: $VERSION" - uv build --package ${{ matrix.PACKAGE }} - uv publish diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml new file mode 100644 index 000000000..b99965dc3 --- /dev/null +++ b/.github/workflows/release-build.yml @@ -0,0 +1,67 @@ +name: Release binaries build + +on: + workflow_call: + inputs: + version: + type: string + required: true + skip_validation: + type: boolean + required: true + +jobs: + releases: + name: Releases + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + target: + - 'bin-Fedora' + - 'bin-Ubuntu-jammy' + - 'bin-Ubuntu-noble' + - 'bin-Ubuntu-resolute' + steps: + - name: Git checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Build environment setup + run: | + distribution=$(echo ${{ matrix.target }} | cut -d'-' -f3) + sudo docker run --rm -v $(pwd):/build ubuntu:${distribution} bash -c "\ + apt-get update && \ + apt-get install -y debootstrap && \ + debootstrap ${distribution} /build/${distribution}" + sudo tar -C ${distribution} -c . | docker import - ${distribution} + docker build -t cl-repro-${distribution} - < contrib/reprobuild/Dockerfile.${distribution} + if: contains(matrix.target, 'Ubuntu') + + - name: Build release + run: | + if [[ "${{ inputs.skip_validation }}" == "true" ]]; then + tools/build-release.sh ${{ matrix.target }} --force-version "${{ inputs.version }}" --force-unclean --force-mtime "$(date +%Y-%m-%d)" + else + tools/build-release.sh ${{ matrix.target }} + fi + + - name: Upload target artifacts + uses: actions/upload-artifact@v7 + with: + path: release/ + name: ${{ matrix.target }} + if-no-files-found: error + + artifact: + name: Construct release artifact + needs: releases + runs-on: ubuntu-24.04 + steps: + - name: Merge artifacts + uses: actions/upload-artifact/merge@v7 + with: + name: c-lightning-${{ inputs.version }} + pattern: bin-* + delete-merged: true diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 000000000..be7146ab1 --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,69 @@ +name: Release publish + +on: + workflow_call: + inputs: + version: + type: string + required: true + create_release: + type: boolean + required: true + +jobs: + release: + name: Sign and prepare release draft + runs-on: ubuntu-24.04 + steps: + - name: Git checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Download artifact + uses: actions/download-artifact@v8 + with: + name: c-lightning-${{ inputs.version }} + path: release/ + + - name: Import GPG keys + id: gpg + uses: crazy-max/ghaction-import-gpg@v7 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + trust_level: 5 + + - name: Set default GPG key + run: echo "default-key ${{ steps.gpg.outputs.keyid }}" >> ~/.gnupg/gpg.conf + + - name: Sign release + run: tools/build-release.sh --without-zip sign + + - name: Upload signed artifact + uses: actions/upload-artifact@v7 + with: + name: c-lightning-${{ inputs.version }} + overwrite: true + path: release/ + + - name: Determine release data + id: release_data + run: | + CHANGELOG_VERSION=${VERSION#v} + VERSION="${{ inputs.version }}" + CHANGELOG_VERSION=${VERSION#v} + CHANGELOG_TITLE=$(grep "## \[${CHANGELOG_VERSION}\]" CHANGELOG.md) + RELEASE_TITLE=$(echo $CHANGELOG_TITLE | cut -d'"' -f2) + echo "release_title=$RELEASE_TITLE" >> "$GITHUB_OUTPUT" + + - name: Prepare release draft + if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.create_release) }} + uses: softprops/action-gh-release@v3 + with: + name: "${{ inputs.version }} ${{ steps.release_data.outputs.release_title }}" + tag_name: ${{ inputs.version }} + draft: true + prerelease: contains(inputs.version, "-rc") + files: release/* + fail_on_unmatched_files: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 824264848..7bb09de67 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,7 @@ on: - 'v[0-9]+.[0-9]+' - 'v[0-9]+.[0-9]+.[0-9]+' - 'v[0-9]+.[0-9]+[0-9a-z]+' + - 'v[0-9]+.[0-9]+.[0-9]+[0-9a-z]+' workflow_dispatch: inputs: version: @@ -20,173 +21,91 @@ on: description: Create a draft release default: false type: boolean + dh-repository-owner: + description: 'Dockerhub repository owner' + default: 'elementsproject' + platforms-to-build: + description: 'List of platforms to build' + default: 'linux/amd64,linux/arm64,linux/arm/v7' + push-latest: + description: 'Push the latest Docker tag' + type: boolean + default: false + dist-location: + description: 'PyPI distribution location' + type: choice + options: + - test + - prod + default: 'test' jobs: - check: - name: Check - outputs: - version: ${{ steps.capture.outputs.version }} + check-version: + name: Verify release tag + uses: ./.github/workflows/check-release-tag.yml + with: + version: ${{ github.event.inputs.version }} + skip_validation: ${{ github.event.inputs.skip_validation == 'true' }} + + + docker-build: + name: Docker build + needs: check-version + uses: ./.github/workflows/docker-build.yml + with: + version: ${{ needs.check-version.outputs.version }} + dh-repository-owner: ${{ github.event.inputs.dh-repository-owner || 'elementsproject' }} + platforms-to-build: ${{ github.event.inputs.platforms-to-build || 'linux/amd64,linux/arm64,linux/arm/v7' }} + secrets: inherit + + pypi-build: + name: PyPI build + needs: check-version + uses: ./.github/workflows/pypi-build.yml + with: + version: ${{ needs.check-version.outputs.version }} + secrets: inherit + + release-build: + name: Release binaries build + needs: check-version + uses: ./.github/workflows/release-build.yml + with: + version: ${{ needs.check-version.outputs.version }} + skip_validation: ${{ github.event.inputs.skip_validation == 'true' }} + secrets: inherit + + gate: + name: All builds succeeded + needs: [docker-build, pypi-build, release-build] runs-on: ubuntu-24.04 steps: - - name: Git checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.ref }} - fetch-depth: 0 + - run: echo "All three build paths succeeded — proceeding to publish." - - name: Determine version - run: | - if [[ "${{ github.event.inputs.version }}" != "" ]]; then - VERSION="${{ github.event.inputs.version }}" - elif [ "${{ github.ref_type }}" == "tag" ]; then - VERSION="${{ github.ref_name }}" - else - echo "No release version provided and no tag found." - exit 1 - fi - echo "VERSION=$VERSION" >> "$GITHUB_ENV" - echo "Determined version: $VERSION" + docker-publish: + name: Docker publish + needs: [check-version, gate] + uses: ./.github/workflows/docker-publish.yml + with: + version: ${{ needs.check-version.outputs.version }} + dh-repository-owner: ${{ github.event.inputs.dh-repository-owner || 'elementsproject' }} + push-latest: ${{ github.event.inputs.push-latest }} + secrets: inherit - - name: Validate release - if: ${{ !(github.event_name == 'workflow_dispatch' && github.event.inputs.skip_validation) }} - run: tools/check-release.sh --version=${VERSION} + pypi-publish: + name: PyPI publish + needs: [check-version, gate] + uses: ./.github/workflows/pypi-publish.yml + with: + version: ${{ needs.check-version.outputs.version }} + dist-location: ${{ github.event.inputs.dist-location }} + secrets: inherit - - name: Catpure version output - id: capture - run: echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - - releases: - name: Releases - needs: check - env: - version: ${{ needs.check.outputs.version }} - runs-on: ubuntu-24.04 - strategy: - fail-fast: false # Let each build finish. - matrix: - target: - - 'bin-Fedora' - - 'bin-Ubuntu-jammy' - - 'bin-Ubuntu-noble' - - 'bin-Ubuntu-resolute' - steps: - - name: Git checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.ref }} - fetch-depth: 0 - - - name: Build environment setup - run: | - distribution=$(echo ${{ matrix.target }} | cut -d'-' -f3) - echo "Building base image for ${distribution}" - sudo docker run --rm -v $(pwd):/build ubuntu:${distribution} bash -c "\ - apt-get update && \ - apt-get install -y debootstrap && \ - debootstrap ${distribution} /build/${distribution}" - sudo tar -C ${distribution} -c . | docker import - ${distribution} - - # Build Docker image - docker build -t cl-repro-${distribution} - < contrib/reprobuild/Dockerfile.${distribution} - if: contains(matrix.target, 'Ubuntu') - - - name: Build release - run: | - # Allow build release to execute if manually triggered for testing - if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.skip_validation }}" == "true" ]]; then - tools/build-release.sh ${{ matrix.target }} --force-version "${{ env.version }}" --force-unclean --force-mtime "$(date +%Y-%m-%d)" - else - tools/build-release.sh ${{ matrix.target }} - fi - - - name: Upload target artifacts - uses: actions/upload-artifact@v7 - with: - path: release/ - name: ${{ matrix.target }} - if-no-files-found: error - - artifact: - name: Construct release artifact - needs: - - check - - releases - env: - version: ${{ needs.check.outputs.version }} - runs-on: ubuntu-24.04 - steps: - - name: Merge artifacts - uses: actions/upload-artifact/merge@v7 - with: - name: c-lightning-${{ env.version }} - pattern: bin-* - delete-merged: true - - release: - name: Sign and prepare release draft - needs: - - check - - artifact - env: - version: ${{ needs.check.outputs.version }} - runs-on: ubuntu-24.04 - steps: - - name: Git checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.ref }} - fetch-depth: 0 - - - name: Download artifact - uses: actions/download-artifact@v8 - with: - name: c-lightning-${{ env.version }} - path: release/ - - - name: Import GPG keys - id: gpg - uses: crazy-max/ghaction-import-gpg@v7 - with: - gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.GPG_PASSPHRASE }} - trust_level: 5 - - - name: Set default GPG key - run: echo "default-key ${{ steps.gpg.outputs.keyid }}" >> ~/.gnupg/gpg.conf - - - name: Sign release - run: tools/build-release.sh --without-zip sign - - - name: Upload signed artifact - uses: actions/upload-artifact@v7 - with: - name: c-lightning-${{ env.version }} - overwrite: true - path: release/ - - - name: Determine release data - id: release_data - run: | - VERSION=${{ env.version }} - CHANGELOG_VERSION=${VERSION#v} - echo "CHANGELOG_VERSION=$CHANGELOG_VERSION" - echo "changelog_version=$CHANGELOG_VERSION" >> "$GITHUB_OUTPUT" - - CHANGELOG_TITLE=$(grep "## \[${CHANGELOG_VERSION}\]" CHANGELOG.md) - echo "CHANGELOG_TITLE=$CHANGELOG_TITLE" - echo "changelog_title=$CHANGELOG_TITLE" >> "$GITHUB_OUTPUT" - - RELEASE_TITLE=$(echo $CHANGELOG_TITLE | cut -d'"' -f2) - echo "RELEASE_TITLE=$RELEASE_TITLE" - echo "release_title=$RELEASE_TITLE" >> "$GITHUB_OUTPUT" - - - name: Prepare release draft - if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.create_release) }} - uses: softprops/action-gh-release@v3 - with: - name: "${{ env.version }} ${{ steps.release_data.outputs.release_title }}" - tag_name: ${{ env.version }} - draft: true - prerelease: contains(env.version, "-rc") - files: release/* - fail_on_unmatched_files: true + release-publish: + name: Release sign + draft + needs: [check-version, gate] + uses: ./.github/workflows/release-publish.yml + with: + version: ${{ needs.check-version.outputs.version }} + create_release: ${{ github.event.inputs.create_release == 'true' }} + secrets: inherit