Github Actions
This project relies heavily on Github Actions to build and release the binaries. The actions are defined in the .github/workflows directory.
Github repo Actions settings
Section titled “Github repo Actions settings”The required permissions for each workflow and job have been configured granularly in the workflows themselves. The permissions are defined in the permissions section of the workflow.
Workflows
Section titled “Workflows”These workflows are using a reusable caller workflow that allows for inputs to be passed to the reusable workflows. This allows for a single workflow to be used to call multiple workflows with different inputs.

This is the structure of the workflows:
ci-main-reusable-caller├─ ci-debian-build├─ ci-alpine-build├─ ci-alpine-release└─ ci-auto-rerun-failed-jobsci-main-reusable-caller
The primary reusable caller workflow
name: ci - main reusable caller
on: workflow_dispatch: inputs: script_name: description: "Which script to run?" required: true default: "qbt-nox-static.bash" type: choice options: ["qbt-nox-static.bash", "qbittorrent-nox-static.sh"] debian-build: description: "Debian: build" required: true default: false type: boolean alpine-build: description: "Alpine: build" required: true default: true type: boolean workflow-files: description: "Workflow files" required: true default: true type: boolean icu: description: "Enable icu" required: true default: false type: boolean debug: description: "Debug builds (symbols)" required: true default: false type: boolean release: description: "Release assets?" required: true default: true type: boolean skip_rerun: description: "Skip rerun?" required: true default: true type: boolean retries: description: "Number of rerun retries" required: true default: "1" type: choice options: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
permissions: {}
jobs: ci-debian-build: if: github.event.inputs.debian-build == 'true' concurrency: group: ci-debian-build cancel-in-progress: true permissions: id-token: write contents: read attestations: write uses: ./.github/workflows/ci-debian-build.yml with: workflow-files: ${{ github.event.inputs.workflow-files == 'true' && 'yes' || 'no' }} icu: ${{ github.event.inputs.icu == 'true' && 'no' || 'yes' }} debug: ${{ github.event.inputs.debug == 'true' && 'yes' || 'no' }} script_name: ${{ github.event.inputs.script_name }}
ci-alpine-build: if: github.event.inputs.alpine-build == 'true' concurrency: group: ci-alpine-build cancel-in-progress: true permissions: id-token: write contents: read attestations: write uses: ./.github/workflows/ci-alpine-build.yml with: workflow-files: ${{ github.event.inputs.workflow-files == 'true' && 'yes' || 'no' }} icu: ${{ github.event.inputs.icu == 'true' && 'no' || 'yes' }} debug: ${{ github.event.inputs.debug == 'true' && 'yes' || 'no' }} script_name: ${{ github.event.inputs.script_name }}
ci-alpine-release: needs: [ci-alpine-build] if: github.event.inputs.release == 'true' && contains(needs.*.result, 'success') && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') concurrency: group: ci-alpine-release cancel-in-progress: true permissions: contents: write uses: ./.github/workflows/ci-alpine-release.yml
ci-auto-rerun-failed-jobs: if: failure() && (github.event.inputs.skip_rerun || 'false') == 'false' needs: [ci-debian-build, ci-alpine-build, ci-alpine-release] concurrency: group: ci-auto-rerun-failed-jobs cancel-in-progress: true permissions: actions: write runs-on: ubuntu-24.04-arm environment: production env: GH_TOKEN: "${{ secrets.AUTO_RERUN || github.token }}" github_repo: "" # To use ci-auto-rerun-failed-jobs.yml hosted in a remote repository else default to the current repository. Requires PAT token AUTO_RERUN retries: ${{ github.event.inputs.retries || '1' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: ci-auto-rerun-failed-jobs via ${{ env.github_repo || github.repository }} run: > gh workflow run ci-auto-rerun-failed-jobs-action.yml --repo "${github_repo:-$GITHUB_REPOSITORY}" -f github_repo=${GITHUB_REPOSITORY} -f run_id=${GITHUB_RUN_ID} -f attempts=${GITHUB_RUN_ATTEMPT} -f retries=${retries}ci-debian-build
The debian build workflow
name: ci - debian build
on: workflow_call: inputs: workflow-files: description: "Alpine: workflow-files files" required: true type: string icu: description: "enable icu" required: true type: string debug: description: "debug builds" required: true type: string script_name: description: "script name" required: true type: string
jobs: build: runs-on: ${{ matrix.runs_on }} strategy: fail-fast: false matrix: runs_on: ["ubuntu-24.04", "ubuntu-24.04-arm"] os_id: ["debian", "ubuntu"] os_version_id: ["trixie", "noble"] qbt_cross_name: ["default", "aarch64", "x86_64", "riscv64"] qbt_libtorrent_version: ["1.2", "2.0"] qbt_build_tool: [""] qbt_qt_version: ["6"] exclude: - os_id: "debian" os_version_id: "noble" - os_id: "ubuntu" os_version_id: "trixie"
- runs_on: "ubuntu-24.04" qbt_cross_name: "x86_64" - runs_on: "ubuntu-24.04-arm" qbt_cross_name: "aarch64"
include: - runs_on: "ubuntu-24.04" host_name: "x86_64" - runs_on: "ubuntu-24.04-arm" host_name: "aarch64" - qbt_build_tool: "" qbt_qt_version_name: ""
name: "${{ matrix.host_name }}-${{ matrix.os_id }}-${{ matrix.os_version_id }}-${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}libtorrent-v${{ matrix.qbt_libtorrent_version }}"
env: qbt_build_dir: "qbt-build" script_name: ${{ inputs.script_name }} set_skip_icu: ${{ inputs.icu }} set_workflow_files: ${{ inputs.workflow-files }} set_build_debug: ${{ inputs.debug }} set_qbt_mcm_url: "" # default is userdocs/qbt-musl-cross-make set_qbt_with_qemu: "" # default is yes set_qbt_host_deps: "" # default is no set_qbt_host_deps_repo: "" # default is userdocs/qbt-host-deps workspace: ${{ github.workspace }}
steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false
- name: Download ${{ env.script_name }} run: | # Make sure the branch is set to master for qbittorrent-nox-static and main qbittorrent-nox-static-test if [[ ! -f "${script_name}" ]]; then echo "Downloading ${script_name} from userdocs/qbittorrent-nox-static" curl -LO "https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/refs/heads/master/${script_name}" chmod +x "${script_name}" fi
- name: Host - Create Docker template env file run: | printf '%s\n' "qbt_revision_url=${{ github.repository }}" > env.custom printf '%s\n' "qbt_zlib_type=zlib" >> env.custom printf '%s\n' "qbt_skip_icu=${set_skip_icu}" >> env.custom printf '%s\n' "qbt_boost_tag=${{ matrix.qbt_boost_tag }}" >> env.custom printf '%s\n' "qbt_libtorrent_version=${{ matrix.qbt_libtorrent_version }}" >> env.custom printf '%s\n' "qbt_libtorrent_tag=${{ matrix.qbt_libtorrent_tag }}" >> env.custom printf '%s\n' "qbt_libtorrent_master_jamfile=" >> env.custom printf '%s\n' "qbt_qt_version=${{ matrix.qbt_qt_version }}" >> env.custom printf '%s\n' "qbt_qt_tag=${{ matrix.qbt_qt_tag }}" >> env.custom printf '%s\n' "qbt_qbittorrent_tag=${{ matrix.qbt_qbittorrent_tag }}" >> env.custom printf '%s\n' "qbt_build_dir=${qbt_build_dir}" >> env.custom printf '%s\n' "qbt_build_tool=${{ matrix.qbt_build_tool }}" >> env.custom printf '%s\n' "qbt_cross_name=${{ matrix.qbt_cross_name }}" >> env.custom printf '%s\n' "qbt_mcm_url=${set_qbt_mcm_url}" >> env.custom printf '%s\n' "qbt_patches_url=${{ github.repository }}" >> env.custom printf '%s\n' "qbt_workflow_files=${set_workflow_files}" >> env.custom printf '%s\n' "qbt_cache_dir=" >> env.custom printf '%s\n' "qbt_optimise_strip=" >> env.custom printf '%s\n' "qbt_build_debug=${set_build_debug}" >> env.custom printf '%s\n' "qbt_standard=" >> env.custom printf '%s\n' "qbt_static_ish=" >> env.custom printf '%s\n' "qbt_optimise=${qbt_optimise}" >> env.custom printf '%s\n' "qbt_with_qemu=${set_qbt_with_qemu}" >> env.custom printf '%s\n' "qbt_host_deps=${set_qbt_host_deps}" >> env.custom printf '%s\n\n' "qbt_host_deps_repo=${set_qbt_host_deps_repo}" >> env.custom
- name: Host - Debian based specific env if: matrix.os_id != 'alpine' run: | printf '%s\n' "LANG=C.UTF-8" >> env.custom printf '%s\n' "LC_ALL=C.UTF-8" >> env.custom printf '%s\n\n' "DEBIAN_FRONTEND=noninteractive" >> env.custom
- name: Host - Bootstrap qemu uses: userdocs/actions/qemu@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 with: target_arch: ${{ matrix.qbt_cross_name }}
- name: Host - Bootstrap docker container uses: userdocs/actions/qbt_docker@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 with: os_id: ${{ matrix.os_id }} os_version_id: ${{ matrix.os_version_id }} additional_apps: "curl git"
- name: Host - patches if: hashFiles('patches/**') != '' run: mkdir -p "${qbt_build_dir}/patches" && cp -rf patches/* "${qbt_build_dir}/patches/"
- name: Docker - bootstrap_deps if: inputs.script_name == 'qbt-nox-static.bash' run: docker exec "${container_name}" bash "${script_name}" bootstrap_deps
- name: Docker - Bootstrap build run: docker exec "${container_name}" bash "${script_name}" -bs-a
- name: Docker - glibc if: matrix.os_id != 'alpine' run: docker exec "${container_name}" bash "${script_name}" glibc
- name: Docker - zlib run: docker exec "${container_name}" bash "${script_name}" zlib
- name: Docker - iconv if: matrix.qbt_libtorrent_version == '1.2' run: docker exec "${container_name}" bash "${script_name}" iconv
- name: Docker - icu if: env.set_skip_icu == 'no' run: docker exec "${container_name}" bash "${script_name}" icu
- name: Docker - openssl run: docker exec "${container_name}" bash "${script_name}" openssl
- name: Docker - boost run: docker exec "${container_name}" bash "${script_name}" boost
- name: Docker - libtorrent run: docker exec "${container_name}" bash "${script_name}" libtorrent
# - name: Docker - double_conversion # if: matrix.qbt_build_tool == '' # run: docker exec "${container_name}" bash "${script_name}" double_conversion
- name: Docker - qtbase run: docker exec "${container_name}" bash "${script_name}" qtbase
- name: Docker - qttools run: docker exec "${container_name}" bash "${script_name}" qttools
- name: Docker - qbittorrent run: docker exec "${container_name}" bash "${script_name}" qbittorrent
- name: Docker - Set release asset name run: docker exec -w ${wd}/${qbt_build_dir}/completed "${container_name}" mv -f qbittorrent-nox ${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox
# - name: Generate artifact attestation # uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 # with: # subject-path: "${{ env.qbt_build_dir }}/completed/${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox"
# - name: Docker - Release Info # working-directory: "${{ env.workspace }}/${{ env.qbt_build_dir }}/release_info" # run: | # mv *.md *.json "${workspace}/${qbt_build_dir}/completed"
# - name: Host - Upload libtorrent-v${{ matrix.qbt_libtorrent_version }}-qbittorrent-nox and release info artifact # if: success() # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 # with: # name: libtorrent-v${{ matrix.qbt_libtorrent_version }}-${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox # path: | # ${{ env.qbt_build_dir }}/completed/* # !${{ env.qbt_build_dir }}/completed/*.png
# - name: Host - Upload cmake graphs artifact # if: success() && matrix.qbt_build_tool == '' # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 # with: # name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-graphs" # path: "${{ env.qbt_build_dir }}/completed/*.png"
# - name: Host - Upload build dir on error or cancel # if: ( cancelled() || failure() ) # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 # with: # name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-logs" # path: "${{ env.qbt_build_dir }}"ci-alpine-build
The alpine build workflow
name: ci - alpine build
on: workflow_call: inputs: workflow-files: description: "Alpine: workflow-files files" required: true type: string icu: description: "enable icu" required: true type: string debug: description: "debug builds" required: true type: string script_name: description: "script name" required: true type: string
jobs: build: runs-on: ${{ matrix.runs_on }} strategy: fail-fast: false matrix: runs_on: ["ubuntu-24.04-arm"] os_id: ["alpine"] os_version_id: ["edge"] qbt_cross_name: ["armhf", "armv7", "aarch64", "riscv64", "x86_64", "x86"] qbt_libtorrent_version: ["1.2", "2.0"] qbt_build_tool: [""] qbt_qbittorrent_tag: [""] include: - qbt_build_tool: "" qbt_qt_version_name: ""
name: "${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}libtorrent-v${{ matrix.qbt_libtorrent_version }}"
env: qbt_build_dir: "qbt-build" script_name: ${{ inputs.script_name }} set_skip_icu: ${{ inputs.icu }} set_workflow_files: ${{ inputs.workflow-files }} set_build_debug: ${{ inputs.debug }} set_qbt_mcm_url: "" # default is userdocs/qbt-musl-cross-make set_qbt_with_qemu: "" # default is yes set_qbt_host_deps: "" # default is no set_qbt_host_deps_repo: "" # default is userdocs/qbt-host-deps workspace: ${{ github.workspace }}
steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false
- name: Download ${{ env.script_name }} env: GH_TOKEN: "${{ github.token }}" run: | if [[ ! -f "${script_name}" ]]; then gh api "repos/${{ github.repository }}/contents/${script_name}" \ --header "Accept: application/vnd.github.raw+json" > "${script_name}" chmod +x "${script_name}" fi
- name: Host - Create Docker template env file run: | printf '%s\n' "qbt_revision_url=${{ github.repository }}" > env.custom printf '%s\n' "qbt_zlib_type=zlib" >> env.custom printf '%s\n' "qbt_skip_icu=${set_skip_icu}" >> env.custom printf '%s\n' "qbt_boost_tag=${{ matrix.qbt_boost_tag }}" >> env.custom printf '%s\n' "qbt_libtorrent_version=${{ matrix.qbt_libtorrent_version }}" >> env.custom printf '%s\n' "qbt_libtorrent_tag=${{ matrix.qbt_libtorrent_tag }}" >> env.custom printf '%s\n' "qbt_libtorrent_master_jamfile=" >> env.custom printf '%s\n' "qbt_qt_version=${{ matrix.qbt_qt_version }}" >> env.custom printf '%s\n' "qbt_qt_tag=${{ matrix.qbt_qt_tag }}" >> env.custom printf '%s\n' "qbt_qbittorrent_tag=${{ matrix.qbt_qbittorrent_tag }}" >> env.custom printf '%s\n' "qbt_build_dir=${qbt_build_dir}" >> env.custom printf '%s\n' "qbt_build_tool=${{ matrix.qbt_build_tool }}" >> env.custom printf '%s\n' "qbt_cross_name=${{ matrix.qbt_cross_name }}" >> env.custom printf '%s\n' "qbt_mcm_url=${set_qbt_mcm_url}" >> env.custom printf '%s\n' "qbt_patches_url=${{ github.repository }}" >> env.custom printf '%s\n' "qbt_workflow_files=${set_workflow_files}" >> env.custom printf '%s\n' "qbt_cache_dir=" >> env.custom printf '%s\n' "qbt_optimise_strip=" >> env.custom printf '%s\n' "qbt_build_debug=${set_build_debug}" >> env.custom printf '%s\n' "qbt_standard=" >> env.custom printf '%s\n' "qbt_static_ish=" >> env.custom printf '%s\n' "qbt_optimise=${qbt_optimise}" >> env.custom printf '%s\n' "qbt_with_qemu=${set_qbt_with_qemu}" >> env.custom printf '%s\n' "qbt_host_deps=${set_qbt_host_deps}" >> env.custom printf '%s\n\n' "qbt_host_deps_repo=${set_qbt_host_deps_repo}" >> env.custom
- name: Host - Debian based specific env if: matrix.os_id != 'alpine' run: | printf '%s\n' "LANG=C.UTF-8" >> env.custom printf '%s\n' "LC_ALL=C.UTF-8" >> env.custom printf '%s\n\n' "DEBIAN_FRONTEND=noninteractive" >> env.custom
- name: Host - Bootstrap qemu uses: userdocs/actions/qemu@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 with: target_arch: ${{ matrix.qbt_cross_name }}
- name: Host - Bootstrap docker container uses: userdocs/actions/qbt_docker@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 with: os_id: ${{ matrix.os_id }} os_version_id: ${{ matrix.os_version_id }} additional_apps: "curl git"
- name: Host - patches if: hashFiles('patches/**') != '' run: mkdir -p "${qbt_build_dir}/patches" && cp -rf patches/* "${qbt_build_dir}/patches/"
- name: Docker - bootstrap_deps if: inputs.script_name == 'qbt-nox-static.bash' run: docker exec "${container_name}" bash "${script_name}" bootstrap_deps
- name: Docker - Bootstrap build run: docker exec "${container_name}" bash "${script_name}" -bs-a
- name: Docker - glibc if: matrix.os_id != 'alpine' run: docker exec "${container_name}" bash "${script_name}" glibc
- name: Docker - zlib run: docker exec "${container_name}" bash "${script_name}" zlib
- name: Docker - iconv if: matrix.qbt_libtorrent_version == '1.2' run: docker exec "${container_name}" bash "${script_name}" iconv
- name: Docker - icu if: env.set_skip_icu == 'no' run: docker exec "${container_name}" bash "${script_name}" icu
- name: Docker - openssl run: docker exec "${container_name}" bash "${script_name}" openssl
- name: Docker - boost run: docker exec "${container_name}" bash "${script_name}" boost
- name: Docker - libtorrent run: docker exec "${container_name}" bash "${script_name}" libtorrent
# - name: Docker - double_conversion # if: matrix.qbt_build_tool == '' # run: docker exec "${container_name}" bash "${script_name}" double_conversion
- name: Docker - qtbase run: docker exec "${container_name}" bash "${script_name}" qtbase
- name: Docker - qttools run: docker exec "${container_name}" bash "${script_name}" qttools
- name: Docker - qbittorrent run: docker exec "${container_name}" bash "${script_name}" qbittorrent
- name: Docker - Set release asset name run: docker exec -w ${wd}/${qbt_build_dir}/completed "${container_name}" mv -f qbittorrent-nox "${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox"
- name: Generate artifact attestation uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 with: subject-path: "${{ env.qbt_build_dir }}/completed/${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox"
- name: Docker - Release Info working-directory: "${{ env.workspace }}/${{ env.qbt_build_dir }}/release_info" run: | mv *.md *.json "${workspace}/${qbt_build_dir}/completed"
- name: Host - Upload libtorrent-v${{ matrix.qbt_libtorrent_version }}-qbittorrent-nox and release info artifact if: success() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: libtorrent-v${{ matrix.qbt_libtorrent_version }}-${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox path: | ${{ env.qbt_build_dir }}/completed/* !${{ env.qbt_build_dir }}/completed/*.png
- name: Host - Upload cmake graphs artifact if: success() && matrix.qbt_build_tool == '' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-graphs" path: "${{ env.qbt_build_dir }}/completed/*.png"
# - name: Host - Upload build dir on error or cancel # if: ( cancelled() || failure() ) # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 # with: # name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-logs" # path: "${{ env.qbt_build_dir }}"ci-alpine-release
The alpine release workflow
name: ci - alpine-release
on: workflow_call:
jobs: release: runs-on: ubuntu-24.04-arm permissions: contents: write strategy: fail-fast: false matrix: qbt_libtorrent_version: ["1.2", "2.0"] include: - qbt_libtorrent_version: "1.2" preview_release: true
- qbt_libtorrent_version: "2.0" preview_release: false
name: "Publish release libtorrent-v${{ matrix.qbt_libtorrent_version }}"
env: qbt_build_dir: "qbt-build"
steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false
- name: Pandoc - Bootstrap run: | pandoc_git_tag="$(git ls-remote -q -t --refs https://github.com/jgm/pandoc.git | awk '/tags\/[0-9]/{sub("refs/tags/", ""); print $2 }' | awk '!/^$/' | sort -rV | head -n 1)" curl -sLo- "https://github.com/jgm/pandoc/releases/latest/download/pandoc-${pandoc_git_tag}-linux-$(dpkg --print-architecture).tar.gz" | tar xzf - --strip-components 2 -C "$(pwd)" --exclude="share"
- name: Host - Download 1.2 qbittorrent-nox artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: "1.2" pattern: libtorrent-v1.2-*-qbittorrent-nox merge-multiple: true
- name: Host - Download 2.0 qbittorrent-nox artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: "2.0" pattern: libtorrent-v2.0-*-qbittorrent-nox merge-multiple: true
- name: Host - merge release-info env: lt_version: ${{ matrix.qbt_libtorrent_version }} run: | shopt -s nullglob
revision="$(jq -r .revision "${lt_version}"/*-dependency-version.json | sort -nr | head -n1)" boost="$(jq -r .boost "${lt_version}"/*-dependency-version.json | head -n1)"
# this need to check both 1.2 and 2.0 folders to merge the libtorrent versions in the dependency-version.json for dependency_version_json in {1.2,2.0}/*-dependency-version.json; do if [[ -f ${dependency_version_json} ]]; then sed -r 's/"boost": (.*)/BOOST_PLACEHOLDER/g' -i "${dependency_version_json}" sed -r 's/"revision": (.*)/REVISION_PLACEHOLDER/g' -i "${dependency_version_json}" dependency_version+=("${dependency_version_json}") fi done
# This file only needs to merge info specific to the libtorrent matrix running it. for release_md in "${lt_version}"/*-release.md; do if [[ -f ${release_md} ]]; then sed -r 's/^\|(.*)revision(.*)\|(.*)\|$/REVISION_PLACEHOLDER/g' -i "${release_md}" release_md+=("${release_md}") fi done
readarray -t release_sorted < <(printf '%s\n' "${release_md[@]}" | sort) readarray -t dependency_version_sorted < <(printf '%s\n' "${dependency_version[@]}" | sort)
paste -d '\n' "${release_sorted[@]}" | uniq | awk '!(NF && seen[$0]++) || /^>/' > "tmp-release.md" paste -d '\n' "${dependency_version_sorted[@]}" | uniq | awk '!(NF && seen[$0]++)' > "dependency-version.json"
sed -i "s|BOOST_PLACEHOLDER|\"boost\": \"${boost}\",|" dependency-version.json sed -i "s|REVISION_PLACEHOLDER|\"revision\": \"${revision}\"|" dependency-version.json sed -i "s/REVISION_PLACEHOLDER/| revision |${revision} |/" tmp-release.md
./pandoc --wrap=preserve -f gfm tmp-release.md -t gfm -o release.md
- name: Host - Bootstrap release tag run: printf '%s\n' "release_tag=$(cat ${{ matrix.qbt_libtorrent_version }}/tag.md)" >> $GITHUB_ENV
- name: Host - Bootstrap release title run: printf '%s\n' "release_title=$(cat ${{ matrix.qbt_libtorrent_version }}/title.md)" >> $GITHUB_ENV
- name: Host- Create release - tag - assets env: GH_TOKEN: "${{ github.TOKEN }}" run: | if git ls-remote --exit-code --tags origin "refs/tags/${release_tag}" >/dev/null 2>&1; then gh release edit "${release_tag}" \ --title "${release_title}" \ --notes-file release.md \ ${{ matrix.preview_release == true && '--prerelease' || '--latest' }} gh release upload "${release_tag}" \ --clobber \ ${{ matrix.qbt_libtorrent_version }}/*-qbittorrent-nox dependency-version.json else gh release create "${release_tag}" \ --title "${release_title}" \ --notes-file release.md \ ${{ matrix.preview_release == true && '--prerelease' || '--latest' }} \ ${{ matrix.qbt_libtorrent_version }}/*-qbittorrent-nox dependency-version.json fici-auto-rerun-failed-jobs-action
This workflow automatically reruns any failed jobs. Mostly targeted for the release jobs to ensure the release is created.
name: ci - auto rerun failed jobs
on: workflow_dispatch: inputs: run_id: description: "The run id of the workflow to rerun" required: true attempts: description: "The number of attempts to rerun the workflow" required: true retries: description: "The number of retries to rerun the workflow" required: true github_repo: description: "The repository to rerun the workflow" required: false
run-name: ci auto rerun failed jobs - attempt ${{ inputs.attempts }}
jobs: gh-cli-rerun: name: rerun - attempt ${{ inputs.attempts }} permissions: actions: write runs-on: ubuntu-24.04-arm environment: production env: GH_TOKEN: "${{ secrets.AUTO_RERUN || github.token }}" steps: - name: Host - Checkout action uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false
- uses: userdocs/gh-cli-workflow-reruns/actions/auto-rerun-failed@95ab77b1c4a1a8667e2f153ffc9a17048a961122 # v1.0.1 with: run_id: ${{ inputs.run_id }} attempts: ${{ inputs.attempts }} retries: ${{ inputs.retries }} github_repo: ${{ inputs.github_repo || github.repository }}