captive-release 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '028b75d95da7f0c5ae533774c1fc1bc353234bd569a58f9c83798e0519a592c2'
4
- data.tar.gz: bb5a5ffbbaf260dad04cd28afb303c476ae5dff295454bbf1b95708bfba58126
3
+ metadata.gz: 766da20e3b1cd49bbc782ea4a7dbf483bc852b025daf791c70a69b6bedc02088
4
+ data.tar.gz: 4b01cdae087a0c6b8990843d076b76325e158578df44278e40f28b6b7364b660
5
5
  SHA512:
6
- metadata.gz: ee228007f5b5cb48c7d2fb2402a019c287b4d2a8dc1e37df0e6a0f3c159af97ce4aa3e5e95e57d6b1b947538414c081ea78a998a056a8db80770d263ea3371d9
7
- data.tar.gz: 1a0ae25c85c204a1ac5431a4d1e704b67715b77c281763b103ff90da04a1a8550b628f4f1e3a785d743a1ec78b9c2d02b328ef1bee37ec5955085ad12b59666d
6
+ metadata.gz: 0f6d0e2c5c1e1fe133c7260b0ad9dba99c99d6224efe152250f9472fb95f19a3ad367d45222f0f27afec06a0d2e89101f4ae851b395e4adc89763fb4741b8ff9
7
+ data.tar.gz: cafef79eae71b7c328cefe468d83981723967bdc2a49f0bb2cf4294c59f217aad8204c9e42f60d109eebe296d4793fb99f0b6fed0a68810ee3fd8eaa040ee343
@@ -10,7 +10,8 @@ module CaptiveRelease
10
10
  end
11
11
 
12
12
  def verifier!(suggestion, courante, prochaine)
13
- return unless suggestion
13
+ # La gravité d'une version a déjà été assumée par sa première pré-release.
14
+ return if suggestion.nil? || Semver.prerelease?(courante)
14
15
 
15
16
  choisie = VersionSeverity.classify(from: courante, to: prochaine)
16
17
  return if BumpSeverity::RANK.fetch(choisie, -1) >= BumpSeverity::RANK.fetch(suggestion)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Ce que veut dire la saisie d'exclusion : des rangs séparés par des virgules, numérotés à
5
+ # partir de 1 comme la liste affichée, et vide pour tout garder.
6
+ #
7
+ # Cette unité change quand la syntaxe de la saisie change, VersionFileSelection quand la
8
+ # façon de présenter le choix change.
9
+ module ExclusionInput
10
+ def self.apply(found, saisie)
11
+ return found if saisie.strip.empty?
12
+
13
+ rangs = saisie.split(",").map { |numero| numero.strip.to_i - 1 }
14
+ found.reject.with_index { |_, rang| rangs.include?(rang) }
15
+ end
16
+ end
17
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CaptiveRelease
4
- # Remet Gemfile.lock d'aplomb après un bump : un .gemspec à la racine porte la version
5
- # bumpée, donc Gemfile.lock devient périmé et --deployment le refuse en CI si personne ne
6
- # le relance.
4
+ # Remet les Gemfile.lock d'aplomb après un bump : un .gemspec porte la version bumpée, donc
5
+ # le Gemfile.lock de son dossier devient périmé et --deployment le refuse en CI si personne
6
+ # ne le relance. Dans un monorepo, ce dossier n'est pas forcément la racine.
7
7
  #
8
- # Cette unité change quand la façon de détecter ou de relancer le lock change,
8
+ # Cette unité change quand la façon de détecter ou de relancer les locks change,
9
9
  # ReleaseCommand quand la suite des étapes change.
10
10
  class GemfileLockRefresh
11
11
  LOCKFILE = "Gemfile.lock"
@@ -14,17 +14,28 @@ module CaptiveRelease
14
14
  @files = files
15
15
  end
16
16
 
17
+ # Les Gemfile.lock à relancer, relatifs à la racine : un par dossier qui porte un .gemspec.
18
+ #
17
19
  # rescue : une arborescence hostile ne doit jamais faire échouer la release, la détection
18
20
  # n'est qu'une commodité. Une fois vraie, l'exécution du bundle lock, elle, échoue haut
19
21
  # la main si elle rate.
20
- def needed?
21
- File.exist?(@files.path(LOCKFILE)) && @files.glob("*.gemspec").any? && !GitCommands.ignored?(LOCKFILE)
22
+ def lockfiles
23
+ @files.glob("**", LOCKFILE).map { |lock| @files.relative(lock) }.select { |lock| a_relancer?(lock) }
22
24
  rescue StandardError
