From 254d33965628fd4c379cfe341c6b6b4a167da787 Mon Sep 17 00:00:00 2001 From: Zsolt Tasnadi Date: Thu, 6 Aug 2026 19:46:06 +0200 Subject: [PATCH] warp_engine: CiRepository -> Pipeline rename everywhere, ci_ service prefixes dropped, unknown platform allowed --- apps/api/db/schema.rb | 40 ++++++------- libs/ruby/warp_engine/README.md | 2 +- .../app/admin/application_tokens.rb | 18 +++--- libs/ruby/warp_engine/app/admin/pipelines.rb | 20 +++---- libs/ruby/warp_engine/app/admin/softwares.rb | 4 +- .../warp_engine/api/ci_controller.rb | 56 +++++++++---------- .../app/jobs/warp_engine/ci_repo_sync_job.rb | 9 --- .../app/jobs/warp_engine/pipeline_sync_job.rb | 9 +++ .../{ci_repository.rb => pipeline.rb} | 12 ++-- .../app/models/warp_engine/software.rb | 2 +- .../warp_engine/ci_pipeline_service.rb | 35 ------------ .../services/warp_engine/pipeline_service.rb | 35 ++++++++++++ ...nc_service.rb => pipeline_sync_service.rb} | 16 +++--- ...sync_service.rb => secret_sync_service.rb} | 38 ++++++------- libs/ruby/warp_engine/config/routes.rb | 6 +- ...002_rename_ci_repositories_to_pipelines.rb | 15 +++++ libs/ruby/warp_engine/spec/dummy/db/schema.rb | 40 ++++++------- .../{ci_repositories.rb => pipelines.rb} | 2 +- ...ci_repository_spec.rb => pipeline_spec.rb} | 21 ++++--- .../spec/requests/ci_controller_spec.rb | 26 ++++----- ...rvice_spec.rb => pipeline_service_spec.rb} | 10 ++-- ..._spec.rb => pipeline_sync_service_spec.rb} | 10 ++-- ...ce_spec.rb => secret_sync_service_spec.rb} | 36 ++++++------ 23 files changed, 243 insertions(+), 219 deletions(-) delete mode 100644 libs/ruby/warp_engine/app/jobs/warp_engine/ci_repo_sync_job.rb create mode 100644 libs/ruby/warp_engine/app/jobs/warp_engine/pipeline_sync_job.rb rename libs/ruby/warp_engine/app/models/warp_engine/{ci_repository.rb => pipeline.rb} (71%) delete mode 100644 libs/ruby/warp_engine/app/services/warp_engine/ci_pipeline_service.rb create mode 100644 libs/ruby/warp_engine/app/services/warp_engine/pipeline_service.rb rename libs/ruby/warp_engine/app/services/warp_engine/{ci_repo_sync_service.rb => pipeline_sync_service.rb} (74%) rename libs/ruby/warp_engine/app/services/warp_engine/{ci_secret_sync_service.rb => secret_sync_service.rb} (54%) create mode 100644 libs/ruby/warp_engine/db/migrate/20260806000002_rename_ci_repositories_to_pipelines.rb rename libs/ruby/warp_engine/spec/factories/{ci_repositories.rb => pipelines.rb} (83%) rename libs/ruby/warp_engine/spec/models/{ci_repository_spec.rb => pipeline_spec.rb} (70%) rename libs/ruby/warp_engine/spec/services/{ci_pipeline_service_spec.rb => pipeline_service_spec.rb} (84%) rename libs/ruby/warp_engine/spec/services/{ci_repo_sync_service_spec.rb => pipeline_sync_service_spec.rb} (86%) rename libs/ruby/warp_engine/spec/services/{ci_secret_sync_service_spec.rb => secret_sync_service_spec.rb} (79%) diff --git a/apps/api/db/schema.rb b/apps/api/db/schema.rb index 950fbee..505e7bd 100644 --- a/apps/api/db/schema.rb +++ b/apps/api/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do +ActiveRecord::Schema[8.1].define(version: 2026_08_06_000002) do create_table "admin_users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "deleted_at", precision: 3 @@ -45,24 +45,6 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do t.index ["token_digest"], name: "idx_application_tokens_token_digest", unique: true end - create_table "ci_repositories", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| - t.boolean "active", default: true, null: false - t.datetime "created_at", precision: 3 - t.datetime "deleted_at", precision: 3 - t.datetime "last_pipeline_at", precision: 3 - t.string "last_pipeline_status", limit: 32 - t.string "platform", limit: 32, null: false - t.string "repo_name", limit: 128, null: false - t.string "repo_owner", limit: 128, null: false - t.bigint "software_id", unsigned: true - t.datetime "updated_at", precision: 3 - t.bigint "woodpecker_repo_id", null: false, unsigned: true - t.index ["deleted_at"], name: "idx_ci_repos_deleted" - t.index ["repo_owner", "repo_name"], name: "idx_ci_repos_owner_name", unique: true - t.index ["software_id"], name: "idx_ci_repos_software" - t.index ["woodpecker_repo_id"], name: "idx_ci_repos_wp_id", unique: true - end - create_table "downloads", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "created_at", precision: 3 t.datetime "deleted_at", precision: 3 @@ -214,6 +196,24 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do t.index ["image_id"], name: "index_members_on_image_id" end + create_table "pipelines", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| + t.boolean "active", default: true, null: false + t.datetime "created_at", precision: 3 + t.datetime "deleted_at", precision: 3 + t.datetime "last_pipeline_at", precision: 3 + t.string "last_pipeline_status", limit: 32 + t.string "platform", limit: 32, null: false + t.string "repo_name", limit: 128, null: false + t.string "repo_owner", limit: 128, null: false + t.bigint "software_id", unsigned: true + t.datetime "updated_at", precision: 3 + t.bigint "woodpecker_repo_id", null: false, unsigned: true + t.index ["deleted_at"], name: "idx_pipelines_deleted" + t.index ["repo_owner", "repo_name"], name: "idx_pipelines_owner_name", unique: true + t.index ["software_id"], name: "idx_pipelines_software" + t.index ["woodpecker_repo_id"], name: "idx_pipelines_wp_id", unique: true + end + create_table "platform_links", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "created_at", precision: 3 t.datetime "deleted_at", precision: 3 @@ -282,10 +282,10 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do end add_foreign_key "admin_users", "members" - add_foreign_key "ci_repositories", "softwares", name: "fk_ci_repos_software", on_delete: :nullify add_foreign_key "downloads", "releases", name: "fk_downloads_release", on_delete: :nullify add_foreign_key "external_links", "softwares", name: "fk_softwares_external_links", on_delete: :cascade add_foreign_key "members", "images" + add_foreign_key "pipelines", "softwares", name: "fk_pipelines_software", on_delete: :nullify add_foreign_key "release_assets", "releases", name: "fk_releases_release_assets", on_delete: :cascade add_foreign_key "releases", "softwares", name: "fk_softwares_releases", on_delete: :cascade add_foreign_key "software_images", "images" diff --git a/libs/ruby/warp_engine/README.md b/libs/ruby/warp_engine/README.md index 9e9d7d7..abd7a81 100644 --- a/libs/ruby/warp_engine/README.md +++ b/libs/ruby/warp_engine/README.md @@ -305,7 +305,7 @@ c.woodpecker_repo_owner = ENV["WOODPECKER_REPO_OWNER"] # forge org the game repo What it unlocks (all surfaced in the admin): - **Repo sync** (*Pipelines → Sync from Woodpecker*): mirrors the Woodpecker - repo list into `CiRepository` records, auto-matching each repo to a catalog + repo list into `Pipeline` records, auto-matching each repo to a catalog `Software` by name; repos that disappear from Woodpecker are deactivated. Platform and software links are editable by hand afterwards. - **Pipeline history**: each entry on the *Pipelines* page lists its recent diff --git a/libs/ruby/warp_engine/app/admin/application_tokens.rb b/libs/ruby/warp_engine/app/admin/application_tokens.rb index 5d1e5ea..dcc9a66 100644 --- a/libs/ruby/warp_engine/app/admin/application_tokens.rb +++ b/libs/ruby/warp_engine/app/admin/application_tokens.rb @@ -60,11 +60,11 @@ ActiveAdmin.register WarpEngine::ApplicationToken, as: "Application Token" do end member_action :rotate, method: :post do - result = WarpEngine::CiSecretSyncService.new.rotate(resource) + result = WarpEngine::SecretSyncService.new.rotate(resource) if result[:rotated] session[:warp_engine_plain_token] = result[:new_token].plain_token redirect_to resource_path(result[:new_token]), - notice: "Token rotated and synced to #{result.dig(:sync_result, :synced)&.size || 0} repo(s)" + notice: "Token rotated and synced to #{result.dig(:sync_result, :synced)&.size || 0} pipeline(s)" else redirect_to resource_path(resource), alert: "Rotation failed: #{result[:reason]}" @@ -101,13 +101,13 @@ ActiveAdmin.register WarpEngine::ApplicationToken, as: "Application Token" do session[:warp_engine_plain_token] = resource.plain_token if WarpEngine.woodpecker_configured? - service = WarpEngine::CiSecretSyncService.new - repos = service.repos_for_token(resource) - if repos.any? - result = service.provision(resource.plain_token, repos: repos) - flash[:notice] = "Token created and synced to #{result[:synced].size} repo(s)." + service = WarpEngine::SecretSyncService.new + pipelines = service.pipelines_for_token(resource) + if pipelines.any? + result = service.provision(resource.plain_token, pipelines: pipelines) + flash[:notice] = "Token created and synced to #{result[:synced].size} pipeline(s)." if result[:failed].any? - flash[:alert] = "Failed to sync to #{result[:failed].size} repo(s)." + flash[:alert] = "Failed to sync to #{result[:failed].size} pipeline(s)." end end end @@ -124,7 +124,7 @@ ActiveAdmin.register WarpEngine::ApplicationToken, as: "Application Token" do def destroy if WarpEngine.woodpecker_configured? - WarpEngine::CiSecretSyncService.new.deprovision(resource) + WarpEngine::SecretSyncService.new.deprovision(resource) end resource.revoke! redirect_to collection_path, notice: "Token revoked and Woodpecker secrets cleaned up." diff --git a/libs/ruby/warp_engine/app/admin/pipelines.rb b/libs/ruby/warp_engine/app/admin/pipelines.rb index 62d4139..7ee947d 100644 --- a/libs/ruby/warp_engine/app/admin/pipelines.rb +++ b/libs/ruby/warp_engine/app/admin/pipelines.rb @@ -1,4 +1,4 @@ -ActiveAdmin.register WarpEngine::CiRepository, as: "Pipeline" do +ActiveAdmin.register WarpEngine::Pipeline, as: "Pipeline" do actions :index, :show, :edit, :update menu parent: "🌀 WarpEngine", priority: 10, label: "🚀 Pipelines" @@ -30,9 +30,9 @@ ActiveAdmin.register WarpEngine::CiRepository, as: "Pipeline" do end } column :last_pipeline_at - actions defaults: true do |repo| - if repo.active && WarpEngine.woodpecker_configured? - item "Trigger", trigger_admin_pipeline_path(repo), method: :post, class: "member_link" + actions defaults: true do |pipeline| + if pipeline.active && WarpEngine.woodpecker_configured? + item "Trigger", trigger_admin_pipeline_path(pipeline), method: :post, class: "member_link" end end end @@ -76,7 +76,7 @@ ActiveAdmin.register WarpEngine::CiRepository, as: "Pipeline" do para "This repository is inactive.", style: "color:#999;" else begin - pipelines = WarpEngine::CiPipelineService.new.list_pipelines(resource, page: 1) + pipelines = WarpEngine::PipelineService.new.list_pipelines(resource, page: 1) if pipelines.is_a?(Array) && pipelines.any? table_for pipelines.first(10) do column("Number") { |p| p["number"] } @@ -97,15 +97,15 @@ ActiveAdmin.register WarpEngine::CiRepository, as: "Pipeline" do end member_action :trigger, method: :post do - repo = WarpEngine::CiRepository.find(params[:id]) - WarpEngine::CiPipelineService.new.trigger(repo) - redirect_to resource_path(repo), notice: "Pipeline triggered for #{repo.full_name}" + pipeline = WarpEngine::Pipeline.find(params[:id]) + WarpEngine::PipelineService.new.trigger(pipeline) + redirect_to resource_path(pipeline), notice: "Pipeline triggered for #{pipeline.full_name}" rescue => e - redirect_to resource_path(repo), alert: "Trigger failed: #{e.message}" + redirect_to resource_path(pipeline), alert: "Trigger failed: #{e.message}" end collection_action :sync, method: :post do - result = WarpEngine::CiRepoSyncService.new.sync_all + result = WarpEngine::PipelineSyncService.new.sync_all redirect_to collection_path, notice: "Synced: #{result[:created].size} new, #{result[:updated].size} updated, #{result[:deactivated].size} deactivated" rescue => e diff --git a/libs/ruby/warp_engine/app/admin/softwares.rb b/libs/ruby/warp_engine/app/admin/softwares.rb index e5224e3..1e511a2 100644 --- a/libs/ruby/warp_engine/app/admin/softwares.rb +++ b/libs/ruby/warp_engine/app/admin/softwares.rb @@ -53,9 +53,9 @@ ActiveAdmin.register WarpEngine::Software, as: "Software" do end end - if resource.ci_repository + if resource.pipeline div style: "margin-bottom:8px;" do - a href: admin_pipeline_path(resource.ci_repository), style: "display:inline-flex;align-items:center;gap:6px;font-weight:bold;color:#5850ec;" do + a href: admin_pipeline_path(resource.pipeline), style: "display:inline-flex;align-items:center;gap:6px;font-weight:bold;color:#5850ec;" do span "🚀", style: "font-size:16px;" text_node "Pipelines" end diff --git a/libs/ruby/warp_engine/app/controllers/warp_engine/api/ci_controller.rb b/libs/ruby/warp_engine/app/controllers/warp_engine/api/ci_controller.rb index 5466241..09884d9 100644 --- a/libs/ruby/warp_engine/app/controllers/warp_engine/api/ci_controller.rb +++ b/libs/ruby/warp_engine/app/controllers/warp_engine/api/ci_controller.rb @@ -6,36 +6,36 @@ module WarpEngine before_action :require_woodpecker! resource_description do - short "CI repository and pipeline management" + short "CI pipeline management" end - api :GET, "/api/ci/repos", "List active CI repositories" - returns code: 200, desc: "JSON array of tracked repos" + api :GET, "/api/ci/pipelines", "List active pipelines" + returns code: 200, desc: "JSON array of tracked pipelines" error code: 503, desc: "Woodpecker not configured" - def repos - records = CiRepository.active.includes(:software) - render json: records.map { |r| repo_json(r) } + def pipelines + records = Pipeline.active.includes(:software) + render json: records.map { |p| pipeline_json(p) } end - api :GET, "/api/ci/repos/:id/status", "Get a CI repository with its latest pipeline" - param :id, :number, required: true, desc: "CiRepository id" - returns code: 200, desc: "JSON with repo and pipeline data" + api :GET, "/api/ci/pipelines/:id/status", "Get a pipeline with its latest run" + param :id, :number, required: true, desc: "Pipeline id" + returns code: 200, desc: "JSON with pipeline and latest run data" error code: 503, desc: "Woodpecker not configured" def status - repo = CiRepository.find(params[:id]) - pipeline = begin - CiPipelineService.new.pipeline_detail(repo, "latest") + pipeline = Pipeline.find(params[:id]) + latest_run = begin + PipelineService.new.pipeline_detail(pipeline, "latest") rescue WoodpeckerClient::ApiError nil end - render json: { repo: repo_json(repo), pipeline: pipeline } + render json: { pipeline: pipeline_json(pipeline), latest_run: latest_run } end - api :POST, "/api/ci/repos/:id/trigger", "Trigger a pipeline for a CI repository" + api :POST, "/api/ci/pipelines/:id/trigger", "Trigger a pipeline" header "X-Update-Secret", "Shared secret or application token (update scope)", required: true - param :id, :number, required: true, desc: "CiRepository id" + param :id, :number, required: true, desc: "Pipeline id" param :branch, String, required: false, desc: "Branch to build (default: main)" - returns code: 200, desc: "JSON with triggered pipeline data" + returns code: 200, desc: "JSON with triggered run data" error code: 401, desc: "Invalid secret" error code: 503, desc: "Woodpecker not configured" def trigger @@ -43,8 +43,8 @@ module WarpEngine return render json: { error: "Unauthorized" }, status: :unauthorized end - repo = CiRepository.find(params[:id]) - result = CiPipelineService.new.trigger(repo, branch: params[:branch] || "main") + pipeline = Pipeline.find(params[:id]) + result = PipelineService.new.trigger(pipeline, branch: params[:branch] || "main") render json: { triggered: true, pipeline: result } end @@ -56,17 +56,17 @@ module WarpEngine render json: { error: "Woodpecker not configured" }, status: :service_unavailable end - def repo_json(repo) + def pipeline_json(pipeline) { - id: repo.id, - woodpecker_repo_id: repo.woodpecker_repo_id, - repo_owner: repo.repo_owner, - repo_name: repo.repo_name, - platform: repo.platform, - active: repo.active, - software_name: repo.software&.name, - last_pipeline_status: repo.last_pipeline_status, - last_pipeline_at: repo.last_pipeline_at + id: pipeline.id, + woodpecker_repo_id: pipeline.woodpecker_repo_id, + repo_owner: pipeline.repo_owner, + repo_name: pipeline.repo_name, + platform: pipeline.platform, + active: pipeline.active, + software_name: pipeline.software&.name, + last_pipeline_status: pipeline.last_pipeline_status, + last_pipeline_at: pipeline.last_pipeline_at } end end diff --git a/libs/ruby/warp_engine/app/jobs/warp_engine/ci_repo_sync_job.rb b/libs/ruby/warp_engine/app/jobs/warp_engine/ci_repo_sync_job.rb deleted file mode 100644 index cd51845..0000000 --- a/libs/ruby/warp_engine/app/jobs/warp_engine/ci_repo_sync_job.rb +++ /dev/null @@ -1,9 +0,0 @@ -module WarpEngine - class CiRepoSyncJob < ApplicationJob - queue_as :default - - def perform - CiRepoSyncService.new.sync_all - end - end -end diff --git a/libs/ruby/warp_engine/app/jobs/warp_engine/pipeline_sync_job.rb b/libs/ruby/warp_engine/app/jobs/warp_engine/pipeline_sync_job.rb new file mode 100644 index 0000000..355463e --- /dev/null +++ b/libs/ruby/warp_engine/app/jobs/warp_engine/pipeline_sync_job.rb @@ -0,0 +1,9 @@ +module WarpEngine + class PipelineSyncJob < ApplicationJob + queue_as :default + + def perform + PipelineSyncService.new.sync_all + end + end +end diff --git a/libs/ruby/warp_engine/app/models/warp_engine/ci_repository.rb b/libs/ruby/warp_engine/app/models/warp_engine/pipeline.rb similarity index 71% rename from libs/ruby/warp_engine/app/models/warp_engine/ci_repository.rb rename to libs/ruby/warp_engine/app/models/warp_engine/pipeline.rb index 23eb88b..5d29322 100644 --- a/libs/ruby/warp_engine/app/models/warp_engine/ci_repository.rb +++ b/libs/ruby/warp_engine/app/models/warp_engine/pipeline.rb @@ -1,6 +1,10 @@ module WarpEngine - class CiRepository < ApplicationRecord - self.table_name = "ci_repositories" + class Pipeline < ApplicationRecord + self.table_name = "pipelines" + + # Repos synced from Woodpecker without a matching Software land here + # until a platform is assigned by hand. + UNKNOWN_PLATFORM = "unknown".freeze belongs_to :software, class_name: "WarpEngine::Software", optional: true @@ -10,7 +14,7 @@ module WarpEngine validates :repo_owner, presence: true validates :repo_name, presence: true validates :platform, presence: true, - inclusion: { in: WarpEngine::PlatformLink::SUPPORTED_PLATFORMS } + inclusion: { in: WarpEngine::PlatformLink::SUPPORTED_PLATFORMS + [ UNKNOWN_PLATFORM ] } scope :active, -> { where(active: true) } @@ -27,6 +31,6 @@ module WarpEngine %w[software] end - ActiveSupport.run_load_hooks(:warp_engine_ci_repository, self) + ActiveSupport.run_load_hooks(:warp_engine_pipeline, self) end end diff --git a/libs/ruby/warp_engine/app/models/warp_engine/software.rb b/libs/ruby/warp_engine/app/models/warp_engine/software.rb index 0a9cfc0..596324a 100644 --- a/libs/ruby/warp_engine/app/models/warp_engine/software.rb +++ b/libs/ruby/warp_engine/app/models/warp_engine/software.rb @@ -11,7 +11,7 @@ module WarpEngine has_many :releases, foreign_key: :software_id has_many :downloads, through: :releases has_many :external_links, foreign_key: :software_id - has_one :ci_repository, foreign_key: :software_id + has_one :pipeline, foreign_key: :software_id accepts_nested_attributes_for :software_images, allow_destroy: true accepts_nested_attributes_for :external_links, allow_destroy: true diff --git a/libs/ruby/warp_engine/app/services/warp_engine/ci_pipeline_service.rb b/libs/ruby/warp_engine/app/services/warp_engine/ci_pipeline_service.rb deleted file mode 100644 index c4075a1..0000000 --- a/libs/ruby/warp_engine/app/services/warp_engine/ci_pipeline_service.rb +++ /dev/null @@ -1,35 +0,0 @@ -module WarpEngine - class CiPipelineService - def initialize(client: WoodpeckerClient.new) - @client = client - end - - def trigger(repo, branch: "main") - @client.trigger_pipeline(repo.woodpecker_repo_id, branch: branch) - end - - # Fetches one page of a repo's pipelines; the newest one refreshes the - # repo's cached last_pipeline_* columns (Pipelines index and the CI API). - def list_pipelines(repo, page: 1) - pipelines = @client.list_pipelines(repo.woodpecker_repo_id, page: page) - refresh_last_pipeline(repo, pipelines.first) if page == 1 && pipelines.is_a?(Array) - pipelines - end - - def pipeline_detail(repo, number) - @client.get_pipeline(repo.woodpecker_repo_id, number) - end - - private - - # Woodpecker returns unix epoch seconds in "created". - def refresh_last_pipeline(repo, pipeline) - return unless pipeline && repo.persisted? - - repo.update_columns( - last_pipeline_status: pipeline["status"], - last_pipeline_at: pipeline["created"] ? Time.zone.at(pipeline["created"]) : nil - ) - end - end -end diff --git a/libs/ruby/warp_engine/app/services/warp_engine/pipeline_service.rb b/libs/ruby/warp_engine/app/services/warp_engine/pipeline_service.rb new file mode 100644 index 0000000..701534c --- /dev/null +++ b/libs/ruby/warp_engine/app/services/warp_engine/pipeline_service.rb @@ -0,0 +1,35 @@ +module WarpEngine + class PipelineService + def initialize(client: WoodpeckerClient.new) + @client = client + end + + def trigger(pipeline, branch: "main") + @client.trigger_pipeline(pipeline.woodpecker_repo_id, branch: branch) + end + + # Fetches one page of a pipeline's runs; the newest one refreshes the + # cached last_pipeline_* columns (Pipelines index and the CI API). + def list_pipelines(pipeline, page: 1) + runs = @client.list_pipelines(pipeline.woodpecker_repo_id, page: page) + refresh_last_pipeline(pipeline, runs.first) if page == 1 && runs.is_a?(Array) + runs + end + + def pipeline_detail(pipeline, number) + @client.get_pipeline(pipeline.woodpecker_repo_id, number) + end + + private + + # Woodpecker returns unix epoch seconds in "created". + def refresh_last_pipeline(pipeline, run) + return unless run && pipeline.persisted? + + pipeline.update_columns( + last_pipeline_status: run["status"], + last_pipeline_at: run["created"] ? Time.zone.at(run["created"]) : nil + ) + end + end +end diff --git a/libs/ruby/warp_engine/app/services/warp_engine/ci_repo_sync_service.rb b/libs/ruby/warp_engine/app/services/warp_engine/pipeline_sync_service.rb similarity index 74% rename from libs/ruby/warp_engine/app/services/warp_engine/ci_repo_sync_service.rb rename to libs/ruby/warp_engine/app/services/warp_engine/pipeline_sync_service.rb index 4b5c203..5259d0b 100644 --- a/libs/ruby/warp_engine/app/services/warp_engine/ci_repo_sync_service.rb +++ b/libs/ruby/warp_engine/app/services/warp_engine/pipeline_sync_service.rb @@ -1,5 +1,5 @@ module WarpEngine - class CiRepoSyncService + class PipelineSyncService def initialize(client: WoodpeckerClient.new) @client = client end @@ -10,7 +10,7 @@ module WarpEngine remote_ids = remote_repos.map { |r| r["id"] } remote_repos.each do |remote| - record = CiRepository.unscoped.find_or_initialize_by( + record = Pipeline.unscoped.find_or_initialize_by( woodpecker_repo_id: remote["id"] ) @@ -22,9 +22,9 @@ module WarpEngine deleted_at: nil ) - if record.platform.blank? || record.platform == "unknown" + if record.platform.blank? || record.platform == Pipeline::UNKNOWN_PLATFORM sw = Software.find_by(name: remote["name"]) - record.platform = sw&.platform || "unknown" + record.platform = sw&.platform || Pipeline::UNKNOWN_PLATFORM record.software = sw if sw end @@ -33,7 +33,7 @@ module WarpEngine results[was_new ? :created : :updated] << record end - CiRepository.where.not(woodpecker_repo_id: remote_ids).find_each do |orphan| + Pipeline.where.not(woodpecker_repo_id: remote_ids).find_each do |orphan| orphan.update!(active: false) if orphan.active? results[:deactivated] << orphan end @@ -48,7 +48,7 @@ module WarpEngine def deactivate(repo_id) @client.deactivate_repo(repo_id) - record = CiRepository.find_by!(woodpecker_repo_id: repo_id) + record = Pipeline.find_by!(woodpecker_repo_id: repo_id) record.update!(active: false) end @@ -56,14 +56,14 @@ module WarpEngine def sync_single(repo_id) remote = @client.get_repo(repo_id) - record = CiRepository.unscoped.find_or_initialize_by(woodpecker_repo_id: repo_id) + record = Pipeline.unscoped.find_or_initialize_by(woodpecker_repo_id: repo_id) record.assign_attributes( repo_name: remote["name"], repo_owner: remote["owner"], active: remote["active"], deleted_at: nil ) if record.platform.blank? sw = Software.find_by(name: remote["name"]) - record.platform = sw&.platform || "unknown" + record.platform = sw&.platform || Pipeline::UNKNOWN_PLATFORM record.software = sw if sw end record.save! diff --git a/libs/ruby/warp_engine/app/services/warp_engine/ci_secret_sync_service.rb b/libs/ruby/warp_engine/app/services/warp_engine/secret_sync_service.rb similarity index 54% rename from libs/ruby/warp_engine/app/services/warp_engine/ci_secret_sync_service.rb rename to libs/ruby/warp_engine/app/services/warp_engine/secret_sync_service.rb index 8a15904..7eb3f11 100644 --- a/libs/ruby/warp_engine/app/services/warp_engine/ci_secret_sync_service.rb +++ b/libs/ruby/warp_engine/app/services/warp_engine/secret_sync_service.rb @@ -1,40 +1,40 @@ module WarpEngine - class CiSecretSyncService + class SecretSyncService SECRET_NAME = "application_token".freeze def initialize(client: WoodpeckerClient.new) @client = client end - def provision(plain_token, repos:) + def provision(plain_token, pipelines:) results = { synced: [], failed: [] } - repos.each do |repo| - if secret_exists?(repo.woodpecker_repo_id) - @client.update_secret(repo.woodpecker_repo_id, SECRET_NAME, value: plain_token) + pipelines.each do |pipeline| + if secret_exists?(pipeline.woodpecker_repo_id) + @client.update_secret(pipeline.woodpecker_repo_id, SECRET_NAME, value: plain_token) else - @client.create_secret(repo.woodpecker_repo_id, name: SECRET_NAME, value: plain_token) + @client.create_secret(pipeline.woodpecker_repo_id, name: SECRET_NAME, value: plain_token) end - results[:synced] << repo + results[:synced] << pipeline rescue WoodpeckerClient::ApiError, WoodpeckerClient::ConnectionError => e - Rails.logger.error("[CiSecretSyncService] failed for #{repo.full_name}: #{e.message}") - results[:failed] << { repo: repo, error: e.message } + Rails.logger.error("[SecretSyncService] failed for #{pipeline.full_name}: #{e.message}") + results[:failed] << { pipeline: pipeline, error: e.message } end results end def deprovision(application_token) - repos_for_token(application_token).each do |repo| - @client.delete_secret(repo.woodpecker_repo_id, SECRET_NAME) + pipelines_for_token(application_token).each do |pipeline| + @client.delete_secret(pipeline.woodpecker_repo_id, SECRET_NAME) rescue WoodpeckerClient::ApiError => e - Rails.logger.warn("[CiSecretSyncService] delete failed for #{repo.full_name}: #{e.message}") + Rails.logger.warn("[SecretSyncService] delete failed for #{pipeline.full_name}: #{e.message}") end end def rotate(application_token) - repos = repos_for_token(application_token) - return { rotated: false, reason: "no repos" } if repos.empty? + pipelines = pipelines_for_token(application_token) + return { rotated: false, reason: "no pipelines" } if pipelines.empty? new_token = ApplicationToken.create!( name: "#{application_token.name} (rotated #{Date.current})", @@ -45,26 +45,26 @@ module WarpEngine unrestricted: application_token.unrestricted? ) - result = provision(new_token.plain_token, repos: repos) + result = provision(new_token.plain_token, pipelines: pipelines) if result[:synced].any? application_token.revoke! { rotated: true, new_token: new_token, sync_result: result } else new_token.revoke! - { rotated: false, reason: "all repos failed", sync_result: result } + { rotated: false, reason: "all pipelines failed", sync_result: result } end end - def repos_for_token(application_token) + def pipelines_for_token(application_token) if application_token.unrestricted? - CiRepository.active.to_a + Pipeline.active.to_a else software_ids = Software.where( owner_type: application_token.owner_type, owner_id: application_token.owner_id ).pluck(:id) - CiRepository.active.where(software_id: software_ids).to_a + Pipeline.active.where(software_id: software_ids).to_a end end diff --git a/libs/ruby/warp_engine/config/routes.rb b/libs/ruby/warp_engine/config/routes.rb index 5b7cc8c..410efa4 100644 --- a/libs/ruby/warp_engine/config/routes.rb +++ b/libs/ruby/warp_engine/config/routes.rb @@ -7,9 +7,9 @@ WarpEngine::Engine.routes.draw do get "builds", to: "builds#index" get "softwares/:name/builds", to: "software_builds#show" - get "ci/repos", to: "ci#repos" - get "ci/repos/:id/status", to: "ci#status" - post "ci/repos/:id/trigger", to: "ci#trigger" + get "ci/pipelines", to: "ci#pipelines" + get "ci/pipelines/:id/status", to: "ci#status" + post "ci/pipelines/:id/trigger", to: "ci#trigger" end post "build/upload", to: "build/uploads#create" diff --git a/libs/ruby/warp_engine/db/migrate/20260806000002_rename_ci_repositories_to_pipelines.rb b/libs/ruby/warp_engine/db/migrate/20260806000002_rename_ci_repositories_to_pipelines.rb new file mode 100644 index 0000000..07428d5 --- /dev/null +++ b/libs/ruby/warp_engine/db/migrate/20260806000002_rename_ci_repositories_to_pipelines.rb @@ -0,0 +1,15 @@ +class RenameCiRepositoriesToPipelines < ActiveRecord::Migration[8.1] + def change + rename_table :ci_repositories, :pipelines + + rename_index :pipelines, "idx_ci_repos_deleted", "idx_pipelines_deleted" + rename_index :pipelines, "idx_ci_repos_owner_name", "idx_pipelines_owner_name" + rename_index :pipelines, "idx_ci_repos_software", "idx_pipelines_software" + rename_index :pipelines, "idx_ci_repos_wp_id", "idx_pipelines_wp_id" + + remove_foreign_key :pipelines, :softwares, + column: :software_id, name: "fk_ci_repos_software", on_delete: :nullify + add_foreign_key :pipelines, :softwares, + column: :software_id, name: "fk_pipelines_software", on_delete: :nullify + end +end diff --git a/libs/ruby/warp_engine/spec/dummy/db/schema.rb b/libs/ruby/warp_engine/spec/dummy/db/schema.rb index bf9e111..cfb98ef 100644 --- a/libs/ruby/warp_engine/spec/dummy/db/schema.rb +++ b/libs/ruby/warp_engine/spec/dummy/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do +ActiveRecord::Schema[8.1].define(version: 2026_08_06_000002) do create_table "application_tokens", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "created_at", precision: 3 t.datetime "deleted_at", precision: 3 @@ -29,24 +29,6 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do t.index ["token_digest"], name: "idx_application_tokens_token_digest", unique: true end - create_table "ci_repositories", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| - t.boolean "active", default: true, null: false - t.datetime "created_at", precision: 3 - t.datetime "deleted_at", precision: 3 - t.datetime "last_pipeline_at", precision: 3 - t.string "last_pipeline_status", limit: 32 - t.string "platform", limit: 32, null: false - t.string "repo_name", limit: 128, null: false - t.string "repo_owner", limit: 128, null: false - t.bigint "software_id", unsigned: true - t.datetime "updated_at", precision: 3 - t.bigint "woodpecker_repo_id", null: false, unsigned: true - t.index ["deleted_at"], name: "idx_ci_repos_deleted" - t.index ["repo_owner", "repo_name"], name: "idx_ci_repos_owner_name", unique: true - t.index ["software_id"], name: "idx_ci_repos_software" - t.index ["woodpecker_repo_id"], name: "idx_ci_repos_wp_id", unique: true - end - create_table "downloads", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "created_at", precision: 3 t.datetime "deleted_at", precision: 3 @@ -82,6 +64,24 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do t.index ["deleted_at"], name: "idx_images_deleted_at" end + create_table "pipelines", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| + t.boolean "active", default: true, null: false + t.datetime "created_at", precision: 3 + t.datetime "deleted_at", precision: 3 + t.datetime "last_pipeline_at", precision: 3 + t.string "last_pipeline_status", limit: 32 + t.string "platform", limit: 32, null: false + t.string "repo_name", limit: 128, null: false + t.string "repo_owner", limit: 128, null: false + t.bigint "software_id", unsigned: true + t.datetime "updated_at", precision: 3 + t.bigint "woodpecker_repo_id", null: false, unsigned: true + t.index ["deleted_at"], name: "idx_pipelines_deleted" + t.index ["repo_owner", "repo_name"], name: "idx_pipelines_owner_name", unique: true + t.index ["software_id"], name: "idx_pipelines_software" + t.index ["woodpecker_repo_id"], name: "idx_pipelines_wp_id", unique: true + end + create_table "platform_links", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.datetime "created_at", precision: 3 t.datetime "deleted_at", precision: 3 @@ -155,9 +155,9 @@ ActiveRecord::Schema[8.1].define(version: 2026_08_06_000001) do t.datetime "updated_at", precision: 3 end - add_foreign_key "ci_repositories", "softwares", name: "fk_ci_repos_software", on_delete: :nullify add_foreign_key "downloads", "releases", name: "fk_downloads_release", on_delete: :nullify add_foreign_key "external_links", "softwares", name: "fk_softwares_external_links", on_delete: :cascade + add_foreign_key "pipelines", "softwares", name: "fk_pipelines_software", on_delete: :nullify add_foreign_key "release_assets", "releases", name: "fk_releases_release_assets", on_delete: :cascade add_foreign_key "releases", "softwares", name: "fk_softwares_releases", on_delete: :cascade add_foreign_key "software_images", "images" diff --git a/libs/ruby/warp_engine/spec/factories/ci_repositories.rb b/libs/ruby/warp_engine/spec/factories/pipelines.rb similarity index 83% rename from libs/ruby/warp_engine/spec/factories/ci_repositories.rb rename to libs/ruby/warp_engine/spec/factories/pipelines.rb index 4478ebe..3f5f677 100644 --- a/libs/ruby/warp_engine/spec/factories/ci_repositories.rb +++ b/libs/ruby/warp_engine/spec/factories/pipelines.rb @@ -1,5 +1,5 @@ FactoryBot.define do - factory :ci_repository, class: "WarpEngine::CiRepository" do + factory :pipeline, class: "WarpEngine::Pipeline" do sequence(:woodpecker_repo_id) { |n| n } repo_owner { "testorg" } sequence(:repo_name) { |n| "game-#{n}" } diff --git a/libs/ruby/warp_engine/spec/models/ci_repository_spec.rb b/libs/ruby/warp_engine/spec/models/pipeline_spec.rb similarity index 70% rename from libs/ruby/warp_engine/spec/models/ci_repository_spec.rb rename to libs/ruby/warp_engine/spec/models/pipeline_spec.rb index b0c92be..7fa8642 100644 --- a/libs/ruby/warp_engine/spec/models/ci_repository_spec.rb +++ b/libs/ruby/warp_engine/spec/models/pipeline_spec.rb @@ -1,8 +1,8 @@ require "rails_helper" -RSpec.describe WarpEngine::CiRepository do +RSpec.describe WarpEngine::Pipeline do describe "validations" do - subject { build(:ci_repository) } + subject { build(:pipeline) } it { is_expected.to validate_presence_of(:woodpecker_repo_id) } it { is_expected.to validate_uniqueness_of(:woodpecker_repo_id) } @@ -11,29 +11,34 @@ RSpec.describe WarpEngine::CiRepository do it { is_expected.to validate_presence_of(:platform) } it "rejects unsupported platforms" do - repo = build(:ci_repository, platform: "amiga") + 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(:ci_repository, platform: p) + 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(:ci_repository, repo_owner: "games", repo_name: "mygame") + 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(:ci_repository) + repo = create(:pipeline) repo.update_column(:deleted_at, Time.current) expect(described_class.all).not_to include(repo) @@ -43,8 +48,8 @@ RSpec.describe WarpEngine::CiRepository do describe ".active" do it "returns only active repos" do - active = create(:ci_repository, active: true) - inactive = create(:ci_repository, active: false) + 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) diff --git a/libs/ruby/warp_engine/spec/requests/ci_controller_spec.rb b/libs/ruby/warp_engine/spec/requests/ci_controller_spec.rb index 03f3af5..589d011 100644 --- a/libs/ruby/warp_engine/spec/requests/ci_controller_spec.rb +++ b/libs/ruby/warp_engine/spec/requests/ci_controller_spec.rb @@ -7,11 +7,11 @@ RSpec.describe "CI API", type: :request do allow(WarpEngine.config).to receive(:update_secret).and_return("s3cret") end - describe "GET /api/ci/repos" do + describe "GET /api/ci/pipelines" do it "returns active repos" do - repo = create(:ci_repository, repo_name: "mygame", platform: "tic80") + repo = create(:pipeline, repo_name: "mygame", platform: "tic80") - get "/api/ci/repos" + get "/api/ci/pipelines" expect(response).to have_http_status(:ok) json = JSON.parse(response.body) @@ -22,45 +22,45 @@ RSpec.describe "CI API", type: :request do it "returns 503 when woodpecker not configured" do allow(WarpEngine.config).to receive(:woodpecker_url).and_return(nil) - get "/api/ci/repos" + get "/api/ci/pipelines" expect(response).to have_http_status(:service_unavailable) end end - describe "GET /api/ci/repos/:id/status" do + describe "GET /api/ci/pipelines/:id/status" do it "returns repo with pipeline status" do - repo = create(:ci_repository, repo_owner: "org", repo_name: "game") + repo = create(:pipeline, repo_owner: "org", repo_name: "game") client = instance_double(WarpEngine::WoodpeckerClient) allow(WarpEngine::WoodpeckerClient).to receive(:new).and_return(client) allow(client).to receive(:get_pipeline) .and_return({ "number" => 1, "status" => "success" }) - get "/api/ci/repos/#{repo.id}/status" + get "/api/ci/pipelines/#{repo.id}/status" expect(response).to have_http_status(:ok) json = JSON.parse(response.body) - expect(json["repo"]["repo_name"]).to eq("game") + expect(json["pipeline"]["repo_name"]).to eq("game") end end - describe "POST /api/ci/repos/:id/trigger" do + describe "POST /api/ci/pipelines/:id/trigger" do it "requires authentication" do - repo = create(:ci_repository) + repo = create(:pipeline) - post "/api/ci/repos/#{repo.id}/trigger" + post "/api/ci/pipelines/#{repo.id}/trigger" expect(response).to have_http_status(:unauthorized) end it "triggers a pipeline with valid secret" do - repo = create(:ci_repository, repo_owner: "org", repo_name: "game") + repo = create(:pipeline, repo_owner: "org", repo_name: "game") client = instance_double(WarpEngine::WoodpeckerClient) allow(WarpEngine::WoodpeckerClient).to receive(:new).and_return(client) allow(client).to receive(:trigger_pipeline) .and_return({ "number" => 7, "status" => "pending" }) - post "/api/ci/repos/#{repo.id}/trigger", + post "/api/ci/pipelines/#{repo.id}/trigger", headers: { "X-Update-Secret" => "s3cret" } expect(response).to have_http_status(:ok) diff --git a/libs/ruby/warp_engine/spec/services/ci_pipeline_service_spec.rb b/libs/ruby/warp_engine/spec/services/pipeline_service_spec.rb similarity index 84% rename from libs/ruby/warp_engine/spec/services/ci_pipeline_service_spec.rb rename to libs/ruby/warp_engine/spec/services/pipeline_service_spec.rb index d6967bd..c88e005 100644 --- a/libs/ruby/warp_engine/spec/services/ci_pipeline_service_spec.rb +++ b/libs/ruby/warp_engine/spec/services/pipeline_service_spec.rb @@ -1,12 +1,12 @@ require "rails_helper" -RSpec.describe WarpEngine::CiPipelineService do +RSpec.describe WarpEngine::PipelineService do let(:client) { instance_double(WarpEngine::WoodpeckerClient) } let(:service) { described_class.new(client: client) } describe "#trigger" do it "delegates to client" do - repo = build(:ci_repository, repo_owner: "org", repo_name: "game") + repo = build(:pipeline, repo_owner: "org", repo_name: "game") allow(client).to receive(:trigger_pipeline).and_return({ "number" => 6 }) result = service.trigger(repo, branch: "main") @@ -18,7 +18,7 @@ RSpec.describe WarpEngine::CiPipelineService do describe "#list_pipelines" do it "returns paginated pipelines and refreshes the repo's cached last pipeline" do - repo = create(:ci_repository, repo_owner: "org", repo_name: "game") + repo = create(:pipeline, repo_owner: "org", repo_name: "game") pipelines = [ { "number" => 2, "status" => "failure", "created" => 1_754_500_000 }, { "number" => 1, "status" => "success", "created" => 1_754_400_000 } @@ -33,7 +33,7 @@ RSpec.describe WarpEngine::CiPipelineService do end it "does not touch the cache on later pages" do - repo = create(:ci_repository, repo_owner: "org", repo_name: "game", + repo = create(:pipeline, repo_owner: "org", repo_name: "game", last_pipeline_status: "success") allow(client).to receive(:list_pipelines).with(repo.woodpecker_repo_id, page: 2) .and_return([{ "number" => 1, "status" => "failure", "created" => 1_754_400_000 }]) @@ -44,7 +44,7 @@ RSpec.describe WarpEngine::CiPipelineService do end it "leaves the cache alone when the repo has no pipelines" do - repo = create(:ci_repository, repo_owner: "org", repo_name: "game", + repo = create(:pipeline, repo_owner: "org", repo_name: "game", last_pipeline_status: "success") allow(client).to receive(:list_pipelines).and_return([]) diff --git a/libs/ruby/warp_engine/spec/services/ci_repo_sync_service_spec.rb b/libs/ruby/warp_engine/spec/services/pipeline_sync_service_spec.rb similarity index 86% rename from libs/ruby/warp_engine/spec/services/ci_repo_sync_service_spec.rb rename to libs/ruby/warp_engine/spec/services/pipeline_sync_service_spec.rb index 4650921..282540a 100644 --- a/libs/ruby/warp_engine/spec/services/ci_repo_sync_service_spec.rb +++ b/libs/ruby/warp_engine/spec/services/pipeline_sync_service_spec.rb @@ -1,11 +1,11 @@ require "rails_helper" -RSpec.describe WarpEngine::CiRepoSyncService do +RSpec.describe WarpEngine::PipelineSyncService do let(:client) { instance_double(WarpEngine::WoodpeckerClient) } let(:service) { described_class.new(client: client) } describe "#sync_all" do - it "creates new CiRepository records from Woodpecker" do + it "creates new Pipeline records from Woodpecker" do allow(client).to receive(:list_repos).and_return([ { "id" => 1, "name" => "mygame", "owner" => "org", "active" => true } ]) @@ -20,7 +20,7 @@ RSpec.describe WarpEngine::CiRepoSyncService do end it "updates existing records" do - existing = create(:ci_repository, woodpecker_repo_id: 1, repo_name: "old", platform: "tic80") + existing = create(:pipeline, woodpecker_repo_id: 1, repo_name: "old", platform: "tic80") allow(client).to receive(:list_repos).and_return([ { "id" => 1, "name" => "newname", "owner" => "org", "active" => true } ]) @@ -32,7 +32,7 @@ RSpec.describe WarpEngine::CiRepoSyncService do end it "deactivates repos missing from Woodpecker" do - orphan = create(:ci_repository, woodpecker_repo_id: 99, active: true) + orphan = create(:pipeline, woodpecker_repo_id: 99, active: true) allow(client).to receive(:list_repos).and_return([]) result = service.sync_all @@ -70,7 +70,7 @@ RSpec.describe WarpEngine::CiRepoSyncService do describe "#deactivate" do it "calls client and marks repo inactive" do - repo = create(:ci_repository, woodpecker_repo_id: 42, active: true) + repo = create(:pipeline, woodpecker_repo_id: 42, active: true) allow(client).to receive(:deactivate_repo).with(42) service.deactivate(42) diff --git a/libs/ruby/warp_engine/spec/services/ci_secret_sync_service_spec.rb b/libs/ruby/warp_engine/spec/services/secret_sync_service_spec.rb similarity index 79% rename from libs/ruby/warp_engine/spec/services/ci_secret_sync_service_spec.rb rename to libs/ruby/warp_engine/spec/services/secret_sync_service_spec.rb index febd4ef..641df4c 100644 --- a/libs/ruby/warp_engine/spec/services/ci_secret_sync_service_spec.rb +++ b/libs/ruby/warp_engine/spec/services/secret_sync_service_spec.rb @@ -1,6 +1,6 @@ require "rails_helper" -RSpec.describe WarpEngine::CiSecretSyncService do +RSpec.describe WarpEngine::SecretSyncService do let(:client) { instance_double(WarpEngine::WoodpeckerClient) } let(:service) { described_class.new(client: client) } @@ -11,11 +11,11 @@ RSpec.describe WarpEngine::CiSecretSyncService do describe "#provision" do it "creates secrets on repos that don't have one" do - repo = create(:ci_repository) + repo = create(:pipeline) allow(client).to receive(:list_secrets).with(repo.woodpecker_repo_id).and_return([]) allow(client).to receive(:create_secret) - result = service.provision("plaintoken", repos: [ repo ]) + result = service.provision("plaintoken", pipelines: [ repo ]) expect(result[:synced]).to eq([ repo ]) expect(client).to have_received(:create_secret).with( @@ -24,12 +24,12 @@ RSpec.describe WarpEngine::CiSecretSyncService do end it "updates secrets on repos that already have one" do - repo = create(:ci_repository) + 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", repos: [ repo ]) + result = service.provision("newtoken", pipelines: [ repo ]) expect(result[:synced]).to eq([ repo ]) expect(client).to have_received(:update_secret).with( @@ -38,12 +38,12 @@ RSpec.describe WarpEngine::CiSecretSyncService do end it "records failed repos without raising" do - repo = create(:ci_repository) + repo = create(:pipeline) allow(client).to receive(:list_secrets).and_raise( WarpEngine::WoodpeckerClient::ConnectionError, "unreachable" ) - result = service.provision("tok", repos: [ repo ]) + result = service.provision("tok", pipelines: [ repo ]) expect(result[:synced]).to be_empty expect(result[:failed].size).to eq(1) @@ -54,7 +54,7 @@ RSpec.describe WarpEngine::CiSecretSyncService do it "deletes secrets from all relevant repos" do token = create(:application_token) sw = create(:software, name: "game1", owner: token.owner) - repo = create(:ci_repository, :with_software, software: sw) + repo = create(:pipeline, :with_software, software: sw) allow(client).to receive(:delete_secret) @@ -68,7 +68,7 @@ RSpec.describe WarpEngine::CiSecretSyncService do it "creates new token, provisions, revokes old" do token = create(:application_token) sw = create(:software, name: "game1", owner: token.owner) - repo = create(:ci_repository, :with_software, software: sw) + repo = create(:pipeline, :with_software, software: sw) allow(client).to receive(:list_secrets).and_return([]) allow(client).to receive(:create_secret) @@ -83,7 +83,7 @@ RSpec.describe WarpEngine::CiSecretSyncService do it "rolls back if all repos fail" do token = create(:application_token) sw = create(:software, name: "game1", owner: token.owner) - create(:ci_repository, :with_software, software: sw) + create(:pipeline, :with_software, software: sw) allow(client).to receive(:list_secrets).and_raise( WarpEngine::WoodpeckerClient::ConnectionError, "down" @@ -101,17 +101,17 @@ RSpec.describe WarpEngine::CiSecretSyncService do result = service.rotate(token) expect(result[:rotated]).to be false - expect(result[:reason]).to eq("no repos") + expect(result[:reason]).to eq("no pipelines") end end - describe "#repos_for_token" do + describe "#pipelines_for_token" do it "returns all active repos for unrestricted tokens" do token = create(:application_token, :unrestricted) - repo1 = create(:ci_repository) - create(:ci_repository, :inactive) + repo1 = create(:pipeline) + create(:pipeline, :inactive) - repos = service.repos_for_token(token) + repos = service.pipelines_for_token(token) expect(repos).to eq([ repo1 ]) end @@ -120,10 +120,10 @@ RSpec.describe WarpEngine::CiSecretSyncService do token = create(:application_token) own_sw = create(:software, name: "mine", owner: token.owner) other_sw = create(:software, name: "theirs", owner: create(:test_owner)) - own_repo = create(:ci_repository, :with_software, software: own_sw) - create(:ci_repository, :with_software, software: other_sw) + own_repo = create(:pipeline, :with_software, software: own_sw) + create(:pipeline, :with_software, software: other_sw) - repos = service.repos_for_token(token) + repos = service.pipelines_for_token(token) expect(repos).to eq([ own_repo ]) end