fastlane-plugin-godot 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6c9d11e9f58005fe0a36c6cb716b3bc3c9b783b67a268209a06387ca854bc8fa
4
+ data.tar.gz: 0b3982d05a6da3176b43f25bbcbec33335766bddb23c04fd7b438d5b2e718c74
5
+ SHA512:
6
+ metadata.gz: f97edeb638c693b982100793757a04156ac759a43e0fc594eb62aa637929dacc96177de51ab82f87ae246ae81a9f890a48c2b1e6b394a7f0b922c0ab9004c7d4
7
+ data.tar.gz: 6e8a10c9ecb3258474d84323b597ebb9c4496a7a8c675f8a93fd91c66b445b3055050dea2c864b1f95cdaa34a8bd508be21cf550f1f9a75a46ddea099bbc3944
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mad Science Software
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # fastlane-plugin-godot
2
+
3
+ A [fastlane](https://fastlane.tools) plugin for shipping [Godot Engine](https://godotengine.org)
4
+ games to mobile app stores: headless exports with real diagnostics, composing
5
+ with the fastlane actions (`gym`, `pilot`, `cert`, `sigh`, `supply`, …) that
6
+ already handle signing and store upload.
7
+
8
+ **New to fastlane?** Start with the
9
+ [Godot → TestFlight from-zero walkthrough](examples/ios-testflight/) — a
10
+ complete copy-paste setup including Ruby installation, the App Store Connect
11
+ API key, Godot project prep, and a working Fastfile. First setup ~30 minutes;
12
+ ~4 minutes per release after that.
13
+
14
+ **Already using fastlane?**
15
+
16
+ ```bash
17
+ fastlane add_plugin godot
18
+ ```
19
+
20
+ ## Actions
21
+
22
+ ### godot_init
23
+
24
+ Scaffolds everything a Godot project needs for mobile releases — run once
25
+ from the project directory:
26
+
27
+ ```bash
28
+ bundle exec fastlane run godot_init
29
+ ```
30
+
31
+ Creates (only when missing — existing files are never touched): `Gemfile`,
32
+ `fastlane/{Pluginfile,Appfile,Fastfile,.env.template}`, an
33
+ `export_presets.cfg` with iOS + Android presets, `build/.gdignore` (so Godot
34
+ doesn't import its own build products), a placeholder 1024×1024 `app_icon.png`
35
+ (iOS export hard-fails without an icon; pass `icon:false` to skip), and a
36
+ `.gitignore` (or a warning listing entries yours is missing). Finishes by
37
+ listing the placeholders you must fill in: bundle identifier, team ID, and
38
+ your App Store Connect API key in `fastlane/.env`.
39
+
40
+ ### godot_export
41
+
42
+ Exports a Godot project headlessly using a named export preset from
43
+ `export_presets.cfg`, wrapping every footgun we have personally hit shipping
44
+ a real game with it:
45
+
46
+ - verifies the preset exists (and lists the available ones when it doesn't)
47
+ - verifies the matching engine version's export templates are installed for
48
+ the preset's platform, with download guidance when they aren't
49
+ - runs a headless `--import` first — a stale import cache aborts Godot
50
+ exports with a crash-lookalike exit 134
51
+ - creates the output directory (Godot errors rather than create it)
52
+ - confirms the artifact was actually produced — Godot has historically
53
+ exited 0 on some failed exports
54
+
55
+ ```ruby
56
+ lane :beta do
57
+ xcodeproj = godot_export(preset: 'iOS')
58
+ build_app(project: xcodeproj, scheme: File.basename(xcodeproj, '.xcodeproj'))
59
+ upload_to_testflight
60
+ end
61
+ ```
62
+
63
+ | Option | Description | Default |
64
+ | --- | --- | --- |
65
+ | `preset` | Export preset name (required) | — |
66
+ | `project_path` | Directory containing `project.godot` | `.` |
67
+ | `godot_binary` | Path to the Godot binary | `godot` |
68
+ | `output_path` | Artifact destination, relative to the project | the preset's `export_path` |
69
+ | `debug` | Export a debug build | `false` |
70
+ | `import_first` | Run headless `--import` before exporting | `true` |
71
+ | `verbose` | Pass `--verbose` to Godot | `false` |
72
+
73
+ Every option is also settable via environment variable (`FL_GODOT_*`).
74
+ Returns the absolute artifact path (for iOS presets, the generated Xcode
75
+ project) and sets `lane_context[:GODOT_EXPORT_OUTPUT]`.
76
+
77
+ ## The iOS signing story (read this once)
78
+
79
+ Godot generates a fresh Xcode project on every export, with two properties
80
+ that break naive pipelines:
81
+
82
+ 1. **It writes `CODE_SIGN_IDENTITY="Apple Distribution"` into an
83
+ automatic-signing configuration**
84
+ ([godot#110052](https://github.com/godotengine/godot/issues/110052)),
85
+ which xcodebuild rejects as conflicting. Fix: archive with
86
+ `xcargs: 'CODE_SIGN_IDENTITY="Apple Development"'` and let the export
87
+ step re-sign for distribution.
88
+ 2. **xcodebuild's cloud signing requires an Admin App Store Connect API
89
+ key** (`Cloud signing permission error` otherwise). You don't need it:
90
+ fastlane's stock `get_certificates` + `get_provisioning_profile` do
91
+ classic signing with an App Manager key, idempotently.
92
+
93
+ The [example Fastfile](examples/ios-testflight/fastlane/Fastfile) wires both
94
+ correctly. Its
95
+ [README's sharp-edges table](examples/ios-testflight/README.md#known-sharp-edges-and-how-this-setup-dodges-them)
96
+ maps the exact error messages to fixes.
97
+
98
+ ## Requirements
99
+
100
+ - Godot 4.x available on the `PATH` (or via `godot_binary`)
101
+ - The engine version's export templates installed for your target platform
102
+ - For iOS builds: macOS with Xcode
103
+
104
+ ## Roadmap
105
+
106
+ See [ROADMAP.md](ROADMAP.md) — next up: RubyGems release, version/build-number
107
+ management actions, engine-version resolution, Android/Google Play, and
108
+ Continuous Integration (CI) workflow templates.
109
+
110
+ ## Development
111
+
112
+ ```bash
113
+ bundle install
114
+ bundle exec rake # runs the RSpec suite
115
+ ```
116
+
117
+ Issues and pull requests welcome — especially reports of export footguns
118
+ this plugin doesn't yet catch.
119
+
120
+ ## License
121
+
122
+ [MIT](LICENSE)
@@ -0,0 +1,119 @@
1
+ require 'fastlane/action'
2
+ require 'shellwords'
3
+ require_relative '../helper/godot_helper'
4
+
5
+ module Fastlane
6
+ module Actions
7
+ class GodotExportAction < Action
8
+ def self.run(params)
9
+ godot = params[:godot_binary]
10
+ project_path = File.expand_path(params[:project_path])
11
+ preset_name = params[:preset]
12
+
13
+ UI.user_error!("No project.godot in #{project_path}") unless File.exist?(File.join(project_path, 'project.godot'))
14
+
15
+ version = Helper::GodotHelper.godot_version(godot)
16
+ UI.message("Godot #{version}")
17
+
18
+ cfg_path = File.join(project_path, 'export_presets.cfg')
19
+ preset = Helper::GodotHelper.find_preset(cfg_path, preset_name)
20
+ Helper::GodotHelper.verify_templates!(version, preset[:platform])
21
+
22
+ output_path = params[:output_path] || preset[:export_path]
23
+ UI.user_error!("Preset '#{preset_name}' has no export_path and no output_path was given") if output_path.nil? || output_path.empty?
24
+ absolute_output = File.expand_path(output_path, project_path)
25
+ FileUtils.mkdir_p(File.dirname(absolute_output))
26
+
27
+ if params[:import_first]
28
+ UI.message('Importing project resources (stale import caches abort exports)…')
29
+ Actions.sh("#{godot.shellescape} --headless --path #{project_path.shellescape} --import")
30
+ end
31
+
32
+ export_flag = params[:debug] ? '--export-debug' : '--export-release'
33
+ command = [
34
+ godot.shellescape,
35
+ '--headless',
36
+ '--path', project_path.shellescape,
37
+ export_flag, preset_name.shellescape,
38
+ absolute_output.shellescape
39
+ ]
40
+ command << '--verbose' if params[:verbose]
41
+
42
+ UI.message("Exporting preset '#{preset_name}' (#{preset[:platform]}) -> #{absolute_output}")
43
+ Actions.sh(command.join(' '))
44
+
45
+ # Godot has historically exited 0 on some export failures; trust the artifact, not the exit code.
46
+ UI.user_error!("Export claimed success but produced nothing at #{absolute_output}") unless File.exist?(absolute_output)
47
+
48
+ UI.success("Exported #{preset[:platform]} build: #{absolute_output}")
49
+ Actions.lane_context[SharedValues::GODOT_EXPORT_OUTPUT] = absolute_output
50
+ absolute_output
51
+ end
52
+
53
+ def self.description
54
+ 'Export a Godot project headlessly using an export preset'
55
+ end
56
+
57
+ def self.return_value
58
+ 'Absolute path to the exported artifact (for iOS, the generated Xcode project)'
59
+ end
60
+
61
+ def self.authors
62
+ ['Mad Science Software']
63
+ end
64
+
65
+ def self.output
66
+ [['GODOT_EXPORT_OUTPUT', 'Absolute path to the exported artifact']]
67
+ end
68
+
69
+ def self.available_options
70
+ [
71
+ FastlaneCore::ConfigItem.new(key: :preset,
72
+ env_name: 'FL_GODOT_PRESET',
73
+ description: 'Name of the export preset in export_presets.cfg',
74
+ type: String),
75
+ FastlaneCore::ConfigItem.new(key: :project_path,
76
+ env_name: 'FL_GODOT_PROJECT_PATH',
77
+ description: 'Directory containing project.godot',
78
+ type: String,
79
+ default_value: '.'),
80
+ FastlaneCore::ConfigItem.new(key: :godot_binary,
81
+ env_name: 'FL_GODOT_BINARY',
82
+ description: 'Path to the Godot binary',
83
+ type: String,
84
+ default_value: 'godot'),
85
+ FastlaneCore::ConfigItem.new(key: :output_path,
86
+ env_name: 'FL_GODOT_OUTPUT_PATH',
87
+ description: 'Where to write the exported artifact (defaults to the preset export_path), relative to the project',
88
+ type: String,
89
+ optional: true),
90
+ FastlaneCore::ConfigItem.new(key: :debug,
91
+ env_name: 'FL_GODOT_DEBUG',
92
+ description: 'Export a debug build instead of a release build',
93
+ type: Boolean,
94
+ default_value: false),
95
+ FastlaneCore::ConfigItem.new(key: :import_first,
96
+ env_name: 'FL_GODOT_IMPORT_FIRST',
97
+ description: 'Run a headless --import before exporting (a stale import cache aborts exports)',
98
+ type: Boolean,
99
+ default_value: true),
100
+ FastlaneCore::ConfigItem.new(key: :verbose,
101
+ env_name: 'FL_GODOT_VERBOSE',
102
+ description: 'Pass --verbose to Godot',
103
+ type: Boolean,
104
+ default_value: false)
105
+ ]
106
+ end
107
+
108
+ def self.is_supported?(platform)
109
+ true
110
+ end
111
+ end
112
+ end
113
+
114
+ module Actions
115
+ module SharedValues
116
+ GODOT_EXPORT_OUTPUT = :GODOT_EXPORT_OUTPUT
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,89 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/godot_scaffold'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class GodotInitAction < Action
7
+ def self.run(params)
8
+ project_path = File.expand_path(params[:project_path])
9
+ UI.user_error!("No project.godot in #{project_path} — run this from (or point project_path at) a Godot project") unless File.exist?(File.join(project_path, 'project.godot'))
10
+
11
+ created = []
12
+ skipped = []
13
+ write = lambda do |relative_path, content, binary: false|
14
+ target = File.join(project_path, relative_path)
15
+ if File.exist?(target)
16
+ skipped << relative_path
17
+ else
18
+ FileUtils.mkdir_p(File.dirname(target))
19
+ binary ? File.binwrite(target, content) : File.write(target, content)
20
+ created << relative_path
21
+ end
22
+ end
23
+
24
+ scaffold = Helper::GodotScaffold
25
+ write.call('Gemfile', scaffold::GEMFILE)
26
+ write.call('fastlane/Pluginfile', scaffold::PLUGINFILE)
27
+ write.call('fastlane/Appfile', scaffold::APPFILE)
28
+ write.call('fastlane/Fastfile', scaffold::FASTFILE)
29
+ write.call('fastlane/.env.template', scaffold::ENV_TEMPLATE)
30
+ write.call('export_presets.cfg', scaffold::EXPORT_PRESETS)
31
+ write.call('build/.gdignore', '')
32
+ write.call('app_icon.png', scaffold.placeholder_icon_png, binary: true) if params[:icon]
33
+
34
+ gitignore = File.join(project_path, '.gitignore')
35
+ if File.exist?(gitignore)
36
+ existing = File.read(gitignore)
37
+ missing = scaffold::GITIGNORE_ENTRIES.reject { |entry| existing.include?(entry) }
38
+ UI.important("Your .gitignore is missing: #{missing.join(', ')} — add them so credentials and build products stay out of git") unless missing.empty?
39
+ skipped << '.gitignore'
40
+ else
41
+ write.call('.gitignore', scaffold::GITIGNORE)
42
+ end
43
+
44
+ created.each { |path| UI.success("created #{path}") }
45
+ skipped.each { |path| UI.message("kept existing #{path}") }
46
+
47
+ unless created.empty?
48
+ UI.important('Placeholders to fill in before building:')
49
+ UI.important(' - fastlane/Appfile: bundle identifier and team ID')
50
+ UI.important(' - export_presets.cfg: bundle identifier, team ID, export_path names')
51
+ UI.important(' - copy fastlane/.env.template to fastlane/.env and add your App Store Connect API key')
52
+ UI.important(' - app_icon.png is an obvious placeholder — replace it before shipping') if params[:icon]
53
+ end
54
+ created
55
+ end
56
+
57
+ def self.description
58
+ 'Scaffold the files a Godot project needs for fastlane mobile releases (never overwrites existing files)'
59
+ end
60
+
61
+ def self.return_value
62
+ 'Array of relative paths that were created'
63
+ end
64
+
65
+ def self.authors
66
+ ['Mad Science Software']
67
+ end
68
+
69
+ def self.available_options
70
+ [
71
+ FastlaneCore::ConfigItem.new(key: :project_path,
72
+ env_name: 'FL_GODOT_PROJECT_PATH',
73
+ description: 'Directory containing project.godot',
74
+ type: String,
75
+ default_value: '.'),
76
+ FastlaneCore::ConfigItem.new(key: :icon,
77
+ env_name: 'FL_GODOT_INIT_ICON',
78
+ description: 'Also create a placeholder 1024x1024 app_icon.png (iOS export fails without an icon)',
79
+ type: Boolean,
80
+ default_value: true)
81
+ ]
82
+ end
83
+
84
+ def self.is_supported?(platform)
85
+ true
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,92 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
5
+
6
+ module Helper
7
+ class GodotHelper
8
+ # Full version string, e.g. "4.7.1.stable.official.a13da4feb"
9
+ def self.godot_version(godot_binary)
10
+ output = `#{godot_binary.shellescape} --version 2>/dev/null`.strip
11
+ UI.user_error!("Could not run '#{godot_binary} --version' — is Godot installed and on the PATH?") if output.empty?
12
+ output.lines.last.strip
13
+ end
14
+
15
+ # Export templates live in a directory named after the version's
16
+ # release segment: "4.7.1.stable.official.a13da4feb" -> "4.7.1.stable"
17
+ def self.template_directory_name(version_string)
18
+ match = version_string.match(/^(\d+\.\d+(?:\.\d+)?\.[a-z0-9]+)/)
19
+ UI.user_error!("Unrecognized Godot version string: '#{version_string}'") unless match
20
+ match[1]
21
+ end
22
+
23
+ def self.templates_root
24
+ if FastlaneCore::Helper.mac?
25
+ File.expand_path('~/Library/Application Support/Godot/export_templates')
26
+ else
27
+ File.expand_path('~/.local/share/godot/export_templates')
28
+ end
29
+ end
30
+
31
+ # Minimal parse of export_presets.cfg: the preset headers plus the
32
+ # name/platform/export_path lines that follow each one.
33
+ def self.parse_presets(cfg_path)
34
+ UI.user_error!("No export_presets.cfg found at #{cfg_path} — create an export preset first (Project > Export in the Godot editor, or commit one)") unless File.exist?(cfg_path)
35
+
36
+ presets = []
37
+ current = nil
38
+ File.foreach(cfg_path) do |line|
39
+ case line
40
+ when /^\[preset\.\d+\]\s*$/
41
+ current = {}
42
+ presets << current
43
+ when /^\[preset\.\d+\.options\]\s*$/
44
+ current = nil
45
+ when /^name="(.*)"\s*$/
46
+ current[:name] = Regexp.last_match(1) if current
47
+ when /^platform="(.*)"\s*$/
48
+ current[:platform] = Regexp.last_match(1) if current
49
+ when /^export_path="(.*)"\s*$/
50
+ current[:export_path] = Regexp.last_match(1) if current
51
+ end
52
+ end
53
+ presets
54
+ end
55
+
56
+ def self.find_preset(cfg_path, preset_name)
57
+ presets = parse_presets(cfg_path)
58
+ preset = presets.find { |p| p[:name] == preset_name }
59
+ unless preset
60
+ available = presets.map { |p| "'#{p[:name]}' (#{p[:platform]})" }.join(', ')
61
+ UI.user_error!("No export preset named '#{preset_name}' in #{cfg_path}. Available presets: #{available.empty? ? 'none' : available}")
62
+ end
63
+ preset
64
+ end
65
+
66
+ # The template archive each platform's export requires, keyed by the
67
+ # platform string Godot writes into export_presets.cfg.
68
+ PLATFORM_TEMPLATE_FILES = {
69
+ 'iOS' => ['ios.zip'],
70
+ 'Android' => ['android_debug.apk', 'android_release.apk', 'android_source.zip'],
71
+ 'macOS' => ['macos.zip'],
72
+ 'Web' => ['web_release.zip', 'web_debug.zip']
73
+ }.freeze
74
+
75
+ def self.verify_templates!(version_string, platform)
76
+ dir = File.join(templates_root, template_directory_name(version_string))
77
+ needed = PLATFORM_TEMPLATE_FILES[platform]
78
+ return if needed.nil? # platform we don't know how to check — let Godot decide
79
+
80
+ missing = needed.reject { |f| File.exist?(File.join(dir, f)) }
81
+ return if missing.empty?
82
+
83
+ UI.user_error!(
84
+ "Godot #{template_directory_name(version_string)} export templates for #{platform} " \
85
+ "are missing (#{missing.join(', ')} not found in #{dir}). " \
86
+ 'Download the templates bundle from https://godotengine.org/download and install it, ' \
87
+ "or unzip the needed files from the .tpz archive into #{dir}"
88
+ )
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,181 @@
1
+ require 'zlib'
2
+
3
+ module Fastlane
4
+ module Helper
5
+ # File templates for godot_init. Placeholder values are ALL-CAPS or
6
+ # com.example so nothing accidentally ships as-is.
7
+ class GodotScaffold
8
+ GEMFILE = <<~RUBY.freeze
9
+ source 'https://rubygems.org'
10
+
11
+ gem 'fastlane'
12
+
13
+ plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
14
+ eval_gemfile(plugins_path) if File.exist?(plugins_path)
15
+ RUBY
16
+
17
+ PLUGINFILE = <<~RUBY.freeze
18
+ gem 'fastlane-plugin-godot'
19
+ RUBY
20
+
21
+ APPFILE = <<~RUBY.freeze
22
+ # Your game's bundle identifier (must match the export preset).
23
+ app_identifier('com.example.mygame')
24
+
25
+ # Your 10-character Apple Developer team ID.
26
+ team_id('YOURTEAMID')
27
+ RUBY
28
+
29
+ FASTFILE = <<~RUBY.freeze
30
+ default_platform(:ios)
31
+
32
+ platform :ios do
33
+ desc 'Export from Godot and build a signed .ipa'
34
+ lane :build do
35
+ app_store_connect_api_key(
36
+ key_id: ENV.fetch('ASC_KEY_ID'),
37
+ issuer_id: ENV.fetch('ASC_ISSUER_ID'),
38
+ key_filepath: File.expand_path(ENV.fetch('ASC_KEY_PATH'))
39
+ )
40
+
41
+ xcodeproj = godot_export(preset: 'iOS')
42
+
43
+ # Reuse-or-create the distribution certificate and App Store
44
+ # profile; classic (non-cloud) signing works with an App Manager
45
+ # App Store Connect API key.
46
+ get_certificates
47
+ get_provisioning_profile
48
+
49
+ build_app(
50
+ project: xcodeproj,
51
+ scheme: File.basename(xcodeproj, '.xcodeproj'),
52
+ output_directory: 'build/ios',
53
+ export_method: 'app-store',
54
+ export_options: {
55
+ signingStyle: 'manual',
56
+ signingCertificate: 'Apple Distribution',
57
+ provisioningProfiles: {
58
+ CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier) =>
59
+ lane_context[SharedValues::SIGH_NAME]
60
+ }
61
+ },
62
+ # Works around godotengine/godot#110052 (Godot writes a
63
+ # distribution identity into an automatic-signing config).
64
+ xcargs: 'CODE_SIGN_IDENTITY="Apple Development" -allowProvisioningUpdates'
65
+ )
66
+ end
67
+
68
+ desc 'Build and upload to TestFlight'
69
+ lane :beta do
70
+ build
71
+ upload_to_testflight
72
+ end
73
+ end
74
+
75
+ platform :android do
76
+ desc 'Export a debug-signed APK'
77
+ lane :build do
78
+ godot_export(preset: 'Android', debug: true)
79
+ end
80
+ end
81
+ RUBY
82
+
83
+ ENV_TEMPLATE = <<~TEXT.freeze
84
+ # Copy to fastlane/.env and fill in — fastlane loads it automatically.
85
+ # Never commit the real .env; commit only this template.
86
+ ASC_KEY_ID=ABC123DEFG
87
+ ASC_ISSUER_ID=12345678-1234-1234-1234-123456789012
88
+ ASC_KEY_PATH=~/.appstoreconnect/AuthKey_ABC123DEFG.p8
89
+ TEXT
90
+
91
+ GITIGNORE = <<~TEXT.freeze
92
+ # fastlane: local credentials and build products
93
+ fastlane/.env
94
+ fastlane/report.xml
95
+ build/
96
+ vendor/
97
+ .bundle/
98
+ TEXT
99
+
100
+ GITIGNORE_ENTRIES = ['fastlane/.env', 'fastlane/report.xml', 'build/'].freeze
101
+
102
+ EXPORT_PRESETS = <<~TEXT.freeze
103
+ [preset.0]
104
+
105
+ name="iOS"
106
+ platform="iOS"
107
+ runnable=true
108
+ dedicated_server=false
109
+ custom_features=""
110
+ export_filter="all_resources"
111
+ include_filter=""
112
+ exclude_filter=""
113
+ export_path="build/ios/Game.xcodeproj"
114
+ script_export_mode=2
115
+
116
+ [preset.0.options]
117
+
118
+ application/app_store_team_id="YOURTEAMID"
119
+ application/bundle_identifier="com.example.mygame"
120
+ application/short_version="0.1.0"
121
+ application/version="1"
122
+ application/min_ios_version="15.0"
123
+ application/export_project_only=true
124
+ icons/icon_1024x1024="res://app_icon.png"
125
+ orientation/portrait=true
126
+ orientation/upside_down=false
127
+ orientation/landscape_left=false
128
+ orientation/landscape_right=false
129
+
130
+ [preset.1]
131
+
132
+ name="Android"
133
+ platform="Android"
134
+ runnable=true
135
+ dedicated_server=false
136
+ custom_features=""
137
+ export_filter="all_resources"
138
+ include_filter=""
139
+ exclude_filter=""
140
+ export_path="build/android/Game.apk"
141
+ script_export_mode=2
142
+
143
+ [preset.1.options]
144
+
145
+ gradle_build/use_gradle_build=false
146
+ architectures/arm64-v8a=true
147
+ version/code=1
148
+ version/name="0.1.0"
149
+ package/unique_name="com.example.mygame"
150
+ package/name=""
151
+ package/signed=true
152
+ launcher_icons/main_192x192="res://app_icon.png"
153
+ screen/immersive_mode=true
154
+ TEXT
155
+
156
+ # Minimal valid 1024x1024 opaque PNG (Apple rejects alpha in the
157
+ # marketing icon): flat two-tone placeholder, obviously temporary.
158
+ def self.placeholder_icon_png(size = 1024)
159
+ background = [40, 90, 100].pack('C3')
160
+ foreground = [235, 180, 70].pack('C3')
161
+ low = size / 4
162
+ high = 3 * size / 4
163
+ raw = +''.b
164
+ size.times do |y|
165
+ raw << "\x00".b
166
+ size.times do |x|
167
+ raw << (x >= low && x < high && y >= low && y < high ? foreground : background)
168
+ end
169
+ end
170
+ chunk = lambda do |tag, data|
171
+ [data.bytesize].pack('N') + tag + data + [Zlib.crc32(tag + data)].pack('N')
172
+ end
173
+ header = [size, size, 8, 2, 0, 0, 0].pack('NNC5')
174
+ "\x89PNG\r\n\x1a\n".b +
175
+ chunk.call('IHDR'.b, header) +
176
+ chunk.call('IDAT'.b, Zlib::Deflate.deflate(raw, Zlib::BEST_COMPRESSION)) +
177
+ chunk.call('IEND'.b, ''.b)
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Godot
3
+ VERSION = '0.1.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ require 'fastlane/plugin/godot/version'
2
+
3
+ module Fastlane
4
+ module Godot
5
+ # Return all .rb files inside the "actions" and "helper" directories
6
+ def self.all_classes
7
+ Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
8
+ end
9
+ end
10
+ end
11
+
12
+ # By default, fastlane loads all actions and helpers of a plugin at once
13
+ Fastlane::Godot.all_classes.each do |current|
14
+ require current
15
+ end
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-godot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mad Science Software
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: 'Godot-specific fastlane actions: headless engine exports, export template
13
+ verification, and Xcode project handling for shipping Godot games to the app stores.'
14
+ email:
15
+ - jamesyoungwrites@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - lib/fastlane/plugin/godot.rb
23
+ - lib/fastlane/plugin/godot/actions/godot_export_action.rb
24
+ - lib/fastlane/plugin/godot/actions/godot_init_action.rb
25
+ - lib/fastlane/plugin/godot/helper/godot_helper.rb
26
+ - lib/fastlane/plugin/godot/helper/godot_scaffold.rb
27
+ - lib/fastlane/plugin/godot/version.rb
28
+ homepage: https://github.com/Mad-Science-Software/fastlane-plugin-godot
29
+ licenses:
30
+ - MIT
31
+ metadata:
32
+ rubygems_mfa_required: 'true'
33
+ source_code_uri: https://github.com/Mad-Science-Software/fastlane-plugin-godot
34
+ changelog_uri: https://github.com/Mad-Science-Software/fastlane-plugin-godot/releases
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '3.1'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubygems_version: 4.0.16
50
+ specification_version: 4
51
+ summary: Export and ship Godot Engine games with fastlane
52
+ test_files: []