name: release on: workflow_dispatch: inputs: tag_name: description: Release tag (for example v0.1.0) required: true release_name: description: Optional release title required: false release_notes: description: Release notes / body required: false jobs: create-release: name: Create release runs-on: ubuntu-latest outputs: release_id: ${{ steps.release.outputs.release_id }} release_name: ${{ steps.release.outputs.release_name }} steps: - name: Create or reuse Gitea release id: release env: GITEA_TOKEN: ${{ github.token }} GITEA_API: ${{ github.server_url }}/api/v1 REPO: ${{ github.repository }} TAG_NAME: ${{ inputs.tag_name }} INPUT_RELEASE_NAME: ${{ inputs.release_name }} RELEASE_NOTES: ${{ inputs.release_notes }} TARGET_COMMITISH: ${{ github.sha }} run: | set -euo pipefail if [ -n "${INPUT_RELEASE_NAME}" ]; then RELEASE_NAME="${INPUT_RELEASE_NAME}" else RELEASE_NAME="Release ${TAG_NAME}" fi export RELEASE_NAME get_release_url="${GITEA_API}/repos/${REPO}/releases/tags/${TAG_NAME}" create_release_url="${GITEA_API}/repos/${REPO}/releases" status="$(curl -sS -o /tmp/release.json -w '%{http_code}' \ -H "Authorization: token ${GITEA_TOKEN}" \ "${get_release_url}")" if [ "${status}" = "200" ]; then python3 - <<'PY' >> "$GITHUB_OUTPUT" import json with open('/tmp/release.json', 'r', encoding='utf-8') as f: data = json.load(f) print(f"release_id={data['id']}") print(f"release_name={data['name']}") PY exit 0 fi if [ "${status}" != "404" ]; then echo "Unexpected response while checking release: HTTP ${status}" cat /tmp/release.json exit 1 fi python3 - <<'PY' > /tmp/release-payload.json import json, os payload = { "tag_name": os.environ["TAG_NAME"], "target_commitish": os.environ["TARGET_COMMITISH"], "name": os.environ["RELEASE_NAME"], "body": os.environ.get("RELEASE_NOTES", ""), "draft": False, "prerelease": False, } print(json.dumps(payload)) PY curl -sS \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -X POST \ --data @/tmp/release-payload.json \ "${create_release_url}" \ -o /tmp/release.json python3 - <<'PY' >> "$GITHUB_OUTPUT" import json with open('/tmp/release.json', 'r', encoding='utf-8') as f: data = json.load(f) if 'id' not in data: raise SystemExit(json.dumps(data, indent=2)) print(f"release_id={data['id']}") print(f"release_name={data['name']}") PY build-release: name: ${{ matrix.toolchain.name }} needs: create-release runs-on: ubuntu-latest strategy: fail-fast: false matrix: toolchain: - name: x86_64 Linux host: x86_64-linux-gnu packages: gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev - name: Win64 host: x86_64-w64-mingw32 packages: cmake python3 g++-mingw-w64-x86-64 - name: ARM v8 host: aarch64-linux-gnu packages: python3 gperf g++-aarch64-linux-gnu - name: Cross-Mac aarch64 host: aarch64-apple-darwin packages: cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools-git steps: - name: Checkout uses: https://github.com/actions/checkout@v4 with: fetch-depth: 1 fetch-tags: true submodules: false - name: Prepare cache keys run: | git submodule status --cached --recursive > .ci-submodules.lock DEPENDS_KEY="$(cat contrib/depends/Makefile contrib/depends/funcs.mk contrib/depends/hosts/*.mk contrib/depends/packages/*.mk contrib/depends/toolchain.cmake.in | sha256sum | cut -d' ' -f1)" echo "EXTERNAL_CACHE_KEY=v2-$(sha256sum .ci-submodules.lock | cut -d' ' -f1)" >> "$GITHUB_ENV" echo "DEPENDS_CACHE_KEY=${DEPENDS_KEY}" >> "$GITHUB_ENV" - name: Restore external cache run: | CACHE_ROOT="${RUNNER_TOOL_CACHE:-/tmp}/peya-ci" EXTERNAL_ARCHIVE="${CACHE_ROOT}/external-${EXTERNAL_CACHE_KEY}.tar.zst" if [ -f "${EXTERNAL_ARCHIVE}" ]; then echo "Restoring external cache from ${EXTERNAL_ARCHIVE}" rm -rf external .git/modules/external mkdir -p external .git/modules tar --zstd -xf "${EXTERNAL_ARCHIVE}" if [ -d ".git/modules/external" ]; then echo "EXTERNAL_CACHE_HIT=true" >> "$GITHUB_ENV" else echo "External cache is missing .git/modules/external, ignoring it" rm -rf external .git/modules/external echo "EXTERNAL_CACHE_HIT=false" >> "$GITHUB_ENV" fi else echo "No external cache found" echo "EXTERNAL_CACHE_HIT=false" >> "$GITHUB_ENV" fi - name: Sync submodules run: | git submodule sync --recursive git submodule update --init --recursive --depth 1 --jobs "$(nproc)" - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ automake \ autotools-dev \ build-essential \ ca-certificates \ ccache \ clang \ cmake \ curl \ git \ libssl-dev \ libtool \ pkg-config \ zip \ ${{ matrix.toolchain.packages }} - name: Restore depends cache run: | CACHE_ROOT="${RUNNER_TOOL_CACHE:-/tmp}/peya-ci" DEPENDS_ARCHIVE="${CACHE_ROOT}/depends-${{ matrix.toolchain.host }}-${DEPENDS_CACHE_KEY}.tar.zst" if [ -f "${DEPENDS_ARCHIVE}" ]; then echo "Restoring depends cache from ${DEPENDS_ARCHIVE}" tar --zstd -xf "${DEPENDS_ARCHIVE}" else echo "No depends cache found" fi - name: Prepare MinGW alternatives if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' }} run: | sudo update-alternatives --set ${{ matrix.toolchain.host }}-g++ "$(which ${{ matrix.toolchain.host }}-g++-posix)" sudo update-alternatives --set ${{ matrix.toolchain.host }}-gcc "$(which ${{ matrix.toolchain.host }}-gcc-posix)" - name: Build run: | make depends target=${{ matrix.toolchain.host }} -j"$(nproc)" - name: Save external cache if: success() run: | CACHE_ROOT="${RUNNER_TOOL_CACHE:-/tmp}/peya-ci" EXTERNAL_ARCHIVE="${CACHE_ROOT}/external-${EXTERNAL_CACHE_KEY}.tar.zst" mkdir -p "${CACHE_ROOT}" if [ ! -f "${EXTERNAL_ARCHIVE}" ]; then tar --zstd -cf "${EXTERNAL_ARCHIVE}" external .git/modules/external fi - name: Save depends cache if: success() run: | CACHE_ROOT="${RUNNER_TOOL_CACHE:-/tmp}/peya-ci" DEPENDS_ARCHIVE="${CACHE_ROOT}/depends-${{ matrix.toolchain.host }}-${DEPENDS_CACHE_KEY}.tar.zst" mkdir -p "${CACHE_ROOT}" if [ ! -f "${DEPENDS_ARCHIVE}" ]; then tar --zstd -cf "${DEPENDS_ARCHIVE}" \ contrib/depends/built \ contrib/depends/sources \ contrib/depends/work/build \ contrib/depends/${{ matrix.toolchain.host }} fi - name: Package release archive run: | REF_NAME="${{ inputs.tag_name }}" if [ "${{ matrix.toolchain.host }}" = "x86_64-w64-mingw32" ]; then ARCHIVE="/tmp/peya-${REF_NAME}-${{ matrix.toolchain.host }}.zip" else ARCHIVE="/tmp/peya-${REF_NAME}-${{ matrix.toolchain.host }}.tar.gz" fi cd "build/${{ matrix.toolchain.host }}/release/bin" FILES=() for pattern in peyad* peya-wallet-cli* peya-wallet-rpc* peya-gen-multisig*; do for file in $pattern; do if [ -e "$file" ]; then FILES+=("$file") fi done done if [ "${#FILES[@]}" -eq 0 ]; then echo "No release binaries found in $(pwd)" exit 1 fi if [ "${ARCHIVE##*.}" = "zip" ]; then zip -ur "${ARCHIVE}" "${FILES[@]}" else tar -czf "${ARCHIVE}" "${FILES[@]}" fi ls -lh "${ARCHIVE}" - name: Upload workflow artifact uses: https://github.com/actions/upload-artifact@v3 with: name: peya-${{ matrix.toolchain.host }} path: | /tmp/peya-*-${{ matrix.toolchain.host }}.zip /tmp/peya-*-${{ matrix.toolchain.host }}.tar.gz if-no-files-found: error - name: Upload release asset env: GITEA_TOKEN: ${{ github.token }} GITEA_API: ${{ github.server_url }}/api/v1 REPO: ${{ github.repository }} RELEASE_ID: ${{ needs.create-release.outputs.release_id }} run: | set -euo pipefail asset="$(find /tmp -maxdepth 1 \( -name 'peya-*-${{ matrix.toolchain.host }}.zip' -o -name 'peya-*-${{ matrix.toolchain.host }}.tar.gz' \) | head -n 1)" if [ -z "${asset}" ]; then echo "No packaged release asset found for ${{ matrix.toolchain.host }}" exit 1 fi asset_name="$(basename "${asset}")" assets_url="${GITEA_API}/repos/${REPO}/releases/${RELEASE_ID}/assets" curl -sS \ -H "Authorization: token ${GITEA_TOKEN}" \ "${assets_url}" \ -o /tmp/release-assets.json existing_id="$(ASSET_NAME="${asset_name}" python3 - <<'PY' import json, os name = os.environ["ASSET_NAME"] with open('/tmp/release-assets.json', 'r', encoding='utf-8') as f: assets = json.load(f) for asset in assets: if asset.get('name') == name: print(asset['id']) break PY )" if [ -n "${existing_id}" ]; then curl -sS \ -H "Authorization: token ${GITEA_TOKEN}" \ -X DELETE \ "${assets_url}/${existing_id}" \ >/dev/null fi curl -sS \ -H "Authorization: token ${GITEA_TOKEN}" \ -X POST \ -F "attachment=@${asset}" \ "${assets_url}?name=${asset_name}" \ >/dev/null