diff --git a/.github/workflows/bitcoin-tests.yml b/.github/workflows/bitcoin-tests.yml index 9aba4e625..48e53915c 100644 --- a/.github/workflows/bitcoin-tests.yml +++ b/.github/workflows/bitcoin-tests.yml @@ -1,205 +1,100 @@ -## -## Bitcoin Integration Tests -## +## Github workflow to run bitcoin tests -name: Bitcoin Integration Tests - -# Only run when: -# - PRs are (re)opened against master branch +name: Tests::Bitcoin on: - pull_request: - types: - - opened - - reopened + workflow_call: + +defaults: + run: + shell: bash + +## env vars are transferred to composite action steps +env: + BITCOIND_TEST: 1 + RUST_BACKTRACE: full + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 15 + RETRIES: 3 + RETRY_DELAY: 10000 + TEST_TIMEOUT: 30 + TEST_RETRIES: 2 concurrency: - group: stacks-bitcoin-integration-tests-${{ github.ref }} - # Only cancel in progress if this is for a PR + group: bitcoin-tests-${{ github.head_ref || github.ref || github.run_id}} + ## Only cancel in progress if this is for a PR cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - # Create bitcoin image used for later tests - build-integration-image: - name: Build Image + # Bitcoin integration tests with code coverage + integration-tests: + name: Integration Tests runs-on: ubuntu-latest - steps: - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - - - name: Reclaim disk space - id: cleanup - run: | - sudo apt-get update - sudo apt-get remove -y '^dotnet-.*' - sudo apt-get remove -y '^llvm-.*' - sudo apt-get remove -y 'php.*' - sudo apt-get remove -y '^mongodb-.*' - sudo apt-get remove -y '^mysql-.*' - sudo apt-get autoremove -y - sudo apt-get clean - docker system prune --force - - - name: Build bitcoin integration testing image - id: build_docker_image - env: - DOCKER_BUILDKIT: 1 - # Remove .dockerignore file so codecov has access to git info and build the image - run: | - rm .dockerignore - docker build -f ./.github/actions/bitcoin-int-tests/Dockerfile.generic.bitcoin-tests -t stacks-blockchain:integrations . - - - name: Export docker image as tarball - id: export_docker_image - run: docker save stacks-blockchain:integrations | gzip > integration-image.tar.gz - - - name: Upload built docker image - id: upload_docker_image - uses: actions/upload-artifact@v3 - with: - name: integration-image.tar.gz - path: integration-image.tar.gz - - # Run integration tests using sampled genesis block - sampled-genesis: - name: Sampled Genesis - runs-on: ubuntu-latest - needs: - - build-integration-image strategy: + ## Continue with the test matrix even if we've had a failure fail-fast: false + ## Run a maximum of 32 concurrent tests from the test matrix + max-parallel: 32 matrix: test-name: - - tests::neon_integrations::miner_submit_twice - - tests::neon_integrations::microblock_integration_test - - tests::neon_integrations::microblock_fork_poison_integration_test - - tests::neon_integrations::size_check_integration_test - - tests::neon_integrations::cost_voting_integration - - tests::integrations::integration_test_get_info - - tests::neon_integrations::bitcoind_integration_test - - tests::neon_integrations::liquid_ustx_integration - - tests::neon_integrations::stx_transfer_btc_integration_test - - tests::neon_integrations::stx_delegate_btc_integration_test - - tests::neon_integrations::bitcoind_forking_test - - tests::neon_integrations::should_fix_2771 - - tests::neon_integrations::pox_integration_test - - tests::neon_integrations::mining_events_integration_test - tests::bitcoin_regtest::bitcoind_integration_test - - tests::should_succeed_handling_malformed_and_valid_txs + - tests::integrations::integration_test_get_info + - tests::neon_integrations::antientropy_integration_test ## forced failure + - tests::neon_integrations::bad_microblock_pubkey + - tests::neon_integrations::bitcoind_forking_test + - tests::neon_integrations::bitcoind_integration_test + - tests::neon_integrations::block_large_tx_integration_test + - tests::neon_integrations::block_limit_hit_integration_test + - tests::neon_integrations::cost_voting_integration + - tests::neon_integrations::filter_long_runtime_tx_integration_test + - tests::neon_integrations::filter_low_fee_tx_integration_test + - tests::neon_integrations::fuzzed_median_fee_rate_estimation_test_window10 + - tests::neon_integrations::fuzzed_median_fee_rate_estimation_test_window5 + - tests::neon_integrations::liquid_ustx_integration + - tests::neon_integrations::microblock_fork_poison_integration_test + - tests::neon_integrations::microblock_integration_test + - tests::neon_integrations::microblock_large_tx_integration_test_FLAKY + - tests::neon_integrations::microblock_limit_hit_integration_test + - tests::neon_integrations::miner_submit_twice + - tests::neon_integrations::mining_events_integration_test + - tests::neon_integrations::pox_integration_test + - tests::neon_integrations::push_boot_receipts + - tests::neon_integrations::runtime_overflow_unconfirmed_microblocks_integration_test + - tests::neon_integrations::should_fix_2771 + - tests::neon_integrations::size_check_integration_test + - tests::neon_integrations::size_overflow_unconfirmed_invalid_stream_microblocks_integration_test - tests::neon_integrations::size_overflow_unconfirmed_microblocks_integration_test - tests::neon_integrations::size_overflow_unconfirmed_stream_microblocks_integration_test - - tests::neon_integrations::size_overflow_unconfirmed_invalid_stream_microblocks_integration_test - - tests::neon_integrations::runtime_overflow_unconfirmed_microblocks_integration_test - - tests::neon_integrations::antientropy_integration_test - - tests::neon_integrations::filter_low_fee_tx_integration_test - - tests::neon_integrations::filter_long_runtime_tx_integration_test - - tests::neon_integrations::microblock_large_tx_integration_test_FLAKY - - tests::neon_integrations::block_large_tx_integration_test - - tests::neon_integrations::microblock_limit_hit_integration_test - - tests::neon_integrations::block_limit_hit_integration_test - - tests::neon_integrations::fuzzed_median_fee_rate_estimation_test_window5 - - tests::neon_integrations::fuzzed_median_fee_rate_estimation_test_window10 - - tests::neon_integrations::use_latest_tip_integration_test - - tests::neon_integrations::test_flash_block_skip_tenure + - tests::neon_integrations::stx_delegate_btc_integration_test + - tests::neon_integrations::stx_transfer_btc_integration_test - tests::neon_integrations::test_chainwork_first_intervals - tests::neon_integrations::test_chainwork_partial_interval - - tests::neon_integrations::test_problematic_txs_are_not_stored + - tests::neon_integrations::test_flash_block_skip_tenure - tests::neon_integrations::test_problematic_blocks_are_not_mined - tests::neon_integrations::test_problematic_blocks_are_not_relayed_or_stored - tests::neon_integrations::test_problematic_microblocks_are_not_mined - tests::neon_integrations::test_problematic_microblocks_are_not_relayed_or_stored - - tests::neon_integrations::push_boot_receipts - - tests::epoch_205::test_dynamic_db_method_costs - - tests::epoch_205::transition_empty_blocks - - tests::epoch_205::test_cost_limit_switch_version205 - - tests::epoch_205::test_exact_block_costs - - tests::epoch_205::bigger_microblock_streams_in_2_05 - - tests::epoch_21::transition_adds_burn_block_height - - tests::epoch_21::transition_fixes_bitcoin_rigidity - - tests::epoch_21::transition_adds_pay_to_contract - - tests::epoch_21::transition_adds_get_pox_addr_recipients - - tests::epoch_21::transition_adds_mining_from_segwit - - tests::epoch_21::transition_removes_pox_sunset - - tests::epoch_21::transition_empty_blocks - - tests::epoch_21::test_pox_reorgs_three_flaps - - tests::epoch_21::test_pox_reorg_one_flap - - tests::epoch_21::test_pox_reorg_flap_duel - - tests::epoch_21::test_pox_reorg_flap_reward_cycles - - tests::epoch_21::test_pox_missing_five_anchor_blocks - - tests::epoch_21::test_sortition_divergence_pre_21 - - tests::epoch_21::test_v1_unlock_height_with_current_stackers - - tests::epoch_21::test_v1_unlock_height_with_delay_and_current_stackers - - tests::epoch_21::trait_invocation_cross_epoch - - tests::epoch_22::pox_2_unlock_all - - tests::epoch_22::disable_pox - - tests::epoch_22::test_pox_reorg_one_flap - - tests::epoch_23::trait_invocation_behavior - - tests::neon_integrations::bad_microblock_pubkey - - tests::epoch_24::fix_to_pox_contract - - tests::epoch_24::verify_auto_unlock_behavior + - tests::neon_integrations::test_problematic_txs_are_not_stored + - tests::neon_integrations::use_latest_tip_integration_test + - tests::should_succeed_handling_malformed_and_valid_txs steps: - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - - name: Download docker image - id: download_docker_image - uses: actions/download-artifact@v3 - with: - name: integration-image.tar.gz - - name: Load docker image - id: load_docker_image - run: docker load -i integration-image.tar.gz && rm integration-image.tar.gz - - name: All integration tests with sampled genesis - id: bitcoin_integration_tests - timeout-minutes: 30 - env: - DOCKER_BUILDKIT: 1 - TEST_NAME: ${{ matrix.test-name }} - run: docker build -o coverage-output --build-arg test_name=${{ matrix.test-name }} -f ./.github/actions/bitcoin-int-tests/Dockerfile.bitcoin-tests . - - name: Code Coverage - id: code_coverage - uses: codecov/codecov-action@v3 - with: - files: ./coverage-output/lcov.info - name: ${{ matrix.test-name }} - fail_ci_if_error: false + ## Setup test environment + - name: Setup Test Environment + id: setup_tests + uses: stacks-network/actions/stacks-core/testenv@main - # Run atlas integration tests - atlas-test: - name: Atlas Test - runs-on: ubuntu-latest - needs: - - build-integration-image - strategy: - fail-fast: false - matrix: - test-name: - - tests::neon_integrations::atlas_integration_test - - tests::neon_integrations::atlas_stress_integration_test - steps: - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - - name: Download docker image - id: download_docker_image - uses: actions/download-artifact@v3 + ## Run test matrix using restored cache of archive file + ## - Test will timeout after env.TEST_TIMEOUT minutes + - name: Run Tests + id: run_tests + timeout-minutes: ${{ fromJSON(env.TEST_TIMEOUT) }} + uses: stacks-network/actions/stacks-core/run-tests@main with: - name: integration-image.tar.gz - - name: Load docker image - id: load_docker_image - run: docker load -i integration-image.tar.gz && rm integration-image.tar.gz - - name: Atlas integration tests - id: atlas_integration_tests - timeout-minutes: 40 - env: - DOCKER_BUILDKIT: 1 - TEST_NAME: ${{ matrix.test-name }} - run: docker build -o coverage-output --build-arg test_name=${{ matrix.test-name }} -f ./.github/actions/bitcoin-int-tests/Dockerfile.bitcoin-tests . + test-name: ${{ matrix.test-name }} + threads: 1 + + ## Create and upload code coverage file - name: Code Coverage - id: code_coverage - uses: codecov/codecov-action@v3 + id: codecov + uses: stacks-network/actions/codecov@main with: - files: ./coverage-output/lcov.info - name: ${{ matrix.test-name }} - fail_ci_if_error: false + test-name: ${{ matrix.test-name }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b72c9faf..907517226 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,180 +1,223 @@ +## The main Github Actions workflow name: CI -## Only run when: -## - manually triggered -## - PR's are (re)opened -## - push to master (i.e. merge develop -> master) - on: push: branches: - master - pull_request: + - develop + paths-ignore: + - "**.md" + - "**.yml" workflow_dispatch: inputs: tag: description: "The tag to create (optional)" required: false + pull_request_target: + types: + - opened + - reopened + - synchronize + paths-ignore: + - "**.md" + - "**.yml" + ## might be better to use inclusive v exclusive paths here, ex: + # paths: + # - "**.rs" + # - "**.clar" + pull_request_review: + types: + - submitted + +defaults: + run: + shell: bash concurrency: - group: ${{ github.head_ref || github.run_id }} + group: ci-${{ github.head_ref || github.ref }} + ## Always cancel duplicate jobs cancel-in-progress: true +run-name: ${{ inputs.tag }} + jobs: - ## rust format: Execute on every run + ## + ## Jobs to execute everytime workflow runs + ## do not run if the trigger is any of the following: + ## - PR review submitted (not approved) + ## and any of: + ## - PR review comment + ## - PR change is requested rustfmt: + if: | + !( + github.event_name == 'pull_request_review' && + github.event.action == 'submitted' && + ( + github.event.review.state == 'commented' || + github.event.review.state == 'changes_requested' + ) + ) name: Rust Format runs-on: ubuntu-latest steps: - name: Checkout the latest code id: git_checkout - uses: actions/checkout@v3 - - name: Define Rust Toolchain - id: define_rust_toolchain - run: echo "RUST_TOOLCHAIN=$(cat ./rust-toolchain)" >> $GITHUB_ENV + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Rust Toolchain id: setup_rust_toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 + uses: actions-rust-lang/setup-rust-toolchain@f3c84ee10bf5a86e7a5d607d487bf17d57670965 # v1.5.0 with: - toolchain: ${{ env.RUST_TOOLCHAIN }} components: rustfmt - - name: Rustfmt + cache: false + + - name: Rustfmt id: rustfmt - uses: actions-rust-lang/rustfmt@v1 + uses: actions-rust-lang/rustfmt@2d1d4e9f72379428552fa1def0b898733fb8472d # v1.1.0 - ## Release tests: Execute on every run - release-tests: - name: Release Tests - uses: stacks-network/stacks-blockchain/.github/workflows/stacks-blockchain-tests.yml@master - - ## Checked for leaked credentials: Execute on every run - leaked-cred-test: - name: Leaked Credential Test - runs-on: ubuntu-latest - steps: - - name: Extract branch name - id: extract_branch - if: ${{ github.event_name != 'pull_request' }} - run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV - - name: Extract branch name - id: extract_branch_pr - if: ${{ github.event_name == 'pull_request' }} - run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF})" >> $GITHUB_ENV - - name: Branch name - run: echo running on branch ${{ env.BRANCH_NAME }} - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: TruffleHog Scan - id: trufflehog_check - uses: trufflesecurity/trufflehog@main - with: - path: ./ - base: ${{ env.BRANCH_NAME }} - head: HEAD - - ############################################### - ## Build Tagged Release - ############################################### - ## Build source binaries - ## Only run if: - ## - Tag is provided - ## - OR - ## - Not the default branch - ## - AND - ## - Not a PR - build-source: - if: ${{ inputs.tag != '' || (github.ref != format('refs/heads/{0}', github.event.repository.default_branch) && !contains(github.ref, 'refs/pull')) }} - name: Build Binaries - uses: stacks-network/stacks-blockchain/.github/workflows/build-source-binary.yml@master + ###################################################################################### + ## Create a tagged github release + ## + ## Runs when the following is true: + ## - tag is provided + ## - workflow is building default branch (master) + create-release: + if: | + inputs.tag != '' && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + name: Create Release needs: - rustfmt - - release-tests - - leaked-cred-test + uses: ./.github/workflows/github-release.yml with: tag: ${{ inputs.tag }} - parallel_jobs: 4 - arch: >- - ["linux-glibc-x64", "linux-musl-x64", "linux-glibc-arm64", "linux-musl-arm64", "macos-x64", "macos-arm64", "windows-x64"] + secrets: inherit - ## Create github release with binary archives - ## Only run if: - ## - Tag is provided - ## - OR - ## - Not the default branch - ## - AND - ## - Not a PR - github-release: - if: ${{ inputs.tag != '' || (github.ref != format('refs/heads/{0}', github.event.repository.default_branch) && !contains(github.ref, 'refs/pull')) }} - name: Github Release - uses: stacks-network/stacks-blockchain/.github/workflows/github-release.yml@master - needs: build-source - with: - tag: ${{ inputs.tag }} - arch: >- - ["linux-glibc-x64", "linux-musl-x64", "linux-glibc-arm64", "linux-musl-arm64", "macos-x64", "macos-arm64", "windows-x64"] - secrets: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - - ## Create docker alpine images - ## Only run if: - ## - Tag is provided - ## - OR - ## - Not the default branch - ## - AND - ## - Not a PR - docker-alpine: - if: ${{ inputs.tag != '' || (github.ref != format('refs/heads/{0}', github.event.repository.default_branch) && !contains(github.ref, 'refs/pull')) }} - name: Docker Alpine (Binary) - uses: stacks-network/stacks-blockchain/.github/workflows/image-build-alpine-binary.yml@master - needs: github-release - with: - tag: ${{ inputs.tag }} - docker_platforms: linux/arm64, linux/amd64, linux/amd64/v2, linux/amd64/v3 - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} - - ## Create docker debian images - ## Only run if: - ## - Tag is provided - ## - OR - ## - Not the default branch - ## - AND - ## - Not a PR - docker-debian: - if: ${{ inputs.tag != '' || (github.ref != format('refs/heads/{0}', github.event.repository.default_branch) && !contains(github.ref, 'refs/pull')) }} - name: Docker Debian (Binary) - uses: stacks-network/stacks-blockchain/.github/workflows/image-build-debian-binary.yml@master - needs: github-release - with: - tag: ${{ inputs.tag }} - docker_platforms: linux/amd64, linux/amd64/v2, linux/amd64/v3 - linux_version: debian - build_type: binary - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} - - ############################################### - ## Build Branch/PR - ############################################### - ## Create docker debian images - ## Only run if: - ## - Tag is *not* provided - build-branch: - if: ${{ inputs.tag == '' }} - name: Docker Debian (Source) - uses: stacks-network/stacks-blockchain/.github/workflows/image-build-debian-source.yml@master + ## Build and push Debian image built from source + ## + ## Runs when: + ## - tag is not provided + ## and the following are not true: + ## - PR review submitted (not approved) + ## and any of: + ## - PR review comment + ## - PR change is requested + docker-image: + if: | + inputs.tag == '' && + !( + github.event_name == 'pull_request_review' && + github.event.action == 'submitted' && + ( + github.event.review.state == 'commented' || + github.event.review.state == 'changes_requested' + ) + ) + name: Docker Image (Source) + uses: ./.github/workflows/image-build-source.yml needs: - rustfmt - - leaked-cred-test - with: - docker_platforms: linux/amd64 - linux_version: debian - build_type: source - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} + secrets: inherit + + ## Create a reusable cache for tests + ## + ## Runs when: + ## - tag is provided + ## or: + ## - no tag provided + ## and any of: + ## - PR is approved (any approval will trigger) + ## - this workflow is called manually + ## - PR is opened + ## - commit to either (development, master) branch + create-cache: + if: | + inputs.tag != '' || ( + inputs.tag == '' && ( + ( + github.event_name == 'pull_request_review' && + github.event.action == 'submitted' && + github.event.review.state == 'approved' + ) || + github.event_name == 'workflow_dispatch' || + github.event_name == 'pull_request_target' || + ( + contains(' + refs/heads/develoment + refs/heads/master + ', github.event.pull_request.head.ref) && + github.event_name == 'push' + ) + ) + ) + name: Create Test Cache + needs: + - rustfmt + uses: ./.github/workflows/create-cache.yml + + ## Tests to run regularly + ## + ## Runs when: + ## - tag is provided + ## either or of the following: + ## - tag is not provided + ## - PR is approved + stacks-blockchain-tests: + if: | + inputs.tag != '' || ( + inputs.tag == '' || ( + github.event_name == 'pull_request_review' && + github.event.action == 'submitted' && + github.event.review.state == 'approved' + ) + ) + name: Stacks Blockchain Tests + needs: + - rustfmt + - create-cache + uses: ./.github/workflows/stacks-blockchain-tests.yml + + bitcoin-tests: + if: | + inputs.tag != '' || ( + inputs.tag == '' || ( + github.event_name == 'pull_request_review' && + github.event.action == 'submitted' && + github.event.review.state == 'approved' + ) + ) + name: Bitcoin Tests + needs: + - rustfmt + - create-cache + uses: ./.github/workflows/bitcoin-tests.yml + + ## Test to run on a tagged release + ## + ## Runs when: + ## - tag is provided + atlas-tests: + if: inputs.tag != '' + name: Atlas Tests + needs: + - rustfmt + - create-cache + uses: ./.github/workflows/atlas-tests.yml + + epoch-tests: + if: inputs.tag != '' + name: Epoch Tests + needs: + - rustfmt + - create-cache + uses: ./.github/workflows/epoch-tests.yml + + slow-tests: + if: inputs.tag != '' + name: Slow Tests + needs: + - rustfmt + - create-cache + uses: ./.github/workflows/slow-tests.yml diff --git a/.github/workflows/clarity-js-sdk-pr.yml b/.github/workflows/clarity-js-sdk-pr.yml index 9ac0956a8..25e96f9f2 100644 --- a/.github/workflows/clarity-js-sdk-pr.yml +++ b/.github/workflows/clarity-js-sdk-pr.yml @@ -4,6 +4,10 @@ name: Open Clarity JS SDK PR +defaults: + run: + shell: bash + env: CLARITY_JS_SDK_REPOSITORY: stacks-network/clarity-js-sdk COMMIT_USER: Hiro DevOps @@ -24,22 +28,25 @@ jobs: steps: - name: Checkout latest clarity js sdk id: git_checkout - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: token: ${{ secrets.GH_TOKEN }} repository: ${{ env.CLARITY_JS_SDK_REPOSITORY }} ref: master + - name: Determine Release Version id: get_release_version run: | RELEASE_VERSION=$(echo ${GITHUB_REF#refs/*/} | tr / -) echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV + - name: Update SDK Tag id: update_sdk_tag run: sed -i "s@CORE_SDK_TAG = \".*\"@CORE_SDK_TAG = \"$RELEASE_VERSION\"@g" packages/clarity-native-bin/src/index.ts + - name: Create Pull Request id: create_pr - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 with: token: ${{ secrets.GH_TOKEN }} commit-message: "chore: update clarity-native-bin tag" diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml index b2a44f729..bb54c28cc 100644 --- a/.github/workflows/docs-pr.yml +++ b/.github/workflows/docs-pr.yml @@ -9,6 +9,10 @@ name: Open Docs PR +defaults: + run: + shell: bash + env: ROBOT_OWNER: kantai-robot ROBOT_REPO: docs.blockstack @@ -16,9 +20,8 @@ env: TARGET_REPO: docs TARGET_REPOSITORY: stacks-network/docs -# Only run when: -# - push to master - +## Only run when: +## - push to master on: push: branches: @@ -33,19 +36,22 @@ jobs: steps: - name: Checkout the latest code id: git_checkout - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Build docs id: build_docs env: DOCKER_BUILDKIT: 1 run: rm -rf docs-output && docker build -o docs-output -f ./.github/actions/docsgen/Dockerfile.docsgen . + - name: Checkout latest docs id: git_checkout_docs - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: token: ${{ secrets.DOCS_GITHUB_TOKEN }} repository: ${{ env.TARGET_REPOSITORY }} path: docs + - name: Branch and commit id: push run: | @@ -67,10 +73,11 @@ jobs: git push robot $ROBOT_BRANCH echo "::set-output name=open_pr::1" fi + - name: Open PR id: open_pr if: ${{ steps.push.outputs.open_pr == '1' }} - uses: actions/github-script@v6 + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 with: github-token: ${{ secrets.DOCS_GITHUB_TOKEN }} script: | diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index c0683f51d..14e7117a9 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -1,50 +1,75 @@ -## -## Create the github release and store artifact files (with checksum) -## +## Github workflow to create a github release and upload binary artifacts name: Github Release -# Only run when: -# - manually triggered via the ci.yml workflow - on: workflow_call: inputs: tag: - required: true - type: string - arch: - description: "Stringified JSON object listing of platform matrix" + description: "Release Tag" required: true type: string secrets: GH_TOKEN: required: true +concurrency: + group: github-release-${{ github.head_ref || github.ref }} + ## Always cancel duplicate jobs + cancel-in-progress: true + +run-name: ${{ inputs.tag }} + jobs: + ## Build arch dependent binaries from source + ## + ## Runs when the following is true: + ## - tag is provided + ## - workflow is building default branch (master) + build-binaries: + if: | + inputs.tag != '' && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + name: Build Binaries + uses: ./.github/workflows/create-source-binary.yml + with: + tag: ${{ inputs.tag }} + secrets: inherit + + ## Runs when the following is true: + ## - tag is provided + ## - workflow is building default branch (master) create-release: - if: ${{ inputs.tag != '' }} + if: | + inputs.tag != '' && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) name: Create Release runs-on: ubuntu-latest + needs: + - build-binaries steps: + ## Downloads the artifacts built in `create-source-binary.yml` - name: Download Artifacts id: download_artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: artifact path: release - # Generate a checksums file to be added to the release page + + ## Generate a checksums file to be added to the release page - name: Generate Checksums id: generate_checksum - uses: jmgilman/actions-generate-checksum@v1 + uses: jmgilman/actions-generate-checksum@24a35957fba81c6cbaefeb1e3d59ee56e3db5077 # v1.0.0 with: + method: sha512 output: CHECKSUMS.txt patterns: | release/*.zip - # Upload the release archives with the checksums file + + ## Upload the release archives with the checksums file - name: Upload Release id: upload_release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 #v0.1.15 env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} with: @@ -56,3 +81,21 @@ jobs: files: | release/*.zip CHECKSUMS.txt + + ## Builds arch dependent Docker images from binaries + ## + ## Runs when the following is true: + ## - tag is provided + ## - workflow is building default branch (master) + docker-image: + if: | + inputs.tag != '' && + github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + name: Docker Image (Binary) + uses: ./.github/workflows/image-build-binary.yml + needs: + - build-binaries + - create-release + with: + tag: ${{ inputs.tag }} + secrets: inherit diff --git a/.github/workflows/stacks-blockchain-tests.yml b/.github/workflows/stacks-blockchain-tests.yml index fb1dffc1a..fa415a9cd 100644 --- a/.github/workflows/stacks-blockchain-tests.yml +++ b/.github/workflows/stacks-blockchain-tests.yml @@ -1,95 +1,138 @@ -## -## Run tests for tagged releases -## +## Github workflow to run full genesis and unit tests -name: Tests - -# Only run when: -# - manually triggered via the ci.yml workflow +name: Tests::Stacks Blockchain on: workflow_call: +defaults: + run: + shell: bash + +## env vars are transferred to composite action steps +env: + BITCOIND_TEST: 1 + RUST_BACKTRACE: full + SEGMENT_DOWNLOAD_TIMEOUT_MINS: 3 + RETRIES: 3 + RETRY_DELAY: 10000 + TEST_TIMEOUT: 30 + TEST_RETRIES: 2 + +concurrency: + group: stacks-blockchain-tests-${{ github.head_ref || github.ref || github.run_id }} + ## Only cancel in progress if this is for a PR + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: - # Run full genesis test + # Full genesis test with code coverage full-genesis: name: Full Genesis Test runs-on: ubuntu-latest + strategy: + ## Continue with the test matrix even if we've had a failure + fail-fast: false + ## Run a maximum of 2 concurrent tests from the test matrix + max-parallel: 2 + matrix: + test-name: + - neon_integrations::bitcoind_integration_test steps: - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - - name: Single full genesis integration test - id: full_genesis_test - env: - DOCKER_BUILDKIT: 1 - # Remove .dockerignore file so codecov has access to git info - run: | - rm .dockerignore - docker build -o coverage-output -f ./.github/actions/bitcoin-int-tests/Dockerfile.large-genesis . - - name: Large Genesis Codecov - id: full_genesis_codecov - uses: codecov/codecov-action@v3 + ## Setup test environment + - name: Setup Test Environment + id: setup_tests + uses: stacks-network/actions/stacks-core/testenv@main with: - files: ./coverage-output/lcov.info - name: large_genesis - fail_ci_if_error: false + genesis: true - # Run unit tests with code coverage + ## Run test matrix using restored cache of archive file + ## - Test will timeout after env.TEST_TIMEOUT minutes + - name: Run Tests + id: run_tests + timeout-minutes: ${{ fromJSON(env.TEST_TIMEOUT) }} + uses: stacks-network/actions/stacks-core/run-tests@main + with: + test-name: ${{ matrix.test-name }} + threads: 1 + archive-file: /tmp/genesis_archive.tar.zst + + ## Upload code coverage file + - name: Code Coverage + id: codecov + uses: stacks-network/actions/codecov@main + with: + test-name: large_genesis + filename: ./lcov.info + + - name: Status Output + run: | + echo "run_tests: ${{ steps.run_tests.outputs.status }}" + echo "codecov: ${{ steps.codecov.outputs.status }}" + + - name: Check Failures + if: steps.run_tests.outputs.status == 'failure' || steps.codecov.outputs.status == 'failure' + run: exit 1 + + # Unit tests with code coverage unit-tests: name: Unit Tests runs-on: ubuntu-latest + ## Continue the workflow in case a step fails (ex a single test fails) + continue-on-error: true + strategy: + ## Continue the workflow in case a step fails (ex a single test fails) + fail-fast: false + matrix: + ## Partition the tests into 8 jobs + ## - This is used in a later step when running `cargo nextest run ... --partition count:num/8` + partition: [1, 2, 3, 4, 5, 6, 7, 8] steps: - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - - name: Run unit tests (with coverage) - id: unit_tests_codecov - env: - DOCKER_BUILDKIT: 1 - # Remove .dockerignore file so codecov has access to git info - run: | - rm .dockerignore - docker build -o coverage-output -f ./.github/actions/bitcoin-int-tests/Dockerfile.code-cov . - - name: Run unit tests - id: codedov - uses: codecov/codecov-action@v3 - with: - files: ./coverage-output/lcov.info - name: unit_tests - fail_ci_if_error: false + ## Setup test environment + - name: Setup Test Environment + id: setup_tests + uses: stacks-network/actions/stacks-core/testenv@main + ## Run test matrix using restored cache of archive file + ## - Test will timeout after env.TEST_TIMEOUT minutes + - name: Run Tests + id: run_tests + timeout-minutes: ${{ fromJSON(env.TEST_TIMEOUT) }} + uses: stacks-network/actions/stacks-core/run-tests/partition@main + with: + partition: ${{ matrix.partition }} + total-partitions: 8 + + ## Create and upload code coverage file + - name: Code Coverage + id: codecov + uses: stacks-network/actions/codecov@main + with: + test-name: ${{ matrix.test-name }} + + ## Generate and upload openapi html artifact open-api-validation: name: OpenAPI Validation runs-on: ubuntu-latest steps: - - name: Checkout the latest code - id: git_checkout - uses: actions/checkout@v3 - - name: Run units tests (with coverage) - id: api_codecov - env: - DOCKER_BUILDKIT: 1 - run: docker build -o dist/ -f .github/actions/open-api/Dockerfile.open-api-validate . - - name: Upload bundled html - id: upload_html_artifact - uses: actions/upload-artifact@v3 + - name: OpenAPI + id: openapi + uses: stacks-network/actions/openapi@main with: - name: open-api-bundle - path: | - dist + input: ./docs/rpc/openapi.yaml + output: ./open-api-docs.html - # Run net-tests + ## Disabled + ## - this test can take several hours to run nettest: - # disable this job/test for now, since we haven't seen this pass - # on github actions in a while, and the failures can take > 4 hours if: ${{ false }} name: Net-Test runs-on: ubuntu-latest steps: + ## checkout the code - name: Checkout the latest code id: git_checkout - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Run network relay tests id: nettest env: @@ -101,17 +144,23 @@ jobs: name: Core Contracts Test runs-on: ubuntu-latest steps: + ## Checkout the code - name: Checkout the latest code id: git_checkout - uses: actions/checkout@v3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + ## Use Clarinet to run contract unit-tests and create code coverage file - name: Execute core contract unit tests in Clarinet id: clarinet_unit_test - uses: docker://hirosystems/clarinet:1.1.0 + uses: docker://hirosystems/clarinet:1.8.0 with: args: test --coverage --manifest-path=./contrib/core-contract-tests/Clarinet.toml - - name: Export code coverage - id: clarinet_codecov - uses: codecov/codecov-action@v3 + + ## Upload code coverage file + - name: Code Coverage + id: codecov + uses: stacks-network/actions/codecov@main with: - files: ./coverage.lcov - verbose: true + test-name: ${{ matrix.test-name }} + upload-only: true + filename: ./coverage.lcov diff --git a/docs/ci-release.md b/docs/ci-release.md index 7025226d1..82fe164ec 100644 --- a/docs/ci-release.md +++ b/docs/ci-release.md @@ -3,148 +3,184 @@ All releases are built via a Github Actions workflow named `CI`, and is responsible for building binary archives, checksums, and resulting docker images. This workflow will also trigger any tests that need to be run, like integration tests. -1. Releases are only created if a tag is manually provided when the ci workflow is triggered. -2. Pushing a new feature branch: Nothing is triggered automatically. PR's are required, or the ci workflow can be triggered manually on a specific branch to build a docker image for the specified branch. - -The following workflow steps are currently disabled: - -- Clippy -- Net-test -- Crate audit +1. Releases are only created if a tag is **manually** provided when the ci workflow is triggered. +2. Pushing a new feature branch: Nothing is triggered automatically. A PR is required, or the ci workflow can be triggered manually on a specific branch to build a docker image (and run the standard PR tests) for the specified branch. +3. Caching is used to speed up testing - a cache is created based on the type of data (i.e. cargo) and the commit sha. tests can be retried quickly since the cache will persist until the cleanup job is run. +4. [nextest](https://nexte.st/) is used to run the tests from an archived file that is cached (using commit sha as a key)) + - Two [archives](https://nexte.st/book/reusing-builds.html) are created, one for genesis tests and one for generic tests (it is done this way to reduce the time spent building) + - Unit-tests are [partitioned](https://nexte.st/book/partitioning.html) and multi-threaded to speed up execution time ## TL;DR -1. A PR will produce a single image built from source on Debian with glibc with 2 tags: +1. An open/re-opened/synchronized PR will produce a single image built from source on Debian with glibc with 2 tags: - `stacks-blockchain:` - `stacks-blockchain:` 2. A merged PR from `develop` to the default branch will produce a single image built from source on Debian with glibc: - `stacks-blockchain:` 3. An untagged build of any branch will produce a single image built from source on Debian with glibc: - `stacks-blockchain:` -4. A tagged release on a non-default branch will produce 2 versions of the docker image (along with all binary archives): - - An Alpine image for several architectures tagged with: +4. A tagged release on a non-default branch will produces: + - Docker Alpine image for several architectures tagged with: - `stacks-blockchain:` - - An Debian image for several architectures tagged with: + - Docker Debian image for several architectures tagged with: - `stacks-blockchain:` -5. A tagged release on the default branch will produce 2 versions of the docker image (along with all binary archives): - - An Alpine image for several architectures tagged with: +5. A tagged release on the default branch will produce: + - Github Release of the specified tag with: + - Binary archives for several architectures + - Docker Alpine image for several architectures tagged with: - `stacks-blockchain:` - `stacks-blockchain:` - - An Debian image for several architectures tagged with: + - Docker Debian image for several architectures tagged with: - `stacks-blockchain:` - `stacks-blockchain:` -## Release workflow: +## Release workflow -1. Create a feature branch: `feat/112-fix-something` -2. PR `feat/112-fix-something` to the `develop` branch - 1. CI Workflow is automatically triggered, resulting in a pushed docker image tagged with the **branch name** and **PR number** -3. PR `develop` to the default branch - 1. CI Workflow is automatically triggered, resulting in a pushed docker image tagged with the **branch name** and **PR number** +1. Create a feature branch: `feat/fix-something` +2. PR `feat/fix-something` to the `develop` branch where the PR is numbered `112` + 1. Docker image tagged with the **branch name** and **PR number** + - ex: + - `stacks-blockchain:feat-fix-something` + - `stacks-blockchain:pr-112` + 2. CI tests are run +3. PR `develop` to the default branch where the PR is numbered `112` + 1. Docker image tagged with the **branch name** and **PR number** + - ex: + - `stacks-blockchain:feat-fix-something` + - `stacks-blockchain:pr-112` + 2. CI tests are run 4. Merge `develop` branch to the default branch - 1. CI Workflow is triggered, resulting in a pushed docker image tagged with the **default branch name** + 1. Docker image is tagged with the **default branch** `master` + - ex: + - `stacks-blockchain:master` + 2. CI tests are run 5. CI workflow is manually triggered on **non-default branch** with a version, i.e. `2.1.0.0.0-rc0` - 1. Github release for the manually input version is created with binaries - 2. Docker image pushed with tags of the **input version** and **branch** + 1. No Docker images/binaries are created + 2. All release tests are run 6. CI workflow is manually triggered on **default branch** with a version, i.e. `2.1.0.0.0` 1. Github release for the manually input version is created with binaries - 2. Docker image pushed with tags of the **input version** and **latest** + 2. All release tests are run + 3. Docker image pushed with tags of the **input version** and **latest** + - ex: + - `stacks-blockchain:2.1.0.0.0-debian` + - `stacks-blockchain:latest-debian` + - `stacks-blockchain:2.1.0.0.0` + - `stacks-blockchain:latest` -## PR a branch to develop: +## Tests -ex: Branch is named `feat/112-fix-something` and the PR is numbered `112` +Tests are separated into several different workflows, with the intention that they can be _conditionally_ run depending upon the triggering operation. For example, on a PR synchronize we don't want to run some identified "slow" tests, but we do want to run the [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) and [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml). -- Steps executed: - - Rust Format - - Integration Tests - - Leaked credential test - - Docker image is built from source on a debian distribution and pushed with the branch name and PR number as tags - - ex: - - `stacks-blockchain:feat-112-fix-something` - - `stacks-blockchain:pr-112` -- Steps _not_ executed: - - No binaries are built - - No github release - - No docker images built from binary artifacts +There are also 2 different methods in use with regard to running tests: -## Merging a branch to develop: +1. [Github Actions matrix](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs) +2. [nextest partitioning](https://nexte.st/book/partitioning.html) + +A matrix is used when there are several known tests that need to be run. Partitions (shards) are used when there is a large and unknown number of tests to run (ex: `cargo test` to run all tests). + +There is also a workflow designed to run tests that are manually triggered: [Standalone Tests](../.github/workflows/standalone-tests.yml). +This workflow requires you to select which test(s) you want to run, which then triggers a reusbale workflow via conditional. For example, selecting "Epoch Tests" will run the tests defined in [Epoch Tests](../.github/workflows/epoch-tests.yml). Likewise, selecting `Release Tests` will run the same tests as a release workflow. + +Files: + +- [Standalone Tests](../.github/workflows/standalone-tests.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Atlas Tests](../.github/workflows/atlas-tests.yml) +- [Epoch Tests](../.github/workflows/epoch-tests.yml) +- [Slow Tests](../.github/workflows/slow-tests.yml) + +## Triggering a workflow + +### PR a branch to develop + +ex: Branch is named `feat/fix-something` and the PR is numbered `112` + +- [Rust format](../.github/workflows/ci.yml) +- [Create Test Cache](../.github/workflows/create-cache.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Docker image](../.github/workflows/image-build-source.yml) is built from source on a debian distribution and pushed with the branch name and PR number as tags +- ex: + - `stacks-blockchain:feat-fix-something` + - `stacks-blockchain:pr-112` + +--- + +### Merging a branch to develop Nothing is triggered automatically -## PR develop to master branches: +--- + +### PR develop to master branches ex: Branch is named `develop` and the PR is numbered `113` -- Steps executed: - - Rust format - - Integration tests - - Leaked credential test - - Docker image is built from source on a debian distribution and pushed with the branch name and PR number as tags - - ex: - - `stacks-blockchain:develop` - - `stacks-blockchain:pr-113` -- Steps _not_ executed: - - No binaries are built - - No github release - - No docker images built from binary artifacts +- [Rust format](../.github/workflows/ci.yml) +- [Create Test Cache](../.github/workflows/create-cache.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Docker image](../.github/workflows/image-build-source.yml) is built from source on a debian distribution and pushed with the branch name and PR number as tags +- ex: + - `stacks-blockchain:develop` + - `stacks-blockchain:pr-113` -## Merging a PR from develop to master: +--- -- Steps executed: - - Rust format - - Integration tests - - Leaked credential test - - Docker image is built from source on a debian distribution and pushed with the branch name as a tag - - ex: - - `stacks-blockchain:master` -- Steps _not_ executed: - - No binaries are built - - No github release - - No docker images built from binary artifacts +### Merging a PR from develop to master -## Manually triggering workflow without tag (any branch): +- [Rust format](../.github/workflows/ci.yml) +- [Create Test Cache](../.github/workflows/create-cache.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Docker image](../.github/workflows/image-build-source.yml) is built from source on a debian distribution and pushed with the branch name as a tag +- ex: + - `stacks-blockchain:master` -- Steps executed: - - Rust format - - Integration tests - - Leaked credential test - - Docker image is built from source on a debian distribution and pushed with the branch name as a tag - - ex: - - `stacks-blockchain:` -- Steps _not_ executed: - - No binaries are built - - No github release - - No docker images built from binary artifacts +--- -## Manually triggering workflow with tag on a non-default branch (i.e. tag of `2.1.0.0.0-rc0`): +### Manually triggering workflow without tag (any branch) -- Steps executed: - - Rust format - - Integration tests - - Leaked credential test - - Binaries built for specified architectures - - Archive and checksum files added to github release - - Github release (with artifacts/checksum) is created using the manually input tag - - Docker image built from binaries on debian/alpine distributions and pushed with the provided input tag and `latest` - - ex: - - `stacks-blockchain:2.1.0.0.0-rc0` -- Steps _not_ executed: - - No docker images built from source +- [Rust format](../.github/workflows/ci.yml) +- [Create Test Cache](../.github/workflows/create-cache.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Docker image](../.github/workflows/image-build-source.yml) is built from source on a debian distribution and pushed with the branch name as a tag +- ex: + - `stacks-blockchain:` -## Manually triggering workflow with tag on default branch (i.e. tag of `2.1.0.0.0`): +--- -- Steps executed: - - Rust format - - Integration tests - - Leaked credential test - - Binaries built for specified architectures - - Archive and checksum files added to github release - - Github release (with artifacts/checksum) is created using the manually input tag - - Docker image built from binaries on debian/alpine distributions and pushed with the provided input tag and `latest` - - ex: - - `stacks-blockchain:2.1.0.0.0-debian` - - `stacks-blockchain:latest-debian` - - `stacks-blockchain:2.1.0.0.0` - - `stacks-blockchain:latest` -- Steps _not_ executed: - - No docker images built from source +### Manually triggering workflow with tag on a non-default branch (i.e. tag of `2.1.0.0.0-rc0`) + +- [Rust format](../.github/workflows/ci.yml) +- [Create Test Cache](../.github/workflows/create-cache.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Atlas Tests](../.github/workflows/atlas-tests.yml) +- [Epoch Tests](../.github/workflows/epoch-tests.yml) +- [Slow Tests](../.github/workflows/slow-tests.yml) + +--- + +### Manually triggering workflow with tag on default branch (i.e. tag of `2.1.0.0.0`) + +- [Rust format](../.github/workflows/ci.yml) +- [Create Test Cache](../.github/workflows/create-cache.yml) +- [Stacks Blockchain Tests](../.github/workflows/stacks-blockchain-tests.yml) +- [Bitcoin Tests](../.github/workflows/bitcoin-tests.yml) +- [Atlas Tests](../.github/workflows/atlas-tests.yml) +- [Epoch Tests](../.github/workflows/epoch-tests.yml) +- [Slow Tests](../.github/workflows/slow-tests.yml) +- [Binaries built for specified architectures](../.github/workflows/create-source-binary.yml) + - Archive and checksum files added to github release +- [Github release](../.github/workflows/github-release.yml) (with artifacts/checksum) is created using the manually input tag +- [Docker image](../.github/workflows/image-build-binary.yml) built from binaries on debian/alpine distributions and pushed with the provided input tag and `latest` +- ex: + - `stacks-blockchain:2.1.0.0.0-debian` + - `stacks-blockchain:latest-debian` + - `stacks-blockchain:2.1.0.0.0` + - `stacks-blockchain:latest` + +---