gembrew 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cea714943b01c87fdc8175f290093cb509dc6df00eb84fb5081cda8db9714e8c
4
- data.tar.gz: 3255bb06ae22d87e2a6f81e7cab6484cf6ac2fe832e881b53bde0b9c95e4be78
3
+ metadata.gz: fe9b9cc5e9535cca862d2adf23aa7887bf0608fa14104d8aa7c3db046358ac61
4
+ data.tar.gz: 7242264cbf2fa6c438445dd180ec73fec06c37513a5d67889ac47dddb748985b
5
5
  SHA512:
6
- metadata.gz: fc656e03acea77d7b449b4985cdf18a6f8fea25bce6c3f14df19c145a6d38e86059c02dc43e572ce776fcda64d6f2154bcc8c23d9de791b42aed87ed775e1795
7
- data.tar.gz: 981ce3693cced89e212da3ab775ffef24875b8128a63e32ef9d32be123bbf9d24fe6d20c4648df8f50543c27b548bf8f6e0ad451cbe76032ea3b886730a1b2d8
6
+ metadata.gz: 412fd3b8bc7d1d92ae3358902eacb1e89d6d5a1c2eee5fbb21512b6ea549d1035e438d45855ee8091eda01b9f92f22603c8a089324e82485bafcb124afe4723c
7
+ data.tar.gz: 5fdb7789ec71ce6838cdc82973765441ada2a2c100b9b73ac121c1d3e8aaa77885477d61b578336e6a92b78fc72e6a3acb0bac3cea9be8a2937a8c7710302919
data/README.md CHANGED
@@ -20,16 +20,21 @@ gembrew build
20
20
  gembrew check
21
21
  ```
22
22
 
23
- `init` creates a tap repository containing `README.md`, `gembrew/`, and
24
- `Formula/`. It accepts an empty directory or an existing tap containing
25
- `Formula/`. Supplying a gem name also creates its first configuration. The gem
26
- name is optional, so `gembrew init` can prepare an empty tap or add Gembrew to
27
- an existing one. An existing `README.md` is never overwritten.
23
+ `init` creates a tap repository containing `README.md`, `gembrew/`, `Formula/`,
24
+ and a GitHub Actions workflow that styles, audits, installs, tests, and checks
25
+ the linkage of every formula on Linux and macOS. It accepts an empty directory
26
+ or an existing tap containing `Formula/`.
27
+ Supplying a gem name also creates its first configuration. The gem name is
28
+ optional, so `gembrew init` can prepare an empty tap or add Gembrew to an
29
+ existing one. Existing README and workflow files are never overwritten.
28
30
 
29
31
  For example, `gembrew init example` generates:
30
32
 
31
33
  ```text
32
34
  README.md
35
+ .github/
36
+ workflows/
37
+ test.yml
33
38
  gembrew/
34
39
  example.yml
35
40
  Formula/
@@ -64,15 +69,16 @@ generate just one:
64
69
  gembrew build example
65
70
  ```
66
71
 
67
- The required settings are `gem` and exactly one of `test` or `test_from_file`.
72
+ The required settings are `gem`, `version`, `source`, and exactly one of `test`
73
+ or `test_from_file`.
68
74
  The output defaults to `Formula/NAME.rb`, where `NAME` is the configuration
69
75
  filename. Relative paths are resolved from the tap root.
70
76
 
71
77
  ```yaml
72
78
  gem: example
73
-
74
- # Optional published gem version. The latest stable version is used by default.
75
79
  version: "1.2.3"
80
+ source:
81
+ type: rubygems
76
82
 
77
83
  # Optional gem metadata overrides:
78
84
  desc: Example command-line application
@@ -80,6 +86,11 @@ homepage: https://example.com
80
86
  license: MIT
81
87
  executable: example
82
88
 
89
+ # Optional additional Homebrew formula dependencies:
90
+ dependencies:
91
+ - bash
92
+ - libffi :system_on_macos
93
+
83
94
  # Optional output override. The default for gembrew/example.yml is shown here.
84
95
  output: Formula/example.rb
85
96
 
@@ -90,6 +101,23 @@ test: |-
90
101
  # test_from_file: support/test.rb