23
- false
25
+ []
24
26
  end
25
27
 
26
- def call
27
- Shell.run! "bundle lock"
28
+ def call(locks = lockfiles)
29
+ locks.each { |lock| Shell.run! commande(lock) }
28
30
  end
31
+
32
+ private
33
+
34
+ def a_relancer?(lock)
35
+ @files.glob(File.dirname(lock), "*.gemspec").any? && !GitCommands.ignored?(lock)
36
+ end
37
+
38
+ # Le Gemfile d'un lock, c'est son chemin sans .lock : captive-ruby/Gemfile.lock → captive-ruby/Gemfile.
39
+ def commande(lock) = "bundle lock --gemfile #{Shell.escape(lock.delete_suffix('.lock'))}"
29
40
  end
30
41
  end
@@ -4,8 +4,7 @@ module CaptiveRelease
4
4
  # Les commandes git d'une release. La façon de les lancer vit dans Shell.
5
5
  class GitCommands
6
6
  def self.dirty?
7
- sortie = Shell.capture("git diff --name-only && git diff --cached --name-only")
8
- !sortie.lines.map(&:strip).reject(&:empty?).empty?
7
+ !Shell.capture("git diff --name-only && git diff --cached --name-only").empty?
9
8
  end
10
9
 
11
10
  def self.remote_url = Shell.capture("git remote get-url origin 2>/dev/null")
@@ -19,7 +18,7 @@ module CaptiveRelease
19
18
  # Les sujets de commit depuis le tag donné jusqu'à HEAD - la matière première de la
20
19
  # suggestion de bump, un message par ligne, propre de toute ligne vide.
21
20
  def self.messages_since(tag)
22
- Shell.capture("git log --pretty=%s #{Shell.escape(tag)}..HEAD").lines.map(&:strip).reject(&:empty?)
21
+ Shell.capture_lines("git log --pretty=%s #{Shell.escape(tag)}..HEAD")
23
22
  end
24
23
 
25
24
  def self.current_branch
@@ -27,7 +27,7 @@ module CaptiveRelease
27
27
  tag = "v#{version}"
28
28
  @api.post("releases",
29
29
  { "tag_name" => tag, "name" => tag, "body" => notes(tag),
30
- "draft" => false, "prerelease" => false, },
30
+ "draft" => false, "prerelease" => Semver.prerelease?(version), },
31
31
  attendu: "201")["html_url"]
32
32
  end
33
33
 
@@ -5,7 +5,7 @@ en:
5
5
 
6
6
  Usage:
7
7
  captive-release init [--files path[:type],...]
8
- captive-release new [patch|minor|major|x.y.z] [--yes]
8
+ captive-release new [patch|minor|major|promote|x.y.z] [--yes]
9
9
  captive-release build [--profile staging|production]
10
10
  captive-release version
11
11
 
@@ -82,7 +82,13 @@ en:
82
82
  suggestion_patch: no notable commit detected
83
83
  choose_release_type: 'Choose release type:'
84
84
  custom: Custom
85
- enter_version: 'Enter version (x.y.z): '
85
+ bump_patch: Patch
86
+ bump_minor: Minor
87
+ bump_major: Major
88
+ bump_promote: Promote
89
+ bump_from_prerelease: 'Cannot %{type} from a pre-release: promote it or enter a version.'
90
+ prerelease_on_app: 'Cannot release pre-release %{version}: %{path} carries an app version, which allows no suffix.'
91
+ enter_version: 'Enter version (x.y.z or x.y.z-alpha.1): '
86
92
  invalid_bump_type: 'Invalid bump type: %{type}. Use patch|minor|major|x.y.z'
87
93
  invalid_semver: 'Invalid semver: %{value}'
88
94
  invalid_version: 'Invalid version: %{value}'
@@ -5,7 +5,7 @@ fr:
5
5
 
6
6
  Utilisation :
7
7
  captive-release init [--files path[:type],...]
8
- captive-release new [patch|minor|major|x.y.z] [--yes]
8
+ captive-release new [patch|minor|major|promote|x.y.z] [--yes]
9
9
  captive-release build [--profile staging|production]
10
10
  captive-release version
11
11
 
@@ -82,7 +82,13 @@ fr:
82
82
  suggestion_patch: aucun commit notable détecté
83
83
  choose_release_type: 'Choisissez le type de release :'
