captive-release 0.13.1 → 0.14.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: b02b5a5f09284656a970f59483743859269916f30e253648baa2d0f2fbadbb36
4
- data.tar.gz: d198e07c7ed8d9875baf64a01fa49dd5cf8e3d361e91d035f0c876ba196fc092
3
+ metadata.gz: 8b6fb2c222824add2e6fe62b462240609b233535e610ef7bd70513bf6ff5f931
4
+ data.tar.gz: ffb5b3704f4a4a4a94cb31c6d2275683077a3437d0b8b841ac727a893d32ff2f
5
5
  SHA512:
6
- metadata.gz: b2fa91cd1c63ba4d1b423979d5aa1b40445fa31e91aafd386baed6e4a1da5eb7b776c4c43f14772e2309f32c8b187cd77d25da4e8bc8b227521edc683f0a0115
7
- data.tar.gz: 8c29dc85a62025e705c5b111137d964b1d76d103cdf6caa044440f64557032a52fe7f15a29814d9ba10d91904ab7abe0df5102928e6c13f9be59fb5a2353ba8f
6
+ metadata.gz: 4045d5e368e362b1307a2f27ce16df74ff0c7f0fc1ae021b9d62af6673441deb0b7a66c8d9623a27ae10a46662f8b51d7214c2b8d32cd1878d5c490acf56e7cc
7
+ data.tar.gz: 6a3f85ea5c5da1e82a3131c10f4b6f0e0dd59ec744b8134b2d470b5c47b11b4dcfe37f227d1f74285e03cdfc41fdcaa7ac9d98e39a798c6e23f6a82886fe41b5
@@ -20,25 +20,7 @@ module CaptiveRelease
20
20
  @terminal.done "git tag v#{version}"
21
21
  return @terminal.done("git push + tag") if GitCommands.push(version)
22
22
 
23
- pull_request(version)
24
- end
25
-
26
- private
27
-
28
- # Le tag est déjà poussé et reste sur le commit de version : la release GitHub peut
29
- # suivre, et un merge commit le ramène sur la branche de base.
30
- def pull_request(version)
31
- @terminal.say " #{@terminal.warn(Messages.t(:push_refused))}"
32
- base = GitCommands.current_branch
33
- branche = "release/v#{version}"
34
- GitCommands.push_branch(branche)
35
- @terminal.done "git push origin #{branche}"
36
-
37
- jeton = @token_provider.call
38
- raise Messages.t(:pull_request_needs_token, branch: branche) unless jeton
39
-
40
- @terminal.done ReleasePullRequest.create(version: version, base: base, head: branche,
41
- remote_url: GitCommands.remote_url, token: jeton)
23
+ ProtectedBranchRelease.new(terminal: @terminal, token_provider: @token_provider).call(version)
42
24
  end
43
25
  end
44
26
  end
@@ -89,8 +89,8 @@ fr:
89
89
  bump_patch: Patch
90
90
  bump_minor: Minor
91
91
  bump_major: Major
92
- bump_pre: Itérer
93
- nothing_to_iterate: 'Pas de pré-release à itérer : saisissez x.y.z-alpha.1'
92
+ bump_pre: Incrémenter
93
+ nothing_to_iterate: 'Pas de pré-release à incrémenter : saisissez x.y.z-alpha.1'
94
94
  bump_promote: Promouvoir
95
95
  bump_from_prerelease: 'Impossible de faire un %{type} depuis une pré-release : promouvez-la ou saisissez une version.'
