captive-release 0.4.4 → 0.6.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: 53520ddc8d72e4aaba6efd5cf52398ddfb5b621316cd366269a9d3d3c78fa38e
4
- data.tar.gz: ed836c92b2e341a49b57136266a62e8a575ea97440db814f1b387ef9846cdc8d
3
+ metadata.gz: 2072f0317ade9acb540bdc600744ac8fafdb5a5dcab0ad4724b636edf6f58e15
4
+ data.tar.gz: ad06b764de6d66ae4c46de5209b52200fc56660765e5d084933bc731e016c81c
5
5
  SHA512:
6
- metadata.gz: a3c33fc6776c8dedee9e5686b6a59ff069a40035890097fc6a7c6f8f695dbabb3eaf86a6e4796c82f88c127818a99746019176f52d2dfd0cb14367fb8a27c843
7
- data.tar.gz: 50e1922a0ba1296719bab58e09cc1620b42e905adc75d4bd7653b7b3980b9fc8d71146f558a454d90fac2503c1ed77eb3ca3375beee8269f0ceb5bf21b7590bf
6
+ metadata.gz: f9d2674635c60e36badb978ada2917d2d233aab1d346786e17e4dc2c9c89d362dc3dccd21e2edeee46aa23fac787fb07cd6be7afc43a82328484f83444b93c8a
7
+ data.tar.gz: 4c528def9c38645ac72221918ecbfe10621e9a8fd7b6dab2d36d19148ccf1f03a65acd163f2eb557995027314b710528f4e0fc8897842ca53b926f74aa8b38f8
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Le garde-fou : si la version choisie est d'une sévérité inférieure à ce que les commits
5
+ # suggèrent, impose une confirmation explicite avant de continuer. Contrairement à
6
+ # confirmer!, une entrée vide refuse : c'est un avertissement, pas la confirmation normale.
7
+ class BumpSafetyNet
8
+ def initialize(terminal:)
9
+ @terminal = terminal
10
+ end
11
+
12
+ def verifier!(suggestion, courante, prochaine)
13
+ return unless suggestion
14
+
15
+ choisie = VersionSeverity.classify(from: courante, to: prochaine)
16
+ return if BumpSeverity::RANK.fetch(choisie, -1) >= BumpSeverity::RANK.fetch(suggestion)
17
+
18
+ avertir_et_confirmer!(suggestion, choisie)
19
+ end
20
+
21
+ private
22
+
23
+ def avertir_et_confirmer!(suggestion, choisie)
24
+ @terminal.say @terminal.warn(
25
+ "\n⚠️ Les commits suggèrent un bump #{suggestion}, mais la version choisie n'est qu'un #{choisie}.",
26
+ )
27
+ reponse = @terminal.ask("Continuer quand même ? [y/N] ").downcase
28
+ exit 1 unless reponse == "y"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # L'ordre de gravité partagé entre la suggestion (gitmoji) et le garde-fou (semver choisi) :
5
+ # dit ce qui prime quand les signaux sont mêlés, patch < minor < major.
6
+ module BumpSeverity
7
+ RANK = { "patch" => 0, "minor" => 1, "major" => 2 }.freeze
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # La sévérité de bump suggérée par les commits depuis le dernier tag - nil tant que ce tag
5
+ # n'existe pas, comme ChangesSince pour le lien de comparaison.
6
+ class BumpSuggestion
7
+ def self.for(version)
8
+ return nil unless GitCommands.tag?("v#{version}")
9
+
10
+ GitmojiSeverity.for(GitCommands.messages_since("v#{version}"))
11
+ rescue StandardError
12
+ nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Le lien vers les commits inclus depuis la dernière version taguée. Absent tant que ce
5
+ # tag n'existe pas ou que le remote ne mène pas à GitHub — la release continue sans lui.
6
+ #
7
+ # Cette unité change quand la façon de comparer deux versions change, ReleaseCommand quand
8
+ # le moment où on l'affiche change.
9
+ class ChangesSince
10
+ def self.url(version)
11
+ return nil unless GitCommands.tag?("v#{version}")
12
+
13
+ GithubRepo.from_remote(GitCommands.remote_url).compare_url("v#{version}", GitCommands.current_branch)
14
+ rescue StandardError
15
+ nil
16
+ end
17
+ end
18
+ end
@@ -10,6 +10,14 @@ module CaptiveRelease
10
10
 
