Files
warp_engine/spec/presenters/asset_coverage_checklist_spec.rb
T
mr.zeroandClaude Opus 5 0adde2070d A checklist of the release assets that exist and the ones the CI could still build
Nothing said whether a release was finished. A pipeline step can fail, a
platform can gain a target, a title can be published from a laptop — and the
catalog happily serves a release with three of its seven assets. The only way
to find out was to open `/api/softwares/<name>/builds` one name at a time.

    $ bin/rails warp_engine:builds:check

    rabbitroller  ebitengine  v1.1.1  1/7
      [x] html
      [ ] win_x86
      [ ] win_x64
      [ ] linux_x64
      [ ] linux_arm64
      [-] mac_x64
      [-] mac_arm64

    The CI can build these and the release does not have them:
      rabbitroller v1.1.1 (ebitengine): win_x86, win_x64, linux_x64, linux_arm64

    5 softwares, 5 releases, 14/32 assets present, 16 missing from CI-built kinds

The third marker is the point. Two different questions were being conflated:
what the **updater** can ingest (`Platform#expected_kinds`) and what the
**pipeline** actually produces. For six of the seven platforms they are the
same list; for ebitengine they are not — the updater accepts macOS builds, the
Woodpecker builder cannot cross-compile them (osxcross), so `mac_x64` and
`mac_arm64` would be reported as gaps on every ebitengine release, for ever.
`[ ]` is now a real gap and `[-]` is "upload it by hand or not at all", so the
list stays worth reading.

That knowledge is data, next to the templates that produce it:
`PipelineConfig::BUILT_KINDS`, reachable through the adapter as
`built_kinds(platform)`. An adapter that cannot answer — no CI configured, a
platform with no builder — returns nil, and then nothing is excused: every
missing kind counts as a gap.

`WarpEngine::AssetCoverage` computes it (`#rows`, `#missing_rows`, `#totals`)
and `AssetCoverageChecklist` renders it, so the numbers are testable without a
terminal. Options are env vars: NAME, PLATFORM, RELEASES=all, ONLY=missing, and
STRICT=1 for a non-zero exit in CI. The default is the newest release per
software, using the same non-`dev-` rule the catalog API uses for "latest".

33 new examples, including two that keep BUILT_KINDS honest: every claimed kind
has to be a kind the updater knows, and has to appear in the platform's rendered
pipeline. Adding a platform without teaching this list about it fails the suite.

Ships in 0.8.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 09:34:23 +02:00

53 lines
2.2 KiB
Ruby

require "rails_helper"
RSpec.describe WarpEngine::AssetCoverageChecklist do
let(:software) { create(:software, name: "rabbitroller", platform: "ebitengine") }
before do
release = create(:release, software: software, version: "1.1.1")
WarpEngine::ReleaseAsset.create!(release: release, kind: "html", path: "/s/rabbitroller-1.1.1")
ci = instance_double(WarpEngine::CI::Woodpecker::Adapter)
allow(ci).to receive(:built_kinds) { |platform| WarpEngine::CI::Woodpecker::PipelineConfig::BUILT_KINDS[platform] }
allow(WarpEngine).to receive(:ci).and_return(ci)
end
def output(**options) = described_class.new(WarpEngine::AssetCoverage.new(**options)).to_s
it "checks off what is there and leaves the rest open" do
lines = output.lines.map(&:chomp)
expect(lines).to include("rabbitroller ebitengine v1.1.1 1/7")
expect(lines).to include(" [x] html")
expect(lines).to include(" [ ] linux_arm64")
expect(lines).to include(" [-] mac_arm64")
end
it "lists what the CI could build and the release does not have" do
expect(output).to include("The CI can build these and the release does not have them:")
expect(output).to include("rabbitroller v1.1.1 (ebitengine): win_x86, win_x64, linux_x64, linux_arm64")
end
it "counts the assets and says how many the CI does not build" do
expect(output).to include("1 softwares, 1 releases, 1/7 assets present, 4 missing from CI-built kinds")
expect(output).to include("2 assets are expected but this CI does not build them")
end
it "shows only the incomplete releases when asked" do
complete = create(:software, name: "pong", platform: "c64")
release = create(:release, software: complete, version: "0.1")
WarpEngine::ReleaseAsset.create!(release: release, kind: "cartridge", path: "/s/pong-0.1.prg")
text = described_class.new(WarpEngine::AssetCoverage.new, only_missing: true).to_s
expect(text).to include("rabbitroller")
expect(text).not_to include("pong")
end
it "says so when there is nothing to report" do
text = described_class.new(WarpEngine::AssetCoverage.new(name: "nothing-here")).to_s
expect(text).to include("Nothing to report.")
end
end