gembrew 0.1.0 → 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: 46aaf0e8b85829162de73512e6c9fe6c892a7dc646513a6cd6d6d9265c06124b
4
- data.tar.gz: 90de5846e5cc45f8e0458d0c0dcf6368ea4071595b152b72279cff91b4e349f1
3
+ metadata.gz: fe9b9cc5e9535cca862d2adf23aa7887bf0608fa14104d8aa7c3db046358ac61
4
+ data.tar.gz: 7242264cbf2fa6c438445dd180ec73fec06c37513a5d67889ac47dddb748985b
5
5
  SHA512:
6
- metadata.gz: 40a61361c893f96bc402ef4c4514236cb7ec4313386f3378e1dfcf026a4726a2fbfec786f6ccdd8120495d7c80adfe240f3b182e79d3890e5b2e6bfa2bff57ca
7
- data.tar.gz: edf9bd6364b9c2409b43d1777739b9591d02adaee91475b72203b64dbfdd5c75f566aab6d632aa1998318f745120ccfb5102ad7f937b6f9be323817521e575e4
6
+ metadata.gz: 412fd3b8bc7d1d92ae3358902eacb1e89d6d5a1c2eee5fbb21512b6ea549d1035e438d45855ee8091eda01b9f92f22603c8a089324e82485bafcb124afe4723c
7
+ data.tar.gz: 5fdb7789ec71ce6838cdc82973765441ada2a2c100b9b73ac121c1d3e8aaa77885477d61b578336e6a92b78fc72e6a3acb0bac3cea9be8a2937a8c7710302919
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Gembrew
2
2
 
