discharger 0.5.1 → 0.5.2
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/CHANGELOG.md +8 -15
- data/README.md +6 -5
- data/lib/discharger/setup_runner/commands/bundler_command.rb +1 -0
- data/lib/discharger/setup_runner/commands/database_command.rb +1 -2
- data/lib/discharger/setup_runner/commands/github_packages_command.rb +26 -55
- data/lib/discharger/setup_runner/configuration.rb +3 -1
- data/lib/discharger/setup_runner/prerequisites_loader.rb +8 -4
- data/lib/discharger/setup_runner/runner.rb +0 -14
- data/lib/discharger/version.rb +1 -1
- data/lib/generators/discharger/install/templates/setup +27 -6
- data/lib/generators/discharger/install/templates/setup.yml +7 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e92d9aa7bcc8894b1db11f44195b1fc5ac26d7995debf672867d4739b8bf3002
|
|
4
|
+
data.tar.gz: a813680ef1fdecbaf8ae436b47d8f11e2d2d2a306dea0f6de03fbbe085035b9f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 957623082c1bd56b60223cf6c940bbed32c46612daad4baaf2fd2ad542f297637ecd0aee033ce50c75ba42cefc43299a35e48d603b373b723c688a91340bf01f
|
|
7
|
+
data.tar.gz: b28f208e2e4057f8d795d01600d840e3634bf75f88968852278bfe624b6a570135a6dda25aa0f95a3b9fb0e489e2950d4c4dcc459639da365e30f84e0073b8bf
|
data/CHANGELOG.md
CHANGED
|
@@ -5,30 +5,23 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
7
7
|
|
|
8
|
-
## [0.5.
|
|
9
|
-
|
|
10
|
-
## [0.5.0] - 2026-10-02
|
|
8
|
+
## [0.5.2] - 2026-10-05
|
|
11
9
|
|
|
12
10
|
### Added
|
|
13
11
|
|
|
14
|
-
-
|
|
12
|
+
- github_packages.gh_timeout in setup.yml sets the gh deadline (e7d7620)
|
|
13
|
+
- pre_steps print elapsed time (9bdb05f)
|
|
15
14
|
|
|
16
15
|
### Changed
|
|
17
16
|
|
|
18
|
-
-
|
|
19
|
-
- rake release refuses to reset the working branch over unpushed local commits (6d87ce7)
|
|
20
|
-
- rake release tags the release commit on the working branch and pushes the tag; nothing merges into a production branch (af4484d)
|
|
21
|
-
- working_branch defaults to main (af4484d)
|
|
22
|
-
- rake release checks the tree, unpushed commits, the release commit and the tag before asking to confirm (af4484d)
|
|
23
|
-
- rake release stops with a clear message when the version's tag already exists on origin (af4484d)
|
|
17
|
+
- github_packages step only checks the gh token; bin/setup stores credentials (e7d7620)
|
|
24
18
|
|
|
25
19
|
### Removed
|
|
26
20
|
|
|
27
|
-
-
|
|
28
|
-
- release:stage, release:build and DISCHARGER_BUILD_BRANCH (af4484d)
|
|
29
|
-
- the runbook preview on the stage build (af4484d)
|
|
21
|
+
- the unreachable seed_env option (8b7c654)
|
|
30
22
|
|
|
31
23
|
### Fixed
|
|
32
24
|
|
|
33
|
-
-
|
|
34
|
-
|
|
25
|
+
- gh calls in setup time out after 15s instead of hanging (e7d7620)
|
|
26
|
+
|
|
27
|
+
## [0.5.1] - 2026-10-02
|
data/README.md
CHANGED
|
@@ -195,7 +195,8 @@ You can rerun it whenever your environment drifts. Every run drops and rebuilds
|
|
|
195
195
|
It works on a fresh clone with no gems installed. The generated script first runs a
|
|
196
196
|
standard-library-only pass that stores bundler credentials for a configured
|
|
197
197
|
`github_packages` source (from your GitHub CLI login, only once the source
|
|
198
|
-
accepts that token
|
|
198
|
+
accepts that token; gh calls time out after `github_packages.gh_timeout` seconds,
|
|
199
|
+
15 by default, or `DISCHARGER_GH_TIMEOUT`), installs the bundle, and then
|
|
199
200
|
re-execs itself under `bundle exec` so default gems such as psych never clash with
|
|
200
201
|
`Gemfile.lock`. The `DISCHARGER_SETUP_BUNDLED` environment variable marks the second
|
|
201
202
|
pass; the `github_packages` step later verifies the stored credentials and warns when
|
|
@@ -204,8 +205,8 @@ creates every missing counterpart of `config/**/*.example` and `.env.example`, s
|
|
|
204
205
|
app whose boot needs `.env` or `config/database.yml` gets them without copying
|
|
205
206
|
them in `pre_steps`.
|
|
206
207
|
|
|
207
|
-
Each step prints its elapsed time when it finishes, and the closing line
|
|
208
|
-
total, so a slow setup shows which step to look at.
|
|
208
|
+
Each pre_step and step prints its elapsed time when it finishes, and the closing line
|
|
209
|
+
reports the total, so a slow setup shows which step to look at.
|
|
209
210
|
|
|
210
211
|
### Keeping bin/setup Generated
|
|
211
212
|
|
|
@@ -307,8 +308,8 @@ The `steps` array specifies which built-in setup commands to run. Available comm
|
|
|
307
308
|
- `brew` - Install Homebrew dependencies
|
|
308
309
|
- `asdf` - Setup version management with asdf
|
|
309
310
|
- `git` - Configure git settings
|
|
310
|
-
- `github_packages` -
|
|
311
|
-
- `bundler` - Install Ruby gems
|
|
311
|
+
- `github_packages` - Check the GitHub CLI token against a private GitHub Packages gem source; the generated `bin/setup` stores the credentials (requires a `github_packages.source` config entry)
|
|
312
|
+
- `bundler` - Install Ruby gems; a check under the generated `bin/setup`, whose first pass already installed the bundle
|
|
312
313
|
- `yarn` - Install JavaScript packages
|
|
313
314
|
- `config` - Copy Procfile.dev to Procfile and any example config file still missing
|
|
314
315
|
- `docker` - Setup Docker containers
|
|
@@ -31,9 +31,8 @@ module Discharger
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# Seed the database
|
|
34
|
-
seed_env = db_env.merge((config.respond_to?(:seed_env) && config.seed_env) ? {"SEED_DEV_ENV" => "true"} : {})
|
|
35
34
|
with_spinner("Seeding the database") do
|
|
36
|
-
_stdout, stderr, status = Open3.capture3(
|
|
35
|
+
_stdout, stderr, status = Open3.capture3(db_env, "bin/rails", "db:seed")
|
|
37
36
|
if status.success?
|
|
38
37
|
{success: true}
|
|
39
38
|
else
|
|
@@ -5,43 +5,10 @@ require_relative "base_command"
|
|
|
5
5
|
module Discharger
|
|
6
6
|
module SetupRunner
|
|
7
7
|
module Commands
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# the source rejects is not stored, so it cannot shadow a working
|
|
11
|
-
# credential in the user's own bundler config. Credentials are written
|
|
12
|
-
# to the app's .bundle/config — keep .bundle gitignored. Run this step
|
|
13
|
-
# before "bundler" in setup.yml.
|
|
8
|
+
# Checks the gh token against the GitHub Packages source; bin/setup
|
|
9
|
+
# stored the credentials. The template's first pass mirrors this.
|
|
14
10
|
class GithubPackagesCommand < BaseCommand
|
|
15
|
-
|
|
16
|
-
# is inert, and the only symptom is bundler failing against the
|
|
17
|
-
# private source. The Runner surfaces this before executing commands.
|
|
18
|
-
# Guarded for duck-typed configs passed to the public Runner API, and
|
|
19
|
-
# quiet when a custom step's command references the source (assumed
|
|
20
|
-
# to handle credentials itself).
|
|
21
|
-
def self.unscheduled_warning(config)
|
|
22
|
-
return unless config.respond_to?(:github_packages)
|
|
23
|
-
|
|
24
|
-
source = config.github_packages&.source
|
|
25
|
-
return if source.to_s.empty?
|
|
26
|
-
if config.respond_to?(:custom_steps) &&
|
|
27
|
-
config.custom_steps.any? { |step| step_handles_source?(step, source) }
|
|
28
|
-
return
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
"github_packages is configured but missing from steps; " \
|
|
32
|
-
"credentials will not be stored and bundler may fail for #{source}"
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# A referencing step only counts as handling credentials when it will
|
|
36
|
-
# actually run: CustomCommand skips itself when its condition is
|
|
37
|
-
# false, storing nothing on this run.
|
|
38
|
-
def self.step_handles_source?(step, source)
|
|
39
|
-
return false unless step["command"].to_s.include?(source)
|
|
40
|
-
|
|
41
|
-
require_relative "../condition_evaluator"
|
|
42
|
-
ConditionEvaluator.evaluate(step["condition"])
|
|
43
|
-
end
|
|
44
|
-
private_class_method :step_handles_source?
|
|
11
|
+
GH_TIMEOUT_SECONDS = 15
|
|
45
12
|
|
|
46
13
|
def execute
|
|
47
14
|
unless gh_installed?
|
|
@@ -61,14 +28,12 @@ module Discharger
|
|
|
61
28
|
return
|
|
62
29
|
end
|
|
63
30
|
|
|
64
|
-
|
|
65
|
-
log "
|
|
66
|
-
|
|
67
|
-
|
|
31
|
+
if source_accepts_token?(username, token)
|
|
32
|
+
log "#{source} accepts the gh token"
|
|
33
|
+
else
|
|
34
|
+
log "#{source} did not accept the gh token. It may lack the read:packages scope — " \
|
|
35
|
+
"run `gh auth refresh -s read:packages` and rerun setup."
|
|
68
36
|
end
|
|
69
|
-
|
|
70
|
-
store_bundler_credentials(username, token)
|
|
71
|
-
log "Configured bundler credentials for #{source}"
|
|
72
37
|
end
|
|
73
38
|
|
|
74
39
|
def can_execute?
|
|
@@ -76,7 +41,7 @@ module Discharger
|
|
|
76
41
|
end
|
|
77
42
|
|
|
78
43
|
def description
|
|
79
|
-
"
|
|
44
|
+
"Check GitHub Packages credentials"
|
|
80
45
|
end
|
|
81
46
|
|
|
82
47
|
protected
|
|
@@ -90,7 +55,7 @@ module Discharger
|
|
|
90
55
|
end
|
|
91
56
|
|
|
92
57
|
def authenticated?
|
|
93
|
-
|
|
58
|
+
!gh("auth", "status").nil?
|
|
94
59
|
end
|
|
95
60
|
|
|
96
61
|
def login
|
|
@@ -102,18 +67,24 @@ module Discharger
|
|
|
102
67
|
|
|
103
68
|
def gh(*args)
|
|
104
69
|
require "open3"
|
|
105
|
-
|
|
106
|
-
|
|
70
|
+
Open3.popen2("gh", *args, err: File::NULL) do |stdin, stdout, wait|
|
|
71
|
+
stdin.close
|
|
72
|
+
out = Thread.new { stdout.read }
|
|
73
|
+
if wait.join(gh_timeout)
|
|
74
|
+
out.value.chomp if wait.value.success?
|
|
75
|
+
else
|
|
76
|
+
Process.kill("KILL", wait.pid)
|
|
77
|
+
out.kill
|
|
78
|
+
log "gh #{args.join(" ")} did not answer within #{gh_timeout.to_i}s."
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
rescue Errno::ENOENT
|
|
83
|
+
nil
|
|
107
84
|
end
|
|
108
85
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def store_bundler_credentials(username, token)
|
|
112
|
-
require "open3"
|
|
113
|
-
_stdout, stderr, status = Open3.capture3(
|
|
114
|
-
"bundle", "config", "set", "--local", source, "#{username}:#{token}"
|
|
115
|
-
)
|
|
116
|
-
raise "bundle config set --local #{source} failed: #{stderr}" unless status.success?
|
|
86
|
+
def gh_timeout
|
|
87
|
+
Float(ENV.fetch("DISCHARGER_GH_TIMEOUT") { config.github_packages&.gh_timeout || GH_TIMEOUT_SECONDS })
|
|
117
88
|
end
|
|
118
89
|
|
|
119
90
|
def source_accepts_token?(username, token)
|
|
@@ -61,14 +61,16 @@ module Discharger
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
class GithubPackagesConfig
|
|
64
|
-
attr_accessor :source
|
|
64
|
+
attr_accessor :source, :gh_timeout
|
|
65
65
|
|
|
66
66
|
def initialize
|
|
67
67
|
@source = nil
|
|
68
|
+
@gh_timeout = nil
|
|
68
69
|
end
|
|
69
70
|
|
|
70
71
|
def from_hash(hash)
|
|
71
72
|
@source = hash["source"] if hash["source"]
|
|
73
|
+
@gh_timeout = hash["gh_timeout"] if hash["gh_timeout"]
|
|
72
74
|
end
|
|
73
75
|
end
|
|
74
76
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "yaml"
|
|
4
|
+
require_relative "../timing"
|
|
4
5
|
require_relative "pre_commands/pre_command_registry"
|
|
5
6
|
|
|
6
7
|
module Discharger
|
|
@@ -130,8 +131,7 @@ module Discharger
|
|
|
130
131
|
end
|
|
131
132
|
|
|
132
133
|
command = command_class.new(config)
|
|
133
|
-
|
|
134
|
-
command.execute
|
|
134
|
+
timed(command.description) { command.execute }
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
def run_custom_pre_step(step)
|
|
@@ -144,8 +144,12 @@ module Discharger
|
|
|
144
144
|
return
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
timed(description) { system(command) }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def timed(description)
|
|
151
|
+
elapsed = Timing.measure { yield }
|
|
152
|
+
puts format(" %s: %.2fs", description, elapsed)
|
|
149
153
|
end
|
|
150
154
|
|
|
151
155
|
def evaluate_condition(condition)
|
|
@@ -26,8 +26,6 @@ module Discharger
|
|
|
26
26
|
puts Rainbow("=" * 50).blue
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
warn_unscheduled_commands
|
|
30
|
-
|
|
31
29
|
elapsed = Timing.measure do
|
|
32
30
|
FileUtils.chdir app_root do
|
|
33
31
|
execute_commands
|
|
@@ -81,18 +79,6 @@ module Discharger
|
|
|
81
79
|
@commands ||= command_factory.create_all_commands
|
|
82
80
|
end
|
|
83
81
|
|
|
84
|
-
# Checked at run time, after the customization block, so commands
|
|
85
|
-
# scheduled through add_command/insert_command_* count as scheduled.
|
|
86
|
-
def warn_unscheduled_commands
|
|
87
|
-
CommandRegistry.all.each do |klass|
|
|
88
|
-
next unless klass.respond_to?(:unscheduled_warning)
|
|
89
|
-
next if commands.any? { |command| command.is_a?(klass) }
|
|
90
|
-
|
|
91
|
-
message = klass.unscheduled_warning(config)
|
|
92
|
-
logger.warn message if message
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
82
|
def execute_commands
|
|
97
83
|
commands.each do |command|
|
|
98
84
|
execute_command(command)
|
data/lib/discharger/version.rb
CHANGED
|
@@ -14,18 +14,21 @@ Dir.chdir(File.expand_path("..", __dir__))
|
|
|
14
14
|
# under bundle exec before yaml loads, or a default psych clashes with Gemfile.lock.
|
|
15
15
|
# Mirrors the github_packages and bundler steps, which re-run under bundle exec.
|
|
16
16
|
unless ENV["DISCHARGER_SETUP_BUNDLED"]
|
|
17
|
+
# Mirrors GithubPackagesCommand and BundlerCommand in the gem; change them together.
|
|
17
18
|
def store_github_packages_credentials
|
|
18
19
|
require "yaml"
|
|
19
|
-
|
|
20
|
-
YAML.safe_load_file("config/setup.yml")&.dig("github_packages"
|
|
20
|
+
packages = begin
|
|
21
|
+
YAML.safe_load_file("config/setup.yml")&.dig("github_packages") || {}
|
|
21
22
|
rescue SystemCallError, Psych::Exception
|
|
22
|
-
|
|
23
|
+
{} # reported by Discharger::Setup on the second pass
|
|
23
24
|
end
|
|
25
|
+
source = packages["source"]
|
|
24
26
|
return if source.to_s.empty?
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
timeout = Float(ENV.fetch("DISCHARGER_GH_TIMEOUT") { packages["gh_timeout"] || 15 })
|
|
29
|
+
username = gh("api", "user", "--jq", ".login", timeout: timeout)
|
|
30
|
+
token = gh("auth", "token", timeout: timeout)
|
|
31
|
+
return if username.to_s.empty? || token.to_s.empty?
|
|
29
32
|
unless source_accepts_token?(source, username, token)
|
|
30
33
|
warn "Leaving bundler credentials for #{source} alone: it did not accept the gh token (gh auth refresh -s read:packages)"
|
|
31
34
|
return
|
|
@@ -34,6 +37,24 @@ unless ENV["DISCHARGER_SETUP_BUNDLED"]
|
|
|
34
37
|
system("bundle", "config", "set", "--local", source, "#{username}:#{token}", out: File::NULL, err: File::NULL)
|
|
35
38
|
end
|
|
36
39
|
|
|
40
|
+
def gh(*args, timeout:)
|
|
41
|
+
require "open3"
|
|
42
|
+
Open3.popen2("gh", *args, err: File::NULL) do |stdin, stdout, wait|
|
|
43
|
+
stdin.close
|
|
44
|
+
out = Thread.new { stdout.read }
|
|
45
|
+
if wait.join(timeout)
|
|
46
|
+
out.value.strip if wait.value.success?
|
|
47
|
+
else
|
|
48
|
+
Process.kill("KILL", wait.pid)
|
|
49
|
+
out.kill
|
|
50
|
+
warn "gh #{args.join(" ")} did not answer within #{timeout.to_i}s; continuing without credentials"
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
rescue Errno::ENOENT
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
37
58
|
def source_accepts_token?(source, username, token)
|
|
38
59
|
require "net/http"
|
|
39
60
|
uri = URI.join("#{source.chomp("/")}/", "versions")
|
|
@@ -19,12 +19,13 @@ redis:
|
|
|
19
19
|
version: "latest"
|
|
20
20
|
|
|
21
21
|
# Private GitHub Packages gem source (optional)
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# "
|
|
25
|
-
# gitignored.
|
|
22
|
+
# bin/setup stores bundler credentials from the GitHub CLI (gh) before
|
|
23
|
+
# installing the bundle, so the Gemfile needs no embedded token. Add
|
|
24
|
+
# "github_packages" to steps to check the token on every run. Credentials
|
|
25
|
+
# are written to .bundle/config — keep .bundle gitignored.
|
|
26
26
|
# github_packages:
|
|
27
27
|
# source: "https://rubygems.pkg.github.com/your-org"
|
|
28
|
+
# gh_timeout: 15 # seconds to wait for gh; DISCHARGER_GH_TIMEOUT overrides
|
|
28
29
|
|
|
29
30
|
# Pre-Rails steps (run BEFORE Rails loads)
|
|
30
31
|
# These are for system dependencies and environment setup that must happen
|
|
@@ -49,9 +50,9 @@ steps:
|
|
|
49
50
|
- brew
|
|
50
51
|
- asdf
|
|
51
52
|
- git
|
|
52
|
-
# Uncomment with the github_packages block above
|
|
53
|
+
# Uncomment with the github_packages block above to check the token.
|
|
53
54
|
# - github_packages
|
|
54
|
-
- bundler
|
|
55
|
+
- bundler # a check; bin/setup already installed the bundle
|
|
55
56
|
- yarn
|
|
56
57
|
- config
|
|
57
58
|
- docker
|