From 0fb477300e730ab1fab45c808b592c230c62b08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Mucha?= Date: Tue, 27 Oct 2026 00:02:16 +0100 Subject: [PATCH 1/2] test(layers): add ZIP compression check for layer channels in PSD saving --- libvips-plugin/test_vips.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libvips-plugin/test_vips.c b/libvips-plugin/test_vips.c index 24c592c..461a25b 100644 --- a/libvips-plugin/test_vips.c +++ b/libvips-plugin/test_vips.c @@ -840,6 +840,23 @@ static void check_layers_saved(const uint8_t *rgba, const char *dir) snprintf(again, sizeof again, "%s/layers-template-minipsd.psd", dir); check(write_file(&doc, again) && same_files(path, again), "the bytes minipsd_write makes from the same layers", path); + /* compression: the layer's channels ZIP, as Platemaker asks. */ + { + uint8_t workspace[WORKSPACE_SIZE], *file; + size_t size = 0; + minipsd_reader *r; + minipsd_info info; + minipsd_layer_view view; + snprintf(again, sizeof again, "%s/layers-template-zip.psd", dir); + file = minipsd_vips_psdsave_layers(pair, 2, again, "composite", template_image, "compression", MINIPSD_VIPS_COMPRESSION_ZIP, + NULL) == 0 ? read_all(again, &size) : NULL; + check(file && minipsd_reader_init(&r, file, size, workspace, sizeof workspace, NULL, &info) == MINIPSD_OK + && minipsd_reader_next_layer(r, &view) == MINIPSD_MORE && view.channel[0].size >= 2 && view.channel[0].data + && view.channel[0].data[1] == STORED_ZIP, + "the layer's channels ZIP", again); + free(file); + } + /* Its composite made by libvips from the layers: the template's own pixels. */ snprintf(again, sizeof again, "%s/layers-template-composed.psd", dir); check(minipsd_vips_psdsave_layers(pair, 2, again, NULL) == 0, "saved, composite composed", again); From 7cc731b8e5457c154a4235c77ad6cf62e314b3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Mucha?= Date: Tue, 27 Oct 2026 01:20:07 +0100 Subject: [PATCH 2/2] build(release): the Debian package attached to each release Each release now attaches libminipsd-dev_X.Y.Z_all.deb and its .sha256, the install tree packed by CPack's existing rules. tools/check_deb.sh packs it, installs it with apt and builds tests/consumer against it by find_package and by pkg-config; CI's linux-gcc job runs it on every pull request, and the release runs it before publishing and attests the package. The docs now say what a release holds: the single header, the plugin zip and the .deb. An archive (.tar.gz, .zip) is packed by the user with CPack. --- .github/workflows/ci.yml | 5 +++++ .github/workflows/release.yml | 19 +++++++++++++++---- README.md | 5 +++-- docs/CHANGELOG.md | 7 +++++++ docs/CODE-ARCH.md | 1 + docs/GITHUB-RELEASE.md | 18 +++++++++++------- docs/INSTALL.md | 16 ++++++++-------- tools/check_deb.sh | 26 ++++++++++++++++++++++++++ 8 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 tools/check_deb.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d41afcd..fa09cbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,6 +82,11 @@ jobs: cmake --build --preset ${{ matrix.preset }} ctest --preset ${{ matrix.preset }} + # The Debian package the release publishes: packed, installed, found by a consumer. + - name: Check the Debian package + if: matrix.preset == 'linux-gcc' + run: sh tools/check_deb.sh + # The plugin as released (minipsd-vips-X.Y.Z.zip, tools/package_vips.cmake): built from the # zip alone, outside the repository, its example run, its SBOM fragment checked against its # files; libvips as fetched above. The release builds it again on Linux before publishing. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6ff7865..ca39952 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,9 @@ # Release: a pushed tag X.Y.Z (bare semver) checks that CI already passed on its commit on master, # checks the tag against the header version and the changelog, and publishes minipsd.h (include/ joined into one file by # tools/amalgamate.cmake) + minipsd.h.sha256, and the libvips plugin as a CMake project that builds as it is -# (minipsd-vips-X.Y.Z.zip, tools/package_vips.cmake, built and run here first) + its .sha256, as a GitHub Release -# with build-provenance attestations. "Run workflow" (workflow_dispatch) does everything except publish, +# (minipsd-vips-X.Y.Z.zip, tools/package_vips.cmake, built and run here first) + its .sha256, and the +# Debian package (libminipsd-dev_X.Y.Z_all.deb, tools/check_deb.sh, installed and found here first) + its +# .sha256, as a GitHub Release with build-provenance attestations. "Run workflow" (workflow_dispatch) does everything except publish, # so it is a dry run. See docs/GITHUB-RELEASE.md. name: Release @@ -78,17 +79,25 @@ jobs: sudo apt-get update && sudo apt-get install -y --no-install-recommends libvips-dev ninja-build mkdir "$RUNNER_TEMP/plugin" && cd "$RUNNER_TEMP/plugin" cmake -E tar xf "$GITHUB_WORKSPACE"/dist/minipsd-vips-*.zip - cmake -DSPDX="$(echo minipsd-vips-*)/minipsd-vips.spdx.json" -DBASE="$(echo minipsd-vips-*)" -DCOMPLETE=ON -P "$GITHUB_WORKSPACE"/tools/check_spdx.cmake + cmake -DSPDX="$(echo minipsd-vips-*)/minipsd-vips.spdx.json" -DBASE="$(echo minipsd-vips-*)" -DCOMPLETE=ON \ + -P "$GITHUB_WORKSPACE"/tools/check_spdx.cmake cmake -S minipsd-vips-* -B build -G Ninja cmake --build build ctest --test-dir build --output-on-failure - # Verifiable with: gh attestation verify minipsd.h --repo ShadobaDev/minipsd (the zip alike) + # The install tree as a Debian package (CPack), installed here and found by a consumer. + - name: Stage the Debian package and its checksum + run: | + sh tools/check_deb.sh + cd dist && for deb in *.deb; do sha256sum "$deb" > "$deb.sha256" && cat "$deb.sha256"; done + + # Verifiable with: gh attestation verify minipsd.h --repo ShadobaDev/minipsd (the zip and the .deb alike) - uses: actions/attest-build-provenance@v4 with: subject-path: | dist/minipsd.h dist/minipsd-vips-*.zip + dist/libminipsd-dev_*_all.deb - name: Publish the GitHub Release if: github.ref_type == 'tag' @@ -102,3 +111,5 @@ jobs: dist/minipsd.h.sha256 dist/minipsd-vips-*.zip dist/minipsd-vips-*.zip.sha256 + dist/libminipsd-dev_*_all.deb + dist/libminipsd-dev_*_all.deb.sha256 diff --git a/README.md b/README.md index 5cb0335..77c2064 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,9 @@ the manual's [PSD in libvips](docs/MANUAL.md#psd-in-libvips-the-plugin). ## Adding it to a project -Copy the `include/` directory, or use CMake (FetchContent, git submodule, `find_package`), -pkg-config, an archive or a `.deb`; see [docs/INSTALL.md](docs/INSTALL.md). +Copy the `include/` directory (or the single `minipsd.h` each GitHub Release attaches), or use +CMake (FetchContent, git submodule, `find_package`), pkg-config, or the release's `.deb`; see +[docs/INSTALL.md](docs/INSTALL.md). ## Configuration diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f83b3f0..298ac87 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,6 +3,13 @@ Changes between releases, for users of minipsd. Versioning follows the pre-1.0 rules in [TODO.md](TODO.md): breaking changes bump the MINOR, additions and fixes the PATCH. +## [Unreleased] + +### Added +- Each GitHub Release attaches `libminipsd-dev_X.Y.Z_all.deb` and its `.sha256`, the install tree + as a Debian/Ubuntu package, installed and found by `find_package` and pkg-config before it is + published. + ## [0.4.0] — 2026-10-26 **Breaking:** `minipsd_doc.composite_alpha` now says, for every composite (given, composed from diff --git a/docs/CODE-ARCH.md b/docs/CODE-ARCH.md index 7366fac..40afdab 100644 --- a/docs/CODE-ARCH.md +++ b/docs/CODE-ARCH.md @@ -134,6 +134,7 @@ tools/ amalgamate.cmake joins include/ into one file, a release artifact package_vips.cmake packs the plugin as released: minipsd-vips-X.Y.Z.zip, its SBOM fragment inside check_spdx.cmake checks an SPDX fragment against its files (checksums, every file listed) + check_deb.sh packs the .deb the release attaches, installs it, builds a consumer against it compat_report.py regenerates COMPATIBILITY.md ``` diff --git a/docs/GITHUB-RELEASE.md b/docs/GITHUB-RELEASE.md index ebada9b..ae46494 100644 --- a/docs/GITHUB-RELEASE.md +++ b/docs/GITHUB-RELEASE.md @@ -16,13 +16,17 @@ Pushing the tag starts the [`Release`](../.github/workflows/release.yml) workflo (`tools/package_vips.cmake`), with its SBOM fragment, then checked against that fragment (`tools/check_spdx.cmake`) and built from the zip alone against Ubuntu's libvips, its example run: a zip that does not build is not published; -5. a build-provenance attestation for `minipsd.h` and the zip; -6. a GitHub Release with `minipsd.h`, the zip and a `.sha256` for each, its notes taken from the - changelog section. +5. the Debian package `libminipsd-dev_X.Y.Z_all.deb` (CPack), installed on the runner and found + by a consumer by `find_package` and pkg-config (`tools/check_deb.sh`): a package that does not + install is not published; +6. a build-provenance attestation for `minipsd.h`, the zip and the `.deb`; +7. a GitHub Release with `minipsd.h`, the zip, the `.deb` and a `.sha256` for each, its notes + taken from the changelog section. There is nothing to build for consumers: the source tree at the tag *is* the release. `minipsd.h` is for users who prefer one file to copying `include/`; the zip, for those who want the plugin -without the repository. CI packs and builds the zip on every push too, so it fails there first. +without the repository; the `.deb`, for an install by apt. CI packs and checks the zip and the +`.deb` on every push too, so they fail there first. ## 0. Pre-flight @@ -52,10 +56,10 @@ notes come from `docs/CHANGELOG.md`, not from the tag. ## 3. Verify - **Actions** → the Release run is green. -- **Releases** → `0.1.0` has `minipsd.h`, `minipsd-vips-0.1.0.zip`, a `.sha256` for each, and - the changelog notes. +- **Releases** → `0.1.0` has `minipsd.h`, `minipsd-vips-0.1.0.zip`, `libminipsd-dev_0.1.0_all.deb`, + a `.sha256` for each, and the changelog notes. - Provenance: `gh attestation verify minipsd.h --repo ShadobaDev/minipsd`, and the same for the - zip. + zip and the `.deb`. - A FetchContent consumer pinned to `GIT_TAG 0.1.0` configures and builds. ## 4. Then the consumers diff --git a/docs/INSTALL.md b/docs/INSTALL.md index f37de5d..3cd5f50 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -59,19 +59,19 @@ You can get that tree in any of these ways: cmake -S minipsd -B build -DMINIPSD_BUILD_TESTS=OFF cmake --install build --prefix /usr/local # Linux: with sudo ``` -- **As an archive**, `minipsd-X.Y.Z.tar.gz` or `.zip`: use it unpacked where it is, or extract - it into a prefix. The tree is relocatable, so nothing needs regenerating: +- **As a Debian/Ubuntu package**, `libminipsd-dev_X.Y.Z_all.deb`, attached to each GitHub + Release with its `.sha256` (installed and found by a consumer before it is published): ```bash - sudo tar -xzf minipsd-0.4.0.tar.gz --strip-components=1 -C /usr/local + sudo apt install ./libminipsd-dev_0.4.0_all.deb ``` -- **As a Debian/Ubuntu package**, `libminipsd-dev_X.Y.Z_all.deb`: +- **As an archive you pack yourself**, `minipsd-X.Y.Z.tar.gz` or `.zip`, with CPack from the source + ([CHEATSHEET.md](CHEATSHEET.md#packages-and-installing)); no release attaches one. Use it + unpacked where it is, or extract it into a prefix. The tree is relocatable, so nothing needs + regenerating: ```bash - sudo apt install ./libminipsd-dev_0.4.0_all.deb + sudo tar -xzf minipsd-0.4.0.tar.gz --strip-components=1 -C /usr/local ``` -The archive and the `.deb` are built with CPack, see -[CHEATSHEET.md](CHEATSHEET.md#packages-and-installing). - Then, in CMake (add `-DCMAKE_PREFIX_PATH=` unless the tree is in a system prefix): ```cmake diff --git a/tools/check_deb.sh b/tools/check_deb.sh new file mode 100644 index 0000000..193d5cd --- /dev/null +++ b/tools/check_deb.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# Packs minipsd as a Debian package, dist/libminipsd-dev_X.Y.Z_all.deb (CPack, CMakeLists.txt's +# rules), installs it, and builds tests/consumer against what it installed, by find_package and by +# pkg-config: a package that does not install, or is not found, is not published. Linux, with +# cmake, pkg-config and sudo; CI's linux-gcc job and the release run it. +# +# sh tools/check_deb.sh +set -eu +root=$(cd "$(dirname "$0")/.." && pwd) +version=$(sed -nE 's/^#define MINIPSD_VERSION_(MAJOR|MINOR|PATCH) +([0-9]+)$/\2/p' "$root/include/minipsd.h" | paste -sd.) +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT + +cmake -S "$root" -B "$work/package" -DMINIPSD_BUILD_TESTS=OFF +cpack --config "$work/package/CPackConfig.cmake" -G DEB +deb="$root/dist/libminipsd-dev_${version}_all.deb" +dpkg-deb -I "$deb" +dpkg-deb -c "$deb" +sudo apt-get install -y "$deb" + +for mode in package pkgconfig; do + cmake -S "$root/tests/consumer" -B "$work/consumer-$mode" -DMODE="$mode" -DMINIPSD_EXPECTED_VERSION="$version" + cmake --build "$work/consumer-$mode" + "$work/consumer-$mode/minipsd-consumer" +done +echo "$deb: installs, found by find_package and pkg-config"