captive-release 0.8.1 → 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: a9e947f971c93535758990c20c7684e5178c345bfee6abddef43ee6584b1378a
4
- data.tar.gz: bc5c688c4d49ad3326104a42e4209e9b99f22cd3dd3511cf5761c8843465053c
3
+ metadata.gz: 766da20e3b1cd49bbc782ea4a7dbf483bc852b025daf791c70a69b6bedc02088
4
+ data.tar.gz: 4b01cdae087a0c6b8990843d076b76325e158578df44278e40f28b6b7364b660
5
5
  SHA512:
6
- metadata.gz: c289101fc72ca8463baad9fd904c060c6a67890d2b0ece8c61e44ddca8df0d2ff387487b67facfcf1c16e69d90ac61516b83728ef1025ad8d8894bea76fbd680
7
- data.tar.gz: 00bf4e5aad63a7ce24786c6a4c39aa1481244ec8bdf5725595084e49c783f98f66d5222a2f39b7adc149d553c931471dd23457fb49b6cf278df64bbf7f3cbc94
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)
@@ -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)
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CaptiveRelease
4
- VERSION = "0.8.1"
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
@@ -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"
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.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Captive Studio
@@ -54,12 +54,15 @@ files:
54
54
  - lib/captive_release/menu.rb
55
55
  - lib/captive_release/messages.rb
56
56
  - lib/captive_release/options.rb
57
+ - lib/captive_release/prerelease_guard.rb
57
58
  - lib/captive_release/release_command.rb
58
59
  - lib/captive_release/release_confirmation.rb
59
60
  - lib/captive_release/release_overview.rb
60
61
  - lib/captive_release/release_preconditions.rb
61
62
  - lib/captive_release/release_publication.rb
62
63
  - lib/captive_release/repo_files.rb
64
+ - lib/captive_release/ruby_gems_version.rb
65
+ - lib/captive_release/semver.rb
63
66
  - lib/captive_release/shell.rb
64
67
  - lib/captive_release/terminal.rb
65
68
  - lib/captive_release/version.rb