# Build, verify and publish Linux packages from the pre-built xrpld and # validator-keys artifacts, in three stages: # # - 'package' builds and signs one format per config that carries a "package" # map in linux.json; that map names the container image and the format # - 'test-install-deb' and 'test-install-rpm' call # reusable-package-test-install.yml to install what was built on a range of # distros and run the binaries there, so a package that cannot be installed # never reaches Nexus # - 'publish' uploads with the image's publish_pkg.py, doing a --dry-run # unless 'publish: true' # # Only linux/amd64 is supported; the runner is hardcoded in the jobs below. name: Package on: workflow_call: inputs: publish: description: "Whether to publish the packages after building them." required: false type: boolean default: false nexus_url: description: "The base URL of the Nexus instance hosting the deb and rpm repositories." required: false type: string default: https://packages-upload.xrplf.org secrets: remote_username: description: "The username of a Nexus account with write access to the repositories." required: false remote_password: description: "The password or token for that Nexus account." required: false signing_key: description: "Armoured PGP private key used to sign the RPMs. Required when publishing." required: false defaults: run: shell: bash env: BUILD_DIR: build PACKAGE_DIR: packages jobs: generate-matrix: runs-on: ubuntu-latest outputs: matrix: ${{ steps.generate.outputs.matrix }} deb_package_names: ${{ steps.generate.outputs.deb_package_names }} rpm_package_names: ${{ steps.generate.outputs.rpm_package_names }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.13" - name: Generate packaging matrix id: generate working-directory: .github/scripts/strategy-matrix run: ./generate.py --packaging >>"${GITHUB_OUTPUT}" package: needs: [generate-matrix] if: ${{ github.event.repository.visibility == 'public' || startsWith(github.ref, 'refs/tags/') }} strategy: fail-fast: false matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} name: "${{ matrix.xrpld_artifact_name }}" permissions: contents: read runs-on: ["self-hosted", "Linux", "X64", "heavy"] container: ${{ matrix.image }} timeout-minutes: 10 steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Prepare runner uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 with: enable_ccache: false - name: Download pre-built xrpld binary uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ matrix.xrpld_artifact_name }} path: ${{ env.BUILD_DIR }} - name: Download pre-built validator-keys binary uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ matrix.validator_keys_artifact_name }} path: ${{ env.BUILD_DIR }} - name: Make binaries executable run: chmod +x "${BUILD_DIR}/xrpld" "${BUILD_DIR}/validator-keys" - name: Determine release info id: release_info uses: ./.github/actions/release-info - name: Build package env: PACKAGE_TYPE: ${{ matrix.package_type }} PACKAGE_VARIANT: ${{ matrix.package_variant }} PKG_RELEASE: ${{ steps.release_info.outputs.pkg_release }} CHANNEL: ${{ steps.release_info.outputs.channel }} run: | ./package/build_pkg.py \ --package-type "${PACKAGE_TYPE}" \ --build-dir "${BUILD_DIR}" \ --pkg-release "${PKG_RELEASE}" \ --variant "${PACKAGE_VARIANT}" \ --channel "${CHANNEL}" # Before the upload, so the artifact, the tested package and the published # package are the same bytes. - name: Sign RPM if: ${{ inputs.publish && matrix.package_type == 'rpm' }} env: PKG_SIGNING_KEY: ${{ secrets.signing_key }} run: ./package/sign_rpm.py --package-dir "${BUILD_DIR}" # Split from the debug symbols, which are an order of magnitude larger, so # that test-install downloads only what it installs. In the globs below the # version follows the name, separated by '_' in a DEB and '-' in an RPM. A # version starts with a digit and a longer name does not, so that one digit # is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'. - name: Upload package artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.xrpld_artifact_name }}-pkg path: | ${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}_[0-9]*.deb ${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-[0-9]*.rpm if-no-files-found: error - name: Upload debug symbol artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.xrpld_artifact_name }}-pkg-debug path: | ${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.deb ${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.ddeb ${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-debuginfo-[0-9]*.rpm if-no-files-found: error # One call per format, so a variant packaged for one format is installed for # that format alone. The images are every distro family that format targets, # oldest release first, so both ends of the dependency range the packages # declare are exercised. test-install-deb: needs: [generate-matrix, package] name: install deb uses: ./.github/workflows/reusable-package-test-install.yml with: package_type: deb package_names: ${{ needs.generate-matrix.outputs.deb_package_names }} images: | [ "debian:11", "debian:12", "debian:13", "ubuntu:20.04", "ubuntu:22.04", "ubuntu:24.04", "ubuntu:26.04" ] test-install-rpm: needs: [generate-matrix, package] name: install rpm uses: ./.github/workflows/reusable-package-test-install.yml with: package_type: rpm package_names: ${{ needs.generate-matrix.outputs.rpm_package_names }} images: | [ "almalinux:9", "almalinux:10", "rockylinux/rockylinux:9", "rockylinux/rockylinux:10", "registry.access.redhat.com/ubi9/ubi", "registry.access.redhat.com/ubi10/ubi" ] publish: needs: [generate-matrix, package, test-install-deb, test-install-rpm] strategy: fail-fast: false matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} # The name says which of the two this is, because the job runs either way: # with publish false it passes --dry-run and uploads nothing, and a job # called "publish ..." succeeding on a pull request reads like a release. name: "publish ${{ matrix.xrpld_artifact_name }}${{ !inputs.publish && ' (dry run)' || '' }}" permissions: contents: read runs-on: ["self-hosted", "Linux", "X64", "heavy"] container: ${{ matrix.image }} timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Prepare runner uses: XRPLF/actions/prepare-runner@b3e255d74d785d053e4903da8ac90983cd7d9e82 with: enable_ccache: false # Both artifacts, so the debug symbols are published alongside the package. - name: Download package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: ${{ matrix.xrpld_artifact_name }}-pkg* merge-multiple: true path: ${{ env.PACKAGE_DIR }} - name: Determine release info id: release_info uses: ./.github/actions/release-info - name: Publish package env: CHANNEL: ${{ steps.release_info.outputs.channel }} DRY_RUN_OPTION: ${{ !inputs.publish && '--dry-run' || '' }} NEXUS_URL: ${{ inputs.nexus_url }} NEXUS_USERNAME: ${{ inputs.publish && secrets.remote_username || '' }} NEXUS_PASSWORD: ${{ inputs.publish && secrets.remote_password || '' }} run: | publish_pkg.py \ --channel "${CHANNEL}" \ --package-dir "${PACKAGE_DIR}" \ --nexus-url "${NEXUS_URL}" \ ${DRY_RUN_OPTION}