advanced pipeline

This commit is contained in:
2026-08-25 23:50:11 +02:00
parent c8dc153e80
commit 3f5caf947f
30 changed files with 44 additions and 42 deletions
+13
View File
@@ -0,0 +1,13 @@
inherit_gem:
rubocop-rails-omakase: rubocop.yml
AllCops:
NewCops: enable
TargetRubyVersion: 3.2
Exclude:
- "bin/**/*"
- "db/**/*"
- "config/**/*"
- "examples/**/*"
- "spec/dummy/**/*"
- "vendor/**/*"
+1
View File
@@ -10,4 +10,5 @@ group :development, :test do
gem "shoulda-matchers", "~> 6.0"
gem "webmock", "~> 3.0"
gem "debug", platforms: %i[mri windows]
gem "rubocop-rails-omakase", require: false
end
+11 -1
View File
@@ -761,6 +761,16 @@ bundle exec rspec
## Development
This repository is a **read-only split mirror** — development happens in the
[`tools/teletypegames`](https://git.teletypegames.org/tools/teletypegames)
[`services/teletypegames`](https://git.teletypegames.org/services/teletypegames)
monorepo under `libs/ruby/warp_engine`, and CI republishes the mirror on every
change. Please do not open pull requests against the mirror.
Two rules the monorepo's pipeline enforces before anything is mirrored or
published:
- **Every commit that touches the engine raises `WarpEngine::VERSION`.** A
pre-commit hook checks it locally, the pipeline's first step checks it again
over the pushed commits, and a `warp_engine-v*` tag must name the version the
tree actually holds.
- **RuboCop is green** (`.rubocop.yml`, rubocop-rails-omakase), and the suite
passes — in that order, before the gem is built.
@@ -1,5 +1,4 @@
module WarpEngine
module SubjectAuthentication
extend ActiveSupport::Concern
@@ -1,5 +1,4 @@
module WarpEngine
module UpdateAuthentication
extend ActiveSupport::Concern
@@ -1,5 +1,4 @@
module WarpEngine
class Api::Auth::DevicesController < ApiController
before_action :ensure_identity_configured
@@ -1,5 +1,4 @@
module WarpEngine
class Api::Auth::TokensController < ApiController
resource_description do
short "Client tokens"
@@ -1,5 +1,4 @@
module WarpEngine
class Api::ServiceController < ApiController
resource_description do
short "Service descriptor"
@@ -1,6 +1,5 @@
module WarpEngine
module Build
class ConfigsController < ApiController
resource_description do
short "CI pipeline configs"
-2
View File
@@ -1,5 +1,4 @@
module WarpEngine
class DeviceGrant < ApplicationRecord
self.table_name = "device_grants"
@@ -58,7 +57,6 @@ module WarpEngine
end
def self.generate_user_code
10.times do
candidate = Array.new(USER_CODE_LENGTH) { USER_CODE_ALPHABET.chars.sample }.join
return candidate unless exists?(user_code: candidate)
+1 -1
View File
@@ -16,7 +16,7 @@ module WarpEngine
validate :c64_cannot_be_web_playable
def self.latest_non_dev(releases)
sorted = releases.sort_by { |r| [r.created_at || Time.at(0), r.id] }.reverse
sorted = releases.sort_by { |r| [ r.created_at || Time.at(0), r.id ] }.reverse
candidates = sorted.reject { |r| r.version.to_s.start_with?("dev-") }
candidates.empty? ? sorted.first : candidates.first
end
@@ -1,7 +1,6 @@
module WarpEngine
module Platforms
module Builds
module BuildLinuxArm64
extend ActiveSupport::Concern
@@ -1,5 +1,4 @@
module WarpEngine
class DeviceGrantService
class NotConfigured < StandardError; end
class UnknownCode < StandardError; end
@@ -2,7 +2,6 @@ require "warp_engine/access_denied"
module WarpEngine
class DownloadService
Denied = WarpEngine::AccessDenied
include AccessPolicyGuard
@@ -1,6 +1,5 @@
module WarpEngine
class FileManagerService
def base_path
@base_path ||= Pathname.new(WarpEngine.config.file_container_path)
end
-1
View File
@@ -2,7 +2,6 @@ require "warp_engine/access_denied"
module WarpEngine
class FileService
include AccessPolicyGuard
def show(input, subject: nil)
@@ -1,6 +1,5 @@
module WarpEngine
class PublishService
NOTIFICATION = "warp_engine.publish".freeze
def publish(input)
+1 -1
View File
@@ -12,7 +12,7 @@ namespace :warp_engine do
checklist = WarpEngine::AssetCoverageChecklist.new(
coverage, only_missing: ENV["ONLY"] == "missing"
)
puts checklist.to_s
puts checklist
if ENV["STRICT"] == "1" && coverage.totals[:missing].positive?
abort "\nSTRICT: #{coverage.totals[:missing]} expected assets are missing."
-1
View File
@@ -13,7 +13,6 @@ require "warp_engine/images"
require "warp_engine/ci"
module WarpEngine
def self.table_name_prefix
""
end
-3
View File
@@ -1,7 +1,5 @@
module WarpEngine
module AccessPolicy
class Open
def visible_software_scope(subject: nil)
WarpEngine::Software.kept
@@ -39,7 +37,6 @@ module WarpEngine
end
class Access
attr_reader :gated, :entitled, :price_cents, :currency, :purchase_url, :web_url
def initialize(gated: false, entitled: true, price_cents: nil, currency: nil,
-1
View File
@@ -1,5 +1,4 @@
module WarpEngine
module CI
class Error < StandardError; end
-1
View File
@@ -1,6 +1,5 @@
module WarpEngine
class Configuration
attr_accessor :site_url,
:file_container_path,
:update_secret,
-2
View File
@@ -1,7 +1,5 @@
module WarpEngine
module Images
class HostModel
URL_PREFIX = "/api/image".freeze
-1
View File
@@ -1,5 +1,4 @@
module WarpEngine
module Storage
Location = Struct.new(:kind, :path, :url, keyword_init: true) do
def file? = kind == :file
+1 -1
View File
@@ -1,5 +1,5 @@
module WarpEngine
VERSION = "0.9.0"
VERSION = "0.9.1"
VERSION_HEADER = "WarpEngine-Version".freeze
end
+4 -4
View File
@@ -15,7 +15,7 @@ RSpec.describe WarpEngine::CI::Gitlab::Client do
describe "repos" do
it "lists repos" do
repos = [{ "id" => 1, "path" => "game1" }]
repos = [ { "id" => 1, "path" => "game1" } ]
stub_gl(:get, "/api/v4/projects?membership=true&per_page=100&simple=true", body: repos)
expect(client.list_repos).to eq(repos)
@@ -39,7 +39,7 @@ RSpec.describe WarpEngine::CI::Gitlab::Client do
describe "secrets (variables)" do
it "lists variables" do
vars = [{ "key" => "application_token" }]
vars = [ { "key" => "application_token" } ]
stub_gl(:get, "/api/v4/projects/1/variables", body: vars)
expect(client.list_secrets(1)).to eq(vars)
@@ -68,7 +68,7 @@ RSpec.describe WarpEngine::CI::Gitlab::Client do
describe "pipelines" do
it "lists pipelines" do
pipelines = [{ "id" => 1, "status" => "success" }]
pipelines = [ { "id" => 1, "status" => "success" } ]
stub_gl(:get, "/api/v4/projects/42/pipelines?page=1&per_page=25", body: pipelines)
expect(client.list_pipelines(42)).to eq(pipelines)
@@ -76,7 +76,7 @@ RSpec.describe WarpEngine::CI::Gitlab::Client do
it "gets latest pipeline" do
pipeline = { "id" => 5, "status" => "running" }
stub_gl(:get, "/api/v4/projects/42/pipelines?per_page=1&sort=desc", body: [pipeline])
stub_gl(:get, "/api/v4/projects/42/pipelines?per_page=1&sort=desc", body: [ pipeline ])
expect(client.latest_pipeline(42)).to eq(pipeline)
end
+3 -3
View File
@@ -15,7 +15,7 @@ RSpec.describe WarpEngine::CI::Woodpecker::Client do
describe "repos" do
it "lists repos" do
repos = [{ "id" => 1, "name" => "game1" }]
repos = [ { "id" => 1, "name" => "game1" } ]
stub_wp(:get, "/api/repos", body: repos)
expect(client.list_repos).to eq(repos)
@@ -37,7 +37,7 @@ RSpec.describe WarpEngine::CI::Woodpecker::Client do
describe "secrets" do
it "lists secrets" do
secrets = [{ "name" => "application_token" }]
secrets = [ { "name" => "application_token" } ]
stub_wp(:get, "/api/repos/1/secrets", body: secrets)
expect(client.list_secrets(1)).to eq(secrets)
@@ -66,7 +66,7 @@ RSpec.describe WarpEngine::CI::Woodpecker::Client do
describe "pipelines" do
it "lists pipelines" do
pipelines = [{ "number" => 1, "status" => "success" }]
pipelines = [ { "number" => 1, "status" => "success" } ]
stub_wp(:get, "/api/repos/42/pipelines?page=1&perPage=25", body: pipelines)
expect(client.list_pipelines(42)).to eq(pipelines)
+7 -6
View File
@@ -20,12 +20,13 @@ RSpec.describe WarpEngine::PlatformLink, type: :model do
end
end
describe "default scope" do
it "excludes soft-deleted records" do
active = create(:platform_link)
create(:platform_link, deleted_at: Time.current)
describe "scopes" do
it "keeps soft-deleted records out of .kept, not out of .all" do
active = create(:platform_link)
deleted = create(:platform_link, deleted_at: Time.current)
expect(WarpEngine::PlatformLink.all).to eq([active])
expect(WarpEngine::PlatformLink.kept).to eq([ active ])
expect(WarpEngine::PlatformLink.all).to contain_exactly(active, deleted)
end
it "does not order: ordering is asked for, not inherited" do
@@ -52,7 +53,7 @@ RSpec.describe WarpEngine::PlatformLink, type: :model do
create(:platform_link, platform: "love")
result = WarpEngine::PlatformLink.for_platform("tic80")
expect(result).to eq([tic80_link])
expect(result).to eq([ tic80_link ])
end
it "returns empty array for platform without links" do
+1 -1
View File
@@ -18,7 +18,7 @@ RSpec.describe WarpEngine::Software, type: :model do
active = create(:software)
create(:software, deleted_at: Time.current)
expect(WarpEngine::Software.kept).to eq([active])
expect(WarpEngine::Software.kept).to eq([ active ])
end
it "includes soft-deleted records without scope" do
+1 -1
View File
@@ -11,7 +11,7 @@ RSpec.describe WarpEngine::BuildsService do
end
it "returns c64 with only cartridge" do
expect(result[:platforms]["c64"][:kinds]).to eq(["cartridge"])
expect(result[:platforms]["c64"][:kinds]).to eq([ "cartridge" ])
end
it "returns allKinds matching WarpEngine::ReleaseAsset::KINDS" do