From 57cf2783b6d8088bfe8066d7ca85d9f8cf071bc9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:10:52 +0000 Subject: [PATCH 1/7] ci: use helper script to bundle artifacts --- .github/workflows/build-src.yml | 23 ++++++++++-- ci/dash/bundle-artifacts.sh | 64 ++++++++++++++++++++++++++++++++ contrib/containers/ci/Dockerfile | 1 + 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100755 ci/dash/bundle-artifacts.sh diff --git a/.github/workflows/build-src.yml b/.github/workflows/build-src.yml index 1383c4e21959..67a363975a45 100644 --- a/.github/workflows/build-src.yml +++ b/.github/workflows/build-src.yml @@ -15,11 +15,17 @@ on: description: "Key needed to access cached depends" required: true type: string + outputs: + key: + description: "Key needed for restoring artifacts bundle" + value: ${{ jobs.build-src.outputs.key }} jobs: build-src: name: Build source runs-on: ubuntu-24.04 + outputs: + key: ${{ steps.bundle.outputs.key }} container: image: ${{ inputs.container-path }} options: --user root @@ -89,9 +95,20 @@ jobs: ./ci/dash/test_unittests.sh shell: bash - - name: Upload build artifacts + - name: Bundle artifacts + id: bundle + run: | + export BUILD_TARGET="${{ inputs.build-target }}" + export BUNDLE_KEY="build-${BUILD_TARGET}-$(git rev-parse --short=8 HEAD)" + ./ci/dash/bundle-artifacts.sh create + echo "key=${BUNDLE_KEY}" >> "${GITHUB_OUTPUT}" + + - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: build-artifacts-${{ inputs.build-target }} + name: ${{ steps.bundle.outputs.key }} path: | - /output + ${{ steps.bundle.outputs.key }}.tar.zst + compression-level: 0 + overwrite: true + retention-days: 3 diff --git a/ci/dash/bundle-artifacts.sh b/ci/dash/bundle-artifacts.sh new file mode 100755 index 000000000000..4bae884b791e --- /dev/null +++ b/ci/dash/bundle-artifacts.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# Copyright (c) 2024-2025 The Dash Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +set -eo pipefail + +SH_NAME="$(basename "${0}")" +VERB="${1}" + +if [ -z "${BUILD_TARGET}" ]; then + echo "${SH_NAME}: BUILD_TARGET not defined, cannot continue!"; + exit 1; +elif [ -z "${BUNDLE_KEY}" ]; then + echo "${SH_NAME}: BUNDLE_KEY not defined, cannot continue!"; + exit 1; +elif [ ! "$(command -v zstd)" ]; then + echo "${SH_NAME}: zstd not found, cannot continue!"; + exit 1; +elif [ -z "${VERB}" ]; then + echo "${SH_NAME}: Verb missing, acceptable values 'create' or 'extract'"; + exit 1; +elif [ "${VERB}" != "create" ] && [ "${VERB}" != "extract" ]; then + echo "${SH_NAME}: Invalid verb '${VERB}', expected 'create' or 'extract'"; + exit 1; +fi + +OUTPUT_ARCHIVE="${BUNDLE_KEY}.tar.zst" +if [ -f "${OUTPUT_ARCHIVE}" ] && [ "${VERB}" = "create" ]; then + echo "${SH_NAME}: ${OUTPUT_ARCHIVE} already exists, cannot continue!"; + exit 1; +elif [ ! -f "${OUTPUT_ARCHIVE}" ] && [ "${VERB}" = "extract" ]; then + echo "${SH_NAME}: ${OUTPUT_ARCHIVE} missing, cannot continue!"; + exit 1; +fi + +if [ "${VERB}" = "create" ]; then + EXCLUSIONS=( + "*.a" + "*.o" + "build-ci/dashcore-${BUILD_TARGET}/src/bench/bench_dash" + "build-ci/dashcore-${BUILD_TARGET}/src/bench/bench_dash.exe" + "build-ci/dashcore-${BUILD_TARGET}/src/qt/test/test_dash-qt" + "build-ci/dashcore-${BUILD_TARGET}/src/qt/test/test_dash-qt.exe" + "build-ci/dashcore-${BUILD_TARGET}/src/test/test_dash" + "build-ci/dashcore-${BUILD_TARGET}/src/test/test_dash.exe" + "build-ci/dashcore-${BUILD_TARGET}/src/test/fuzz/fuzz" + ) + EXCLUSIONS_ARG="" + for excl in "${EXCLUSIONS[@]}" + do + EXCLUSIONS_ARG+=" --exclude=${excl}"; + done + + # shellcheck disable=SC2086 + tar ${EXCLUSIONS_ARG} --use-compress-program="zstd -T0 -5" -cf "${OUTPUT_ARCHIVE}" "build-ci"; +elif [ "${VERB}" = "extract" ]; then + tar --use-compress-program="unzstd" -xf "${OUTPUT_ARCHIVE}"; +else + echo "${SH_NAME}: Generic error"; + exit 1; +fi diff --git a/contrib/containers/ci/Dockerfile b/contrib/containers/ci/Dockerfile index d642ffc3984d..cdce794c5731 100644 --- a/contrib/containers/ci/Dockerfile +++ b/contrib/containers/ci/Dockerfile @@ -184,6 +184,7 @@ RUN apt-get update && apt-get install $APT_ARGS \ wine-stable \ wine64 \ zip \ + zstd \ && rm -rf /var/lib/apt/lists/* # Make sure std::thread and friends is available From 0a1e6350220c233abd86dfe73139523ca3339a60 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 25 Feb 2025 11:09:31 +0000 Subject: [PATCH 2/7] ci: add reusable workflow for running functional tests --- .github/workflows/test-src.yml | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/test-src.yml diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml new file mode 100644 index 000000000000..de9739cef9d6 --- /dev/null +++ b/.github/workflows/test-src.yml @@ -0,0 +1,49 @@ +name: Test source + +on: + workflow_call: + inputs: + bundle-key: + description: "Key needed to access bundle of artifacts" + required: true + type: string + build-target: + description: "Target name as defined by inputs.sh" + required: true + type: string + container-path: + description: "Path to built container at registry" + required: true + type: string + +env: + INTEGRATION_TESTS_ARGS: "--extended --exclude feature_pruning,feature_dbcrash" + +jobs: + test-src: + name: Test source + runs-on: ubuntu-24.04 + container: + image: ${{ inputs.container-path }} + options: --user root + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 1 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.bundle-key }} + + - name: Run functional tests + run: | + git config --global --add safe.directory "$PWD" + export BUILD_TARGET="${{ inputs.build-target }}" + export BUNDLE_KEY="${{ inputs.bundle-key }}" + ./ci/dash/bundle-artifacts.sh extract + source ./ci/dash/matrix.sh + ./ci/dash/test_integrationtests.sh ${INTEGRATION_TESTS_ARGS} + shell: bash From b25e8462f703a717ab5ccbbb0f8cb8bc0e93c0f9 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:54:19 +0000 Subject: [PATCH 3/7] ci: handle space exhaustion by deleting files we don't need --- .github/workflows/test-src.yml | 1 + ci/dash/bundle-artifacts.sh | 9 ++------ ci/dash/slim-workspace.sh | 41 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100755 ci/dash/slim-workspace.sh diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml index de9739cef9d6..8e252febfe3f 100644 --- a/.github/workflows/test-src.yml +++ b/.github/workflows/test-src.yml @@ -44,6 +44,7 @@ jobs: export BUILD_TARGET="${{ inputs.build-target }}" export BUNDLE_KEY="${{ inputs.bundle-key }}" ./ci/dash/bundle-artifacts.sh extract + ./ci/dash/slim-workspace.sh source ./ci/dash/matrix.sh ./ci/dash/test_integrationtests.sh ${INTEGRATION_TESTS_ARGS} shell: bash diff --git a/ci/dash/bundle-artifacts.sh b/ci/dash/bundle-artifacts.sh index 4bae884b791e..4dee64717933 100755 --- a/ci/dash/bundle-artifacts.sh +++ b/ci/dash/bundle-artifacts.sh @@ -40,13 +40,8 @@ if [ "${VERB}" = "create" ]; then EXCLUSIONS=( "*.a" "*.o" - "build-ci/dashcore-${BUILD_TARGET}/src/bench/bench_dash" - "build-ci/dashcore-${BUILD_TARGET}/src/bench/bench_dash.exe" - "build-ci/dashcore-${BUILD_TARGET}/src/qt/test/test_dash-qt" - "build-ci/dashcore-${BUILD_TARGET}/src/qt/test/test_dash-qt.exe" - "build-ci/dashcore-${BUILD_TARGET}/src/test/test_dash" - "build-ci/dashcore-${BUILD_TARGET}/src/test/test_dash.exe" - "build-ci/dashcore-${BUILD_TARGET}/src/test/fuzz/fuzz" + ".deps" + ".libs" ) EXCLUSIONS_ARG="" for excl in "${EXCLUSIONS[@]}" diff --git a/ci/dash/slim-workspace.sh b/ci/dash/slim-workspace.sh new file mode 100755 index 000000000000..1a3aa3a60189 --- /dev/null +++ b/ci/dash/slim-workspace.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Copyright (c) 2025 The Dash Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +set -eo pipefail + +SH_NAME="$(basename "${0}")" + +if [ -z "${BUILD_TARGET}" ]; then + echo "${SH_NAME}: BUILD_TARGET not defined, cannot continue!"; + exit 1; +elif [ -z "${BUNDLE_KEY}" ]; then + echo "${SH_NAME}: BUNDLE_KEY not defined, cannot continue!"; + exit 1; +fi + +TARGETS=( + # Bundle restored from artifact + "${BUNDLE_KEY}.tar.zst" + # Binaries not needed by functional tests + "build-ci/dashcore-${BUILD_TARGET}/src/dash-tx" + "build-ci/dashcore-${BUILD_TARGET}/src/bench/bench_dash" + "build-ci/dashcore-${BUILD_TARGET}/src/qt/dash-qt" + "build-ci/dashcore-${BUILD_TARGET}/src/qt/test/test_dash-qt" + "build-ci/dashcore-${BUILD_TARGET}/src/test/test_dash" + "build-ci/dashcore-${BUILD_TARGET}/src/test/fuzz/fuzz" + # Misc. files that can be heavy + "build-ci/dashcore-${BUILD_TARGET}/src/qt/qrc_bitcoin.cpp" + "build-ci/dashcore-${BUILD_TARGET}/src/qt/qrc_dash_locale.cpp" +) + +# Delete directories we don't need +for target in "${TARGETS[@]}" +do + if [[ -d "${target}" ]] || [[ -f "${target}" ]]; then + rm -rf "${target}"; + fi +done From fc2efb6ea97d9a5c9cb90d060c0849f956fe44d7 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 19:45:04 +0000 Subject: [PATCH 4/7] ci: upload functional test logs as artifacts We want logs even if tests fail, so we need some extra logic. Also, we shouldn't create artifacts if there's nothing to upload, so there's extra logic for that too. --- .github/workflows/test-src.yml | 25 +++++++++++++++++++++++++ ci/dash/bundle-logs.sh | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100755 ci/dash/bundle-logs.sh diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml index 8e252febfe3f..cfda55e39880 100644 --- a/.github/workflows/test-src.yml +++ b/.github/workflows/test-src.yml @@ -39,6 +39,7 @@ jobs: name: ${{ inputs.bundle-key }} - name: Run functional tests + id: test run: | git config --global --add safe.directory "$PWD" export BUILD_TARGET="${{ inputs.build-target }}" @@ -48,3 +49,27 @@ jobs: source ./ci/dash/matrix.sh ./ci/dash/test_integrationtests.sh ${INTEGRATION_TESTS_ARGS} shell: bash + + - name: Bundle test logs + id: bundle + if: success() || (failure() && steps.test.outcome == 'failure') + run: | + export BUILD_TARGET="${{ inputs.build-target }}" + echo "short-sha=$(git rev-parse --short=8 HEAD)" >> "${GITHUB_OUTPUT}" + ( [ -d "testlogs" ] && echo "upload-logs=true" >> "${GITHUB_OUTPUT}" && ./ci/dash/bundle-logs.sh ) \ + || echo "upload-logs=false" >> "${GITHUB_OUTPUT}" + shell: bash + + - name: Upload test logs + uses: actions/upload-artifact@v4 + if: | + success() || (failure() && steps.test.outcome == 'failure') + && steps.bundle.outputs.upload-logs == 'true' + with: + name: test_logs-${{ inputs.build-target }}-${{ steps.bundle.outputs.short-sha }} + path: | + test_logs-${{ inputs.build-target }}.tar.zst + test_logs-${{ inputs.build-target }}.tar.zst.sha256 + compression-level: 0 + overwrite: true + retention-days: 1 diff --git a/ci/dash/bundle-logs.sh b/ci/dash/bundle-logs.sh new file mode 100755 index 000000000000..f2c022a7a929 --- /dev/null +++ b/ci/dash/bundle-logs.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Copyright (c) 2025 The Dash Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +set -eo pipefail + +SH_NAME="$(basename "${0}")" +LOG_DIRECTORY="testlogs" + +if [ ! -d "${LOG_DIRECTORY}" ]; then + echo "${SH_NAME}: '${LOG_DIRECTORY}' directory missing, will skip!"; + exit 0; +elif [ -z "${BUILD_TARGET}" ]; then + echo "${SH_NAME}: BUILD_TARGET not defined, cannot continue!"; + exit 1; +fi + +LOG_ARCHIVE="test_logs-${BUILD_TARGET}.tar.zst" +if [ -f "${LOG_ARCHIVE}" ]; then + echo "${SH_NAME}: ${LOG_ARCHIVE} already exists, cannot continue!"; + exit 1; +fi + +tar --use-compress-program="zstd -T0 -5" -cf "${LOG_ARCHIVE}" "${LOG_DIRECTORY}" +sha256sum "${LOG_ARCHIVE}" > "${LOG_ARCHIVE}.sha256"; From cca0d89b096dd3327d5b5f5f1e7619e34141935b Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 24 Feb 2025 20:49:57 +0000 Subject: [PATCH 5/7] ci: add functional tests for linux builds --- .github/workflows/build.yml | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6b14bf2dfa1e..3ac8fa8a7c94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -154,3 +154,57 @@ jobs: build-target: win64 container-path: ${{ needs.container.outputs.path }} depends-key: ${{ needs.depends-win64.outputs.key }} + + test-linux64: + name: linux64-test + uses: ./.github/workflows/test-src.yml + needs: [container, depends-linux64, src-linux64] + with: + bundle-key: ${{ needs.src-linux64.outputs.key }} + build-target: linux64 + container-path: ${{ needs.container.outputs.path }} + + test-linux64_multiprocess: + name: linux64_multiprocess-test + uses: ./.github/workflows/test-src.yml + needs: [container, depends-linux64_multiprocess, src-linux64_multiprocess] + with: + bundle-key: ${{ needs.src-linux64_multiprocess.outputs.key }} + build-target: linux64_multiprocess + container-path: ${{ needs.container.outputs.path }} + + test-linux64_nowallet: + name: linux64_nowallet-test + uses: ./.github/workflows/test-src.yml + needs: [container, depends-linux64_nowallet, src-linux64_nowallet] + with: + bundle-key: ${{ needs.src-linux64_nowallet.outputs.key }} + build-target: linux64_nowallet + container-path: ${{ needs.container.outputs.path }} + + test-linux64_sqlite: + name: linux64_sqlite-test + uses: ./.github/workflows/test-src.yml + needs: [container, depends-linux64, src-linux64_sqlite] + with: + bundle-key: ${{ needs.src-linux64_sqlite.outputs.key }} + build-target: linux64_sqlite + container-path: ${{ needs.container.outputs.path }} + + test-linux64_tsan: + name: linux64_tsan-test + uses: ./.github/workflows/test-src.yml + needs: [container, depends-linux64_multiprocess, src-linux64_tsan] + with: + bundle-key: ${{ needs.src-linux64_tsan.outputs.key }} + build-target: linux64_tsan + container-path: ${{ needs.container.outputs.path }} + + test-linux64_ubsan: + name: linux64_ubsan-test + uses: ./.github/workflows/test-src.yml + needs: [container, depends-linux64, src-linux64_ubsan] + with: + bundle-key: ${{ needs.src-linux64_ubsan.outputs.key }} + build-target: linux64_ubsan + container-path: ${{ needs.container.outputs.path }} From 5db8fa0d539498f66a8259e063010823ea8a05e7 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 16 Feb 2025 15:37:04 +0000 Subject: [PATCH 6/7] ci: cache previous releases if running `linux64` variant We don't offer alternate restore keys because get_previous_releases.py bails if it already finds a 'releases' directory present, so a cache miss is desirable to allow the script to re-fetch them. --- .github/workflows/test-src.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/test-src.yml b/.github/workflows/test-src.yml index cfda55e39880..62e47d0152ee 100644 --- a/.github/workflows/test-src.yml +++ b/.github/workflows/test-src.yml @@ -38,6 +38,14 @@ jobs: with: name: ${{ inputs.bundle-key }} + - name: Manage releases cache + uses: actions/cache@v4 + if: inputs.build-target == 'linux64' + with: + path: | + releases + key: releases-${{ hashFiles('ci/test/00_setup_env_native_qt5.sh', 'test/get_previous_releases.py') }} + - name: Run functional tests id: test run: | From 3461c14155f99fa0981b3b412fb4a8b084123d07 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 16 Feb 2025 19:06:48 +0000 Subject: [PATCH 7/7] ci: tentatively drop multiprocess and tsan functional tests Currently, we are experiencing issues surrounding exhausting disk space during the log collection of these runs. While actions exist to free up space on the runner, they are unusable when the job runs in a container context nor are deleting files a viable way to get by, we will drop this for now until a remedy for this can be figured out. --- .github/workflows/build.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3ac8fa8a7c94..8b3ba8921780 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -164,15 +164,6 @@ jobs: build-target: linux64 container-path: ${{ needs.container.outputs.path }} - test-linux64_multiprocess: - name: linux64_multiprocess-test - uses: ./.github/workflows/test-src.yml - needs: [container, depends-linux64_multiprocess, src-linux64_multiprocess] - with: - bundle-key: ${{ needs.src-linux64_multiprocess.outputs.key }} - build-target: linux64_multiprocess - container-path: ${{ needs.container.outputs.path }} - test-linux64_nowallet: name: linux64_nowallet-test uses: ./.github/workflows/test-src.yml @@ -191,15 +182,6 @@ jobs: build-target: linux64_sqlite container-path: ${{ needs.container.outputs.path }} - test-linux64_tsan: - name: linux64_tsan-test - uses: ./.github/workflows/test-src.yml - needs: [container, depends-linux64_multiprocess, src-linux64_tsan] - with: - bundle-key: ${{ needs.src-linux64_tsan.outputs.key }} - build-target: linux64_tsan - container-path: ${{ needs.container.outputs.path }} - test-linux64_ubsan: name: linux64_ubsan-test uses: ./.github/workflows/test-src.yml