captive-release 0.13.2 → 0.15.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/build_dispatch_run.rb +7 -5
- data/lib/captive_release/build_tag.rb +35 -0
- data/lib/captive_release/git_commands.rb +16 -0
- data/lib/captive_release/locales/en.yml +3 -0
- data/lib/captive_release/locales/fr.yml +3 -0
- data/lib/captive_release/version.rb +1 -1
- data/lib/captive_release/version_detector.rb +21 -27
- data/lib/captive_release/version_files_argument.rb +2 -0
- data/lib/captive_release/version_format.rb +9 -6
- data/lib/captive_release.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 615663c58dbf71da94afba56edf11a7c269c288e419458ab147109174cb32b70
|
|
4
|
+
data.tar.gz: c00fa194187b633dd2b2560cb14f5fce0b9de2247734c3f5cb1caf8ba23cbade
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 98ec33d80bc912c27c262225173c783aa94d34013219377dab148ce633f975f14cd8214e17d7e25608d03ea79c8b2bcde1b3549840ada1665881a2448bd7170e
|
|
7
|
+
data.tar.gz: 516607116274624df99f5a98ce15cf13881e1fb75d697fc7e451eb8258f1b14fcede77c5855fb3045bcb78f51755c484fd7f9c7b25876bebd16a6a264d7cefa2
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module CaptiveRelease
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# Tague le commit du build, puis déclenche le workflow sur la branche courante après avoir dit
|
|
5
|
+
# ce qu'il va faire : profil, workflow, branche et tag sont ce qu'on vérifie avant de lancer.
|
|
6
6
|
#
|
|
7
7
|
# Cette unité change quand ce qu'on déclenche change, BuildCommand quand la façon de
|
|
8
8
|
# constituer la demande change.
|
|
@@ -13,7 +13,8 @@ module CaptiveRelease
|
|
|
13
13
|
|
|
14
14
|
def call(profil:, workflow:, jeton:)
|
|
15
15
|
branche = GitCommands.current_branch
|
|
16
|
-
|
|
16
|
+
tag = BuildTag.pose!
|
|
17
|
+
annoncer(profil, workflow, branche, tag)
|
|
17
18
|
|
|
18
19
|
url = GithubDispatch.dispatch(workflow_file: workflow, ref: branche,
|
|
19
20
|
inputs: { "profile" => profil },
|
|
@@ -21,17 +22,18 @@ module CaptiveRelease
|
|
|
21
22
|
|
|
22
23
|
@terminal.done Messages.t(:build_dispatched)
|
|
23
24
|
@terminal.say " #{url}\n"
|
|
24
|
-
rescue WorkflowIntrouvable => e
|
|
25
|
+
rescue WorkflowIntrouvable, BuildTagImpossible => e
|
|
25
26
|
@terminal.say @terminal.error(e.message)
|
|
26
27
|
exit 1
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
private
|
|
30
31
|
|
|
31
|
-
def annoncer(profil, workflow, branche)
|
|
32
|
+
def annoncer(profil, workflow, branche, tag)
|
|
32
33
|
@terminal.say Messages.t(:dispatch_profile, value: @terminal.bold(profil))
|
|
33
34
|
@terminal.say Messages.t(:dispatch_workflow, value: @terminal.bold(workflow))
|
|
34
35
|
@terminal.say Messages.t(:dispatch_branch, value: @terminal.bold(branche))
|
|
36
|
+
@terminal.say Messages.t(:dispatch_tag, value: @terminal.bold(tag))
|
|
35
37
|
@terminal.say "\n#{Messages.t(:dispatching)}\n"
|
|
36
38
|
end
|
|
37
39
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CaptiveRelease
|
|
4
|
+
# Le build ne peut pas être tagué : HEAD absent du remote, ou aucun tag de release.
|
|
5
|
+
class BuildTagImpossible < StandardError; end
|
|
6
|
+
|
|
7
|
+
# Le tag qui marque le commit d'un build : build/<prochaine version>-build.<N>+g<sha>.
|
|
8
|
+
#
|
|
9
|
+
# Il ne commence jamais par v, préfixe qui déclenche les déploiements. Sans build/, il reste
|
|
10
|
+
# un semver qui se trie entre la release qu'il suit et la suivante.
|
|
11
|
+
module BuildTag
|
|
12
|
+
DESCRIBE = /\Av(?<version>.+)-(?<distance>\d+)-(?<sha>g\h+)\z/
|
|
13
|
+
|
|
14
|
+
def self.pose!
|
|
15
|
+
raise BuildTagImpossible, Messages.t(:build_head_not_pushed) unless GitCommands.head_pushed?
|
|
16
|
+
|
|
17
|
+
tag = nom(GitCommands.describe_release)
|
|
18
|
+
GitCommands.tag_and_push(tag)
|
|
19
|
+
tag
|
|
20
|
+
rescue RuntimeError => e # tag ou push refusé par git : un message, pas une trace
|
|
21
|
+
raise BuildTagImpossible, e.message
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Depuis une pré-release, la prochaine version est son cœur : on prolonge la pré-release
|
|
25
|
+
# plutôt que de viser un patch qui sortirait après elle.
|
|
26
|
+
def self.nom(describe)
|
|
27
|
+
morceaux = describe.match(DESCRIBE)
|
|
28
|
+
raise BuildTagImpossible, Messages.t(:build_no_release_tag) unless morceaux && Semver.valid?(morceaux[:version])
|
|
29
|
+
|
|
30
|
+
version, distance, sha = morceaux.values_at(:version, :distance, :sha)
|
|
31
|
+
base = Semver.prerelease?(version) ? "#{version}." : "#{VersionBumper.bump(version, "patch")}-"
|
|
32
|
+
"build/#{base}build.#{distance}+#{sha}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -49,6 +49,22 @@ module CaptiveRelease
|
|
|
49
49
|
Shell.run? "git push origin HEAD"
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
# --match ignore les tags build/ : seul un tag de release sert de point de départ.
|
|
53
|
+
def self.describe_release
|
|
54
|
+
Shell.capture("git describe --tags --long --match 'v[0-9]*' 2>/dev/null")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Vu depuis les branches de suivi locales : un commit qu'aucune ne contient n'existe pas
|
|
58
|
+
# pour le workflow qui le buildera.
|
|
59
|
+
def self.head_pushed? = !Shell.capture("git branch -r --contains HEAD 2>/dev/null").empty?
|
|
60
|
+
|
|
61
|
+
# Relancer un build sur le même commit retombe sur le même tag : on le repousse sans
|
|
62
|
+
# le recréer.
|
|
63
|
+
def self.tag_and_push(nom)
|
|
64
|
+
Shell.run! "git tag #{Shell.escape(nom)}" unless tag?(Shell.escape(nom))
|
|
65
|
+
Shell.run! "git push origin refs/tags/#{Shell.escape(nom)}"
|
|
66
|
+
end
|
|
67
|
+
|
|
52
68
|
# Pousse HEAD sous un autre nom sans quitter la branche courante.
|
|
53
69
|
def self.push_branch(nom)
|
|
54
70
|
Shell.run! "git push origin HEAD:refs/heads/#{Shell.escape(nom)}"
|
|
@@ -71,6 +71,9 @@ en:
|
|
|
71
71
|
dispatch_profile: 'Profile: %{value}'
|
|
72
72
|
dispatch_workflow: 'Workflow: %{value}'
|
|
73
73
|
dispatch_branch: 'Branch: %{value}'
|
|
74
|
+
build_head_not_pushed: HEAD is not pushed to the remote. Push the branch before building.
|
|
75
|
+
build_no_release_tag: No v* release tag found. Make a first release with captive-release new.
|
|
76
|
+
dispatch_tag: 'Tag: %{value}'
|
|
74
77
|
dispatching: Dispatching...
|
|
75
78
|
build_dispatched: Build dispatched!
|
|
76
79
|
workflow_not_found: |-
|
|
@@ -71,6 +71,9 @@ fr:
|
|
|
71
71
|
dispatch_profile: 'Profil : %{value}'
|
|
72
72
|
dispatch_workflow: 'Workflow : %{value}'
|
|
73
73
|
dispatch_branch: 'Branche : %{value}'
|
|
74
|
+
build_head_not_pushed: HEAD n'est pas poussé sur le remote. Poussez la branche avant de lancer le build.
|
|
75
|
+
build_no_release_tag: Aucun tag de release v* trouvé. Faites une première release avec captive-release new.
|
|
76
|
+
dispatch_tag: 'Tag : %{value}'
|
|
74
77
|
dispatching: Déclenchement...
|
|
75
78
|
build_dispatched: Build déclenché !
|
|
76
79
|
workflow_not_found: |-
|
|
@@ -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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
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
|
|
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|
|
|
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
|
|
@@ -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"
|
|
60
|
-
|
|
61
|
-
|
|
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|
|
data/lib/captive_release.rb
CHANGED
|
@@ -37,6 +37,7 @@ require_relative "captive_release/config_writer"
|
|
|
37
37
|
require_relative "captive_release/version_files_argument"
|
|
38
38
|
require_relative "captive_release/version_file_bootstrap"
|
|
39
39
|
require_relative "captive_release/init_command"
|
|
40
|
+
require_relative "captive_release/build_tag"
|
|
40
41
|
require_relative "captive_release/build_dispatch_run"
|
|
41
42
|
require_relative "captive_release/build_command"
|
|
42
43
|
require_relative "captive_release/menu"
|
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.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Captive Studio
|
|
@@ -24,6 +24,7 @@ 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/build_tag.rb
|
|
27
28
|
- lib/captive_release/bump_safety_net.rb
|
|
28
29
|
- lib/captive_release/bump_severity.rb
|
|
29
30
|
- lib/captive_release/bump_suggestion.rb
|