3
+ ![repocard](https://repocard.dannyben.com/svg/gembrew.svg)
4
+
3
5
  Generate conventional Homebrew formulae for published Ruby command-line gems.
4
6
 
5
7
  ## Install
@@ -18,38 +20,65 @@ gembrew build
18
20
  gembrew check
19
21
  ```
20
22
 
21
- `init` requires an empty directory, with the exception of Git's `.git`
22
- directory. It creates a tap repository containing `gembrew.yml`, `Formula/`,
23
- and a Docker Compose environment under `support/`. `build` reads the
24
- configuration and writes the formula.
25
-
26
- The configuration filename is always `gembrew.yml`.
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.
27
30
 
28
31
  For example, `gembrew init example` generates:
29
32
 
33
+ ```text
34
+ README.md
35
+ .github/
36
+ workflows/
37
+ test.yml
38
+ gembrew/
39
+ example.yml
40
+ Formula/
41
+ ```
42
+
43
+ `gembrew/example.yml` contains:
44
+
30
45
  ```yaml
31
46
  gem: example
32
- output: Formula/example.rb
33
47
 
34
48
  test: |-
35
49
  system bin/"example", "--version"
36
50
  ```
37
51
 
38
- Edit `gembrew.yml` as needed, then generate the formula:
52
+ Edit the configuration as needed, then generate `Formula/example.rb`:
39
53
 
40
54
  ```shell
41
55
  gembrew build
42
56
  ```
43
57
 
44
- The required settings are `gem`, `output`, and exactly one of `test` or
45
- `test_from_file`. Relative paths are resolved from `gembrew.yml`.
58
+ Each YAML file under `gembrew/` describes one formula. Add more published gems
59
+ with:
60
+
61
+ ```shell
62
+ gembrew add another-gem
63
+ ```
64
+
65
+ Plain `build` generates every configured formula. Pass a configuration name to
66
+ generate just one:
67
+
68
+ ```shell
69
+ gembrew build example
70
+ ```
71
+
72
+ The required settings are `gem`, `version`, `source`, and exactly one of `test`
73
+ or `test_from_file`.
74
+ The output defaults to `Formula/NAME.rb`, where `NAME` is the configuration
75
+ filename. Relative paths are resolved from the tap root.
46
76
 
47
77
  ```yaml
48
78
  gem: example
49
- output: Formula/example.rb
50
-
51
- # Optional published gem version. The latest stable version is used by default.
52
79
  version: "1.2.3"
80
+ source:
81
+ type: rubygems
53
82
 
54
83
  # Optional gem metadata overrides:
55
84
  desc: Example command-line application
@@ -57,6 +86,14 @@ homepage: https://example.com
57
86
  license: MIT
58
87
  executable: example
59
88
 
89
+ # Optional additional Homebrew formula dependencies:
90
+ dependencies:
91
+ - bash
92
+ - libffi :system_on_macos
93
+
94
+ # Optional output override. The default for gembrew/example.yml is shown here.
95
+ output: Formula/example.rb
96
+
60
97
  test: |-
61
98
  system bin/"example", "--version"
62
99
 
@@ -64,6 +101,23 @@ test: |-
64
101
  # test_from_file: support/test.rb
65
102
  ```
66
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
+
67
121
  Gembrew resolves the generic Ruby dependency graph and generates a Homebrew
68
122
  `resource` for every runtime dependency. Original `.gem` archives are reused
69
123
  from RubyGems' local cache when available. Downloaded archives are retained in
@@ -83,6 +137,14 @@ brew style example
83
137
  brew audit --new --online example
84
138
  brew install --build-from-source example
85
139
  brew test example
140
+ brew linkage --test example
141
+ ```
142
+
143
+ To test a published tap without mounting the local repository, open a pristine
144
+ Homebrew shell:
145
+
146
+ ```shell
147
+ gembrew shell --pristine
86
148
  ```
87
149
 
88
150
  Run the complete workflow non-interactively in one clean container:
@@ -91,9 +153,11 @@ Run the complete workflow non-interactively in one clean container:
91
153
  gembrew check
92
154
  ```
93
155
 
94
- This rebuilds the formula, then runs Homebrew style, online audit, source
95
- installation, and the formula test. The generated Compose `check` service can
96
- also be invoked directly.
156
+ This rebuilds every configured formula, then runs Homebrew style, online audit,
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.
97
161
 
98
162
  ## Contributing / Support
99
163
 
data/bin/gembrew CHANGED
@@ -10,6 +10,8 @@ runner = Gembrew::CLI.runner
10
10
 
11
11
  begin
12
12
  exit runner.run ARGV
13
+ rescue Interrupt
14
+ exit 130
13
15
  rescue => e
14
16
  puts e.backtrace.reverse if ENV['DEBUG']
15
17
  say! "rib` #{e.class} `\n#{e.message}"
@@ -0,0 +1,39 @@
1
+ require 'erb'
2
+ require 'pathname'
3
+ require 'gembrew/config'
4
+ require 'gembrew/error'
5
+
6
+ module Gembrew
7
+ class Adder
8
+ attr_reader :gem_name, :project_path
9
+
10
+ def initialize(gem_name, project_path: Pathname.pwd)
11
+ @gem_name = gem_name
12
+ @project_path = Pathname(project_path).expand_path
13
+ end
14
+
15
+ def call
16
+ Config.validate_name! gem_name
17
+ unless formula_path.directory?
18
+ raise Error, "Directory is not a Homebrew tap: #{project_path} (Formula/ does not exist)"
19
+ end
20
+
21
+ config_directory.mkpath
22
+ raise Error, "Gem configuration already exists: #{config_path}" if config_path.exist?
23
+
24
+ config_path.write render
25
+ config_path
26
+ end
27
+
28
+ private
29
+
30
+ def formula_path = project_path/'Formula'
31
+ def config_directory = project_path/'gembrew'
32
+ def config_path = config_directory/"#{gem_name}.yml"
33
+
34
+ def render
35
+ template = Pathname(__dir__)/'templates/gembrew.yml.erb'
36
+ ERB.new(template.read, trim_mode: '-').result(binding)
37
+ end
38
+ end
39
+ end
data/lib/gembrew/cli.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'mister_bin'
2
2
  require 'gembrew/commands/build'
3
+ require 'gembrew/commands/add'
3
4
  require 'gembrew/commands/check'
4
5
  require 'gembrew/commands/init'
5
6
  require 'gembrew/commands/shell'
@@ -13,6 +14,7 @@ module Gembrew
13
14
  footer: 'Run m`gembrew COMMAND --help` for more information'
14
15
 
15
16
  runner.route 'init', to: Commands::Init
17
+ runner.route 'add', to: Commands::Add
16
18
  runner.route 'build', to: Commands::Build
17
19
  runner.route 'check', to: Commands::Check
18
20
  runner.route 'shell', to: Commands::Shell
@@ -0,0 +1,20 @@
1
+ require 'mister_bin'
2
+ require 'gembrew/adder'
3
+
4
+ module Gembrew
5
+ module Commands
6
+ class Add < MisterBin::Command
7
+ help 'Add a Ruby gem to this tap repository'
8
+
9
+ usage 'gembrew add GEM'
10
+ usage 'gembrew add (-h|--help)'
11
+
12
+ param 'GEM', 'Published Ruby gem name'
13
+
14
+ def run
15
+ path = Adder.new(args['GEM']).call
16
+ say "Added m`#{path}`"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -4,14 +4,25 @@ require 'gembrew/generator'
4
4
  module Gembrew
5
5
  module Commands
6
6
  class Build < MisterBin::Command
7
- help 'Generate a Homebrew formula from gembrew.yml'
7
+ help 'Generate Homebrew formulae from gembrew/*.yml'
8
8
 
9
- usage 'gembrew build'
9
+ usage 'gembrew build [GEM]'
10
10
  usage 'gembrew build (-h|--help)'
11
11
 
12
+ param 'GEM', 'Optional gem configuration name'
13
+
12
14
  def run
13
- output_path = Generator.new.call
14
- say "Generated m`#{output_path}`"
15
+ configs.each do |config|
16
+ say "bb`==> gembrew: building #{config.name}`"
17
+ output_path = Generator.new(config: config).call
18
+ say "Generated m`#{output_path}`"
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def configs
25
+ args['GEM'] ? [Config.find(args['GEM'])] : Config.all
15
26
  end
16
27
  end
17
28
  end
@@ -5,17 +5,28 @@ require 'gembrew/generator'
5
5
  module Gembrew
6
6
  module Commands
7
7
  class Check < MisterBin::Command
8
- help 'Build and test the formula in a clean Homebrew environment'
8
+ help 'Build and test formulae in clean Homebrew environments'
9
9
 
10
- usage 'gembrew check'
10
+ usage 'gembrew check [GEM]'
11
11
  usage 'gembrew check (-h|--help)'
12
12
 
13
+ param 'GEM', 'Optional gem configuration name'
14
+
13
15
  def run
14
- output_path = Generator.new.call
15
- say "Generated m`#{output_path}`"
16
- DockerCheck.new.call
16
+ configs.each do |config|
17
+ say "bb`==> gembrew: building #{config.name}`"
18
+ output_path = Generator.new(config: config).call
19
+ say "Generated m`#{output_path}`"
20
+ DockerCheck.new.call output_path.basename('.rb').to_s
21
+ end
17
22
  say 'g`All checks passed`'
18
23
  end
24
+
25
+ private
26
+
27
+ def configs
28
+ args['GEM'] ? [Config.find(args['GEM'])] : Config.all
29
+ end
19
30
  end
20
31
  end
21
32
  end
@@ -4,16 +4,18 @@ require 'gembrew/initializer'
4
4
  module Gembrew
5
5
  module Commands
6
6
  class Init < MisterBin::Command
7
- help 'Initialize a Homebrew tap repository for a Ruby gem'
7
+ help 'Initialize a Homebrew tap repository'
8
8
 
9
- usage 'gembrew init GEM'
9
+ usage 'gembrew init [GEM]'
10
10
  usage 'gembrew init (-h|--help)'
11
11
 
12
- param 'GEM', 'Published Ruby gem name'
12
+ param 'GEM', 'Optional published Ruby gem name'
13
13
 
14
14
  def run
15
15
  Initializer.new(args['GEM']).call
16
- say "Initialized m`#{Dir.pwd}` for bb`#{args['GEM']}`"
16
+ message = "Initialized m`#{Dir.pwd}`"
17
+ message += " for bb`#{args['GEM']}`" if args['GEM']
18
+ say message
17
19
  end
18
20
  end
19
21
  end
@@ -6,11 +6,13 @@ module Gembrew
6
6
  class Shell < MisterBin::Command
7
7
  help 'Open a Homebrew shell for this tap repository'
8
8
 
9
- usage 'gembrew shell'
9
+ usage 'gembrew shell [--pristine]'
10
10
  usage 'gembrew shell (-h|--help)'
11
11
 
12
+ option '-p --pristine', 'Open without mounting the local tap'
13
+
12
14
  def run
13
- DockerShell.new.call
15
+ DockerShell.new.call pristine: args['--pristine']
14
16
  end
15
17
  end
16
18
  end
@@ -4,32 +4,68 @@ require 'gembrew/error'
4
4
 
5
5
  module Gembrew
6
6
  class Config
7
- FILENAME = 'gembrew.yml'
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
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
- attr_reader :path
17
+ attr_reader :path, :project_path
18
+
19
+ def self.all(project_path = Pathname.pwd)
20
+ project_path = Pathname(project_path).expand_path
21
+ paths = (project_path/DIRECTORY).glob('*.yml').sort
22
+ raise Error, "No gem configurations found in #{project_path/DIRECTORY}" if paths.empty?
23
+
24
+ paths.map { |path| new path, project_path: project_path }
25
+ end
26
+
27
+ def self.find(name, project_path = Pathname.pwd)
28
+ validate_name! name
29
+ project_path = Pathname(project_path).expand_path
30
+ new project_path/DIRECTORY/"#{name}.yml", project_path: project_path
31
+ end
32
+
33
+ def self.validate_name!(name)
34
+ return name if name&.match?(/\A[a-zA-Z0-9._-]+\z/)
35
+
36
+ raise Error, "Invalid gem name: #{name.inspect}"
37
+ end
13
38
 
14
- def initialize(project_path = Pathname.pwd)
15
- @path = Pathname(project_path).expand_path/FILENAME
39
+ def initialize(path, project_path: nil)
40
+ @path = Pathname(path).expand_path
41
+ @project_path = project_path ? Pathname(project_path).expand_path : @path.dirname.parent
16
42
  @data = load_data
17
43
  validate
18
44
  end
19
45
 
46
+ def name = path.basename('.yml').to_s
20
47
  def gem_name = data.fetch('gem').to_s
21
48
  def version = data['version']&.to_s
22
- def output_path = (path.dirname/data.fetch('output')).expand_path
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"
54
+ def output_path = (project_path/(data['output'] || "Formula/#{name}.rb")).expand_path
23
55
  def description = data['desc']
24
56
  def homepage = data['homepage']
25
57
  def license = data['license']
26
58
  def executable = data['executable']
27
59
 
60
+ def dependencies
61
+ @dependencies ||= data.fetch('dependencies', []).map { |value| parse_dependency value }
62
+ end
63
+
28
64
  def test_body
29
65
  @test_body ||= if data.has_key?('test')
30
66
  data.fetch('test').to_s
31
67
  else
32
- test_path = path.dirname/data.fetch('test_from_file')
68
+ test_path = project_path/data.fetch('test_from_file')
33
69
  raise Error, "Test file does not exist: #{test_path}" unless test_path.file?
34
70
 
35
71
  test_path.read
@@ -55,7 +91,10 @@ module Gembrew
55
91
  raise Error, "Unknown configuration keys: #{unknown_keys.join(', ')}" if unknown_keys.any?
56
92
 
57
93
  require_value 'gem'
58
- require_value 'output'
94
+ require_value 'version'
95
+ require_value 'source'
96
+ validate_source
97
+ validate_dependencies
59
98
 
60
99
  return unless data.has_key?('test') == data.has_key?('test_from_file')
61
100
 
@@ -66,5 +105,69 @@ module Gembrew
66
105
  value = data[key]
67
106
  raise Error, "#{key} is required" if value.nil? || value.to_s.empty?
68
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
69
172
  end
70
173
  end
@@ -1,25 +1,15 @@
1
- require 'pathname'
1
+ require 'shellwords'
2
+ require 'gembrew/docker_runner'
2
3
  require 'gembrew/error'
3
4
 
4
5
  module Gembrew
5
6
  class DockerCheck
6
- COMPOSE_PATH = Pathname('support/compose.yaml')
7
-
8
- attr_reader :project_path
9
-
10
- def initialize(project_path: Pathname.pwd, command_runner: nil)
11
- @project_path = Pathname(project_path).expand_path
12
- @command_runner = command_runner || method(:run_command)
7
+ def initialize(runner: DockerRunner.new)
8
+ @runner = runner
13
9
  end
14
10
 
15
- def call
16
- raise Error, "Compose file does not exist: #{compose_path}" unless compose_path.file?
17
-
18
- success = command_runner.call(
19
- 'docker', 'compose', '-f', COMPOSE_PATH.to_s,
20
- 'run', '--rm', '--no-TTY', 'check',
21
- chdir: project_path
22
- )
11
+ def call(formula)
12
+ success = runner.call 'bash', '-euc', script(formula)
23
13
  raise Error, 'Homebrew checks failed' unless success
24
14
 
25
15
  true
@@ -27,14 +17,24 @@ module Gembrew
27
17
 
28
18
  private
29
19
 
30
- attr_reader :command_runner
31
-
32
- def compose_path
33
- project_path/COMPOSE_PATH
34
- end
35
-
36
- def run_command(*command, chdir:)
37
- system(*command, chdir: chdir.to_s)
20
+ attr_reader :runner
21
+
22
+ def script(formula)
23
+ formula = Shellwords.escape formula
24
+ <<~BASH
25
+ caption() { printf '\\n\\033[1;34m==> gembrew: %s\\033[0m\\n' "$1"; }
26
+ formula=#{formula}
27
+ caption "styling $formula"
28
+ brew style "$formula"
29
+ caption "auditing $formula"
30
+ brew audit --new --online "$formula"
31
+ caption "installing $formula"
32
+ brew install --build-from-source "$formula"
33
+ caption "testing $formula"
34
+ brew test "$formula"
35
+ caption "checking linkage for $formula"
36
+ brew linkage --test "$formula"
37
+ BASH
38
38
  end
39
39
  end
40
40
  end
@@ -0,0 +1,67 @@
1
+ require 'pathname'
2
+
3
+ module Gembrew
4
+ class DockerRunner
5
+ IMAGE = 'homebrew/brew:main'
6
+ TAP_PATH = '/home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/gembrew/homebrew-tap'
7
+
8
+ attr_reader :project_path
9
+
10
+ def initialize(project_path: Pathname.pwd, command_runner: nil)
11
+ @project_path = Pathname(project_path).expand_path
12
+ @command_runner = command_runner || method(:run_command)
13
+ end
14
+
15
+ def call(*command, interactive: false, pristine: false)
16
+ docker_command = ['docker', 'run', '--rm', '--init', '--name', container_name]
17
+ docker_command << '-it' if interactive
18
+ docker_command.concat environment(interactive: interactive, pristine: pristine)
19
+ unless pristine
20
+ docker_command.push '--workdir', '/work'
21
+ docker_command.push '--volume', "#{project_path}:/work"
22
+ docker_command.push '--volume', "#{project_path}:#{TAP_PATH}"
23
+ end
24
+ docker_command << IMAGE
25
+ docker_command.concat command
26
+ command_runner.call(*docker_command, chdir: project_path)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :command_runner
32
+
33
+ def environment(interactive:, pristine:)
34
+ result = %w[
35
+ --env HOMEBREW_NO_AUTO_UPDATE=1
36
+ --env HOMEBREW_NO_INSTALL_CLEANUP=1
37
+ --env HOMEBREW_NO_INSTALL_FROM_API=1
38
+ ]
39
+ prompt = pristine ? 'homebrew' : 'gembrew'
40
+ result.push '--env', "PS1=\\n\\n#{prompt} $ " if interactive
41
+ result
42
+ end
43
+
44
+ def run_command(*command, chdir:)
45
+ success = system(*command, chdir: chdir.to_s)
46
+ cleanup_container command unless success
47
+ success
48
+ rescue Interrupt
49
+ previous_handler = Signal.trap 'INT', 'IGNORE'
50
+ begin
51
+ cleanup_container command
52
+ ensure
53
+ Signal.trap 'INT', previous_handler
54
+ end
55
+ raise
56
+ end
57
+
58
+ def container_name
59
+ "gembrew-#{Process.pid}"
60
+ end
61
+
62
+ def cleanup_container(command)
63
+ name = command.fetch(command.index('--name') + 1)
64
+ system 'docker', 'rm', '--force', name, out: File::NULL, err: File::NULL
65
+ end
66
+ end
67
+ end
@@ -1,24 +1,14 @@
1
- require 'pathname'
1
+ require 'gembrew/docker_runner'
2
2
  require 'gembrew/error'
3
3
 
4
4
  module Gembrew
5
5
  class DockerShell
6
- COMPOSE_PATH = Pathname('support/compose.yaml')
7
-
8
- attr_reader :project_path
9
-
10
- def initialize(project_path: Pathname.pwd, command_runner: nil)
11
- @project_path = Pathname(project_path).expand_path
12
- @command_runner = command_runner || method(:run_command)
6
+ def initialize(runner: DockerRunner.new)
7
+ @runner = runner
13
8
  end
14
9
 
15
- def call
16
- raise Error, "Compose file does not exist: #{compose_path}" unless compose_path.file?
17
-
18
- success = command_runner.call(
19
- 'docker', 'compose', '-f', COMPOSE_PATH.to_s, 'run', '--rm', 'brew',
20
- chdir: project_path
21
- )
10
+ def call(pristine: false)
11
+ success = runner.call 'bash', '--norc', interactive: true, pristine: pristine
22
12
  raise Error, 'Homebrew shell exited with an error' unless success
23
13
 
24
14
  true
@@ -26,14 +16,6 @@ module Gembrew
26
16
 
27
17
  private
28
18
 
29
- attr_reader :command_runner
30
-
31
- def compose_path
32
- project_path/COMPOSE_PATH
33
- end
34
-
35
- def run_command(*command, chdir:)
36
- system(*command, chdir: chdir.to_s)
37
- end
19
+ attr_reader :runner
38
20
  end
39
21
  end
@@ -4,14 +4,14 @@ require 'gembrew/resolver'
4
4
 
5
5
  module Gembrew
6
6
  class Generator
7
- def initialize(config: Config.new, resolver: Resolver.new, renderer: Renderer.new)
7
+ def initialize(config:, resolver: Resolver.new, renderer: Renderer.new)
8
8
  @config = config
9
9
  @resolver = resolver
10
10
  @renderer = renderer
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
@@ -1,63 +1,67 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
3
  require 'pathname'
4
+ require 'gembrew/adder'
4
5
  require 'gembrew/error'
5
6
 
6
7
  module Gembrew
7
8
  class Initializer
8
- CONFIG_FILENAME = 'gembrew.yml'
9
-
10
9
  attr_reader :gem_name, :project_path
11
10
 
12
- def initialize(gem_name, project_path: Pathname.pwd)
11
+ def initialize(gem_name = nil, project_path: Pathname.pwd)
13
12
  @gem_name = gem_name
14
13
  @project_path = Pathname(project_path).expand_path
15
14
  end
16
15
 
17
16
  def call
18
- raise Error, "Directory is not empty: #{project_path} (found: #{entry_names.join(', ')})" if entries.any?
17
+ Config.validate_name! gem_name if gem_name
18
+ validate_project
19
19
 
20
20
  formula_path.mkpath
21
- support_path.mkpath
22
- config_path.write render
23
- compose_path.write render('compose.yaml.erb')
21
+ config_directory.mkpath
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?
25
+ Adder.new(gem_name, project_path: project_path).call if gem_name
24
26
 
25
27
  project_path
26
28
  end
27
29
 
28
30
  private
29
31
 
30
- def config_path
31
- project_path/CONFIG_FILENAME
32
+ def formula_path
33
+ project_path/'Formula'
32
34
  end
33
35
 
34
- def compose_path
35
- support_path/'compose.yaml'
36
+ def config_directory
37
+ project_path/'gembrew'
36
38
  end
37
39
 
38
- def formula_path
39
- project_path/'Formula'
40
+ def readme_path
41
+ project_path/'README.md'
40
42
  end
41
43
 
42
- def support_path
43
- project_path/'support'
44
+ def workflow_path
45
+ project_path/'.github/workflows/test.yml'
46
+ end
47
+
48
+ def workflow_template
49
+ Pathname(__dir__)/'templates/test.yml'
44
50
  end
45
51
 
46
52
  def entries
47
53
  @entries ||= project_path.children.reject { |path| path.basename.to_s == '.git' }
48
54
  end
49
55
 
50
- def entry_names
51
- entries.map { |path| path.basename.to_s }.sort
52
- end
56
+ def validate_project
57
+ return if entries.empty? || formula_path.directory?
53
58
 
54
- def render(filename = 'gembrew.yml.erb')
55
- template = asset_path filename
56
- ERB.new(template.read, trim_mode: '-').result(binding)
59
+ raise Error, "Directory is not a Homebrew tap: #{project_path} (Formula/ does not exist)"
57
60
  end
58
61
 
59
- def asset_path(filename)
60
- Pathname(__dir__)/'templates'/filename
62
+ def render_readme
63
+ template = Pathname(__dir__)/'templates/README.md.erb'
64
+ ERB.new(template.read, trim_mode: '-').result(binding)
61
65
  end
62
66
  end
63
67
  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(
@@ -0,0 +1,55 @@
1
+ # Homebrew Tap
2
+
3
+ <!-- Replace OWNER/TAP with your Homebrew tap name, for example dannyben/tools. -->
4
+
5
+ ## Install
6
+
7
+ ```shell
8
+ brew tap OWNER/TAP
9
+ brew install <%= gem_name || 'FORMULA' %>
10
+ ```
11
+
12
+ Or install the formula directly:
13
+
14
+ ```shell
15
+ brew install OWNER/TAP/<%= gem_name || 'FORMULA' %>
16
+ ```
17
+
18
+ ## Development
19
+
20
+ Install [Gembrew](https://github.com/DannyBen/gembrew):
21
+
22
+ ```shell
23
+ gem install gembrew
24
+ ```
25
+
26
+ Generate all formulae:
27
+
28
+ ```shell
29
+ gembrew build
30
+ ```
31
+
32
+ Generate or check one formula:
33
+
34
+ ```shell
35
+ gembrew build <%= gem_name || 'FORMULA' %>
36
+ gembrew check <%= gem_name || 'FORMULA' %>
37
+ ```
38
+
39
+ Check every formula:
40
+
41
+ ```shell
42
+ gembrew check
43
+ ```
44
+
45
+ Add another Ruby gem:
46
+
47
+ ```shell
48
+ gembrew add another-gem
49
+ ```
50
+
51
+ Open an interactive Homebrew environment:
52
+
53
+ ```shell
54
+ gembrew shell
55
+ ```
@@ -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,15 +1,29 @@
1
1
  gem: <%= gem_name %>
2
- output: Formula/<%= gem_name %>.rb
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
3
14
 
4
15
  test: |-
5
16
  system bin/"<%= gem_name %>", "--version"
6
17
 
7
- # Optional overrides:
8
- # version: "1.2.3"
18
+ # Optional metadata and formula overrides:
9
19
  # desc: Example command-line application
10
20
  # homepage: https://example.com
11
21
  # license: MIT
12
22
  # executable: <%= gem_name %>
23
+ # output: Formula/<%= gem_name %>.rb
24
+ # dependencies:
25
+ # - bash
26
+ # - libffi :system_on_macos
13
27
 
14
28
  # To load the Homebrew test body from a Ruby file, replace `test` above with:
15
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.0'
2
+ VERSION = '0.1.2'
3
3
  end
data/lib/gembrew.rb CHANGED
@@ -1,9 +1,12 @@
1
1
  require 'gembrew/archive_store'
2
+ require 'gembrew/adder'
2
3
  require 'gembrew/config'
3
4
  require 'gembrew/docker_check'
4
5
  require 'gembrew/docker_shell'
6
+ require 'gembrew/docker_runner'
5
7
  require 'gembrew/error'
6
8
  require 'gembrew/generator'
9
+ require 'gembrew/github_archive_store'
7
10
  require 'gembrew/initializer'
8
11
  require 'gembrew/reporter'
9
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.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
@@ -63,24 +63,29 @@ files:
63
63
  - README.md
64
64
  - bin/gembrew
65
65
  - lib/gembrew.rb
66
+ - lib/gembrew/adder.rb
66
67
  - lib/gembrew/archive_store.rb
67
68
  - lib/gembrew/cli.rb
69
+ - lib/gembrew/commands/add.rb
68
70
  - lib/gembrew/commands/build.rb
69
71
  - lib/gembrew/commands/check.rb
70
72
  - lib/gembrew/commands/init.rb
71
73
  - lib/gembrew/commands/shell.rb
72
74
  - lib/gembrew/config.rb
73
75
  - lib/gembrew/docker_check.rb
76
+ - lib/gembrew/docker_runner.rb
74
77
  - lib/gembrew/docker_shell.rb
75
78
  - lib/gembrew/error.rb
76
79
  - lib/gembrew/generator.rb
80
+ - lib/gembrew/github_archive_store.rb
77
81
  - lib/gembrew/initializer.rb
78
82
  - lib/gembrew/renderer.rb
79
83
  - lib/gembrew/reporter.rb
80
84
  - lib/gembrew/resolver.rb
81
- - lib/gembrew/templates/compose.yaml.erb
85
+ - lib/gembrew/templates/README.md.erb
82
86
  - lib/gembrew/templates/formula.rb.erb
83
87
  - lib/gembrew/templates/gembrew.yml.erb
88
+ - lib/gembrew/templates/test.yml
84
89
  - lib/gembrew/version.rb
85
90
  homepage: https://github.com/DannyBen/gembrew
86
91
  licenses:
@@ -1,29 +0,0 @@
1
- services:
2
- brew: &base
3
- image: homebrew/brew:main
4
- working_dir: /work
5
- environment:
6
- HOMEBREW_NO_AUTO_UPDATE: "1"
7
- HOMEBREW_NO_INSTALL_CLEANUP: "1"
8
- HOMEBREW_NO_INSTALL_FROM_API: "1"
9
- GEMBREW_GEM: <%= gem_name %>
10
- PS1: "\n\nbrew $ "
11
- volumes:
12
- - ..:/work
13
- - ..:/home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/gembrew/homebrew-tap
14
- command: ["bash", "--norc"]
15
- stdin_open: true
16
- tty: true
17
-
18
- check:
19
- <<: *base
20
- command:
21
- - bash
22
- - -euc
23
- - |
24
- brew style "$${GEMBREW_GEM}"
25
- brew audit --new --online "$${GEMBREW_GEM}"
26
- brew install --build-from-source "$${GEMBREW_GEM}"
27
- brew test "$${GEMBREW_GEM}"
28
- stdin_open: false
29
- tty: false