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 +4 -4
- data/lib/captive_release/bump_safety_net.rb +2 -1
- data/lib/captive_release/github_release.rb +1 -1
- data/lib/captive_release/locales/en.yml +8 -2
- data/lib/captive_release/locales/fr.yml +8 -2
- data/lib/captive_release/prerelease_guard.rb +24 -0
- data/lib/captive_release/release_command.rb +1 -0
- data/lib/captive_release/ruby_gems_version.rb +31 -0
- data/lib/captive_release/semver.rb +16 -0
- data/lib/captive_release/version.rb +1 -1
- data/lib/captive_release/version_bumper.rb +33 -8
- data/lib/captive_release/version_choice.rb +8 -6
- data/lib/captive_release/version_format.rb +5 -4
- data/lib/captive_release/version_severity.rb +3 -3
- data/lib/captive_release.rb +3 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 766da20e3b1cd49bbc782ea4a7dbf483bc852b025daf791c70a69b6bedc02088
|
|
4
|
+
data.tar.gz: 4b01cdae087a0c6b8990843d076b76325e158578df44278e40f28b6b7364b660
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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" =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -2,28 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
module CaptiveRelease
|
|
4
4
|
class VersionBumper
|
|
5
|
-
|
|
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
|
|
13
|
+
raise ArgumentError, Messages.t(:invalid_semver, value: current) unless Semver.valid?(current)
|
|
13
14
|
|
|
14
|
-
@
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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]
|
data/lib/captive_release.rb
CHANGED
|
@@ -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.
|
|
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
|