84
84
  custom: Personnalisée
85
- enter_version: 'Saisissez la version (x.y.z) : '
85
+ bump_patch: Patch
86
+ bump_minor: Minor
87
+ bump_major: Major
88
+ bump_promote: Promouvoir
89
+ bump_from_prerelease: 'Impossible de faire un %{type} depuis une pré-release : promouvez-la ou saisissez une version.'
90
+ prerelease_on_app: "Pré-release %{version} impossible : %{path} porte une version d'app, qui n'admet pas de suffixe."
91
+ enter_version: 'Saisissez la version (x.y.z ou x.y.z-alpha.1) : '
86
92
  invalid_bump_type: 'Type de bump invalide : %{type}. Utilisez patch|minor|major|x.y.z'
87
93
  invalid_semver: 'Semver invalide : %{value}'
88
94
  invalid_version: 'Version invalide : %{value}'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Refuse une pré-release dès qu'une app porte la version : la version marketing iOS
5
+ # (CFBundleShortVersionString, que nourrissent aussi app.json et app.config.js) n'admet
6
+ # pas de suffixe. Une alpha d'app passe par un build interne, pas par une version.
7
+ class PrereleaseGuard
8
+ APP_TYPES = %w[ios_plist android_gradle app_json app_config_js].freeze
9
+
10
+ def initialize(terminal:)
11
+ @terminal = terminal
12
+ end
13
+
14
+ def verifier!(version, fichiers)
15
+ return unless Semver.prerelease?(version)
16
+
17
+ app = fichiers.find { |fichier| APP_TYPES.include?(fichier.type) }
18
+ return unless app
19
+
20
+ @terminal.say @terminal.error(Messages.t(:prerelease_on_app, version: version, path: app.path))
21
+ exit 1
22
+ end
23
+ end
24
+ end
@@ -18,6 +18,7 @@ module CaptiveRelease
18
18
  suggestion = ReleaseOverview.new(terminal: @terminal).call(courante)
19
19
 
20
20
  prochaine = VersionChoice.new(terminal: @terminal).call(courante, bump_arg)
21
+ PrereleaseGuard.new(terminal: @terminal).verifier!(prochaine, @config.version_files)
21
22
  ReleaseConfirmation.new(terminal: @terminal).verifier!(suggestion, courante, prochaine) if confirmation
22
23
 
23
24
  VersionFilesWriting.new(terminal: @terminal).call(prochaine, @config.version_files)
@@ -30,13 +31,15 @@ module CaptiveRelease
30
31
 
31
32
  def chemins_a_commiter
32
33
  chemins = @config.version_files.map(&:path)
33
- return chemins unless (refresh = GemfileLockRefresh.new).needed?
34
+ refresh = GemfileLockRefresh.new
35
+ locks = refresh.lockfiles
36
+ return chemins if locks.empty?
34
37
 
35
38
  @terminal.say "\n#{@terminal.bold(Messages.t(:refreshing_lockfile))}"
36
- refresh.call
37
- @terminal.done GemfileLockRefresh::LOCKFILE
39
+ refresh.call(locks)
40
+ locks.each { |lock| @terminal.done lock }
38
41
 
39
- chemins + [ GemfileLockRefresh::LOCKFILE ]
42
+ chemins + locks
40
43
  end
41
44
 
