reflex-packager 0.2.0 → 0.3.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 +4 -4
- data/.github/workflows/package.yml +310 -0
- data/.github/workflows/release-gem.yml +2 -49
- data/.github/workflows/tag.yml +11 -28
- data/.github/workflows/test.yml +16 -37
- data/.gitignore +2 -0
- data/ChangeLog.md +28 -0
- data/Gemfile.lock +26 -0
- data/README.md +232 -27
- data/Rakefile +21 -0
- data/VERSION +1 -1
- data/bin/reflex +2 -32
- data/examples/hello/icon.png +0 -0
- data/examples/hello/main.rb +18 -0
- data/examples/hello/reflex.yml +3 -0
- data/lib/reflex/packager/app_store_connect.rb +162 -0
- data/lib/reflex/packager/cli.rb +42 -9
- data/lib/reflex/packager/config.rb +233 -36
- data/lib/reflex/packager/data_compiler.rb +59 -0
- data/lib/reflex/packager/data_file.rb +183 -0
- data/lib/reflex/packager/data_loader.rb +127 -0
- data/lib/reflex/packager/gems.rb +282 -0
- data/lib/reflex/packager/library.rb +120 -0
- data/lib/reflex/packager/macos.rb +592 -94
- data/lib/reflex/packager/platform.rb +289 -10
- data/lib/reflex/packager/profile.rb +38 -26
- data/lib/reflex/packager/profiles/reflex.rb +43 -0
- data/lib/reflex/packager/rake.rb +115 -0
- data/lib/reflex/packager/stores/app_store.rb +60 -0
- data/lib/reflex/packager/stores/itchio.rb +53 -0
- data/lib/reflex/packager/templates/macos/AppStore.entitlements.erb +8 -0
- data/lib/reflex/packager/templates/macos/AppStoreExportOptions.plist.erb +14 -0
- data/lib/reflex/packager/templates/macos/ExportOptions.plist.erb +20 -0
- data/lib/reflex/packager/templates/macos/InfoPlist.strings.erb +5 -0
- data/lib/reflex/packager/templates/macos/boot.rb.erb +29 -0
- data/lib/reflex/packager/templates/macos/compile.rb.erb +7 -0
- data/lib/reflex/packager/templates/macos/main.mm.erb +10 -7
- data/lib/reflex/packager/templates/macos/project.yml.erb +60 -3
- data/lib/reflex/packager/templates/windows/app.manifest.erb +25 -0
- data/lib/reflex/packager/templates/windows/app.rc.erb +38 -0
- data/lib/reflex/packager/templates/windows/boot.rb.erb +32 -0
- data/lib/reflex/packager/templates/windows/main.cpp.erb +47 -0
- data/lib/reflex/packager/templates/windows/runtime.manifest.erb +7 -0
- data/lib/reflex/packager/windows.rb +370 -0
- data/lib/reflex/packager.rb +18 -1
- data/reflex-packager.gemspec +8 -7
- data/test/helper.rb +50 -5
- data/test/test_packager_app_store_connect.rb +108 -0
- data/test/test_packager_cli.rb +38 -3
- data/test/test_packager_config.rb +166 -27
- data/test/test_packager_data_file.rb +96 -0
- data/test/test_packager_data_loader.rb +114 -0
- data/test/test_packager_library.rb +81 -0
- data/test/test_packager_macos.rb +714 -86
- data/test/test_packager_platform.rb +16 -0
- data/test/test_packager_rake.rb +165 -0
- data/test/test_packager_stores_app_store.rb +66 -0
- data/test/test_packager_stores_itchio.rb +38 -0
- data/test/test_packager_windows.rb +685 -0
- metadata +72 -15
- data/.github/workflows/utils.rb +0 -127
- data/lib/reflex/packager/templates/macos/Podfile.erb +0 -30
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPackagerPlatform < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
RP = Reflex::Packager
|
|
7
|
+
|
|
8
|
+
def test_methods_to_implement()
|
|
9
|
+
platform = RP::Platform.new nil
|
|
10
|
+
%i[generate build archive_command platform_name].each do |name|
|
|
11
|
+
error = assert_raise(RuntimeError) {platform.send name}
|
|
12
|
+
assert_include error.message, "must implement #{name}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end# TestPackagerPlatform
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
require 'reflex/packager/rake'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TestPackagerRake < Test::Unit::TestCase
|
|
6
|
+
|
|
7
|
+
include ::Rake::DSL
|
|
8
|
+
include Xot::Rake
|
|
9
|
+
include Reflex::Packager::Rake
|
|
10
|
+
|
|
11
|
+
def application(&block)
|
|
12
|
+
Dir.mktmpdir do |dir|
|
|
13
|
+
Dir.chdir dir do
|
|
14
|
+
{
|
|
15
|
+
'reflex.yml' => "name: My Game\nfiles: ['lib/**/*']\n",
|
|
16
|
+
'main.rb' => '',
|
|
17
|
+
'VERSION' => '1.2.3',
|
|
18
|
+
'lib/a/b.rb' => ''
|
|
19
|
+
}.each do |path, text|
|
|
20
|
+
FileUtils.mkdir_p File.dirname(path)
|
|
21
|
+
File.write path, text
|
|
22
|
+
end
|
|
23
|
+
# not signed, whatever this runs with
|
|
24
|
+
with_env(ENV_TO_SIGN) {block.call File.realpath(dir)}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def setup()
|
|
30
|
+
::Rake::Task.clear
|
|
31
|
+
::Rake::TaskManager.record_task_metadata = true # for the descriptions
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_package_application()
|
|
35
|
+
application do |dir|
|
|
36
|
+
stub Gem, :win_platform?, false do
|
|
37
|
+
package_application
|
|
38
|
+
end
|
|
39
|
+
app = File.join dir, 'dist/adhoc/My Game.app'
|
|
40
|
+
archive = File.join dir, 'dist/adhoc/MyGame-1.2.3-macos-universal.zip'
|
|
41
|
+
assert_equal [app], ::Rake::Task['package'].prerequisites
|
|
42
|
+
assert_equal [archive], ::Rake::Task['archive'].prerequisites
|
|
43
|
+
assert_equal [app], ::Rake::Task[archive].prerequisites
|
|
44
|
+
assert_equal [], ::Rake::Task['release'].prerequisites # made apart on CI
|
|
45
|
+
assert_equal %w[lib/a/b.rb main.rb reflex.yml VERSION].sort,
|
|
46
|
+
::Rake::Task[app].prerequisites.sort # the files of the app, not lib/a
|
|
47
|
+
assert_include ::Rake::Task['package'].comment, 'dist/adhoc/My Game.app'
|
|
48
|
+
assert_include ::Rake::Task['release'].comment, 'v1.2.3'
|
|
49
|
+
|
|
50
|
+
pkg = File.join dir, 'dist/appstore/MyGame-1.2.3.pkg'
|
|
51
|
+
assert_equal [pkg], ::Rake::Task['package:appstore'].prerequisites
|
|
52
|
+
assert_equal ::Rake::Task[app].prerequisites, ::Rake::Task[pkg].prerequisites
|
|
53
|
+
assert_include ::Rake::Task['package:appstore'].comment, 'dist/appstore/MyGame-1.2.3.pkg'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
::Rake::Task.clear
|
|
57
|
+
application do
|
|
58
|
+
stub Gem, :win_platform?, true do
|
|
59
|
+
package_application
|
|
60
|
+
end
|
|
61
|
+
assert_false ::Rake::Task.task_defined?('package:appstore') # only on macos
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_release()
|
|
66
|
+
application do |dir|
|
|
67
|
+
archive = File.join dir, 'dist/adhoc/MyGame-1.2.3-macos-universal.zip'
|
|
68
|
+
pkg = File.join dir, 'dist/appstore/MyGame-1.2.3.pkg'
|
|
69
|
+
releases = []
|
|
70
|
+
define_singleton_method(:release_on_github) {|*args, **kwargs| releases << [args, kwargs]}
|
|
71
|
+
stub Gem, :win_platform?, false do
|
|
72
|
+
package_application
|
|
73
|
+
end
|
|
74
|
+
release = -> *paths do
|
|
75
|
+
paths.each {FileUtils.mkdir_p File.dirname(_1); FileUtils.touch _1}
|
|
76
|
+
stub(self, :release_notes, 'notes') {::Rake::Task['release'].execute}
|
|
77
|
+
ensure
|
|
78
|
+
FileUtils.rm_f paths
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
with_env 'GITHUB_REF_NAME' => nil do
|
|
82
|
+
error = assert_raise(RuntimeError) {release.call}
|
|
83
|
+
assert_include error.message, 'nothing to release'
|
|
84
|
+
release.call archive
|
|
85
|
+
release.call pkg
|
|
86
|
+
release.call archive, pkg
|
|
87
|
+
end
|
|
88
|
+
notes = {tag: 'v1.2.3', notes: 'notes'}
|
|
89
|
+
assert_equal [[[archive], notes], [[pkg], notes], [[archive, pkg], notes]], releases
|
|
90
|
+
|
|
91
|
+
with_env 'GITHUB_REF_NAME' => 'v9.9.9' do
|
|
92
|
+
error = assert_raise(RuntimeError) {release.call archive}
|
|
93
|
+
assert_include error.message, 'not the tag of the version'
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_upload()
|
|
99
|
+
application do |dir|
|
|
100
|
+
archive = File.join dir, 'dist/adhoc/MyGame-1.2.3-macos-universal.zip'
|
|
101
|
+
stub Gem, :win_platform?, false do
|
|
102
|
+
package_application
|
|
103
|
+
end
|
|
104
|
+
assert_equal [archive], ::Rake::Task['upload:itchio'].prerequisites
|
|
105
|
+
assert_include ::Rake::Task['upload:itchio'].comment, 'itch.io'
|
|
106
|
+
# only the actions of the task, not building the zip it takes
|
|
107
|
+
error = assert_raise(RuntimeError) {::Rake::Task['upload:itchio'].execute}
|
|
108
|
+
assert_include error.message, 'upload.itchio.project'
|
|
109
|
+
|
|
110
|
+
::Rake::Task.clear
|
|
111
|
+
File.write 'reflex.yml', "name: My Game\nupload: {itchio: {project: user/game}}\n"
|
|
112
|
+
uploads = []
|
|
113
|
+
uploader = Object.new
|
|
114
|
+
uploader.define_singleton_method(:upload) {|*args, **kwargs| uploads << [args, kwargs]}
|
|
115
|
+
stub Gem, :win_platform?, false do
|
|
116
|
+
package_application
|
|
117
|
+
stub Reflex::Packager::Stores::Itchio, :new, uploader do
|
|
118
|
+
::Rake::Task['upload:itchio'].execute
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
assert_equal [[[archive], {channel: 'macos', version: '1.2.3'}]], uploads
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
::Rake::Task.clear
|
|
125
|
+
application do |dir|
|
|
126
|
+
pkg = File.join dir, 'dist/appstore/MyGame-1.2.3.pkg'
|
|
127
|
+
stub Gem, :win_platform?, false do
|
|
128
|
+
package_application
|
|
129
|
+
end
|
|
130
|
+
assert_equal [pkg], ::Rake::Task['upload:appstore'].prerequisites
|
|
131
|
+
assert_include ::Rake::Task['upload:appstore'].comment, 'App Store Connect'
|
|
132
|
+
# only the actions of the task, not building the package it takes
|
|
133
|
+
error = assert_raise(Reflex::Packager::Error) {::Rake::Task['upload:appstore'].execute}
|
|
134
|
+
assert_include error.message, 'no API key'
|
|
135
|
+
|
|
136
|
+
uploads = []
|
|
137
|
+
uploader = Object.new
|
|
138
|
+
uploader.define_singleton_method(:upload) {|*args, **kwargs| uploads << [args, kwargs]}
|
|
139
|
+
stub Reflex::Packager::Stores::AppStore, :new, uploader do
|
|
140
|
+
::Rake::Task['upload:appstore'].execute
|
|
141
|
+
end
|
|
142
|
+
assert_equal [[[pkg], {platform: 'macos'}]], uploads
|
|
143
|
+
|
|
144
|
+
::Rake::Task.clear
|
|
145
|
+
stub Gem, :win_platform?, true do
|
|
146
|
+
package_application
|
|
147
|
+
end
|
|
148
|
+
assert_false ::Rake::Task.task_defined?('upload:appstore') # only on macos
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def test_release_notes()
|
|
153
|
+
application do
|
|
154
|
+
File.write 'ChangeLog.md', "# My Game ChangeLog\n\n\n## [v1.2.3] - 2026-10-13\n\n- Add a\n"
|
|
155
|
+
stub self, :git, "abc\n" do
|
|
156
|
+
assert_equal "- Add a\n\nBuilt with xord/all@abc.", release_notes('v1.2.3')
|
|
157
|
+
assert_equal 'Built with xord/all@abc.', release_notes('v9.9.9')
|
|
158
|
+
end
|
|
159
|
+
stub self, :git, '' do # the libraries of no checkout
|
|
160
|
+
assert_equal '- Add a', release_notes('v1.2.3')
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end# TestPackagerRake
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPackagerStoresAppStore < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
RP = Reflex::Packager
|
|
7
|
+
|
|
8
|
+
# The App Store with the commands it runs, which succeed by +result+, and
|
|
9
|
+
# the content of the key file each command is given.
|
|
10
|
+
def app_store(credentials, result = true, &block)
|
|
11
|
+
app_store = RP::Stores::AppStore.new RP::AppStoreConnect.new(credentials)
|
|
12
|
+
commands = []
|
|
13
|
+
keys = []
|
|
14
|
+
app_store.define_singleton_method(:system) do |*cmd|
|
|
15
|
+
commands << cmd
|
|
16
|
+
keys << File.read(cmd.last)
|
|
17
|
+
result
|
|
18
|
+
end
|
|
19
|
+
app_store.define_singleton_method(:puts) {|*|}
|
|
20
|
+
Dir.mktmpdir do |dir|
|
|
21
|
+
pkg = File.join dir, 'a.pkg'
|
|
22
|
+
File.write pkg, ''
|
|
23
|
+
block.call app_store, pkg, commands, keys
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_upload()
|
|
28
|
+
creds = {issuer_id: 'ISSUER', key_id: 'KEY', key_p8: 'P8'}
|
|
29
|
+
app_store creds do |app_store, pkg, commands, keys|
|
|
30
|
+
app_store.upload pkg, platform: 'macos'
|
|
31
|
+
assert_equal [
|
|
32
|
+
'xcrun', 'altool', '--upload-package', pkg, '--platform', 'macos',
|
|
33
|
+
'--api-key', 'KEY', '--api-issuer', 'ISSUER', '--p8-file-path'
|
|
34
|
+
], commands.first[0..-2]
|
|
35
|
+
assert_equal 'AuthKey_KEY.p8', File.basename(commands.first.last)
|
|
36
|
+
assert_equal ['P8'], keys
|
|
37
|
+
assert_false File.exist?(commands.first.last) # only while uploading
|
|
38
|
+
|
|
39
|
+
error = assert_raise(RP::Error) {app_store.upload "#{pkg}.no", platform: 'macos'}
|
|
40
|
+
assert_include error.message, 'nothing to upload'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Tempfile.create 'key' do |key|
|
|
44
|
+
key.write 'FILE'
|
|
45
|
+
key.flush
|
|
46
|
+
app_store({issuer_id: 'ISSUER', key_id: 'KEY', key_path: key.path}) do |app_store, pkg, commands, keys|
|
|
47
|
+
app_store.upload pkg, platform: 'macos'
|
|
48
|
+
assert_equal key.path, commands.first.last # the file as it is
|
|
49
|
+
assert_equal ['FILE'], keys
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
[[false, 'failed to upload'], [nil, 'xcrun not found']].each do |result, message|
|
|
54
|
+
app_store creds, result do |app_store, pkg, _|
|
|
55
|
+
error = assert_raise(RP::Error) {app_store.upload pkg, platform: 'macos'}
|
|
56
|
+
assert_include error.message, message
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
with_env(ENV_TO_SIGN) do
|
|
61
|
+
error = assert_raise(RP::Error) {RP::Stores::AppStore.new}
|
|
62
|
+
assert_include error.message, 'no API key'
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end# TestPackagerStoresAppStore
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require_relative 'helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestPackagerStoresItchio < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
RP = Reflex::Packager
|
|
7
|
+
|
|
8
|
+
# itch.io with the commands it runs, which succeed by +result+.
|
|
9
|
+
def itchio(result = true, &block)
|
|
10
|
+
itchio = RP::Stores::Itchio.new 'user/game'
|
|
11
|
+
commands = []
|
|
12
|
+
itchio.define_singleton_method(:system) {|*cmd| commands << cmd; result}
|
|
13
|
+
itchio.define_singleton_method(:puts) {|*|}
|
|
14
|
+
Dir.mktmpdir do |dir|
|
|
15
|
+
zip = File.join dir, 'a.zip'
|
|
16
|
+
File.write zip, ''
|
|
17
|
+
block.call itchio, zip, commands
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_upload()
|
|
22
|
+
itchio do |itchio, zip, commands|
|
|
23
|
+
itchio.upload zip, channel: 'macos', version: '1.2.3'
|
|
24
|
+
assert_equal [['butler', 'push', zip, 'user/game:macos', '--userversion', '1.2.3']], commands
|
|
25
|
+
|
|
26
|
+
error = assert_raise(RP::Error) {itchio.upload "#{zip}.no", channel: 'macos', version: '1'}
|
|
27
|
+
assert_include error.message, 'nothing to upload'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
[[false, 'failed to upload'], [nil, 'butler not found']].each do |result, message|
|
|
31
|
+
itchio result do |itchio, zip, _|
|
|
32
|
+
error = assert_raise(RP::Error) {itchio.upload zip, channel: 'macos', version: '1'}
|
|
33
|
+
assert_include error.message, message
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end# TestPackagerStoresItchio
|