96
96
  prerelease_on_app: "Pré-release %{version} impossible : %{path} porte une version d'app, qui n'admet pas de suffixe."
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Relancer les Gemfile.lock que le bump a périmés, et le dire au fur et à mesure. Rend les
5
+ # locks relancés, qui partent dans le commit de version.
6
+ #
7
+ # Cette unité change quand la façon d'annoncer la relance change, GemfileLockRefresh quand
8
+ # la détection ou la relance changent, ReleaseCommand quand la suite des étapes change.
9
+ class LockfilesRefreshing
10
+ def initialize(terminal:, refresh: GemfileLockRefresh.new)
11
+ @terminal = terminal
12
+ @refresh = refresh
13
+ end
14
+
15
+ def call
16
+ locks = @refresh.lockfiles
17
+ return locks if locks.empty?
18
+
19
+ @terminal.say "\n#{@terminal.bold(Messages.t(:refreshing_lockfile))}"
20
+ @refresh.call(locks)
21
+ locks.each { |lock| @terminal.done lock }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Le repli quand une branche protégée refuse le push direct : pousser une branche de
5
+ # release et ouvrir la PR qui la ramène sur la branche de base. Le tag est déjà poussé et
6
+ # reste sur le commit de version : la release GitHub peut suivre, et un merge commit le
7
+ # ramène sur la branche de base.
8
+ #
9
+ # Cette unité change quand la politique de repli change, GitRelease quand la séquence
10
+ # git nominale change.
11
+ class ProtectedBranchRelease
12
+ def initialize(terminal:, token_provider:)
13
+ @terminal = terminal
14
+ @token_provider = token_provider
15
+ end
16
+
17
+ def call(version)
18
+ @terminal.say " #{@terminal.warn(Messages.t(:push_refused))}"
19
+ base = GitCommands.current_branch
20
+ branche = "release/v#{version}"
21
+ GitCommands.push_branch(branche)
22
+ @terminal.done "git push origin #{branche}"
23
+
24
+ jeton = @token_provider.call
25
+ raise Messages.t(:pull_request_needs_token, branch: branche) unless jeton
26
+
27
+ @terminal.done ReleasePullRequest.create(version: version, base: base, head: branche,
28
+ remote_url: GitCommands.remote_url, token: jeton)
29
+ end
30
+ end
31
+ end
@@ -30,16 +30,7 @@ module CaptiveRelease
30
30
  private
31
31
 
32
32
  def chemins_a_commiter
33
- chemins = @config.version_files.map(&:path)
34
- refresh = GemfileLockRefresh.new
35
- locks = refresh.lockfiles
36
- return chemins if locks.empty?
37
-
38
- @terminal.say "\n#{@terminal.bold(Messages.t(:refreshing_lockfile))}"
39
- refresh.call(locks)
40
- locks.each { |lock| @terminal.done lock }
41
-
42
- chemins + locks
33
+ @config.version_files.map(&:path) + LockfilesRefreshing.new(terminal: @terminal).call
43
34
  end
44
35
 
45
36
  def publication
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CaptiveRelease
4
- VERSION = "0.13.1"
4
+ VERSION = "0.14.0"
5
5
  end
@@ -3,9 +3,23 @@
3
3
  module CaptiveRelease
4
4
  # Quels fichiers d'un dépôt portent une version, et sous quel format.
5
5
  class VersionDetector
