From ecf44512c2629c8b04cd25fc2d78ac083c6cb669 Mon Sep 17 00:00:00 2001 From: SteveGilvarry Date: Sat, 13 Jun 2026 01:26:44 +1000 Subject: [PATCH] ci: attach complete source tarball with submodules to releases refs #4725 refs #3781 GitHub's auto-generated 'Source code' release assets are plain git archive output without submodules, so cmake fails immediately on the submodule check and the release cannot be built standalone. On every published release (or manual dispatch with a tag, to backfill existing releases) build zoneminder-.tar.gz from a recursive checkout and attach it plus a sha256 to the release. The tarball is reproducible (commit mtime, sorted entries, no owner, no gzip timestamp) and is sanity-checked for the same file CMakeLists.txt requires before upload. Co-Authored-By: Claude Fable 5 --- .github/workflows/release-source-tarball.yml | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 .github/workflows/release-source-tarball.yml diff --git a/.github/workflows/release-source-tarball.yml b/.github/workflows/release-source-tarball.yml new file mode 100644 index 000000000..b79c17d2f --- /dev/null +++ b/.github/workflows/release-source-tarball.yml @@ -0,0 +1,77 @@ +name: release-source-tarball + +# GitHub's auto-generated "Source code" release assets are plain `git archive` +# output and do not contain submodules, so they cannot be built (see #3781, +# #4725). This workflow attaches a complete source tarball, submodules +# included, to every release. It can also be dispatched manually to backfill +# the asset onto an existing release tag. + +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: 'Existing release tag to build and attach the tarball to' + required: true + type: string + +permissions: + contents: write + +jobs: + tarball: + name: Build full source tarball + if: github.repository == 'ZoneMinder/zoneminder' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + steps: + - name: Determine release tag + id: tag + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" + else + echo "tag=${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT" + fi + + - uses: actions/checkout@v6 + with: + ref: ${{ steps.tag.outputs.tag }} + submodules: recursive + + - name: Create tarball + id: tarball + run: | + set -eux + TAG="${{ steps.tag.outputs.tag }}" + TARBALL="zoneminder-${TAG}.tar.gz" + # Reproducible: fixed mtime from the tagged commit, sorted entries, + # no owner info, no gzip timestamp. Re-running the workflow for the + # same tag produces byte-identical output. + COMMIT_TS="$(git log -1 --format=%ct)" + tar --exclude-vcs \ + --sort=name \ + --mtime="@${COMMIT_TS}" \ + --owner=0 --group=0 --numeric-owner \ + --transform "s,^\.,zoneminder-${TAG}," \ + -cf - . | gzip -n > "../${TARBALL}" + mv "../${TARBALL}" . + sha256sum "${TARBALL}" > "${TARBALL}.sha256" + echo "tarball=${TARBALL}" >> "$GITHUB_OUTPUT" + + - name: Sanity check submodules are populated + run: | + set -eux + TARBALL="${{ steps.tarball.outputs.tarball }}" + # The same file CMakeLists.txt checks before allowing a build + tar -tzf "${TARBALL}" | grep -q 'web/api/app/Plugin/Crud/Lib/CrudControllerTrait.php' + tar -tzf "${TARBALL}" | grep -q 'dep/RtspServer/CMakeLists.txt' + tar -tzf "${TARBALL}" | grep -q 'dep/CxxUrl/CMakeLists.txt' + + - name: Attach to release + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ steps.tag.outputs.tag }} + files: | + ${{ steps.tarball.outputs.tarball }} + ${{ steps.tarball.outputs.tarball }}.sha256