captive-release 0.12.0 → 0.13.1
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 +3 -0
- data/lib/captive_release/git_commands.rb +9 -1
- data/lib/captive_release/git_release.rb +24 -4
- data/lib/captive_release/github_api.rb +9 -0
- data/lib/captive_release/github_dispatch.rb +15 -0
- data/lib/captive_release/locales/en.yml +6 -0
- data/lib/captive_release/locales/fr.yml +6 -0
- data/lib/captive_release/release_command.rb +1 -1
- data/lib/captive_release/release_pull_request.rb +26 -0
- data/lib/captive_release/shell.rb +3 -0
- data/lib/captive_release/update_check.rb +1 -1
- data/lib/captive_release/version.rb +1 -1
- 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: b02b5a5f09284656a970f59483743859269916f30e253648baa2d0f2fbadbb36
|
|
4
|
+
data.tar.gz: d198e07c7ed8d9875baf64a01fa49dd5cf8e3d361e91d035f0c876ba196fc092
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2fa91cd1c63ba4d1b423979d5aa1b40445fa31e91aafd386baed6e4a1da5eb7b776c4c43f14772e2309f32c8b187cd77d25da4e8bc8b227521edc683f0a0115
|
|
7
|
+
data.tar.gz: 8c29dc85a62025e705c5b111137d964b1d76d103cdf6caa044440f64557032a52fe7f15a29814d9ba10d91904ab7abe0df5102928e6c13f9be59fb5a2353ba8f
|
|
@@ -41,9 +41,17 @@ module CaptiveRelease
|
|
|
41
41
|
# Le tag part avant HEAD : au moment où le webhook du push sur main arrive, le tag existe
|
|
42
42
|
# déjà. Dans l'autre sens, demander « ce sha porte-t-il un tag v* ? » répond non presque
|
|
43
43
|
# toujours, et la même release se construit deux fois.
|
|
44
|
+
#
|
|
45
|
+
# Le refus de HEAD se rend plutôt qu'il ne lève : une branche protégée refuse le push
|
|
46
|
+
# direct, et la release se replie alors sur une pull request.
|
|
44
47
|
def self.push(version)
|
|
45
48
|
Shell.run! "git push origin v#{version}"
|
|
46
|
-
Shell.run
|
|
49
|
+
Shell.run? "git push origin HEAD"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Pousse HEAD sous un autre nom sans quitter la branche courante.
|
|
53
|
+
def self.push_branch(nom)
|
|
54
|
+
Shell.run! "git push origin HEAD:refs/heads/#{Shell.escape(nom)}"
|
|
47
55
|
end
|
|
48
56
|
end
|
|
49
57
|
end
|
|
@@ -7,8 +7,9 @@ module CaptiveRelease
|
|
|
7
7
|
# change. Chaque étape est annoncée au fur et à mesure : une release qui s'arrête doit
|
|
8
8
|
# laisser voir jusqu'où elle est allée.
|
|
9
9
|
class GitRelease
|
|
10
|
-
def initialize(terminal:)
|
|
11
|
-
@terminal
|
|
10
|
+
def initialize(terminal:, token_provider:)
|
|
11
|
+
@terminal = terminal
|
|
12
|
+
@token_provider = token_provider
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def call(version, paths)
|
|
@@ -17,8 +18,27 @@ module CaptiveRelease
|
|
|
17
18
|
@terminal.done %(git commit "🔖 Set version v#{version}")
|
|
18
19
|
GitCommands.tag(version)
|
|
19
20
|
@terminal.done "git tag v#{version}"
|
|
20
|
-
GitCommands.push(version)
|
|
21
|
-
|
|
21
|
+
return @terminal.done("git push + tag") if GitCommands.push(version)
|
|
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)
|
|
22
42
|
end
|
|
23
43
|
end
|
|
24
44
|
end
|
|
@@ -25,6 +25,15 @@ module CaptiveRelease
|
|
|
25
25
|
|
|
26
26
|
def get(chemin) = analyser(@http.get(adresse(chemin)), "200")
|
|
27
27
|
|
|
28
|
+
# Un 404 dit l'absence ; tout autre échec reste une erreur plutôt qu'une absence supposée.
|
|
29
|
+
def existe?(chemin)
|
|
30
|
+
reponse = @http.get(adresse(chemin))
|
|
31
|
+
return false if reponse.code == "404"
|
|
32
|
+
|
|
33
|
+
analyser(reponse, "200")
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
28
37
|
def post(chemin, corps, attendu:)
|
|
29
38
|
analyser(@http.post(adresse(chemin), JSON.generate(corps)), attendu)
|
|
30
39
|
end
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
require_relative "github_api"
|
|
4
4
|
|
|
5
5
|
module CaptiveRelease
|
|
6
|
+
# Le workflow demandé n'existe pas sur la branche par défaut du dépôt, seule que GitHub
|
|
7
|
+
# consulte pour accepter un dispatch.
|
|
8
|
+
class WorkflowIntrouvable < StandardError; end
|
|
9
|
+
|
|
6
10
|
# Déclenche un workflow GitHub Actions. Elle compose ce qu'elle demande ; l'API, son
|
|
7
11
|
# authentification et ses échecs vivent dans GithubApi.
|
|
8
12
|
class GithubDispatch
|
|
@@ -16,10 +20,21 @@ module CaptiveRelease
|
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
def dispatch(workflow_file:, ref:, inputs:)
|
|
23
|
+
exiger(workflow_file)
|
|
19
24
|
@api.post("actions/workflows/#{workflow_file}/dispatches",
|
|
20
25
|
{ "ref" => ref, "inputs" => inputs }, attendu: "204")
|
|
21
26
|
|
|
22
27
|
@api.depot.actions_url
|
|
23
28
|
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def exiger(workflow_file)
|
|
33
|
+
return if @api.existe?("actions/workflows/#{workflow_file}")
|
|
34
|
+
|
|
35
|
+
depot = @api.depot
|
|
36
|
+
raise WorkflowIntrouvable, Messages.t(:workflow_not_found, workflow: workflow_file,
|
|
37
|
+
repo: "#{depot.owner}/#{depot.repo}")
|
|
38
|
+
end
|
|
24
39
|
end
|
|
25
40
|
end
|
|
@@ -73,6 +73,9 @@ en:
|
|
|
73
73
|
dispatch_branch: 'Branch: %{value}'
|
|
74
74
|
dispatching: Dispatching...
|
|
75
75
|
build_dispatched: Build dispatched!
|
|
76
|
+
workflow_not_found: |-
|
|
77
|
+
Workflow %{workflow} not found on %{repo}.
|
|
78
|
+
Add .github/workflows/%{workflow} to the default branch, or fix build_workflow in the configuration.
|
|
76
79
|
dirty_tree: The working tree is not clean.
|
|
77
80
|
dirty_tree_hint: Commit or stash your changes before releasing.
|
|
78
81
|
current_version: 'Current version: %{version}'
|
|
@@ -102,6 +105,9 @@ en:
|
|
|
102
105
|
updating_version_files: Updating version files...
|
|
103
106
|
refreshing_lockfile: Refreshing Gemfile.lock...
|
|
104
107
|
running_git: Running git commands...
|
|
108
|
+
push_refused: "⚠️ Direct push refused (protected branch?) - falling back to a pull request."
|
|
109
|
+
pull_request_needs_token: 'GITHUB_TOKEN required to open the pull request: branch %{branch} is pushed, open it by hand.'
|
|
110
|
+
pull_request_body: "Direct push to %{base} was refused. Merge with a **merge commit**: a squash or a rebase would change the sha, and tag v%{version} would no longer be on %{base}."
|
|
105
111
|
creating_github_release: Creating GitHub release...
|
|
106
112
|
no_token_skip_release: "⚠️ GITHUB_TOKEN not set - skipping GitHub release creation."
|
|
107
113
|
released: Version v%{version} released successfully!
|
|
@@ -73,6 +73,9 @@ fr:
|
|
|
73
73
|
dispatch_branch: 'Branche : %{value}'
|
|
74
74
|
dispatching: Déclenchement...
|
|
75
75
|
build_dispatched: Build déclenché !
|
|
76
|
+
workflow_not_found: |-
|
|
77
|
+
Workflow %{workflow} introuvable sur %{repo}.
|
|
78
|
+
Ajoutez .github/workflows/%{workflow} sur la branche par défaut, ou corrigez build_workflow dans la configuration.
|
|
76
79
|
dirty_tree: L'arbre de travail n'est pas propre.
|
|
77
80
|
dirty_tree_hint: Commitez ou remisez vos modifications avant de releaser.
|
|
78
81
|
current_version: 'Version actuelle : %{version}'
|
|
@@ -102,6 +105,9 @@ fr:
|
|
|
102
105
|
updating_version_files: Mise à jour des fichiers de version...
|
|
103
106
|
refreshing_lockfile: Rafraîchissement du Gemfile.lock...
|
|
104
107
|
running_git: Exécution des commandes git...
|
|
108
|
+
push_refused: "⚠️ Push direct refusé (branche protégée ?) - repli sur une pull request."
|
|
109
|
+
pull_request_needs_token: 'GITHUB_TOKEN requis pour ouvrir la pull request : la branche %{branch} est poussée, ouvrez-la à la main.'
|
|
110
|
+
pull_request_body: "Le push direct sur %{base} a été refusé. Mergez avec un **merge commit** : un squash ou un rebase changerait le sha, et le tag v%{version} ne serait plus sur %{base}."
|
|
105
111
|
creating_github_release: Création de la release GitHub...
|
|
106
112
|
no_token_skip_release: "⚠️ GITHUB_TOKEN absent - la release GitHub n'est pas créée."
|
|
107
113
|
released: Version v%{version} publiée avec succès !
|
|
@@ -22,7 +22,7 @@ module CaptiveRelease
|
|
|
22
22
|
ReleaseConfirmation.new(terminal: @terminal).verifier!(suggestion, courante, prochaine) if confirmation
|
|
23
23
|
|
|
24
24
|
VersionFilesWriting.new(terminal: @terminal).call(prochaine, @config.version_files)
|
|
25
|
-
GitRelease.new(terminal: @terminal).call(prochaine, chemins_a_commiter)
|
|
25
|
+
GitRelease.new(terminal: @terminal, token_provider: @token_provider).call(prochaine, chemins_a_commiter)
|
|
26
26
|
publication.call(prochaine)
|
|
27
27
|
@terminal.say "\n🎉 #{@terminal.bold(Messages.t(:released, version: prochaine))}\n"
|
|
28
28
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "github_api"
|
|
4
|
+
|
|
5
|
+
module CaptiveRelease
|
|
6
|
+
# Ouvre la pull request d'une release que la branche protégée a refusée en push direct.
|
|
7
|
+
# Elle compose ce qu'elle demande ; l'API, son authentification et ses échecs vivent dans
|
|
8
|
+
# GithubApi.
|
|
9
|
+
class ReleasePullRequest
|
|
10
|
+
def self.create(version:, base:, head:, remote_url:, token:, api: nil)
|
|
11
|
+
api ||= GithubApi.new(remote_url: remote_url, token: token)
|
|
12
|
+
new(api).create(version, base: base, head: head)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(api)
|
|
16
|
+
@api = api
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create(version, base:, head:)
|
|
20
|
+
@api.post("pulls",
|
|
21
|
+
{ "title" => "🔖 Set version v#{version}", "head" => head, "base" => base,
|
|
22
|
+
"body" => Messages.t(:pull_request_body, base: base, version: version), },
|
|
23
|
+
attendu: "201")["html_url"]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -11,6 +11,9 @@ module CaptiveRelease
|
|
|
11
11
|
system(commande) || raise(Messages.t(:command_failed, command: commande))
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
# Pour une commande dont l'échec est une issue attendue, que l'appelant traite.
|
|
15
|
+
def self.run?(commande) = system(commande)
|
|
16
|
+
|
|
14
17
|
def self.capture(commande) = `#{commande}`.strip
|
|
15
18
|
|
|
16
19
|
def self.capture_lines(commande) = capture(commande).lines.map(&:strip).reject(&:empty?)
|
|
@@ -29,7 +29,7 @@ module CaptiveRelease
|
|
|
29
29
|
derniere = @thread&.join(ATTENTE)&.value
|
|
30
30
|
return unless derniere && Gem::Version.new(derniere) > Gem::Version.new(courante)
|
|
31
31
|
|
|
32
|
-
@output.puts "\e[
|
|
32
|
+
@output.puts "\e[33m#{Messages.t(:update_available, current: courante, latest: derniere)}\e[0m"
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
private
|
data/lib/captive_release.rb
CHANGED
|
@@ -43,6 +43,7 @@ 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/release_pull_request"
|
|
46
47
|
require_relative "captive_release/git_release"
|
|
47
48
|
require_relative "captive_release/changes_since"
|
|
48
49
|
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.
|
|
4
|
+
version: 0.13.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Captive Studio
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/captive_release/release_overview.rb
|
|
64
64
|
- lib/captive_release/release_preconditions.rb
|
|
65
65
|
- lib/captive_release/release_publication.rb
|
|
66
|
+
- lib/captive_release/release_pull_request.rb
|
|
66
67
|
- lib/captive_release/repo_files.rb
|
|
67
68
|
- lib/captive_release/ruby_gems_version.rb
|
|
68
69
|
- lib/captive_release/semver.rb
|