tetra 2.0.9 → 2.0.10

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: 5db5ea75f9c82a90663fa954a76755a89c747ba0650dbc61a871ed2efebaf5cd
4
- data.tar.gz: 8c1489dbf9d42d1ababad948ccc4d7a87973d5036045b6e8836011c178f8a74c
3
+ metadata.gz: 44bc9f5ff042bf65fddacc23815cc68ec600a00ea27434b44af4bd548f459296
4
+ data.tar.gz: c1fcab0d1c9495ae6bba7fd22031627dbedfe0aa21a1837dc054ad2b9ec478dc
5
5
  SHA512:
6
- metadata.gz: bbf33e5dd0da6aafcfc838827c2e254df11c7cee95851884440d41a9dd288a5d503ccb355d2158cad80dc0886a00a0846bea80958e9fc6cdc68a07ee7531efb2
7
- data.tar.gz: aba9f7940b23a830be803f723f381461b4bca72515c5800b2eabc2e9797ff9af423c47dd55accb60361761fad65fd1505d220b2db685baa466880511fa2cf71f
6
+ metadata.gz: 67088cf14db8bd5ce2b488feb99878f142eed9630e66afce9cbaf8e19f706fbfe978f5fdfd9ed24a187b226d1649b86a015ded57926464cc22bb17625d3d8a9e
7
+ data.tar.gz: e7c38c4d2cd8182e9b9f9c0d35598b52f1a2a92cb1dec35c3fcb1bc79573acd5aa13aff220c0611768bf341cd51a2ce1e697cf3717ffb72c833758bda3d3ca50
data/CONTRIBUTING.md CHANGED
@@ -4,9 +4,8 @@
4
4
 
5
5
  To develop tetra, you will need:
6
6
 
7
- * to install Bundler and Ruby development headers. On SUSE distros, use
8
- `sudo zypper install ruby3.4-rubygem-bundler ruby3.4-devel`;
9
- * to get development dependencies: `bundle install`;
7
+ * to install Bundler and Ruby development headers.
8
+ * to get development dependencies: `bundle install`.
10
9
 
11
10
  To install a development version of tetra use:
12
11
 
@@ -14,20 +13,51 @@ To install a development version of tetra use:
14
13
  sudo rake install
