discharger 0.2.8 → 0.2.9
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/discharger/procedure.rb +117 -0
- data/lib/discharger/railway.rb +111 -0
- data/lib/discharger/task.rb +1 -0
- data/lib/discharger/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d98bb157c8cb3b219d105f4c6f1b18715cba0706a6cedf93f1991852fc11a04
|
4
|
+
data.tar.gz: 1115667f6e8c9e94662b7ba7d76769e522b3fa26961b6217b78420fe9b095baa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85870fbc537b4d4c3c86326c3c6cfc0f06adeeba24a831ff65f7ab858004e068baa6f1b69ec46945dbbdbfd42094f2614614402f931369815f72c13c970d38d6
|
7
|
+
data.tar.gz: 4ac3f985792dc65968030f09319e08e41a840df0c96113791bdee1afa8c8aa989ec347b1ebb7412cdbb42b1331c411403f620948dc3ae14a3e78bf5adce667cd
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Discharger
|
2
|
+
class Procedure
|
3
|
+
include Railway::Steps
|
4
|
+
|
5
|
+
def initialize(name, system_command: nil, **data)
|
6
|
+
@name = name
|
7
|
+
@data = data
|
8
|
+
@system_command = system_command || method(:syscall)
|
9
|
+
@steps = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
result = run_steps(
|
14
|
+
*step_procs,
|
15
|
+
branches: {
|
16
|
+
permission_denied: :handle_permissions,
|
17
|
+
network_error: :retry_network_operation,
|
18
|
+
any_failure: ->(_) {
|
19
|
+
puts "An error occurred but we'll try to recover"
|
20
|
+
Success()
|
21
|
+
}
|
22
|
+
}
|
23
|
+
)
|
24
|
+
|
25
|
+
if result.failure?
|
26
|
+
puts "Failed: #{result.error}".bg(:red).black
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def step_procs
|
33
|
+
steps.map do |step|
|
34
|
+
->(_) { @system_command.call(step) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Run a multiple system commands and return a Result
|
39
|
+
# If any command fails, returns a Failure result
|
40
|
+
def syscall(*cmd, output: $stdout, error: $stderr)
|
41
|
+
puts cmd.join(" ").bg(:green).black
|
42
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
43
|
+
|
44
|
+
if status.success?
|
45
|
+
output.puts stdout
|
46
|
+
Success(stdout)
|
47
|
+
else
|
48
|
+
error.puts stderr
|
49
|
+
|
50
|
+
# Different failure types based on the error
|
51
|
+
if stderr.include?("Permission denied")
|
52
|
+
Failure(stderr, :permission_denied)
|
53
|
+
elsif stderr.include?("Network")
|
54
|
+
Failure(stderr, :network_error)
|
55
|
+
else
|
56
|
+
Failure(stderr)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
rescue => e
|
60
|
+
Failure("Exception: #{e.message}")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Version that supports evaluating the result with a block
|
64
|
+
def syscall_with_block(*cmd, output: $stdout, error: $stderr, &block)
|
65
|
+
result = syscall(*cmd, output: output, error: error)
|
66
|
+
|
67
|
+
if result.success? && block_given?
|
68
|
+
stdout, stderr, status = result.value, "", $?
|
69
|
+
block_result = !!yield(stdout, stderr, status)
|
70
|
+
|
71
|
+
# Handle the bypassed rule case
|
72
|
+
if !block_result && stderr.match?(/bypassed rule violations/i)
|
73
|
+
block_result = true
|
74
|
+
end
|
75
|
+
|
76
|
+
return block_result ? Success(stdout) : Failure(stderr)
|
77
|
+
end
|
78
|
+
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
# Handle permission errors
|
83
|
+
def handle_permissions(result)
|
84
|
+
puts "Permission error: #{result.error}"
|
85
|
+
# Try to fix permissions
|
86
|
+
if fix_permissions
|
87
|
+
Success("Permissions fixed")
|
88
|
+
else
|
89
|
+
result # Return the original failure if we couldn't fix it
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Retry network operations
|
94
|
+
def retry_network_operation(result)
|
95
|
+
3.times do |i|
|
96
|
+
puts "Network error, retrying (#{i + 1}/3)..."
|
97
|
+
sleep 2
|
98
|
+
result = retry_last_command
|
99
|
+
return result if result.success?
|
100
|
+
end
|
101
|
+
Failure("Network operation failed after 3 retries")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class Build < Procedure
|
106
|
+
def steps
|
107
|
+
@steps ||= [
|
108
|
+
["fetch origin #{working_branch}"],
|
109
|
+
["checkout #{working_branch}"],
|
110
|
+
["reset --hard origin/#{working_branch}"],
|
111
|
+
["branch -D #{staging_branch} 2>/dev/null || true"],
|
112
|
+
["checkout -b #{staging_branch}"],
|
113
|
+
["push origin #{staging_branch} --force"]
|
114
|
+
]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Discharger
|
2
|
+
module Railway
|
3
|
+
# Represents the result of an operation - either Success or Failure
|
4
|
+
class Result
|
5
|
+
attr_reader :value, :error, :status
|
6
|
+
|
7
|
+
def initialize(status, value = nil, error = nil)
|
8
|
+
@status = status
|
9
|
+
@value = value
|
10
|
+
@error = error
|
11
|
+
end
|
12
|
+
|
13
|
+
def success?
|
14
|
+
@status == :success
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure?
|
18
|
+
!success?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get the failure type/status
|
22
|
+
def failure_type
|
23
|
+
failure? ? @status : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Factory method for creating success results
|
27
|
+
def self.success(value = nil)
|
28
|
+
new(:success, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Factory method for creating failure results
|
32
|
+
def self.failure(error = nil, type = :error)
|
33
|
+
new(type, nil, error)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Allows chaining operations if this result is a success
|
37
|
+
def then
|
38
|
+
return self if failure?
|
39
|
+
yield(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Module to include in classes that want to use railway flows
|
44
|
+
module Steps
|
45
|
+
def Success(value = nil)
|
46
|
+
Result.success(value)
|
47
|
+
end
|
48
|
+
|
49
|
+
def Failure(error = nil, type = :error)
|
50
|
+
Result.failure(error, type)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Execute a series of steps with branching logic
|
54
|
+
def run_steps(*steps, branches: {})
|
55
|
+
result = Success()
|
56
|
+
step_index = 0
|
57
|
+
|
58
|
+
while step_index < steps.length
|
59
|
+
step = steps[step_index]
|
60
|
+
|
61
|
+
# Execute the current step
|
62
|
+
result = execute_step(step, result.value)
|
63
|
+
|
64
|
+
if result.failure?
|
65
|
+
# Check if there's a branch for this failure type
|
66
|
+
branch = branches[result.status] || branches[:any_failure]
|
67
|
+
|
68
|
+
if branch
|
69
|
+
if branch.is_a?(Integer)
|
70
|
+
# Jump to the specified step index
|
71
|
+
step_index = branch
|
72
|
+
next
|
73
|
+
elsif branch.is_a?(Proc)
|
74
|
+
# Execute the branch handler
|
75
|
+
branch_result = branch.call(result)
|
76
|
+
return branch_result if branch_result.is_a?(Result)
|
77
|
+
# If the branch handler doesn't return a Result, continue with the next step
|
78
|
+
elsif branch.is_a?(Symbol)
|
79
|
+
# Execute the named method
|
80
|
+
branch_result = send(branch, result)
|
81
|
+
return branch_result if branch_result.is_a?(Result)
|
82
|
+
elsif branch == :continue
|
83
|
+
# Continue to the next step despite the failure
|
84
|
+
else
|
85
|
+
return result # Default: stop processing on failure
|
86
|
+
end
|
87
|
+
else
|
88
|
+
return result # No branch defined, stop processing
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
step_index += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def execute_step(step, input)
|
101
|
+
if step.is_a?(Proc)
|
102
|
+
step.call(input)
|
103
|
+
elsif step.is_a?(Symbol)
|
104
|
+
send(step, input)
|
105
|
+
else
|
106
|
+
raise ArgumentError, "Step must be a Proc or Symbol, got #{step.class}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/discharger/task.rb
CHANGED
@@ -211,6 +211,7 @@ module Discharger
|
|
211
211
|
["git checkout -b #{staging_branch}"],
|
212
212
|
["git push origin #{staging_branch} --force"]
|
213
213
|
) do
|
214
|
+
current_version = Object.const_get(version_constant)
|
214
215
|
tasker["#{name}:slack"].invoke("Building #{app_name} #{current_version} (#{commit_identifier.call}) on #{staging_branch}.", release_message_channel)
|
215
216
|
syscall ["git checkout #{working_branch}"]
|
216
217
|
end
|
data/lib/discharger/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: discharger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Gay
|
8
8
|
- Savannah Moore
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: open3
|
@@ -91,7 +91,9 @@ files:
|
|
91
91
|
- README.md
|
92
92
|
- Rakefile
|
93
93
|
- lib/discharger.rb
|
94
|
+
- lib/discharger/procedure.rb
|
94
95
|
- lib/discharger/railtie.rb
|
96
|
+
- lib/discharger/railway.rb
|
95
97
|
- lib/discharger/task.rb
|
96
98
|
- lib/discharger/version.rb
|
97
99
|
- lib/generators/discharger/install/install_generator.rb
|