WarpEngine 0.7.0: a képtár és a CI is a hoszté, adapteren keresztül

Két dolog volt beépítve az engine-be, ami nem az övé.

A **képtár** eddig `WarpEngine::Image` volt, pedig a modell teljesen általános:
a teletypegames-ben a tagok arcképét is ez hordozza, nem csak a katalógus
borítóit. Az `Image` modell, a feltöltött fájlok, az `/api/image/:id` végpont
és az admin oldal ezért átkerült a hosztba, az engine pedig adapteren szól
hozzá (`WarpEngine::Images`): `url_for` adja a katalógus JSON `imageUrl`-jét,
`select_options` a software-form képválasztóját, `build_from_upload` a
"tölts fel új képet" ágat. Az alapértelmezés az `Image` osztály, tehát a
default útvonal bitre a régi. A `SoftwareImage` (a katalógus-kapcsolat)
maradt az engine-ben, és **az `images` tábla nem mozdult**: az engine csak
abbahagyta a létrehozását, a generátor írja meg hoszt-kódként.

A **CI** eddig végig Woodpecker volt: kliens, aláírás-ellenőrzés,
pipeline-receptek, repo-szinkron, secret-kiosztás. Mindez egy adapter mögé
került (`WarpEngine.ci`), a Woodpecker-implementáció pedig az engine-ben
maradt `WarpEngine::CI::Woodpecker` néven — kliens, adapter, httpsig-ellenőrző
és a platformonkénti pipeline-receptek, mert a YAML-dialektus a szolgáltatóé.
Az engine saját kódja már nem nevez szolgáltatót: `CI::Repo` és `CI::Run`
értékeket kap, `CI::ConnectionError`/`ApiError`/`NotConfigured` hibákat dob, a
`Pipeline` pedig `remote_repo_id`-t ad a történelmi `woodpecker_repo_id`
kolumna fölött (a tábla itt sem mozdult). `c.ci_adapter = :none` azt jelenti,
hogy ez a hoszt nem buildel: az `/api/ci/*` 503, a `/build/config` elutasít,
az admin akciók elbújnak.

Mindkét seam a hoszt initializerében van kimondva, nem alapértelmezésre
hagyva — a hoszt megnevezi, mi a képtára és mi a CI-ja.

Törés a 0.6-hoz képest: `image_container_path`, `image_owners`,
`ci_platforms`, `ci_update_server`, `ci_extension_public_key(_url)`,
`woodpecker_url`, `woodpecker_api_token`, `woodpecker_repo_owner` és a
`WarpEngine.woodpecker_configured?` megszűnt; a helyük `c.image_class_name` /
`c.image_adapter` és `c.ci_adapter`. Az `/api/ci/*` `latest_run`/`trigger`
válasza a normalizált `CI::Run` alakot adja (number, status, branch, message,
createdAt, url), a `pipelines` lista pedig `repo_id`-t is közöl a megtartott
`woodpecker_repo_id` mellett.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-23 00:56:01 +02:00
co-authored by Claude Opus 5
parent a0fbf1e2b4
commit 19d142ef64
62 changed files with 1391 additions and 793 deletions
+13 -29
View File
@@ -1,8 +1,8 @@
require "rails_helper"
RSpec.describe WarpEngine::SecretSyncService do
let(:client) { instance_double(WarpEngine::WoodpeckerClient) }
let(:service) { described_class.new(client: client) }
let(:ci) { instance_double(WarpEngine::CI::Woodpecker::Adapter) }
let(:service) { described_class.new(ci: ci) }
before do
allow(WarpEngine.config).to receive(:application_token_source).and_return(:database)
@@ -10,37 +10,22 @@ RSpec.describe WarpEngine::SecretSyncService do
end
describe "#provision" do
it "creates secrets on repos that don't have one" do
it "hands the token to the provider for every pipeline" do
repo = create(:pipeline)
allow(client).to receive(:list_secrets).with(repo.woodpecker_repo_id).and_return([])
allow(client).to receive(:create_secret)
allow(ci).to receive(:secret_set)
result = service.provision("plaintoken", pipelines: [ repo ])
expect(result[:synced]).to eq([ repo ])
expect(client).to have_received(:create_secret).with(
repo.woodpecker_repo_id, name: "application_token", value: "plaintoken"
)
end
it "updates secrets on repos that already have one" do
repo = create(:pipeline)
allow(client).to receive(:list_secrets).with(repo.woodpecker_repo_id)
.and_return([ { "name" => "application_token" } ])
allow(client).to receive(:update_secret)
result = service.provision("newtoken", pipelines: [ repo ])
expect(result[:synced]).to eq([ repo ])
expect(client).to have_received(:update_secret).with(
repo.woodpecker_repo_id, "application_token", value: "newtoken"
expect(ci).to have_received(:secret_set).with(
repo.remote_repo_id, name: "application_token", value: "plaintoken"
)
end
it "records failed repos without raising" do
repo = create(:pipeline)
allow(client).to receive(:list_secrets).and_raise(
WarpEngine::WoodpeckerClient::ConnectionError, "unreachable"
allow(ci).to receive(:secret_set).and_raise(
WarpEngine::CI::ConnectionError, "unreachable"
)
result = service.provision("tok", pipelines: [ repo ])
@@ -56,11 +41,11 @@ RSpec.describe WarpEngine::SecretSyncService do
sw = create(:software, name: "game1", owner: token.owner)
repo = create(:pipeline, :with_software, software: sw)
allow(client).to receive(:delete_secret)
allow(ci).to receive(:secret_delete)
service.deprovision(token)
expect(client).to have_received(:delete_secret).with(repo.woodpecker_repo_id, "application_token")
expect(ci).to have_received(:secret_delete).with(repo.remote_repo_id, "application_token")
end
end
@@ -70,8 +55,7 @@ RSpec.describe WarpEngine::SecretSyncService do
sw = create(:software, name: "game1", owner: token.owner)
repo = create(:pipeline, :with_software, software: sw)
allow(client).to receive(:list_secrets).and_return([])
allow(client).to receive(:create_secret)
allow(ci).to receive(:secret_set)
result = service.rotate(token)
@@ -85,8 +69,8 @@ RSpec.describe WarpEngine::SecretSyncService do
sw = create(:software, name: "game1", owner: token.owner)
create(:pipeline, :with_software, software: sw)
allow(client).to receive(:list_secrets).and_raise(
WarpEngine::WoodpeckerClient::ConnectionError, "down"
allow(ci).to receive(:secret_set).and_raise(
WarpEngine::CI::ConnectionError, "down"
)
result = service.rotate(token)