11
11
  def self.remote_url = Shell.capture("git remote get-url origin 2>/dev/null")
12
12
 
13
+ def self.tag?(nom) = !Shell.capture("git tag -l #{nom} 2>/dev/null").empty?
14
+
15
+ # Les sujets de commit depuis le tag donné jusqu'à HEAD - la matière première de la
16
+ # suggestion de bump, un message par ligne, propre de toute ligne vide.
17
+ def self.messages_since(tag)
18
+ Shell.capture("git log --pretty=%s #{Shell.escape(tag)}..HEAD").lines.map(&:strip).reject(&:empty?)
19
+ end
20
+
13
21
  def self.current_branch
14
22
  branche = Shell.capture("git rev-parse --abbrev-ref HEAD 2>/dev/null")
15
23
  branche.empty? ? "main" : branche
@@ -25,5 +25,7 @@ module CaptiveRelease
25
25
  def path(suite) = "repos/#{owner}/#{repo}/#{suite}"
26
26
 
27
27
  def actions_url = "https://github.com/#{owner}/#{repo}/actions"
28
+
29
+ def compare_url(from, to) = "https://github.com/#{owner}/#{repo}/compare/#{from}...#{to}"
28
30
  end
29
31
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Traduit une liste de messages de commit en sévérité de bump suggérée : 💥 casse, ✨
5
+ # ajoute, tout le reste est un patch par défaut. Signaux mêlés : le plus sévère gagne.
6
+ class GitmojiSeverity
7
+ MAJOR = "💥"
8
+ MINOR = "✨"
9
+
10
+ def self.for(messages)
11
+ messages.reduce("patch") { |pire, message| plus_severe(pire, severity_of(message)) }
12
+ end
13
+
14
+ def self.severity_of(message)
15
+ return "major" if message.start_with?(MAJOR)
16
+ return "minor" if message.start_with?(MINOR)
17
+
18
+ "patch"
19
+ end
20
+ private_class_method :severity_of
21
+
22
+ def self.plus_severe(a, b) = BumpSeverity::RANK[a] >= BumpSeverity::RANK[b] ? a : b
23
+ private_class_method :plus_severe
24
+ end
25
+ end
@@ -17,9 +17,15 @@ module CaptiveRelease
17
17
  courante = @config.current_version
18
18
  @terminal.say "\n#{@terminal.bold("captive-release")}\n"
19
19
  @terminal.say "Current version: #{@terminal.bold(courante)}\n"
20
+ afficher_changements(courante)
21
+ suggestion = BumpSuggestion.for(courante)
22
+ afficher_suggestion(suggestion)
20
23
 
21
24
  prochaine = VersionChoice.new(terminal: @terminal).call(courante, bump_arg)
22
- confirmer!(prochaine) if confirmation
25
+ if confirmation
26
+ BumpSafetyNet.new(terminal: @terminal).verifier!(suggestion, courante, prochaine)
27
+ confirmer!(prochaine)
28
+ end
23
29
 
24
30
  VersionFilesWriting.new(terminal: @terminal).call(prochaine, @config.version_files)
25
31
  GitRelease.new(terminal: @terminal).call(prochaine, @config.version_files.map(&:path))
@@ -29,6 +35,20 @@ module CaptiveRelease
29
35
 
30
36
  private
31
37
 
38
+ def afficher_changements(courante)
39
+ lien = ChangesSince.url(courante)
40
+ return unless lien
41
+
42
+ @terminal.say "Changement : #{@terminal.link(lien)}\n\n"
43
+ end
44
+
45
+ def afficher_suggestion(suggestion)
46
+ return unless suggestion
47
+
48
+ detail = { "major" => "💥 détecté", "minor" => "✨ détecté", "patch" => "aucun commit notable détecté" }
49
+ @terminal.say "Suggestion : #{suggestion} (#{detail.fetch(suggestion)})\n"
50
+ end
51
+
32
52
  def confirmer!(version)
33
53
  @terminal.say "\nNew version: #{@terminal.bold(version)}"
34
54
  reponse = @terminal.ask("Confirm? [Y/n] ").downcase
@@ -28,10 +28,16 @@ module CaptiveRelease
28
28
  # finissaient par ne plus être les mêmes.
29
29
  def done(etape) = say(" #{ok("✅")} #{etape}")
30
30
 