42
45
  def publication
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module CaptiveRelease
6
+ # Traduit entre semver et RubyGems, qui refuse 2.0.0-alpha.1 et attend 2.0.0.alpha.1.
7
+ # Le reste de l'outil ne voit que du semver ; seul le fichier parle RubyGems.
8
+ class RubyGemsVersion
9
+ extend Forwardable
10
+
11
+ GEM_PRERELEASE = /\A(\d+\.\d+\.\d+)\.(.+)\z/
12
+
13
+ def initialize(format)
14
+ @format = format
15
+ end
16
+
17
+ def_delegator :@format, :expected
18
+
19
+ def read(content)
20
+ @format.read(content)&.sub(GEM_PRERELEASE, '\1-\2')
21
+ end
22
+
23
+ def write(content, old_version, new_version)
24
+ @format.write(content, vers_gem(old_version), vers_gem(new_version))
25
+ end
26
+
27
+ private
28
+
29
+ def vers_gem(version) = version.sub("-", ".")
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Ce qu'est une version pour l'outil : x.y.z, éventuellement suivi d'une pré-release
5
+ # (-alpha, -rc.2). Les métadonnées de build (+sha) ne servent à rien ici et sont refusées.
6
+ module Semver
7
+ IDENT = /[0-9A-Za-z-]+/
8
+ PATTERN = /\A(\d+\.\d+\.\d+)(?:-#{IDENT}(?:\.#{IDENT})*)?\z/
9
+
10
+ def self.valid?(version) = version.to_s.match?(PATTERN)
11
+
12
+ def self.prerelease?(version) = version.to_s.include?("-")
13
+
14
+ def self.core(version) = version.to_s[PATTERN, 1]
15
+ end
16
+ end
@@ -13,6 +13,8 @@ module CaptiveRelease
13
13
 
14
14
  def self.capture(commande) = `#{commande}`.strip
15
15
 
16
+ def self.capture_lines(commande) = capture(commande).lines.map(&:strip).reject(&:empty?)
17
+
16
18
  # Rubocop veut Shellwords, mais son échappement diffère du nôtre sur des chemins que git
17
19
  # accepte : la liste blanche dit exactement ce qui passe sans protection.
18
20
  def self.escape(chaine) = chaine.gsub(%r{[^a-zA-Z0-9._\-/]}) { |caractere| "\\#{caractere}" }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CaptiveRelease
4
- VERSION = "0.8.0"
4
+ VERSION = "0.9.0"
5
5
  end
@@ -2,28 +2,53 @@
2
2
 
3
3
  module CaptiveRelease
4
4
  class VersionBumper
5
- SEMVER_RE = /\A\d+\.\d+\.\d+\z/
5
+ BUMP_TYPES = %w[patch minor major].freeze
6
+ PROMOTE = "promote"
6
7
 
7
8
  def self.bump(current, type)
8
9
  new(current).bump(type)
9
10
  end
10
11
 
11
12
  def initialize(current)
12
- raise ArgumentError, Messages.t(:invalid_semver, value: current) unless current.match?(SEMVER_RE)
13
+ raise ArgumentError, Messages.t(:invalid_semver, value: current) unless Semver.valid?(current)
13
14
 
14
- @major, @minor, @patch = current.split(".").map(&:to_i)
15
+ @current = current
16
+ @major, @minor, @patch = Semver.core(current).split(".").map(&:to_i)
15
17
  end
16
18
 
17
19
  def bump(type)
18
- case type.to_s
20
+ type = type.to_s
21
+ verifier_depuis_prerelease!(type)
22
+
23
+ case type
19
24
  when "major" then "#{@major + 1}.0.0"
20
25
  when "minor" then "#{@major}.#{@minor + 1}.0"
21
26
  when "patch" then "#{@major}.#{@minor}.#{@patch + 1}"
22
- else
23
- raise ArgumentError, Messages.t(:invalid_version, value: type) unless type.to_s.match?(SEMVER_RE)
24
-
25
- type.to_s
27
+ when PROMOTE then promouvoir
28
+ else saisie(type)
26
29
  end
27
30
  end
31
+
32
+ private
33
+
34
+ # Depuis une pré-release, seule la promotion a un sens : un patch de 2.0.0-alpha
35
+ # donnerait 2.0.0 en semver, ce que personne ne lit comme un patch.
36
+ def verifier_depuis_prerelease!(type)
37
+ return unless Semver.prerelease?(@current) && BUMP_TYPES.include?(type)
38
+
39
+ raise ArgumentError, Messages.t(:bump_from_prerelease, type: type)
40
+ end
41
+
42
+ def promouvoir
43
+ raise ArgumentError, Messages.t(:invalid_version, value: PROMOTE) unless Semver.prerelease?(@current)
44
+
45
+ Semver.core(@current)
46
+ end
47
+
48
+ def saisie(type)
49
+ raise ArgumentError, Messages.t(:invalid_version, value: type) unless Semver.valid?(type)
50
+
51
+ type
52
+ end
28
53
  end
29
54
  end
@@ -7,8 +7,7 @@ module CaptiveRelease
7
7
  # Cette unité change quand les façons de nommer une version changent, ReleaseCommand quand
8
8
  # le geste de release change.
9
9
  class VersionChoice
10
- BUMP_TYPES = %w[patch minor major].freeze
11
- SEMVER_RE = /\A\d+\.\d+\.\d+\z/
10
+ BUMP_TYPES = (VersionBumper::BUMP_TYPES + [ VersionBumper::PROMOTE ]).freeze
12
11
  CUSTOM = "Custom"
13
12
 
14
13
  def initialize(terminal:)
@@ -22,7 +21,7 @@ module CaptiveRelease
22
21
  private
23
22
 
24
23
  def resolve(current, type)
25
- return VersionBumper.bump(current, type) if type.match?(SEMVER_RE) || BUMP_TYPES.include?(type)
24
+ return VersionBumper.bump(current, type) if Semver.valid?(type) || BUMP_TYPES.include?(type)
26
25
 
27
26
  refuse(Messages.t(:invalid_bump_type, type: type))
28
27
  end
@@ -33,17 +32,20 @@ module CaptiveRelease
33
32
  end
34
33
 
35
34
  # La valeur rendue est la version elle-même, sauf pour Custom qui n'en a pas encore une.
35
+ # Depuis une pré-release, seule la promotion est proposée : patch, minor et major y
36
+ # prêteraient à confusion.
36
37
  def candidates_for(current)
37
- candidats = BUMP_TYPES.to_h do |type|
38
+ types = Semver.prerelease?(current) ? [ VersionBumper::PROMOTE ] : VersionBumper::BUMP_TYPES
39
+ candidats = types.to_h do |type|
38
40
  version = VersionBumper.bump(current, type)
39
- [ "#{type.capitalize} → #{@terminal.bold(version)}", version ]
41
+ [ "#{Messages.t(:"bump_#{type}")} → #{@terminal.bold(version)}", version ]
40
42
  end
41
43
  candidats.merge("#{Messages.t(:custom)} → ?" => CUSTOM)
42
44
  end
43
45
 
44
46
  def type_it
45
47
  version = @terminal.ask(Messages.t(:enter_version))
46
- return version if version.match?(SEMVER_RE)
48
+ return version if Semver.valid?(version)
47
49
 
48
50
  refuse(Messages.t(:invalid_semver, value: version))
49
51
  end
@@ -33,21 +33,22 @@ module CaptiveRelease
33
33
 
34
34
  def by_content(segments, type, pattern)
35
35
  @files.glob(*segments)
36
- .select { |chemin| File.read(chemin).match?(pattern) }
36
+ .select { |chemin| contient?(chemin, pattern) }
37
37
  .map { |chemin| version_file(chemin, type) }
38
- rescue StandardError
39
- []
40
38
  end
41
39
 
42
40
  # Le build.gradle est à un chemin fixe : le chercher par glob remonterait ceux des
43
41
  # modules Android embarqués, qui ne portent pas la version de l'app.
44
42
  def android_gradle
45
- chemin = @files.path(*GRADLE_PATH)
46
- return [] unless File.exist?(chemin) && File.read(chemin).match?(/versionName\s+['"]/)
43
+ return [] unless contient?(@files.path(*GRADLE_PATH), /versionName\s+['"]/)
47
44
 
48
45
  [ VersionFile.new(GRADLE_PATH.join("/"), "android_gradle") ]
46
+ end
47
+
48
+ def contient?(chemin, pattern)
49
+ File.exist?(chemin) && File.read(chemin).match?(pattern)
49
50
  rescue StandardError
50
- []
51
+ false
51
52
  end
52
53
 
53
54
  def version_file(chemin, type) = VersionFile.new(@files.relative(chemin), type)
@@ -13,7 +13,7 @@ module CaptiveRelease
13
13
 
14
14
  def call(found)
15
15
  list(found)
16
- found.size == 1 ? seul(found) : exclude(found, demander)
16
+ found.size == 1 ? seul(found) : ExclusionInput.apply(found, demander)
17
17
  end
18
18
 
19
19
  private
@@ -37,13 +37,6 @@ module CaptiveRelease
37
37
  found
38
38
  end
39
39
 
40
- def exclude(found, saisie)
41
- return found if saisie.strip.empty?
42
-
43
- rangs = saisie.split(",").map { |numero| numero.strip.to_i - 1 }
44
- found.reject.with_index { |_, rang| rangs.include?(rang) }
45
- end
46
-
47
40
  def readable_version(fichier)
48
41
  fichier.read_version
49
42
  rescue StandardError
@@ -63,12 +63,13 @@ module CaptiveRelease
63
63
  },
64
64
  expected: %("version": "x.y.z")),
65
65
 
66
- # Le style de guillemets du fichier est conservé : réécrire en double quand le fichier
67
- # écrit en simple produirait un diff plus large que le changement de version.
68
- "ruby_version" => by_pattern(/VERSION\s*=\s*["'](.+?)["']/, %(VERSION = "x.y.z")) \
69
- { |occurrence, nouvelle|
66
+ "ruby_version" => RubyGemsVersion.new(
67
+ by_pattern(/VERSION\s*=\s*["'](.+?)["']/, %(VERSION = "x.y.z")) { |occurrence, nouvelle|
68
+ # Le style de guillemets du fichier est conservé : réécrire en double quand le
69
+ # fichier écrit en simple produirait un diff plus large que le changement de version.
70
70
  occurrence.include?('"') ? %(VERSION = "#{nouvelle}") : %(VERSION = '#{nouvelle}')
71
71
  },
72
+ ),
72
73
 
73
74
  "app_config_js" => by_label(/version:\s*/, "version: "),
74
75
  "android_gradle" => by_label(/versionName\s+/, "versionName "),
@@ -3,11 +3,11 @@
3
3
  module CaptiveRelease
4
4
  # Classe la taille réelle d'un bump en comparant les composants major.minor.patch entre
5
5
  # deux versions - y compris un semver tapé à la main, qui ne porte plus de "type" une fois
6
- # sorti de VersionChoice.
6
+ # sorti de VersionChoice. Le suffixe de pré-release ne compte pas : 2.0.0-alpha est un major.
7
7
  class VersionSeverity
8
8
  def self.classify(from:, to:)
9
- depart = from.split(".").map(&:to_i)
10
- arrivee = to.split(".").map(&:to_i)
9
+ depart = Semver.core(from).split(".").map(&:to_i)
10
+ arrivee = Semver.core(to).split(".").map(&:to_i)
11
11
 
12
12
  return "major" if depart[0] != arrivee[0]
13
13
  return "minor" if depart[1] != arrivee[1]
@@ -2,7 +2,9 @@
2
2
 
3
3
  require_relative "captive_release/version"
4
4
  require_relative "captive_release/messages"
5
+ require_relative "captive_release/semver"
5
6
  require_relative "captive_release/version_bumper"
7
+ require_relative "captive_release/ruby_gems_version"
6
8
  require_relative "captive_release/version_format"
7
9
  require_relative "captive_release/version_file"
8
10
  require_relative "captive_release/build_config"
@@ -18,6 +20,7 @@ require_relative "captive_release/gitmoji_severity"
18
20
  require_relative "captive_release/bump_suggestion"
19
21
  require_relative "captive_release/version_severity"
20
22
  require_relative "captive_release/bump_safety_net"
23
+ require_relative "captive_release/prerelease_guard"
21
24
  require_relative "captive_release/github_repo"
22
25
  require_relative "captive_release/github_http"
23
26
  require_relative "captive_release/github_api"
@@ -38,6 +41,7 @@ require_relative "captive_release/build_command"
38
41
  require_relative "captive_release/menu"
39
42
  require_relative "captive_release/version_choice"
40
43
  require_relative "captive_release/gemfile_lock_refresh"
44
+ require_relative "captive_release/exclusion_input"
41
45
  require_relative "captive_release/git_release"
42
46
  require_relative "captive_release/changes_since"
43
47
  require_relative "captive_release/release_publication"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: captive-release
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Captive Studio
@@ -33,6 +33,7 @@ files:
33
33
  - lib/captive_release/config_file.rb
34
34
  - lib/captive_release/config_loader.rb
35
35
  - lib/captive_release/config_writer.rb
36
+ - lib/captive_release/exclusion_input.rb
36
37
  - lib/captive_release/framework_detector.rb
37
38
  - lib/captive_release/gemfile_lock_refresh.rb
38
39
  - lib/captive_release/git_commands.rb
@@ -53,12 +54,15 @@ files:
53
54
  - lib/captive_release/menu.rb
54
55
  - lib/captive_release/messages.rb
55
56
  - lib/captive_release/options.rb
57
+ - lib/captive_release/prerelease_guard.rb
56
58
  - lib/captive_release/release_command.rb
57
59
  - lib/captive_release/release_confirmation.rb
58
60
  - lib/captive_release/release_overview.rb
59
61
  - lib/captive_release/release_preconditions.rb
60
62
  - lib/captive_release/release_publication.rb
61
63
  - lib/captive_release/repo_files.rb
64
+ - lib/captive_release/ruby_gems_version.rb
65
+ - lib/captive_release/semver.rb
62
66
  - lib/captive_release/shell.rb
63
67
  - lib/captive_release/terminal.rb
64
68
  - lib/captive_release/version.rb