6
- RUBY_VERSION_PATTERN = /VERSION\s*=\s*["'].+?["']/
7
- EXPO_APP_JSON_PATTERN = /"expo"\s*:.*"version"\s*:/m
8
- GRADLE_PATH = %w[android app build.gradle].freeze
6
+ GRADLE_PATH = %w[android app build.gradle].freeze
7
+ CLAUDE_PLUGIN_PATH = %w[.claude-plugin plugin.json].freeze
8
+
9
+ # Où chercher, quel format y lire, et ce que le fichier doit contenir pour en être un.
10
+ RULES = [
11
+ [ %w[** package.json], "package_json" ],
12
+ [ %w[** app.config.js], "app_config_js" ],
13
+ [ %w[** app.json], "app_json", /"expo"\s*:.*"version"\s*:/m ],
14
+ [ %w[lib ** version.rb], "ruby_version", /VERSION\s*=\s*["'].+?["']/ ],
15
+ [ %w[** VERSION], "plain" ],
16
+ # Chemin fixe : un glob remonterait les build.gradle des modules Android embarqués, qui ne
17
+ # portent pas la version de l'app.
18
+ [ GRADLE_PATH, "android_gradle", /versionName\s+['"]/ ],
19
+ # Un dépôt publie un seul plugin : son manifeste est à la racine.
20
+ [ CLAUDE_PLUGIN_PATH, "claude_plugin", /"version"/ ],
21
+ [ %w[ios ** Info.plist], "ios_plist", /CFBundleShortVersionString/ ],
22
+ ].freeze
9
23
 
10
24
  def self.scan(root = ".")
11
25
  new(root).scan
@@ -16,33 +30,15 @@ module CaptiveRelease
16
30
  end
17
31
 
18
32
  def scan
19
- by_name("package.json", "package_json") +
20
- by_name("app.config.js", "app_config_js") +
21
- by_content(%w[** app.json], "app_json", EXPO_APP_JSON_PATTERN) +
22
- by_content(%w[lib ** version.rb], "ruby_version", RUBY_VERSION_PATTERN) +
23
- by_name("VERSION", "plain") +
24
- android_gradle +
25
- by_content(%w[ios ** Info.plist], "ios_plist", /CFBundleShortVersionString/)
33
+ RULES.flat_map { |segments, type, pattern| detect(segments, type, pattern) }
26
34
  end
27
35
 
28
36
  private
29
37
 
30
- def by_name(filename, type)
31
- @files.glob("**", filename).map { |chemin| version_file(chemin, type) }
32
- end
33
-
34
- def by_content(segments, type, pattern)
38
+ def detect(segments, type, pattern)
35
39
  @files.glob(*segments)
36
- .select { |chemin| contient?(chemin, pattern) }
37
- .map { |chemin| version_file(chemin, type) }
38
- end
39
-
40
- # Le build.gradle est à un chemin fixe : le chercher par glob remonterait ceux des
41
- # modules Android embarqués, qui ne portent pas la version de l'app.
42
- def android_gradle
43
- return [] unless contient?(@files.path(*GRADLE_PATH), /versionName\s+['"]/)
44
-
45
- [ VersionFile.new(GRADLE_PATH.join("/"), "android_gradle") ]
40
+ .select { |chemin| pattern.nil? || contient?(chemin, pattern) }
41
+ .map { |chemin| VersionFile.new(@files.relative(chemin), type) }
46
42
  end
47
43
 
48
44
  def contient?(chemin, pattern)
@@ -50,7 +46,5 @@ module CaptiveRelease
50
46
  rescue StandardError
51
47
  false
52
48
  end
53
-
54
- def version_file(chemin, type) = VersionFile.new(@files.relative(chemin), type)
55
49
  end
56
50
  end
@@ -15,6 +15,8 @@ module CaptiveRelease
15
15
  end
16
16
 
17
17
  def self.type_deduit(chemin)
18
+ return "claude_plugin" if chemin == VersionDetector::CLAUDE_PLUGIN_PATH.join("/")
19
+
18
20
  File.basename(chemin) == "package.json" ? "package_json" : "plain"
19
21
  end
20
22
  end
@@ -52,16 +52,19 @@ module CaptiveRelease
52
52
 
53
53
  PLIST_VALUE = %r{(?<=<string>).+?(?=</string>)}
54
54
 
55
+ PACKAGE_JSON = new(read: ->(content) { JSON.parse(content)["version"] },
56
+ write: lambda { |content, old, nouvelle|
57
+ content.gsub(/"version": "#{Regexp.escape(old)}"/, %("version": "#{nouvelle}"))
58
+ },
59
+ expected: %("version": "x.y.z"))
60
+
55
61
  FORMATS = {
56
62
  "plain" => new(read: ->(content) { content.strip },
57
63
  write: ->(_content, _old, nouvelle) { "#{nouvelle}\n" },
58
64
  expected: "x.y.z"),
59
- "package_json" => new(read: ->(content) { JSON.parse(content)["version"] },
60
- write: lambda { |content, old, nouvelle|
61
- content.gsub(/"version": "#{Regexp.escape(old)}"/,
62
- %("version": "#{nouvelle}"))
63
- },
64
- expected: %("version": "x.y.z")),
65
+ "package_json" => PACKAGE_JSON,
66
+ # Le manifeste d'un plugin Claude porte sa version comme un package.json.
67
+ "claude_plugin" => PACKAGE_JSON,
65
68
 
66
69
  "ruby_version" => RubyGemsVersion.new(
67
70
  by_pattern(/VERSION\s*=\s*["'](.+?)["']/, %(VERSION = "x.y.z")) { |occurrence, nouvelle|
@@ -43,7 +43,9 @@ require_relative "captive_release/menu"
43
43
  require_relative "captive_release/version_choice"
44
44
  require_relative "captive_release/gemfile_lock_refresh"
45
45
  require_relative "captive_release/exclusion_input"
46
+ require_relative "captive_release/lockfiles_refreshing"
46
47
  require_relative "captive_release/release_pull_request"
48
+ require_relative "captive_release/protected_branch_release"
47
49
  require_relative "captive_release/git_release"
48
50
  require_relative "captive_release/changes_since"
49
51
  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.13.1
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Captive Studio
@@ -52,11 +52,13 @@ files:
52
52
  - lib/captive_release/locale.rb
53
53
  - lib/captive_release/locales/en.yml
54
54
  - lib/captive_release/locales/fr.yml
55
+ - lib/captive_release/lockfiles_refreshing.rb
55
56
  - lib/captive_release/menu.rb
56
57
  - lib/captive_release/messages.rb
57
58
  - lib/captive_release/options.rb
58
59
  - lib/captive_release/prerelease_guard.rb
59
60
  - lib/captive_release/prerelease_iteration.rb
61
+ - lib/captive_release/protected_branch_release.rb
60
62
  - lib/captive_release/release_command.rb
61
63
  - lib/captive_release/release_confirmation.rb
62
64
  - lib/captive_release/release_notes.rb