Every WarpEngine API response now carries `WarpEngine-Version`, so a client can branch on the engine's age without a round trip to ask. Set in a before_action rather than after: `rescue_from` never reaches an after_action, and a client needs the version most when something came back wrong. The name lives in `WarpEngine::VERSION_HEADER`. The host's own endpoints — the store registry — do not carry it, because they are not the engine. A software has one pipeline, and the newest assignment now wins. Two pipelines pointing at the same software was not an error the database caught; it was a link that silently did nothing, with the software still showing whichever row came first. Assigning a software another pipeline holds therefore moves it, the admin says which pipeline it was taken from, and `Pipeline#software_taken_from` carries that for anything else that cares. Deliberately a callback and not a unique index: rows here are soft-deleted, and a unique index counts deleted rows, so a pipeline removed last year would block its software from ever being linked again. The engine is 0.4.0. The site's /stores page and its screenshot follow the client's new name, and the shot is a fresh one showing the greyed-out titles the client now lists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
101 lines
3.3 KiB
Ruby
101 lines
3.3 KiB
Ruby
require "rails_helper"
|
|
|
|
RSpec.describe WarpEngine::Pipeline do
|
|
describe "validations" do
|
|
subject { build(:pipeline) }
|
|
|
|
it { is_expected.to validate_presence_of(:woodpecker_repo_id) }
|
|
it { is_expected.to validate_uniqueness_of(:woodpecker_repo_id) }
|
|
it { is_expected.to validate_presence_of(:repo_owner) }
|
|
it { is_expected.to validate_presence_of(:repo_name) }
|
|
it { is_expected.to validate_presence_of(:platform) }
|
|
|
|
it "rejects unsupported platforms" do
|
|
repo = build(:pipeline, platform: "amiga")
|
|
expect(repo).not_to be_valid
|
|
expect(repo.errors[:platform]).to be_present
|
|
end
|
|
|
|
WarpEngine::PlatformLink::SUPPORTED_PLATFORMS.each do |p|
|
|
it "accepts #{p}" do
|
|
repo = build(:pipeline, platform: p)
|
|
expect(repo).to be_valid
|
|
end
|
|
end
|
|
|
|
it "accepts the unknown placeholder platform" do
|
|
repo = build(:pipeline, platform: WarpEngine::Pipeline::UNKNOWN_PLATFORM)
|
|
expect(repo).to be_valid
|
|
end
|
|
end
|
|
|
|
describe "#full_name" do
|
|
it "returns owner/name" do
|
|
repo = build(:pipeline, repo_owner: "games", repo_name: "mygame")
|
|
expect(repo.full_name).to eq("games/mygame")
|
|
end
|
|
end
|
|
|
|
describe "default_scope" do
|
|
it "excludes soft-deleted records" do
|
|
repo = create(:pipeline)
|
|
repo.update_column(:deleted_at, Time.current)
|
|
|
|
expect(described_class.all).not_to include(repo)
|
|
expect(described_class.unscoped).to include(repo)
|
|
end
|
|
end
|
|
|
|
describe ".active" do
|
|
it "returns only active repos" do
|
|
active = create(:pipeline, active: true)
|
|
inactive = create(:pipeline, active: false)
|
|
|
|
expect(described_class.active).to include(active)
|
|
expect(described_class.active).not_to include(inactive)
|
|
end
|
|
end
|
|
|
|
describe "associations" do
|
|
it { is_expected.to belong_to(:software).optional }
|
|
end
|
|
|
|
# A software has one pipeline. Two pipelines pointing at the same one is not an error
|
|
# the database catches, it is a link that silently does nothing — so the newest
|
|
# assignment takes it, and says what it took it from.
|
|
describe "assigning a software another pipeline already has" do
|
|
it "moves the link and leaves the other pipeline without one" do
|
|
software = create(:software)
|
|
held_by = create(:pipeline, software: software, repo_owner: "games", repo_name: "old")
|
|
taking = create(:pipeline, repo_owner: "games", repo_name: "new")
|
|
|
|
taking.update!(software: software)
|
|
|
|
expect(taking.reload.software).to eq(software)
|
|
expect(held_by.reload.software).to be_nil
|
|
expect(software.reload.pipeline).to eq(taking)
|
|
end
|
|
|
|
it "names the pipelines it took the software from" do
|
|
software = create(:software)
|
|
create(:pipeline, software: software, repo_owner: "games", repo_name: "old")
|
|
taking = create(:pipeline, repo_owner: "games", repo_name: "new")
|
|
|
|
taking.update!(software: software)
|
|
|
|
expect(taking.software_taken_from).to eq([ "games/old" ])
|
|
end
|
|
|
|
it "leaves other pipelines alone when the software is cleared" do
|
|
software = create(:software)
|
|
keeps = create(:pipeline, software: software, repo_owner: "games", repo_name: "keeps")
|
|
other = create(:pipeline, repo_owner: "games", repo_name: "other")
|
|
|
|
other.update!(software: nil)
|
|
|
|
expect(keeps.reload.software).to eq(software)
|
|
expect(other.software_taken_from).to be_nil
|
|
end
|
|
end
|
|
end
|