31
- def bold(str) = "\e[1m#{str}\e[0m"
32
- def dim(str) = "\e[2m#{str}\e[0m"
33
- def ok(str) = "\e[32m#{str}\e[0m"
34
- def warn(str) = "\e[33m#{str}\e[0m"
35
- def error(str) = "\e[31m#{str}\e[0m"
31
+ # OSC 8 : le terminal affiche `texte` mais ouvre `url` au clic, sans exposer l'URL brute.
32
+ # Le texte est souligné pour signaler qu'il est cliquable, certains terminaux ne le faisant
33
+ # pas eux-mêmes pour les liens OSC 8.
34
+ def link(url, texte = url) = "\e]8;;#{url}\e\\#{underline(texte)}\e]8;;\e\\"
35
+
36
+ def bold(str) = "\e[1m#{str}\e[0m"
37
+ def underline(str) = "\e[4m#{str}\e[0m"
38
+ def dim(str) = "\e[2m#{str}\e[0m"
39
+ def ok(str) = "\e[32m#{str}\e[0m"
40
+ def warn(str) = "\e[33m#{str}\e[0m"
41
+ def error(str) = "\e[31m#{str}\e[0m"
36
42
  end
37
43
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CaptiveRelease
4
- VERSION = "0.4.4"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CaptiveRelease
4
+ # Classe la taille réelle d'un bump en comparant les composants major.minor.patch entre
5
+ # deux versions - y compris un semver tapé à la main, qui ne porte plus de "type" une fois
6
+ # sorti de VersionChoice.
7
+ class VersionSeverity
8
+ def self.classify(from:, to:)
9
+ depart = from.split(".").map(&:to_i)
10
+ arrivee = to.split(".").map(&:to_i)
11
+
12
+ return "major" if depart[0] != arrivee[0]
13
+ return "minor" if depart[1] != arrivee[1]
14
+ return "patch" if depart[2] != arrivee[2]
15
+
16
+ "other"
17
+ end
18
+ end
19
+ end
@@ -12,6 +12,11 @@ require_relative "captive_release/framework_detector"
12
12
  require_relative "captive_release/version_detector"
13
13
  require_relative "captive_release/shell"
14
14
  require_relative "captive_release/git_commands"
15
+ require_relative "captive_release/bump_severity"
16
+ require_relative "captive_release/gitmoji_severity"
17
+ require_relative "captive_release/bump_suggestion"
18
+ require_relative "captive_release/version_severity"
19
+ require_relative "captive_release/bump_safety_net"
15
20
  require_relative "captive_release/github_repo"
16
21
  require_relative "captive_release/github_http"
17
22
  require_relative "captive_release/github_api"
@@ -32,6 +37,7 @@ require_relative "captive_release/build_command"
32
37
  require_relative "captive_release/menu"
33
38
  require_relative "captive_release/version_choice"
34
39
  require_relative "captive_release/git_release"
40
+ require_relative "captive_release/changes_since"
35
41
  require_relative "captive_release/release_publication"
36
42
  require_relative "captive_release/version_files_writing"
37
43
  require_relative "captive_release/release_preconditions"
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.4
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Captive Studio
@@ -24,6 +24,10 @@ files:
24
24
  - lib/captive_release/build_config.rb
25
25
  - lib/captive_release/build_config_prompt.rb
26
26
  - lib/captive_release/build_dispatch_run.rb
27
+ - lib/captive_release/bump_safety_net.rb
28
+ - lib/captive_release/bump_severity.rb
29
+ - lib/captive_release/bump_suggestion.rb
30
+ - lib/captive_release/changes_since.rb
27
31
  - lib/captive_release/cli.rb
28
32
  - lib/captive_release/config.rb
29
33
  - lib/captive_release/config_file.rb
@@ -38,6 +42,7 @@ files:
38
42
  - lib/captive_release/github_release.rb
39
43
  - lib/captive_release/github_repo.rb
40
44
  - lib/captive_release/github_token.rb
45
+ - lib/captive_release/gitmoji_severity.rb
41
46
  - lib/captive_release/help.rb
42
47
  - lib/captive_release/init_command.rb
43
48
  - lib/captive_release/menu.rb
@@ -58,6 +63,7 @@ files:
58
63
  - lib/captive_release/version_files_argument.rb
59
64
  - lib/captive_release/version_files_writing.rb
60
65
  - lib/captive_release/version_format.rb
66
+ - lib/captive_release/version_severity.rb
61
67
  homepage: https://github.com/captive-studio/captive-release
62
68
  licenses:
63
69
  - MIT