From f1e524166ef582b25418fa0ba951b82f7c2619da Mon Sep 17 00:00:00 2001 From: Kaede Akino Date: Wed, 7 Oct 2026 23:56:39 +0800 Subject: [PATCH] build(screenshots): use versioned device templates --- Scripts/Tests/test_screenshots.rb | 27 +++++++++++++++++++++++++-- com.akinokaede.termind | 2 +- fastlane/lib/screenshot_frames.rb | 20 ++++++++++++-------- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/Scripts/Tests/test_screenshots.rb b/Scripts/Tests/test_screenshots.rb index 73e71db5..b5d3b722 100644 --- a/Scripts/Tests/test_screenshots.rb +++ b/Scripts/Tests/test_screenshots.rb @@ -299,7 +299,7 @@ class ScreenshotFramesTests < Minitest::Test File.write(File.join(@root, "com.akinokaede.termind/.git"), "gitdir: fixture") FileUtils.mkdir_p(File.join(@root, "fastlane")) FileUtils.cp(File.expand_path("../../fastlane/Framefile.json", __dir__), File.join(@root, "fastlane")) - frame_template(File.join(@root, ".build/frameit-assets/iphone-18-pro.png"), 1350, 2760) + frame_template(File.join(@root, "com.akinokaede.termind/assets/device_templates/iphone-18-pro.png"), 1350, 2760) @templates = File.join(@root, "templates") FileUtils.mkdir_p(@templates) end @@ -400,12 +400,14 @@ class ScreenshotFramesTests < Minitest::Test end def test_explicit_frame_paths_work_without_submodule_and_keep_source_bytes + template = File.join(@root, "external-template.png") + FileUtils.mv(File.join(@root, "com.akinokaede.termind/assets/device_templates/iphone-18-pro.png"), template) FileUtils.remove_entry(File.join(@root, "com.akinokaede.termind")) source = File.join(@root, "review-input/en/iphone-6.3/vault.png") png(source, 1206, 2622) original_hash = Digest::SHA256.file(source).hexdigest runner = ScreenshotFrames.new({ devices: "iphone", scenes: "vault", locales: "en", - input: "review-input", output: "review-output" }, root: @root) + input: "review-input", output: "review-output", iphone_frame: template }, root: @root) downloader = Object.new downloader.define_singleton_method(:frames_exist?) { true } Frameit::FrameDownloader.stub(:templates_path, @templates) do @@ -423,6 +425,26 @@ class ScreenshotFramesTests < Minitest::Test refute Dir.exist?(File.join(@root, "com.akinokaede.termind")) end + def test_default_template_works_without_a_local_build_cache + source = File.join(@root, "com.akinokaede.termind/assets/captures/en/iphone-6.3/vault.png") + png(source, 1206, 2622) + refute Dir.exist?(File.join(@root, ".build")) + runner = ScreenshotFrames.new({ devices: "iphone", scenes: "vault", locales: "en" }, root: @root) + downloader = Object.new + downloader.define_singleton_method(:frames_exist?) { true } + Frameit::FrameDownloader.stub(:templates_path, @templates) do + Frameit::FrameDownloader.stub(:new, downloader) do + runner.run do |options| + installed = File.join(@templates, "Apple iPhone 18 Pro Silver.png") + assert_equal Digest::SHA256.file(File.join(@root, "com.akinokaede.termind/assets/device_templates/iphone-18-pro.png")).hexdigest, + Digest::SHA256.file(installed).hexdigest + png(File.join(options.fetch(:path), "iphone_framed.png"), 1350, 2760) + end + end + end + assert_equal [1350, 2760], FastImage.size(File.join(@root, "com.akinokaede.termind/assets/device_frames/en/iphone-6.3/vault.png")) + end + def test_rejects_pro_max_sources_before_calling_frameit source = File.join(@root, "com.akinokaede.termind/assets/captures/en/iphone-6.3/vault.png") png(source, 1320, 2868) @@ -471,6 +493,7 @@ class ScreenshotFramesTests < Minitest::Test runner = ScreenshotFrames.new({ devices: "iphone-duo-inner", locales: "en" }, root: @root) error = assert_raises(RuntimeError) { runner.run { flunk "frameit must not start" } } assert_includes error.message, "iphone_duo_inner_frame:" + assert_includes error.message, "git submodule update --init com.akinokaede.termind" refute Dir.exist?(File.join(@root, "com.akinokaede.termind/assets/device_frames")) end diff --git a/com.akinokaede.termind b/com.akinokaede.termind index 08c5ba3b..295a2570 160000 --- a/com.akinokaede.termind +++ b/com.akinokaede.termind @@ -1 +1 @@ -Subproject commit 08c5ba3b00ec1ae7805a2fb95cf84106332cd3fa +Subproject commit 295a2570ddc787b4dba3f45f69f3c082ece1122b diff --git a/fastlane/lib/screenshot_frames.rb b/fastlane/lib/screenshot_frames.rb index 4da3abe2..0e76bde3 100644 --- a/fastlane/lib/screenshot_frames.rb +++ b/fastlane/lib/screenshot_frames.rb @@ -5,6 +5,7 @@ require_relative "screenshots" # read-only, and the website's existing feature/file names remain stable. class ScreenshotFrames DEVICES = %w[iphone iphone-duo-outer iphone-duo-inner ipad mac].freeze + TEMPLATE_DIRECTORY = "com.akinokaede.termind/assets/device_templates".freeze CUSTOM_FRAMES = { "iphone" => { name: "iPhone 18 Pro", size: [1350, 2760], offset: "+72+69", width: 1206, color: "Silver", template: "iphone-18-pro" }, @@ -18,11 +19,11 @@ class ScreenshotFrames def initialize(options = {}, root: Screenshots::ROOT) @root = root - @mac_frame = File.expand_path(options[:mac_frame] || ".build/frameit-assets/macbook-pro-14-template.png", root) - @ipad_frame = File.expand_path(options[:ipad_frame] || ".build/frameit-assets/ipad-pro-13-m5.png", root) + @mac_frame = File.expand_path(options[:mac_frame] || "#{TEMPLATE_DIRECTORY}/macbook-pro-14-template.png", root) + @ipad_frame = File.expand_path(options[:ipad_frame] || "#{TEMPLATE_DIRECTORY}/ipad-pro-13-m5.png", root) @custom_frames = CUSTOM_FRAMES.to_h do |device, specification| option = device.tr("-", "_").concat("_frame").to_sym - [device, File.expand_path(options[option] || ".build/frameit-assets/#{specification[:template] || device}.png", root)] + [device, File.expand_path(options[option] || "#{TEMPLATE_DIRECTORY}/#{specification[:template] || device}.png", root)] end selector = Screenshots.new(:ios, {}, environment: {}, root: root) @devices = selector.selection(options[:devices], %w[iphone ipad mac], DEVICES, "devices") @@ -53,8 +54,9 @@ class ScreenshotFrames (@devices & CUSTOM_FRAMES.keys).each do |device| specification = CUSTOM_FRAMES.fetch(device) unless FastImage.size(@custom_frames.fetch(device)) == specification.fetch(:size) - raise "Import the official #{specification.fetch(:name)} #{specification.fetch(:color)} portrait PNG first; " \ - "see openwiki/operations/marketing-assets-and-app-icons.md or pass #{device.tr('-', '_')}_frame:/path/to/frame.png" + raise "Missing or invalid #{specification.fetch(:name)} template: #{@custom_frames.fetch(device)}. " \ + "Restore templates from the assets repository (git submodule update --init com.akinokaede.termind); " \ + "or pass #{device.tr('-', '_')}_frame:/path/to/frame.png" end constant = device.tr("-", "_").upcase unless Frameit::Devices.const_defined?(constant) @@ -72,11 +74,13 @@ class ScreenshotFrames )) end if @devices.include?("ipad") && FastImage.size(@ipad_frame) != [2300, 3000] - raise "Import the official iPad Pro (M5) 13-inch Space Black portrait PNG first; " \ - "see openwiki/operations/marketing-assets-and-app-icons.md or pass ipad_frame:/path/to/frame.png" + raise "Missing or invalid iPad template: #{@ipad_frame}. " \ + "Restore templates from the assets repository (git submodule update --init com.akinokaede.termind); " \ + "or pass ipad_frame:/path/to/frame.png" end if @devices.include?("mac") && FastImage.size(@mac_frame) != [3860, 2320] - raise "Import the narrow MacBook Pro template first; see openwiki/operations/marketing-assets-and-app-icons.md " \ + raise "Missing or invalid Mac template: #{@mac_frame}. " \ + "Restore templates from the assets repository (git submodule update --init com.akinokaede.termind); " \ "or pass mac_frame:/path/to/frame.png" end @jobs.each do |job|