15
14
  ```
16
15
 
17
- To run tests, simply run `rake` or `bundle exec rake`. Please note that tests are divided into fine
18
- (more similar to unit tests) and coarse (more similar to integration tests).
16
+ ## Tests
17
+
18
+ To run tests, simply run `rake` or `bundle exec rake` which runs the full set of tests.
19
+
20
+ > [!NOTE]
21
+ > Tests are divided into fine (more similar to unit tests) and coarse (more similar to integration tests).
22
+
23
+ ```bash
24
+ # only run fine tests
25
+ bundle exec rspec spec/lib/fine/*
26
+
27
+ # only run coarse tests
28
+ bundle exec rspec spec/lib/coarse/*
29
+
30
+ # run all coarse tests with and show example names
31
+ bundle exec rspec spec/lib/coarse/* --format documentation
32
+
33
+ # only run selected tests
34
+ bundle exec rspec spec/lib/coarse/version_spec.rb
35
+ ```
19
36
 
20
37
  ## Coding style
21
38
 
22
39
  We use RuboCop to enforce a certain coding style for Ruby. With every Pull request and push, RuboCop checks the coding
23
- style and reports any errors.
40
+ style and reports any errors. You can do this locally by simple executing `rubocop` if you have RuboCop installed. For
41
+ the exact RuboCop version used, take a look at `tetra.gemspec`.
24
42
 
25
43
  ## New features
26
44
 
27
45
  In case you want to add new features, please be aware to also add the necessary fine grained or coarse grained tests
28
46
  for it.
29
47
 
30
- ## Release
48
+ ## Maintainers
49
+
50
+ ### Release
51
+
52
+ This is an example for the version number 2.0.9.
31
53
 
32
- Install gem-release: `gem install gem-release`
33
- Bump a patch version: `gem bump -v patch -p -t -r`
54
+ 1. Install release helper gem `gem install gem-release`
55
+ 1. Bump the version in `lib/tetra/version.rb`
56
+ 1. Regenerate `Gemfile.lock` with `bundle install`
57
+ 1. Build the gem with `gem build tetra.gemspec`
58
+ 1. Run the local tests with `rake`
59
+ 1. Add both files and commit them
60
+ 1. Tag new version: `git tag -am "tag v2.0.9" v2.0.9`
61
+ 1. Push to master: `git push upstream` and `git push --tags upstream`
62
+ 1. (Optional: Take a look at the GitHub Action tests)
63
+ 1. Release the gem on [rubygems.org](https://rubygems.org): `gem release --pretend` and `gem release`
data/README.md CHANGED
@@ -1,7 +1,10 @@
1
- [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/6678/badge)](https://www.bestpractices.dev/projects/6678)
2
- [![Tests](https://github.com/uyuni-project/tetra/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/uyuni-project/tetra/actions/workflows/test.yml)
1
+ [![Fine tests](https://github.com/uyuni-project/tetra/actions/workflows/test_fine.yml/badge.svg)](https://github.com/uyuni-project/tetra/actions/workflows/test_fine.yml)
2
+ [![Coarse tests](https://github.com/uyuni-project/tetra/actions/workflows/test_coarse.yml/badge.svg)](https://github.com/uyuni-project/tetra/actions/workflows/test_coarse.yml)
3
+ [![RuboCop](https://github.com/uyuni-project/tetra/actions/workflows/rubocop.yml/badge.svg)](https://github.com/uyuni-project/tetra/actions/workflows/rubocop.yml)
3
4
  [![codecov](https://codecov.io/github/uyuni-project/tetra/branch/master/graph/badge.svg?token=iLBGZqGXwa)](https://codecov.io/github/uyuni-project/tetra)
4
5
  [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=uyuni-project_tetra&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=uyuni-project_tetra)
6
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/6678/badge)](https://www.bestpractices.dev/projects/6678)
7
+ [![OpenSSF Baseline](https://www.bestpractices.dev/projects/6678/baseline)](https://www.bestpractices.dev/projects/6678)
5
8
 
6
9
  # tetra – builds RPMs for Java software
7
10
 
@@ -14,7 +17,7 @@ See [MOTIVATION.md](MOTIVATION.md) for further information.
14
17
 
15
18
  ## Prerequisites
16
19
 
17
- - [Ruby 3.2](https://www.ruby-lang.org) or later;
20
+ - [Ruby 3.4](https://www.ruby-lang.org) or later;
18
21
  - [git](https://git-scm.com) with your credentials set in `~/.gitconfig` (name and email);
19
22
  - some basic Unix commands: `bash`, `unzip`, `tar`;
20
23
  - a JDK > 8 that can compile whatever software you need to package;
data/bin/tetra CHANGED
@@ -6,9 +6,7 @@
6
6
  # Copyright 2015 Silvio Moioli <moio@suse.de>
7
7
 
8
8
  # Add lib/ to load path if running from a git clone (dev mode)
9
- if File.exist?(File.join(__dir__, "..", ".git"))
10
- $LOAD_PATH.unshift(File.join(__dir__, "..", "lib"))
11
- end
9
+ $LOAD_PATH.unshift(File.join(__dir__, "..", "lib")) if File.exist?(File.join(__dir__, "..", ".git"))
12
10
 
13
11
  begin
14
12
  require "tetra"
@@ -2,7 +2,7 @@
2
2
 
3
3
  # base module for tetra
4
4
  module Tetra
5
- CCOLLECTIONS = "commons-collections4-4.5.0-M2-src".freeze
5
+ CCOLLECTIONS = "commons-collections4-4.5.0-M2-src"
6
6
  CHUNK_SEPARATOR_VERSION_MATCHER = /[.\-_ ~,]/ # Constant regex for splitting version chunks
7
7
  LICENSE_MAP_PATH = File.join(__dir__, "data", "license_map.yml").freeze
8
8
  LICENSE_MAPPINGS = {
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Tetra
3
4
  # encapsulates tetra-specific Ant commandline options
4
5
  class Ant
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Tetra
3
4
  # runs Bash with tetra-specific options
4
5
  class Bash
@@ -44,7 +45,7 @@ module Tetra
44
45
  # The 'bash -c' flag normally takes a single string, so we must be careful.
45
46
  # Ideally, passing it as a single array element ["bash", ..., "-c", command]
46
47
  # is handled safely by ProcessRunner if it uses exec/system/spawn.
47
- run(["bash", "--rcfile", bashrc_file.path, "-i", "-c", command])
48
+ run(["bash", "--rcfile", bashrc_file.path, "-i", "-c", command], echo: false, stdin_data: nil)
48
49
  [command]
49
50
  else
50
51
  # Interactive mode
@@ -17,11 +17,9 @@ module Tetra
17
17
  # inits a repo
18
18
  def init
19
19
  Dir.chdir(@directory) do
20
- if Dir.exist?(".git")
21
- fail GitAlreadyInitedError
22
- else
23
- git_cmd("init")
24
- end
20
+ raise GitAlreadyInitedError if Dir.exist?(".git")
21
+
22
+ git_cmd("init")
25
23
  end
26
24
  end
27
25
 
@@ -127,14 +125,12 @@ module Tetra
127
125
  "-L", "previously generated",
128
126
  "-L", "user edited")
129
127
  rescue ExecutionFailed => e
130
- if e.status > 0
131
- conflict_count = e.status
132
- else
133
- raise e
134
- end
128
+ raise e unless e.status.positive?
129
+
130
+ conflict_count = e.status
135
131
  ensure
136
132
  # Clean up the temporary file
137
- File.delete(temp_old_version) if File.exist?(temp_old_version)
133
+ FileUtils.rm_f(temp_old_version)
138
134
  end
139
135
  conflict_count
140
136
  end
@@ -167,12 +163,12 @@ module Tetra
167
163
  # This streams stdout from git directly to stdin of xz without loading
168
164
  # data into Ruby memory (which could be big).
169
165
  git_command = ["git", "archive", "--format=tar", id, "--", directory]
170
- xz_command = ["xz", "-9e"]
166
+ xz_command = ["xz", "-6", "-T0"]
171
167
 
172
168
  statuses = Open3.pipeline(git_command, xz_command, out: destination_path)
173
169
 
174
170
  unless statuses.all?(&:success?)
175
- fail ExecutionFailed.new(
171
+ raise ExecutionFailed.new(
176
172
  "git archive pipeline failed (exit codes: #{statuses.map(&:exitstatus)})",
177
173
  statuses.last.exitstatus
178
174
  )
@@ -193,11 +189,11 @@ module Tetra
193
189
 
194
190
  # Automatically passes "git" as the first argument in an Array.
195
191
  def git_cmd(*args)
196
- run(["git"] + args)
192
+ run(["git"] + args, echo: false, stdin_data: nil)
197
193
  end
198
194
 
199
195
  def git_cmd_with_stdin(stdin_data, *args)
200
- run(["git"] + args, false, stdin_data)
196
+ run(["git"] + args, echo: false, stdin_data: stdin_data)
201
197
  end
202
198
  end
203
199
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Tetra
3
4
  # encapsulates tetra-specific Maven commandline options
4
5
  class Mvn
@@ -19,7 +20,7 @@ module Tetra
19
20
  "--strict-checksums"
20
21
  ]
21
22
 
22
- "#{executable} #{options.join(' ')}"
23
+ "#{executable} #{options.join(" ")}"
23
24
  end
24
25
  end
25
26
  end
@@ -8,64 +8,21 @@ module Tetra
8
8
  # runs a noninteractive executable and returns its output as a string
9
9
  # raises ExecutionFailed if the exit status is not 0
10
10
  # optionally echoes the executable's output/error to standard output/error
11
- def run(commandline, echo = false, stdin_data = nil)
11
+ def run(commandline, echo: false, stdin_data: nil)
12
12
  log.debug "running `#{commandline}`"
13
13
 
14
- # Prepare buffers to capture output
15
14
  out_buffer = StringIO.new
16
15
  err_buffer = StringIO.new
17
- exit_status = nil
18
16
  # Flatten handles nested arrays, Compact removes nils
19
17
  cmd_args = Array(commandline).flatten.compact.map(&:to_s)
20
18
 
21
- Open3.popen3(*cmd_args) do |stdin, stdout, stderr, wait_thr|
22
- # 1. Handle Input (if any)
23
- stdin.write(stdin_data) if stdin_data
24
- stdin.close # Close stdin so the process knows input is finished
25
-
26
- # Use threads to read stdout and stderr simultaneously.
27
- readers = []
28
-
29
- readers << Thread.new do
30
- stdout.each_line do |line|
31
- print line if echo # Echo to real STDOUT if requested
32
- out_buffer << line # Capture to memory
33
- end
34
- end
35
-
36
- readers << Thread.new do
37
- stderr.each_line do |line|
38
- $stderr.print line if echo # Echo to real STDERR if requested
39
- err_buffer << line # Capture to memory
40
- end
41
- end
42
-
43
- # Wait for reading to finish
44
- readers.each(&:join)
45
-
46
- # Get the exit code
47
- exit_status = wait_thr.value
48
- end
49
-
50
- # Check for failure
51
- unless exit_status.success?
52
- # Extract strings from buffers
53
- out = out_buffer.string
54
- err = err_buffer.string
55
-
56
- log.warn("`#{commandline}` failed with status #{exit_status.exitstatus}")
57
-
58
- if !out.empty? || !err.empty?
59
- log.warn("Output follows:")
60
- log.warn(out) unless out.empty?
61
- log.warn(err) unless err.empty?
62
- end
19
+ exit_status = spawn_and_capture(cmd_args, stdin_data, echo, out_buffer, err_buffer)
63
20
 
64
- fail ExecutionFailed.new(commandline, exit_status.exitstatus, out, err)
65
- end
21
+ out = out_buffer.string
22
+ err = err_buffer.string
23
+ raise_execution_failed(commandline, exit_status, out, err) unless exit_status.success?
66
24
 
67
- # Return the standard output
68
- out_buffer.string
25
+ out
69
26
  end
70
27
 
71
28
  # runs an interactive executable in a subshell
@@ -78,16 +35,55 @@ module Tetra
78
35
 
79
36
  log.debug "`#{command}` exited with success #{success}"
80
37
 
81
- fail ExecutionFailed.new(command, $CHILD_STATUS.exitstatus, nil, nil) unless success
38
+ raise ExecutionFailed.new(command, $CHILD_STATUS.exitstatus, nil, nil) unless success
39
+ end
40
+
41
+ private
42
+
43
+ # spawns commandline, writing stdin and reading stdout/stderr concurrently
44
+ # (writing stdin to completion before draining stdout/stderr can deadlock
45
+ # if the child fills its output pipe buffer before consuming all of stdin)
46
+ # returns the resulting Process::Status
47
+ def spawn_and_capture(cmd_args, stdin_data, echo, out_buffer, err_buffer)
48
+ Open3.popen3(*cmd_args) do |stdin, stdout, stderr, wait_thr|
49
+ threads = [
50
+ Thread.new { write_stdin(stdin, stdin_data) },
51
+ Thread.new { pipe_to_buffer(stdout, out_buffer, echo ? $stdout : nil) },
52
+ Thread.new { pipe_to_buffer(stderr, err_buffer, echo ? $stderr : nil) }
53
+ ]
54
+ threads.each(&:join)
55
+
56
+ wait_thr.value
57
+ end
58
+ end
59
+
60
+ def write_stdin(stdin, stdin_data)
61
+ stdin.write(stdin_data) if stdin_data
62
+ stdin.close # Close stdin so the process knows input is finished
63
+ end
64
+
65
+ def pipe_to_buffer(io, buffer, echo_io)
66
+ io.each_line do |line|
67
+ echo_io&.print(line)
68
+ buffer << line
69
+ end
70
+ end
71
+
72
+ def raise_execution_failed(commandline, exit_status, out, err)
73
+ log.warn("`#{commandline}` failed with status #{exit_status.exitstatus}")
74
+ if !out.empty? || !err.empty?
75
+ log.warn("Output follows:")
76
+ log.warn(out) unless out.empty?
77
+ log.warn(err) unless err.empty?
78
+ end
79
+
80
+ raise ExecutionFailed.new(commandline, exit_status.exitstatus, out, err)
82
81
  end
83
82
  end
84
83
 
85
84
  # raised when a command returns a non-zero status
86
85
  class ExecutionFailed < StandardError
87
- attr_reader :commandline
88
- attr_reader :status
89
- attr_reader :out
90
- attr_reader :err
86
+ attr_reader :commandline, :status, :out, :err
91
87
 
92
88
  def initialize(commandline, status, out, err)
93
89
  @commandline = commandline
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Tetra
3
4
  # encapsulates tar
4
5
  class Tar
@@ -7,7 +8,7 @@ module Tetra
7
8
  # decompresses a file in a target directory
8
9
  def decompress(tarfile, directory)
9
10
  # Use Array format to prevent shell injection.
10
- result = run(["tar", "xvf", tarfile, "--directory", directory])
11
+ result = run(["tar", "xvf", tarfile, "--directory", directory], echo: false, stdin_data: nil)
11
12
 
12
13
  result&.strip
13
14
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Tetra
3
4
  # encapsulates unzip
4
5
  class Unzip
@@ -7,7 +8,7 @@ module Tetra
7
8
  # decompresses a file in a target directory
8
9
  def decompress(zipfile, directory)
9
10
  # Use Array execution to prevent shell injection
10
- result = run(["unzip", zipfile, "-d", directory])
11
+ result = run(["unzip", zipfile, "-d", directory], echo: false, stdin_data: nil)
11
12
 
12
13
  result&.strip
13
14
  end
@@ -10,8 +10,8 @@ module Tetra
10
10
  include Logging
11
11
 
12
12
  # API Constants
13
- SEARCH_API = "https://search.maven.org/solrsearch/select".freeze
14
- DOWNLOAD_API = "https://repo1.maven.org/maven2".freeze
13
+ SEARCH_API = "https://search.maven.org/solrsearch/select"
14
+ DOWNLOAD_API = "https://repo1.maven.org/maven2"
15
15
 
16
16
  def search_by_sha1(sha1)
17
17
  search(q: "1:\"#{sha1}\"")
@@ -77,14 +77,16 @@ module Tetra
77
77
  when Net::HTTPSuccess
78
78
  response.body
79
79
  when Net::HTTPRedirection
80
- location = response["location"]
80
+ # Location may be relative (RFC 7231); resolve it against the
81
+ # current URI so relative redirects don't crash Net::HTTP.start.
82
+ location = (uri + response["location"]).to_s
81
83
  log.info("Redirected to #{location}")
82
84
  # Recursive call to follow redirect (params are usually part of the new URL)
83
85
  fetch(location, {}, limit - 1)
84
86
  when Net::HTTPNotFound
85
- fail NotFoundOnMavenWebsiteError
87
+ raise NotFoundOnMavenWebsiteError
86
88
  else
87
- fail "Remote error: #{response.code} #{response.message}"
89
+ raise "Remote error: #{response.code} #{response.message}"
88
90
  end
89
91
  rescue Net::OpenTimeout, Net::ReadTimeout, SocketError, Errno::ECONNRESET => e
90
92
  if (retries += 1) <= 3
@@ -13,7 +13,7 @@ module Tetra
13
13
  "cd #{project.latest_dry_run_directory}"
14
14
  ] + generate_aliases(project) + project.build_script_lines
15
15
 
16
- new_content = script_lines.join("\n") + "\n"
16
+ new_content = "#{script_lines.join("\n")}\n"
17
17
 
18
18
  result_dir = File.join(project.packages_dir, project.name)
19
19
  FileUtils.mkdir_p(result_dir)
@@ -44,8 +44,5 @@ module Tetra
44
44
 
45
45
  cmds
46
46
  end
47
-
48
- # Alias for backward compatibility if other classes call 'aliases'
49
- alias aliases generate_aliases
50
47
  end
51
48
  end
@@ -23,7 +23,9 @@ module Tetra
23
23
  log.debug("Attempting unpack of #{file} to find a POM")
24
24
  begin
25
25
  Zip::File.foreach(file) do |entry|
26
- # Security check (Zip Slip)
26
+ # Defense in depth against malicious entry names. Note this method
27
+ # never extracts entries to disk (only reads pom.xml into memory),
28
+ # so Zip Slip path traversal is not actually reachable here.
27
29
  next if entry.name.include?("..") || entry.name.start_with?("/")
28
30
 
29
31
  # PERFORMANCE: end_with? is much faster than Regexp for simple suffixes
@@ -55,7 +57,7 @@ module Tetra
55
57
 
56
58
  if found_doc
57
59
  log.info("pom.xml for #{file} found on search.maven.org for sha1 #{sha1} " \
58
- "(#{found_doc['g']}:#{found_doc['a']}:#{found_doc['v']})")
60
+ "(#{found_doc["g"]}:#{found_doc["a"]}:#{found_doc["v"]})")
59
61
 
60
62
  group_id, artifact_id, version = site.get_maven_id_from(found_doc)
61
63
  return site.download_pom(group_id, artifact_id, version), :found_via_sha1
data/lib/tetra/project.rb CHANGED
@@ -31,11 +31,9 @@ module Tetra
31
31
  # finds the project directory up in the tree, like git does
32
32
  def self.find_project_dir(starting_dir)
33
33
  result = starting_dir
34
- while project?(result) == false && result != "/"
35
- result = File.expand_path("..", result)
36
- end
34
+ result = File.expand_path("..", result) while project?(result) == false && result != "/"
37
35
 
38
- fail NoProjectDirectoryError, starting_dir if result == "/"
36
+ raise NoProjectDirectoryError, starting_dir if result == "/"
39
37
 
40
38
  result
41
39
  end
@@ -61,7 +59,7 @@ module Tetra
61
59
  def dry_running?
62
60
  latest_comment = @git.latest_comment("tetra: dry-run-")
63
61
  # MODERNIZATION: Use match? instead of =~
64
- !latest_comment.nil? && !latest_comment.match?(/tetra: dry-run-finished/)
62
+ !latest_comment.nil? && !latest_comment.include?("tetra: dry-run-finished")
65
63
  end
66
64
 
67
65
  # ends a dry-run assuming a successful build:
@@ -127,7 +125,7 @@ module Tetra
127
125
 
128
126
  previous_id = @git.latest_id(generated_comment)
129
127
 
130
- File.open(path, "w") { |io| io.write(new_content) }
128
+ File.write(path, new_content)
131
129
  log.debug "committing new content: #{comment}"
132
130
  @git.commit_file(path, whole_comment)
133
131
 
@@ -136,7 +134,7 @@ module Tetra
136
134
  conflict_count = @git.merge_with_id(path, "#{path}.tetra_user_edited", previous_id)
137
135
  File.delete("#{path}.tetra_user_edited")
138
136
 
139
- @git.commit_file(path, "User changes merged back") if conflict_count == 0
137
+ @git.commit_file(path, "User changes merged back") if conflict_count.zero?
140
138
 
141
139
  return conflict_count
142
140
  end
@@ -145,10 +143,8 @@ module Tetra
145
143
  end
146
144
 
147
145
  # runs a block from the project directory or a subdirectory
148
- def from_directory(subdirectory = "")
149
- Dir.chdir(File.join(@full_path, subdirectory)) do
150
- yield
151
- end
146
+ def from_directory(subdirectory = "", &)
147
+ Dir.chdir(File.join(@full_path, subdirectory), &)
152
148
  end
153
149
 
154
150
  # returns the latest dry run start directory
@@ -159,18 +155,16 @@ module Tetra
159
155
  # returns a list of files produced during the last dry-run
160
156
  def produced_files
161
157
  @git.latest_comment("tetra: dry-run-finished")
162
- .split("\n")
163
- .map { |line| line[%r{^tetra: file-changed: src/(.+)$}, 1] }
164
- .compact
165
- .sort
158
+ .split("\n")
159
+ .filter_map { |line| line[%r{^tetra: file-changed: src/(.+)$}, 1] }
160
+ .sort
166
161
  end
167
162
 
168
163
  def build_script_lines
169
164
  @git.latest_comment("tetra: dry-run-finished")
170
- .split("\n")
171
- .map { |line| line[/^tetra: build-script-line: (.+)$/, 1] }
172
- .compact
173
- .sort
165
+ .split("\n")
166
+ .filter_map { |line| line[/^tetra: build-script-line: (.+)$/, 1] }
167
+ .sort
174
168
  end
175
169
 
176
170
  # archives a tarball of kit/ in packages/
@@ -216,8 +210,8 @@ module Tetra
216
210
 
217
211
  # Calculate relative path for symlink
218
212
  link_target = Pathname.new(new_location)
219
- .relative_path_from(Pathname.new(file).dirname)
220
- .to_s
213
+ .relative_path_from(Pathname.new(file).dirname)
214
+ .to_s
221
215
 
222
216
  File.symlink(link_target, file)
223
217
  result << [file, new_location]
@@ -234,6 +228,7 @@ module Tetra
234
228
 
235
229
  def initialize(directory)
236
230
  @directory = directory
231
+ super("Not a tetra project directory: #{directory}")
237
232
  end
238
233
  end
239
234
  end
@@ -27,7 +27,7 @@ module Tetra
27
27
  end
28
28
 
29
29
  # inits a new project directory structure
30
- def init(dir, include_bundled_software = true)
30
+ def init(dir, include_bundled_software: true)
31
31
  Dir.mkdir(dir)
32
32
 
33
33
  # Avoid Dir.chdir(dir). Use absolute paths instead.
@@ -5,7 +5,7 @@ module Tetra
5
5
  class ChangeSourcesSubcommand < Tetra::Subcommand
6
6
  parameter "[SOURCE_ARCHIVE]", "new source tarball or zipfile"
7
7
  parameter "[MESSAGE]", "a short change description", default: "Sources changed"
8
- option %w(-n --no-archive), :flag, "use current src/ contents instead of an archive (see SPECIAL_CASES.md)",
8
+ option %w[-n --no-archive], :flag, "use current src/ contents instead of an archive (see SPECIAL_CASES.md)",
9
9
  default: false
10
10
 
11
11
  def execute
@@ -17,19 +17,19 @@ module Tetra
17
17
 
18
18
  project = Tetra::Project.new(".")
19
19
  ensure_dry_running(:is_not_in_progress, project) do
20
- if !no_archive?
20
+ if no_archive?
21
+ # CASE 2: Updating from manual changes in src/
22
+ project.commit_sources(message, true)
23
+
24
+ puts "New sources committed."
25
+ puts "Please copy source archive(s) corresponding to src/ in packages/ before proceeding."
26
+ else
21
27
  # CASE 1: Updating from a new archive file
22
28
  full_archive_path = File.expand_path(source_archive)
23
29
  project.commit_source_archive(full_archive_path, message)
24
30
 
25
31
  puts "New sources committed."
26
32
  puts "Please delete any stale source archives from packages/ before proceeding."
27
- else
28
- # CASE 2: Updating from manual changes in src/
29
- project.commit_sources(message, true)
30
-
31
- puts "New sources committed."
32
- puts "Please copy source archive(s) corresponding to src/ in packages/ before proceeding."
33
33
  end
34
34
  end
35
35
  end
@@ -3,7 +3,7 @@
3
3
  module Tetra
4
4
  # tetra generate-all
5
5
  class GenerateAllSubcommand < Tetra::Subcommand
6
- option %w(-f --filter), "FILTER", "filter files to be installed by this package spec", default: "*.jar"
6
+ option %w[-f --filter], "FILTER", "filter files to be installed by this package spec", default: "*.jar"
7
7
  parameter "[POM]", "a package pom file path", default: "pom.xml"
8
8
 
9
9
  def execute
@@ -3,7 +3,7 @@
3
3
  module Tetra
4
4
  # tetra generate-spec
5
5
  class GenerateSpecSubcommand < Tetra::Subcommand
6
- option %w(-f --filter), "FILTER", "filter files to be installed by this spec", default: "*.jar"
6
+ option %w[-f --filter], "FILTER", "filter files to be installed by this spec", default: "*.jar"
7
7
  parameter "[POM]", "a pom file path", default: "pom.xml"
8
8
 
9
9
  def execute
@@ -15,14 +15,11 @@ module Tetra
15
15
  path, status = pom_getter.get_pom(name)
16
16
 
17
17
  if path
18
- text_status = case status
19
- when :found_in_jar
20
- "was inside the jar"
21
- when :found_via_sha1
22
- "found by sha1 search from search.maven.org"
23
- when :found_via_heuristic
24
- "found by heuristic search from search.maven.org"
25
- end
18
+ text_status = {
19
+ found_in_jar: "was inside the jar",
20
+ found_via_sha1: "found by sha1 search from search.maven.org",
21
+ found_via_heuristic: "found by heuristic search from search.maven.org"
22
+ }[status]
26
23
 
27
24
  puts "#{format_path(path, project)} written, #{text_status}"
28
25
  else
@@ -5,7 +5,7 @@ module Tetra
5
5
  class InitSubcommand < Tetra::Subcommand
6
6
  parameter "PACKAGE_NAME", "name of the package to create"
7
7
  parameter "[SOURCE_ARCHIVE]", "source tarball or zipfile"
8
- option %w(-n --no-archive), :flag, "create a project without a source archive (see SPECIAL_CASES.md)",
8
+ option %w[-n --no-archive], :flag, "create a project without a source archive (see SPECIAL_CASES.md)",
9
9
  default: false
10
10
 
11
11
  def execute
@@ -16,9 +16,7 @@ module Tetra
16
16
  end
17
17
 
18
18
  # Ensure the file exists if provided
19
- if source_archive && !File.readable?(source_archive)
20
- signal_usage_error "#{source_archive} is not a file or it is not readable."
21
- end
19
+ signal_usage_error "#{source_archive} is not a file or it is not readable." if source_archive && !File.readable?(source_archive)
22
20
 
23
21
  Tetra::Project.init(package_name)
24
22
  project = Tetra::Project.new(package_name)
@@ -25,15 +25,15 @@ module Tetra
25
25
 
26
26
  # maps verbosity options to log level
27
27
  def configure_log_level(verbose, very_verbose, very_very_verbose)
28
- if very_very_verbose
29
- log.level = ::Logger::DEBUG
30
- elsif very_verbose
31
- log.level = ::Logger::INFO
32
- elsif verbose
33
- log.level = ::Logger::WARN
34
- else
35
- log.level = ::Logger::ERROR
36
- end
28
+ log.level = if very_very_verbose
29
+ ::Logger::DEBUG
30
+ elsif very_verbose
31
+ ::Logger::INFO
32
+ elsif verbose
33
+ ::Logger::WARN
34
+ else
35
+ ::Logger::ERROR
36
+ end
37
37
  end
38
38
 
39
39
  # override default option parsing to pass options to other commands
@@ -89,15 +89,15 @@ module Tetra
89
89
  def checking_exceptions
90
90
  yield
91
91
  rescue Errno::EACCES, Errno::ENOENT, Errno::EEXIST => e
92
- $stderr.puts e
92
+ warn e
93
93
  rescue Tetra::NoProjectDirectoryError => e
94
- $stderr.puts "#{e.directory} is not a tetra project directory, see \"tetra init\""
94
+ warn "#{e.directory} is not a tetra project directory, see \"tetra init\""
95
95
  rescue Tetra::GitAlreadyInitedError
96
- $stderr.puts "This directory is already a tetra project"
96
+ warn "This directory is already a tetra project"
97
97
  rescue Tetra::ExecutionFailed => e
98
- $stderr.puts "Failed to run `#{e.commandline}` (exit status #{e.status})"
98
+ warn "Failed to run `#{e.commandline}` (exit status #{e.status})"
99
99
  rescue Interrupt
100
- $stderr.puts "Execution interrupted by the user"
100
+ warn "Execution interrupted by the user"
101
101
  end
102
102
 
103
103
  private
data/lib/tetra/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # base module for tetra
3
4
  module Tetra
4
- VERSION = "2.0.9"
5
+ VERSION = "2.0.10"
5
6
  end
@@ -28,7 +28,7 @@ module Tetra
28
28
  def best_match(my_version, their_versions)
29
29
  return nil if their_versions.nil? || their_versions.empty?
30
30
 
31
- log.debug("version comparison: #{my_version} vs #{their_versions.join(', ')}")
31
+ log.debug("version comparison: #{my_version} vs #{their_versions.join(", ")}")
32
32
 
33
33
  my_chunks = my_version.split(Tetra::CHUNK_SEPARATOR_VERSION_MATCHER)
34
34
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tetra
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.9
4
+ version: 2.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Gedon
@@ -70,14 +70,14 @@ dependencies:
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '3.2'
73
+ version: '3.4'
74
74
  type: :runtime
75
75
  prerelease: false
76
76
  version_requirements: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
- version: '3.2'
80
+ version: '3.4'
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: text
83
83
  requirement: !ruby/object:Gem::Requirement
@@ -92,132 +92,6 @@ dependencies:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
94
  version: '1.3'
95
- - !ruby/object:Gem::Dependency
96
- name: aruba
97
- requirement: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: '2.4'
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - "~>"
107
- - !ruby/object:Gem::Version
108
- version: '2.4'
109
- - !ruby/object:Gem::Dependency
110
- name: rake
111
- requirement: !ruby/object:Gem::Requirement
112
- requirements:
113
- - - "~>"
114
- - !ruby/object:Gem::Version
115
- version: '13.4'
116
- type: :development
117
- prerelease: false
118
- version_requirements: !ruby/object:Gem::Requirement
119
- requirements:
120
- - - "~>"
121
- - !ruby/object:Gem::Version
122
- version: '13.4'
123
- - !ruby/object:Gem::Dependency
124
- name: rspec
125
- requirement: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - "~>"
128
- - !ruby/object:Gem::Version
129
- version: '3.13'
130
- type: :development
131
- prerelease: false
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - "~>"
135
- - !ruby/object:Gem::Version
136
- version: '3.13'
137
- - !ruby/object:Gem::Dependency
138
- name: rubocop
139
- requirement: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - "~>"
142
- - !ruby/object:Gem::Version
143
- version: '1.86'
144
- type: :development
145
- prerelease: false
146
- version_requirements: !ruby/object:Gem::Requirement
147
- requirements:
148
- - - "~>"
149
- - !ruby/object:Gem::Version
150
- version: '1.86'
151
- - !ruby/object:Gem::Dependency
152
- name: rubocop-performance
153
- requirement: !ruby/object:Gem::Requirement
154
- requirements:
155
- - - "~>"
156
- - !ruby/object:Gem::Version
157
- version: '1.26'
158
- type: :development
159
- prerelease: false
160
- version_requirements: !ruby/object:Gem::Requirement
161
- requirements:
162
- - - "~>"
163
- - !ruby/object:Gem::Version
164
- version: '1.26'
165
- - !ruby/object:Gem::Dependency
166
- name: rubocop-rake
167
- requirement: !ruby/object:Gem::Requirement
168
- requirements:
169
- - - "~>"
170
- - !ruby/object:Gem::Version
171
- version: '0.7'
172
- type: :development
173
- prerelease: false
174
- version_requirements: !ruby/object:Gem::Requirement
175
- requirements:
176
- - - "~>"
177
- - !ruby/object:Gem::Version
178
- version: '0.7'
179
- - !ruby/object:Gem::Dependency
180
- name: rubocop-rspec
181
- requirement: !ruby/object:Gem::Requirement
182
- requirements:
183
- - - "~>"
184
- - !ruby/object:Gem::Version
185
- version: 3.9.0
186
- type: :development
187
- prerelease: false
188
- version_requirements: !ruby/object:Gem::Requirement
189
- requirements:
190
- - - "~>"
191
- - !ruby/object:Gem::Version
192
- version: 3.9.0
193
- - !ruby/object:Gem::Dependency
194
- name: simplecov
195
- requirement: !ruby/object:Gem::Requirement
196
- requirements:
197
- - - "~>"
198
- - !ruby/object:Gem::Version
199
- version: '0.22'
200
- type: :development
201
- prerelease: false
202
- version_requirements: !ruby/object:Gem::Requirement
203
- requirements:
204
- - - "~>"
205
- - !ruby/object:Gem::Version
206
- version: '0.22'
207
- - !ruby/object:Gem::Dependency
208
- name: simplecov-cobertura
209
- requirement: !ruby/object:Gem::Requirement
210
- requirements:
211
- - - "~>"
212
- - !ruby/object:Gem::Version
213
- version: '3.1'
214
- type: :development
215
- prerelease: false
216
- version_requirements: !ruby/object:Gem::Requirement
217
- requirements:
218
- - - "~>"
219
- - !ruby/object:Gem::Version
220
- version: '3.1'
221
95
  description: |
222
96
  Tetra simplifies the creation of spec files and archives
223
97
  to distribute Java projects in RPM format.
@@ -2045,7 +1919,7 @@ licenses:
2045
1919
  - MIT
2046
1920
  metadata:
2047
1921
  bug_tracker_uri: https://github.com/uyuni-project/tetra/issues
2048
- homepage_uri: https://github.com/uyuni-project/tetra
1922
+ homepage_uri: https://rubygems.org/gems/tetra
2049
1923
  source_code_uri: https://github.com/uyuni-project/tetra
2050
1924
  rubygems_mfa_required: 'true'
2051
1925
  allowed_push_host: https://rubygems.org
@@ -2057,14 +1931,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
2057
1931
  requirements:
2058
1932
  - - ">="
2059
1933
  - !ruby/object:Gem::Version
2060
- version: '3.2'
1934
+ version: '3.4'
2061
1935
  required_rubygems_version: !ruby/object:Gem::Requirement
2062
1936
  requirements:
2063
1937
  - - ">="
2064
1938
  - !ruby/object:Gem::Version
2065
1939
  version: '0'
2066
1940
  requirements: []
2067
- rubygems_version: 4.0.11
1941
+ rubygems_version: 4.0.17
2068
1942
  specification_version: 4
2069
1943
  summary: A tool to package Java projects
2070
1944
  test_files: []