Skip to content

Validation CI

Validation CI #6273

Workflow file for this run

name: Validation CI
on:
pull_request:
push:
branches: [ master ]
release:
types: [ published ]
schedule:
# run every day at 0252, 0852, 1452, and 2052 UTC
- cron: '52 1,7,13,19 * * *'
workflow_dispatch:
env:
TERM: xterm
jobs:
changes:
name: Check for file changes
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
ci: ${{ steps.filter.outputs.ci }}
dependencies: ${{ steps.filter.outputs.dependencies }}
docker: ${{ steps.filter.outputs.docker }}
docker-files: ${{ steps.filter.outputs.docker_files }}
markdown: ${{ steps.filter.outputs.markdown }}
helpers: ${{ steps.filter.outputs.helpers }}
shell: ${{ steps.filter.outputs.shell }}
spelling: ${{ steps.filter.outputs.spelling }}
test: ${{ steps.filter.outputs.test }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: resources/config/paths-filter.yaml
list-files: 'shell'
dependencies-check:
name: Check depencencies
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Renovate
uses: renovatebot/[email protected]
with:
configurationFile: 'resources/config/renovate-config.json'
token: ${{ secrets.RENOVATE_TOKEN }}
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
config-file: 'resources/config/dependency-review.yaml'
base-ref: ${{ github.event.pull_request.base.sha || 'master' }}
head-ref: ${{ github.event.pull_request.head.sha || github.ref }}
shell-lint:
name: Lint the shell code
needs: changes
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.docker == 'true' ||
needs.changes.outputs.helpers == 'true' ||
needs.changes.outputs.shell == 'true' ||
needs.changes.outputs.test == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint with shellcheck and shfmt
uses: luizm/[email protected]
env:
SHELLCHECK_OPTS: >-
--enable add-default-case
--enable avoid-nullary-conditions
--enable check-unassigned-uppercase
--enable deprecate-which
--enable quote-safe-variables
--enable require-variable-braces
SHFMT_OPTS: >-
--case-indent
--func-next-line
--indent 2
--space-redirects
yaml-lint:
name: Lint the yaml code
needs: changes
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.docker == 'true' ||
needs.changes.outputs.shell == 'true' ||
needs.changes.outputs.test == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint workflow files
run: |
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
./actionlint -color -verbose
shell: bash
dockerfile-lint:
name: Lint the Dockerfile code
needs: changes
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.docker == 'true' ||
needs.changes.outputs.shell == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint Dockerfiles
uses: luke142367/[email protected]
with:
target: docker/Dockerfile*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
markdown-checks:
name: Check the documentation
needs: changes
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.markdown == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint the markdown
uses: avto-dev/markdown-lint@v1
with:
config: 'resources/config/markdownlint.yaml'
args: '*/*.md'
ignore: './docs/pull_request_template.md'
- name: Check spelling
uses: rojopolis/spellcheck-github-actions@v0
with:
config_path: 'resources/config/spellcheck.yaml'
output_file: 'spellcheck-output.txt'
- uses: actions/upload-artifact@v4
if: '!cancelled()'
with:
name: Spellcheck Output
path: spellcheck-output.txt
markdown-links:
name: Check hyperlinks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run linkspector on markdown
uses: umbrelladocs/action-linkspector@v1
with:
config_file: 'resources/config/linkspector.yaml'
fail_on_error: true
reporter: github-check
conventional-commits:
name: Check pull request title
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate pull request title as a conventional commit
run: |
PR_TITLE="$(jq --raw-output .pull_request.title "$GITHUB_EVENT_PATH")"
PR_REGEX="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9\-]+\))?: .{1,}$"
if [[ ${PR_TITLE} =~ ${PR_REGEX} ]]; then
echo "Pull request title '${PR_TITLE}' is valid."
else
echo "Error: Pull request title does not follow Conventional Commits format."
echo "Expected format: <type>(<scope>): <description>"
echo "Actual title: ${PR_TITLE}"
exit 1
fi
run-nodebuilder-baremetal:
name: Test ${{ matrix.job-purpose }} on ${{ matrix.os-friendly-name }}
needs: [changes, shell-lint, yaml-lint]
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.shell == 'true' ||
needs.changes.outputs.test == 'true'
}}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
max-parallel: 5
matrix:
job-purpose: [package, source]
os: [ubuntu-22.04, ubuntu-24.04, macos-13, macos-latest, macos-15]
exclude:
- { job-purpose: source, os: macos-13 }
include:
- job-purpose: package
additional-args: ''
- job-purpose: source
additional-args: '--compile'
- os: ubuntu-22.04
os-friendly-name: Ubuntu 22
check-environment-command: cat /etc/os-release && lscpu && grep Mem /proc/meminfo
remove-firefox-command: sudo apt-get remove --assume-yes firefox
cache-path: |
/var/cache/apt/archives/*.deb
/var/lib/apt/lists/*.ubuntu.com_ubuntu_dists_*
/var/lib/apt/lists/download.docker.com_linux_ubuntu_dists_*
/var/lib/apt/lists/dl.google.com_linux_chrome_deb_dists_*
/var/lib/apt/lists/packages.microsoft.com_repos_code_dists_*
/var/lib/apt/lists/pkg.cloudflareclient.com_dists_*
path-to-bitcoin-log: '/home/runner/.bitcoin/debug.log'
- os: ubuntu-24.04
os-friendly-name: Ubuntu 24
check-environment-command: cat /etc/os-release && lscpu && grep Mem /proc/meminfo
remove-firefox-command: sudo apt-get remove --assume-yes firefox
path-to-bitcoin-log: '/home/runner/.bitcoin/debug.log'
- os: macos-13
os-friendly-name: macOS 13
check-environment-command: sw_vers && sysctl machdep.cpu.core_count machdep.cpu.thread_count machdep.cpu.brand_string && memory_pressure -Q
path-to-bitcoin-log: '/Users/runner/Library/Application Support/Bitcoin/debug.log'
- os: macos-latest
os-friendly-name: macOS 14
check-environment-command: sw_vers && sysctl machdep.cpu.core_count machdep.cpu.thread_count machdep.cpu.brand_string && memory_pressure -Q
path-to-bitcoin-log: '/Users/runner/Library/Application Support/Bitcoin/debug.log'
- os: macos-15
os-friendly-name: macOS 15
check-environment-command: sw_vers && sysctl machdep.cpu.core_count machdep.cpu.thread_count machdep.cpu.brand_string && memory_pressure -Q
path-to-bitcoin-log: '/Users/runner/Library/Application Support/Bitcoin/debug.log'
steps:
- uses: actions/checkout@v4
- name: Check the current environment
run: |
uname -a
${{ matrix.check-environment-command }}
df -h
date -u
- name: Change owner of apt archives
if: contains(matrix.os, 'ubuntu')
run: sudo chown -R "$(whoami)" /var/cache/apt/archives
- name: Cache system archives
if: matrix.cache-path != null
uses: actions/cache@v4
with:
path: ${{ matrix.cache-path }}
key: cache-updates-${{ matrix.os }}-${{ github.run_id }}
restore-keys: cache-updates-${{ matrix.os }}
- name: Remove the snap package
if: matrix.remove-firefox-command != null
run: ${{ matrix.remove-firefox-command }}
- name: Test the console output ${{ matrix.additional-args }}
id: test-nodebuilder
run: /bin/sh -x ./test/test_nodebuilder --ref "${GITHUB_SHA}" ${{ matrix.additional-args }}
timeout-minutes: 120
continue-on-error: true
- name: If test failed, debug nodebuilder ${{ matrix.additional-args }}
if: steps.test-nodebuilder.outcome == 'failure'
run: |
CI_NODEBUILDER_URL="https://github.com/bitcoin-tools/nodebuilder/raw/${GITHUB_SHA}/nodebuilder"
CI_NODEBUILDER_SCRIPT="$(basename "${CI_NODEBUILDER_URL}")"
[ -n "$(ls /usr/local/bin/*bitcoin* 2> /dev/null)" ] &&
rm /usr/local/bin/*bitcoin*
wget --no-verbose --retry-connrefused "${CI_NODEBUILDER_URL}" &&
chmod u+x "${CI_NODEBUILDER_SCRIPT}"
sh -x "./${CI_NODEBUILDER_SCRIPT}" ${{ matrix.additional-args }}
timeout-minutes: 120
- name: Save Bitcoin Core log as artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}-${{ matrix.job-purpose }}-bitcoin-debug.log
path: ${{ matrix.path-to-bitcoin-log }}
- name: If test failed, fail the job
if: steps.test-nodebuilder.outcome == 'failure'
run: printf '%s\n' "Review the step 'Test the console output' above." && exit 1
run-nodebuilder-freebsd:
name: Test source on FreeBSD
needs: [changes, shell-lint, yaml-lint]
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.shell == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Test the console output
uses: vmactions/freebsd-vm@v1
timeout-minutes: 180
with:
prepare: |
echo "${TERM:-TERM is not found}"
uname -a
cat /etc/os-release
nproc
sysctl -a | grep ' memory' | head -2
df -h
commmand -v tput
tput colors
date -u
run: |
sh -x ./test/test_nodebuilder --ref "${GITHUB_SHA}"
[ "$?" -gt 0 ] && echo "test_nodebuilder exited with non-zero status" >&2 && exit 1
[ -f "${HOME}/.bitcoin/debug.log" ] && cp "${HOME}/.bitcoin/debug.log" .
- name: Save Bitcoin Core log as artifact
uses: actions/upload-artifact@v4
with:
name: freebsd-source-bitcoin-debug.log
path: /home/runner/work/nodebuilder/nodebuilder/debug.log
run-nodebuilder-netbsd:
name: Test source on NetBSD
needs: [changes, shell-lint, yaml-lint]
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.shell == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Test the console output
uses: vmactions/netbsd-vm@v1
timeout-minutes: 180
with:
prepare: |
echo "${TERM:-TERM is not found}"
uname -a
sysctl -n hw.ncpu
sysctl -n hw.physmem64
swapctl -l
df -h
date -u
run: |
sh -x ./nodebuilder
[ "$?" -gt 0 ] && echo "test_nodebuilder exited with status $?" >&2 && exit 1
[ -f "/root/.bitcoin/debug.log" ] && cp "/root/.bitcoin/debug.log" .
- name: Save Bitcoin Core log as artifact
uses: actions/upload-artifact@v4
with:
name: netbsd-source-bitcoin-debug.log
path: /home/runner/work/nodebuilder/nodebuilder/debug.log
run-nodebuilder-openbsd:
name: Test source on OpenBSD
needs: [changes, shell-lint, yaml-lint]
if: >-
${{
github.event.action == 'prerelease' ||
github.event.action == 'published' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.shell == 'true'
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Test the console output
uses: vmactions/openbsd-vm@v1
timeout-minutes: 180
with:
prepare: |
echo "${TERM:-TERM is not found}"
uname -a
sysctl hw.ncpu
sysctl -a | grep 'hw.physmem\|hw.usermem'
df -h
commmand -v tput
tput colors
date -u
run: |
sh -x ./test/test_nodebuilder --ref "${GITHUB_SHA}"
[ "$?" -gt 0 ] && echo "test_nodebuilder exited with status $?" >&2 && exit 1
[ -f "/home/bitcoin/.bitcoin/debug.log" ] && cp "/home/bitcoin/.bitcoin/debug.log" .
find / -name debug.log 2> /dev/null | grep bitcoin || true
- name: Save Bitcoin Core log as artifact
uses: actions/upload-artifact@v4
with:
name: openbsd-source-bitcoin-debug.log
path: /home/runner/work/nodebuilder/nodebuilder/debug.log
run-nodebuilder-docker:
name: Docker image for ${{ matrix.container }}
needs: [changes, dockerfile-lint, shell-lint, yaml-lint]
if: >-
github.event.action != 'prerelease' &&
github.event.action != 'published' &&
(
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
needs.changes.outputs.docker == 'true' ||
needs.changes.outputs.shell == 'true'
)
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
include:
- { container: Gentoo, dockerfile: Dockerfile_gentoo }
- { container: Alpine, dockerfile: Dockerfile_alpine }
- { container: Amazon Linux, dockerfile: Dockerfile_amazonlinux }
- { container: Arch, dockerfile: Dockerfile_archlinux }
- { container: Clear Linux, dockerfile: Dockerfile_clearlinux }
- { container: Debian, dockerfile: Dockerfile_debian }
- { container: Fedora, dockerfile: Dockerfile_fedora }
- { container: Kali, dockerfile: Dockerfile_kali }
- { container: Manjaro, dockerfile: Dockerfile_manjarolinux }
- { container: Oracle Linux, dockerfile: Dockerfile_oraclelinux }
- { container: Red Hat Enterprise, dockerfile: Dockerfile_redhat-ubi9 }
- { container: Rocky Linux, dockerfile: Dockerfile_rockylinux }
- { container: SUSE Enterprise, dockerfile: Dockerfile_sles }
- { container: Ubuntu, dockerfile: Dockerfile }
- { container: openSUSE Leap, dockerfile: Dockerfile_opensuse-leap }
- { container: openSUSE Tumbleweed, dockerfile: Dockerfile_opensuse-tumbleweed }
steps:
- uses: actions/checkout@v4
- name: Check the current OS version
run: grep 'VERSION\|ID' /etc/os-release && uname -a
- name: Build the ${{ matrix.container }} docker image
if: >-
(
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.dependencies == 'true' ||
contains(needs.changes.outputs.docker-files, matrix.dockerfile) ||
needs.changes.outputs.shell == 'true'
)
&&
(
matrix.container != 'Gentoo' ||
contains(needs.changes.outputs.docker-files, 'Dockerfile_gentoo') ||
(
github.event.action == '' &&
github.event.before == '' &&
github.event.inputs == null
)
)
uses: docker/build-push-action@v6
timeout-minutes: 300
with:
build-args: NODEBUILDER_VERSION=${{ github.sha || github.head_ref || 'master' }}
context: .
file: docker/${{ matrix.dockerfile }}