91
102
  ```
92
103
 
104
+ Tag a dependency with `:system_on_macos` when macOS provides it and Homebrew
105
+ should install its formula only on other platforms.
106
+
107
+ To build the root gem from a GitHub tag while continuing to fetch its
108
+ dependencies from RubyGems, use:
109
+
110
+ ```yaml
111
+ source:
112
+ type: github
113
+ repo: owner/repository
114
+ # tag: v1.2.3
115
+ # gemspec: example.gemspec
116
+ ```
117
+
118
+ The tag defaults to `vVERSION`; the gemspec path defaults to
119
+ `GEMNAME.gemspec`.
120
+
93
121
  Gembrew resolves the generic Ruby dependency graph and generates a Homebrew
94
122
  `resource` for every runtime dependency. Original `.gem` archives are reused
95
123
  from RubyGems' local cache when available. Downloaded archives are retained in
@@ -109,6 +137,7 @@ brew style example
109
137
  brew audit --new --online example
110
138
  brew install --build-from-source example
111
139
  brew test example
140
+ brew linkage --test example
112
141
  ```
113
142
 
114
143
  To test a published tap without mounting the local repository, open a pristine
@@ -125,9 +154,10 @@ gembrew check
125
154
  ```
126
155
 
127
156
  This rebuilds every configured formula, then runs Homebrew style, online audit,
128
- source installation, and the formula test in disposable Homebrew containers.
129
- Use `gembrew check example` to check only one formula. Gembrew invokes Docker
130
- directly; the tap does not need generated container support files.
157
+ source installation, the formula test, and linkage validation in disposable
158
+ Homebrew containers. Use `gembrew check example` to check only one formula.
159
+ Gembrew invokes Docker directly; the tap does not need generated container
160
+ support files.
131
161
 
132
162
  ## Contributing / Support
133
163
 
@@ -4,9 +4,14 @@ require 'gembrew/error'
4
4
 
5
5
  module Gembrew
6
6
  class Config
7
+ Dependency = Data.define(:name, :tags) do
8
+ def system_on_macos? = tags.include? :system_on_macos
9
+ end
10
+
11
+ DEPENDENCY_TAGS = %w[:system_on_macos].freeze
7
12
  DIRECTORY = 'gembrew'
8
13
  ALLOWED_KEYS = %w[
9
- gem version output desc homepage license executable test test_from_file
14
+ gem version source output desc homepage license executable dependencies test test_from_file
10
15
  ].freeze
11
16
 
12
17
  attr_reader :path, :project_path
@@ -41,12 +46,21 @@ module Gembrew
41
46
  def name = path.basename('.yml').to_s
42
47
  def gem_name = data.fetch('gem').to_s
43
48
  def version = data['version']&.to_s
49
+ def source = data.fetch('source')
50
+ def source_type = source.fetch('type')
51
+ def source_repo = source['repo']
52
+ def source_tag = source['tag'] || "v#{version}"
53
+ def source_gemspec = source['gemspec'] || "#{gem_name}.gemspec"
44
54
  def output_path = (project_path/(data['output'] || "Formula/#{name}.rb")).expand_path
45
55
  def description = data['desc']
46
56
  def homepage = data['homepage']
47
57
  def license = data['license']
48
58
  def executable = data['executable']
49
59
 
60
+ def dependencies
61
+ @dependencies ||= data.fetch('dependencies', []).map { |value| parse_dependency value }
62
+ end
63
+
50
64
  def test_body
51
65
  @test_body ||= if data.has_key?('test')
52
66
  data.fetch('test').to_s
@@ -77,6 +91,10 @@ module Gembrew
77
91
  raise Error, "Unknown configuration keys: #{unknown_keys.join(', ')}" if unknown_keys.any?
78
92
 
79
93
  require_value 'gem'
94
+ require_value 'version'
95
+ require_value 'source'
96
+ validate_source
97
+ validate_dependencies
80
98
 
81
99
  return unless data.has_key?('test') == data.has_key?('test_from_file')
82
100
 
@@ -87,5 +105,69 @@ module Gembrew
87
105
  value = data[key]
88
106
  raise Error, "#{key} is required" if value.nil? || value.to_s.empty?
89
107
  end
108
+
109
+ def validate_source
110
+ raise Error, 'source must be a mapping' unless source.is_a?(Hash)
111
+
112
+ validate_source_keys
113
+ case source['type']&.to_s
114
+ when 'rubygems' then validate_rubygems_source
115
+ when 'github' then validate_github_source
116
+ else raise Error, 'source.type must be github or rubygems'
117
+ end
118
+ end
119
+
120
+ def validate_source_keys
121
+ unknown_keys = source.keys - %w[type repo tag gemspec]
122
+ raise Error, "Unknown source keys: #{unknown_keys.join(', ')}" if unknown_keys.any?
123
+ end
124
+
125
+ def validate_rubygems_source
126
+ extra_keys = source.keys - ['type']
127
+ raise Error, "source.#{extra_keys.first} is only valid for GitHub sources" if extra_keys.any?
128
+ end
129
+
130
+ def validate_github_source
131
+ repo = source['repo']&.to_s
132
+ raise Error, 'source.repo is required for GitHub sources' if repo.nil? || repo.empty?
133
+ raise Error, 'source.repo must be in owner/repository form' unless repo.match?(%r{\A[^/\s]+/[^/\s]+\z})
134
+
135
+ validate_relative_source_path 'gemspec' if source.has_key?('gemspec')
136
+ raise Error, 'source.tag must not be empty' if source.has_key?('tag') && source['tag'].to_s.empty?
137
+ end
138
+
139
+ def validate_relative_source_path(key)
140
+ value = source[key].to_s
141
+ path = Pathname(value)
142
+ valid = !value.empty? && !path.absolute? && path.each_filename.none?('..')
143
+ raise Error, "source.#{key} must be a relative path within the archive" unless valid
144
+ end
145
+
146
+ def validate_dependencies
147
+ return unless data.has_key?('dependencies')
148
+
149
+ raise Error, 'dependencies must be a sequence' unless data['dependencies'].is_a?(Array)
150
+
151
+ dependencies
152
+ names = dependencies.map(&:name)
153
+ duplicate = names.find { |name| names.count(name) > 1 }
154
+ raise Error, "dependency #{duplicate.inspect} is specified more than once" if duplicate
155
+ end
156
+
157
+ def parse_dependency(value)
158
+ raise Error, 'each dependency must be a name followed by optional tags' unless value.is_a?(String)
159
+
160
+ values = value.split
161
+ name = values.shift
162
+ unless name && !name.start_with?(':')
163
+ raise Error, 'dependency name must be a non-empty string'
164
+ end
165
+
166
+ invalid_tag = values.find { |tag| !tag.is_a?(String) || !DEPENDENCY_TAGS.include?(tag) }
167
+ raise Error, "unknown dependency tag: #{invalid_tag.inspect}" if invalid_tag
168
+ raise Error, "dependency #{name.inspect} has duplicate tags" unless values.uniq.length == values.length
169
+
170
+ Dependency.new(name:, tags: values.map { |tag| tag.delete_prefix(':').to_sym }.freeze)
171
+ end
90
172
  end
91
173
  end
@@ -32,6 +32,8 @@ module Gembrew
32
32
  brew install --build-from-source "$formula"
33
33
  caption "testing $formula"
34
34
  brew test "$formula"
35
+ caption "checking linkage for $formula"
36
+ brew linkage --test "$formula"
35
37
  BASH
36
38
  end
37
39
  end
@@ -11,7 +11,7 @@ module Gembrew
11
11
  end
12
12
 
13
13
  def call
14
- resolution = resolver.resolve(config.gem_name, config.version)
14
+ resolution = resolver.resolve(config.gem_name, config.version, source: config.source)
15
15
  output_path = config.output_path
16
16
  output_path.dirname.mkpath
17
17
  output_path.write renderer.render(formula_data(resolution))
@@ -35,14 +35,25 @@ module Gembrew
35
35
 
36
36
  def metadata(spec)
37
37
  {
38
- description: config.description || spec.summary,
39
- homepage: config.homepage || inferred_homepage(spec),
40
- license: config.license || spec.license || spec.licenses.first,
41
- executable: config.executable || spec.executables.first || spec.name,
42
- test_body: config.test_body,
38
+ description: config.description || spec.summary,
39
+ homepage: config.homepage || inferred_homepage(spec),
40
+ license: config.license || spec.license || spec.licenses.first,
41
+ executable: config.executable || spec.executables.first || spec.name,
42
+ source_type: config.source_type,
43
+ source_repo: config.source_repo,
44
+ source_tag: config.source_tag,
45
+ source_gemspec: config.source_gemspec,
46
+ dependencies: formula_dependencies,
47
+ test_body: config.test_body,
43
48
  }
44
49
  end
45
50
 
51
+ def formula_dependencies
52
+ ([Config::Dependency.new(name: 'ruby', tags: [])] + config.dependencies)
53
+ .uniq(&:name)
54
+ .sort_by(&:name)
55
+ end
56
+
46
57
  def formula_name(gem_name)
47
58
  gem_name.split(/[-_]/).map(&:capitalize).join
48
59
  end
@@ -0,0 +1,51 @@
1
+ require 'fileutils'
2
+ require 'open3'
3
+ require 'pathname'
4
+ require 'gembrew/error'
5
+ require 'gembrew/reporter'
6
+
7
+ module Gembrew
8
+ class GithubArchiveStore
9
+ def initialize(cache_path:, reporter: Reporter.new, command_runner: nil)
10
+ @cache_path = Pathname(cache_path)
11
+ @reporter = reporter
12
+ @command_runner = command_runner || method(:run_command)
13
+ @cache_path.mkpath
14
+ end
15
+
16
+ def fetch(repository, tag)
17
+ name = repository.tr '/', '-'
18
+ path = @cache_path/"#{name}-#{tag.tr '/', '-'}.tar.gz"
19
+ if path.file? && !path.empty?
20
+ reporter.archive :github_cache, repository, tag
21
+ return path
22
+ end
23
+
24
+ reporter.archive :downloading, repository, tag
25
+ url = "https://github.com/#{repository}/archive/refs/tags/#{tag}.tar.gz"
26
+ command_runner.call 'curl', '--fail', '--location', '--silent', '--show-error',
27
+ '--output', path.to_s, url, chdir: @cache_path
28
+ raise Error, "GitHub archive is empty: #{url}" unless path.file? && !path.empty?
29
+
30
+ path
31
+ end
32
+
33
+ def extract(archive, destination)
34
+ destination = Pathname(destination)
35
+ destination.mkpath
36
+ command_runner.call 'tar', '-xzf', archive.to_s, '-C', destination.to_s, chdir: destination
37
+ destination
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :reporter, :command_runner
43
+
44
+ def run_command(*command, chdir:)
45
+ result, status = Open3.capture2e(*command, chdir: chdir.to_s)
46
+ raise Error, result unless status.success?
47
+
48
+ result
49
+ end
50
+ end
51
+ end
@@ -20,6 +20,8 @@ module Gembrew
20
20
  formula_path.mkpath
21
21
  config_directory.mkpath
22
22
  readme_path.write render_readme unless readme_path.exist?
23
+ workflow_path.dirname.mkpath
24
+ workflow_path.write workflow_template.read unless workflow_path.exist?
23
25
  Adder.new(gem_name, project_path: project_path).call if gem_name
24
26
 
25
27
  project_path
@@ -39,6 +41,14 @@ module Gembrew
39
41
  project_path/'README.md'
40
42
  end
41
43
 
44
+ def workflow_path
45
+ project_path/'.github/workflows/test.yml'
46
+ end
47
+
48
+ def workflow_template
49
+ Pathname(__dir__)/'templates/test.yml'
50
+ end
51
+
42
52
  def entries
43
53
  @entries ||= project_path.children.reject { |path| path.basename.to_s == '.git' }
44
54
  end
@@ -7,6 +7,7 @@ module Gembrew
7
7
  LABELS = {
8
8
  rubygems_cache: ['g', 'RubyGems cache'],
9
9
  gembrew_cache: ['g', 'Gembrew cache'],
10
+ github_cache: ['g', 'GitHub cache'],
10
11
  downloading: %w[y Downloading],
11
12
  }.freeze
12
13
 
@@ -6,6 +6,7 @@ require 'rubygems/package'
6
6
  require 'tmpdir'
7
7
  require 'gembrew/archive_store'
8
8
  require 'gembrew/error'
9
+ require 'gembrew/github_archive_store'
9
10
  require 'gembrew/reporter'
10
11
 
11
12
  module Gembrew
@@ -15,21 +16,22 @@ module Gembrew
15
16
  class Resolver
16
17
  attr_reader :cache_root
17
18
 
18
- def initialize(cache_root: nil, reporter: Reporter.new, command_runner: nil, archive_store: nil)
19
+ def initialize(cache_root: nil, reporter: Reporter.new, command_runner: nil, archive_store: nil,
20
+ github_archive_store: nil)
19
21
  @cache_root = Pathname(cache_root || default_cache_root)
20
22
  @reporter = reporter
21
23
  @command_runner = command_runner || method(:run_command)
22
24
  @archive_store = archive_store || ArchiveStore.new(
23
25
  cache_path: @cache_root/'gems', reporter: reporter, command_runner: @command_runner
24
26
  )
27
+ @github_archive_store = github_archive_store
25
28
  temporary_root.mkpath
26
29
  end
27
30
 
28
- def resolve(name, version = nil)
31
+ def resolve(name, version, source:)
29
32
  Dir.mktmpdir('build-', temporary_root.to_s) do |directory|
30
33
  temporary = Pathname(directory)
31
- root_archive = archive_store.fetch(name, version, temporary)
32
- root_spec = Gem::Package.new(root_archive.to_s).spec
34
+ root_archive, root_spec = root_source name, version, source, temporary
33
35
  dependencies = dependency_specs(lock(root_spec, temporary), root_spec)
34
36
 
35
37
  reporter.collecting dependencies.length
@@ -45,6 +47,57 @@ module Gembrew
45
47
 
46
48
  attr_reader :reporter, :command_runner, :archive_store
47
49
 
50
+ def github_archive_store
51
+ @github_archive_store ||= GithubArchiveStore.new(
52
+ cache_path: cache_root/'github', reporter: reporter, command_runner: command_runner
53
+ )
54
+ end
55
+
56
+ def root_source(name, version, source_config, temporary)
57
+ return rubygems_root_source(name, version, temporary) if source_config.fetch('type') == 'rubygems'
58
+
59
+ github_root_source name, version, source_config, temporary
60
+ end
61
+
62
+ def rubygems_root_source(name, version, temporary)
63
+ archive = archive_store.fetch(name, version, temporary)
64
+ [archive, Gem::Package.new(archive.to_s).spec]
65
+ end
66
+
67
+ def github_root_source(name, version, source_config, temporary)
68
+ repository = source_config.fetch('repo')
69
+ tag = source_config['tag'] || "v#{version}"
70
+ gemspec_path = source_config['gemspec'] || "#{name}.gemspec"
71
+ archive = github_archive_store.fetch repository, tag
72
+ root = github_project_root archive, temporary
73
+ spec = load_github_spec root/gemspec_path, gemspec_path
74
+ validate_github_spec spec, name, version
75
+
76
+ [archive, spec]
77
+ end
78
+
79
+ def github_project_root(archive, temporary)
80
+ extracted = github_archive_store.extract archive, temporary/'source'
81
+ roots = extracted.children.select(&:directory?)
82
+ raise Error, 'Expected one project directory in the GitHub archive' unless roots.one?
83
+
84
+ roots.first
85
+ end
86
+
87
+ def load_github_spec(gemspec, gemspec_path)
88
+ raise Error, "Gemspec not found in GitHub archive: #{gemspec_path}" unless gemspec.file?
89
+
90
+ spec = Dir.chdir(gemspec.dirname) { Gem::Specification.load(gemspec.basename.to_s) }
91
+ raise Error, "Could not load gemspec from GitHub archive: #{gemspec_path}" unless spec
92
+
93
+ spec
94
+ end
95
+
96
+ def validate_github_spec(spec, name, version)
97
+ raise Error, "Gemspec name #{spec.name} does not match configured gem #{name}" unless spec.name == name
98
+ raise Error, "GitHub gemspec version #{spec.version} does not match #{version}" unless spec.version == Gem::Version.new(version)
99
+ end
100
+
48
101
  def resource(spec, temporary, index, total)
49
102
  archive = archive_store.fetch spec.name, spec.version, temporary, index: index, total: total
50
103
  Resource.new spec.name, spec.version.to_s, Digest::SHA256.file(archive).hexdigest
@@ -62,10 +115,11 @@ module Gembrew
62
115
  def lock(root_spec, temporary)
63
116
  gemfile = temporary/'Gemfile'
64
117
  lockfile = temporary/'Gemfile.lock'
65
- gemfile.write <<~RUBY
66
- source "https://rubygems.org"
67
- gem #{root_spec.name.inspect}, "= #{root_spec.version}"
68
- RUBY
118
+ dependencies = root_spec.runtime_dependencies.map do |dependency|
119
+ requirements = dependency.requirement.requirements.map { |operator, version| "#{operator} #{version}" }
120
+ "gem #{dependency.name.inspect}, #{requirements.map(&:inspect).join(', ')}"
121
+ end
122
+ gemfile.write([[%[source "https://rubygems.org"]], dependencies, ['']].flatten.join("\n"))
69
123
 
70
124
  reporter.resolving root_spec.name, root_spec.version
71
125
  command_runner.call(
@@ -1,16 +1,25 @@
1
- # Generated by Gembrew: https://github.com/dannyben/gembrew
2
- # Manual edits are not recommended. Update gembrew/*.yml and regenerate with:
3
- # gem install gembrew
4
- # gembrew build
5
-
6
1
  class <%= formula_name %> < Formula
7
2
  desc <%= description.inspect %>
8
3
  homepage <%= homepage.inspect %>
4
+ <% if source_type == 'github' -%>
5
+ url "https://github.com/<%= source_repo %>/archive/refs/tags/<%= source_tag %>.tar.gz"
6
+ <% else -%>
9
7
  url "https://rubygems.org/downloads/<%= gem_name %>-<%= version %>.gem"
8
+ <% end -%>
10
9
  sha256 "<%= sha256 %>"
11
10
  license <%= license.inspect %>
12
11
 
13
- depends_on "ruby"
12
+ <% formula_dependencies = dependencies.reject(&:system_on_macos?) -%>
13
+ <% macos_dependencies = dependencies.select(&:system_on_macos?) -%>
14
+ <% formula_dependencies.each do |dependency| -%>
15
+ depends_on <%= dependency.name.inspect %>
16
+ <% end -%>
17
+ <% if formula_dependencies.any? && macos_dependencies.any? -%>
18
+
19
+ <% end -%>
20
+ <% macos_dependencies.each do |dependency| -%>
21
+ uses_from_macos <%= dependency.name.inspect %>
22
+ <% end -%>
14
23
  <% resources.each do |resource| -%>
15
24
 
16
25
  resource <%= resource.name.inspect %> do
@@ -27,8 +36,17 @@ class <%= formula_name %> < Formula
27
36
  "--ignore-dependencies", "--install-dir", libexec, "--no-document"
28
37
  end
29
38
 
39
+ <% if source_type == 'github' -%>
40
+ system "gem", "build", "<%= source_gemspec %>"
41
+ system "gem", "install", "--ignore-dependencies", "<%= gem_name %>-#{version}.gem",
42
+ "--install-dir", libexec, "--no-document"
43
+ <% else -%>
30
44
  system "gem", "install", cached_download,
31
45
  "--ignore-dependencies", "--install-dir", libexec, "--no-document"
46
+ <% end -%>
47
+
48
+ rm libexec.glob("extensions/*/*/*/mkmf.log")
49
+ deuniversalize_machos if OS.mac?
32
50
 
33
51
  (bin/<%= executable.inspect %>).write_env_script libexec/"bin/<%= executable %>", GEM_HOME: ENV.fetch("GEM_HOME")
34
52
  end
@@ -1,14 +1,29 @@
1
1
  gem: <%= gem_name %>
2
+ version: "" # required
3
+
4
+ # Required source. Use the published RubyGem:
5
+ source:
6
+ type: rubygems
7
+
8
+ # Or replace the source above with a GitHub tag archive:
9
+ # source:
10
+ # type: github
11
+ # repo: owner/repository # required for GitHub
12
+ # tag: v1.2.3 # optional; defaults to vVERSION
13
+ # gemspec: <%= gem_name %>.gemspec # optional; defaults to GEMNAME.gemspec
2
14
 
3
15
  test: |-
4
16
  system bin/"<%= gem_name %>", "--version"
5
17
 
6
- # Optional overrides:
7
- # version: "1.2.3"
18
+ # Optional metadata and formula overrides:
8
19
  # desc: Example command-line application
9
20
  # homepage: https://example.com
10
21
  # license: MIT
11
22
  # executable: <%= gem_name %>
23
+ # output: Formula/<%= gem_name %>.rb
24
+ # dependencies:
25
+ # - bash
26
+ # - libffi :system_on_macos
12
27
 
13
28
  # To load the Homebrew test body from a Ruby file, replace `test` above with:
14
29
  # test_from_file: support/test.rb
@@ -0,0 +1,65 @@
1
+ name: Test Formulae
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - master
8
+ pull_request:
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ test:
16
+ name: ${{ matrix.os }}
17
+ runs-on: ${{ matrix.os }}
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ os:
22
+ - ubuntu-latest
23
+ - macos-latest
24
+
25
+ steps:
26
+ - name: Set up Homebrew
27
+ id: set-up-homebrew
28
+ uses: Homebrew/actions/setup-homebrew@fd832223f9f99ebf0244dd20658680e5d4aca049 # 2026.08.03.2
29
+
30
+ - name: Cache Homebrew Bundler gems
31
+ id: cache
32
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
33
+ with:
34
+ path: ${{ steps.set-up-homebrew.outputs.gems-path }}
35
+ key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
36
+ restore-keys: ${{ runner.os }}-rubygems-
37
+
38
+ - name: Install Homebrew Bundler gems
39
+ if: steps.cache.outputs.cache-hit != 'true'
40
+ run: brew install-bundler-gems
41
+
42
+ - name: Test formulae
43
+ shell: bash
44
+ env:
45
+ HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46
+ run: |
47
+ shopt -s nullglob
48
+ formulae=(Formula/*.rb)
49
+
50
+ if (( ${#formulae[@]} == 0 )); then
51
+ echo "No formulae found in Formula/"
52
+ exit 1
53
+ fi
54
+
55
+ for formula in "${formulae[@]}"; do
56
+ formula_name="${formula##*/}"
57
+ formula_name="${formula_name%.rb}"
58
+
59
+ brew style "$formula"
60
+ brew audit --new --online "$formula_name"
61
+ brew install --build-from-source "$formula_name"
62
+ brew test "$formula_name"
63
+ brew linkage --test "$formula_name"
64
+ brew uninstall "$formula_name"
65
+ done
@@ -1,3 +1,3 @@
1
1
  module Gembrew
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
data/lib/gembrew.rb CHANGED
@@ -6,6 +6,7 @@ require 'gembrew/docker_shell'
6
6
  require 'gembrew/docker_runner'
7
7
  require 'gembrew/error'
8
8
  require 'gembrew/generator'
9
+ require 'gembrew/github_archive_store'
9
10
  require 'gembrew/initializer'
10
11
  require 'gembrew/reporter'
11
12
  require 'gembrew/renderer'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gembrew
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
@@ -77,6 +77,7 @@ files:
77
77
  - lib/gembrew/docker_shell.rb
78
78
  - lib/gembrew/error.rb
79
79
  - lib/gembrew/generator.rb
80
+ - lib/gembrew/github_archive_store.rb
80
81
  - lib/gembrew/initializer.rb
81
82
  - lib/gembrew/renderer.rb
82
83
  - lib/gembrew/reporter.rb
@@ -84,6 +85,7 @@ files:
84
85
  - lib/gembrew/templates/README.md.erb
85
86
  - lib/gembrew/templates/formula.rb.erb
86
87
  - lib/gembrew/templates/gembrew.yml.erb
88
+ - lib/gembrew/templates/test.yml
87
89
  - lib/gembrew/version.rb
88
90
  homepage: https://github.com/DannyBen/gembrew
89
91
  licenses: