Skip to content

Commit ca5a449

Browse files
authored
Merge pull request #21 from code0-tech/20-add-release-checks
Add release checks
2 parents 97c697c + 7ed5da7 commit ca5a449

10 files changed

Lines changed: 285 additions & 14 deletions

File tree

.gitlab/ci/release-coordinator.canary.gitlab-ci.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.release-coordinator:canary:stages:
2-
- release-coordinator:canary:notify-start
2+
- release-coordinator:canary:prepare
33
- release-coordinator:canary:build
44
- release-coordinator:canary:publish
55
- release-coordinator:canary:notify-finish
@@ -11,12 +11,23 @@
1111
release-coordinator:canary:notify-start:
1212
extends:
1313
- .release-coordinator:canary
14-
stage: release-coordinator:canary:notify-start
14+
stage: release-coordinator:canary:prepare
1515
script:
1616
- bin/pyxis internal notify_new_coordinator --coordinator-pipeline-id $CI_PIPELINE_ID
1717
variables:
1818
DRY_RUN: "false"
1919

20+
release-coordinator:canary:check:
21+
extends:
22+
- .release-coordinator:canary
23+
stage: release-coordinator:canary:prepare
24+
needs:
25+
- release-coordinator:canary:notify-start
26+
script:
27+
- bin/pyxis internal check_canary_release --build-id-to-promote $BUILD_ID_TO_PROMOTE
28+
variables:
29+
DRY_RUN: "false"
30+
2031
release-coordinator:canary:tmp-branch:
2132
extends:
2233
- .release-coordinator:canary

.rubocop.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
AllCops:
2-
TargetRubyVersion: 3.2.0
2+
TargetRubyVersion: 3.2
33
NewCops: enable
44

55
Metrics:
66
Enabled: false
77

8+
Naming/PredicateMethod:
9+
AllowBangMethods: true
10+
811
Style/Documentation:
912
Enabled: false
1013

14+
Style/EmptyClassDefinition:
15+
Enabled: false
16+
1117
Style/NumericLiterals:
1218
Enabled: false
1319

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ gem 'semantic_logger', '~> 4.16', require: 'semantic_logger/sync'
1818
gem 'json', '~> 2.12'
1919

2020
gem 'discordrb', '~> 3.7'
21+
22+
gem 'toml-rb', '~> 4.1'

Gemfile.lock

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ GEM
55
public_suffix (>= 2.0.2, < 7.0)
66
ast (2.4.3)
77
base64 (0.3.0)
8+
bigdecimal (4.0.1)
9+
citrus (3.0.2)
810
concurrent-ruby (1.3.5)
911
discordrb (3.7.2)
1012
base64 (~> 0.2)
@@ -29,12 +31,17 @@ GEM
2931
http-accept (1.7.0)
3032
http-cookie (1.1.0)
3133
domain_name (~> 0.5)
32-
json (2.12.2)
34+
json (2.18.1)
35+
json-schema (6.1.0)
36+
addressable (~> 2.8)
37+
bigdecimal (>= 3.1, < 5)
3338
jwt (2.10.1)
3439
base64
3540
language_server-protocol (3.17.0.5)
3641
lint_roller (1.1.0)
3742
logger (1.7.0)
43+
mcp (0.8.0)
44+
json-schema (>= 4.1)
3845
mime-types (3.7.0)
3946
logger
4047
mime-types-data (~> 3.2025, >= 3.2025.0507)
@@ -50,43 +57,47 @@ GEM
5057
opus-ruby (1.0.1)
5158
ffi
5259
parallel (1.27.0)
53-
parser (3.3.8.0)
60+
parser (3.3.10.2)
5461
ast (~> 2.4.1)
5562
racc
56-
prism (1.4.0)
63+
prism (1.9.0)
5764
public_suffix (6.0.2)
5865
racc (1.8.1)
5966
rainbow (3.1.1)
60-
regexp_parser (2.10.0)
67+
regexp_parser (2.11.3)
6168
rest-client (2.1.0)
6269
http-accept (>= 1.7.0, < 2.0)
6370
http-cookie (>= 1.0.2, < 2.0)
6471
mime-types (>= 1.16, < 4.0)
6572
netrc (~> 0.8)
66-
rubocop (1.76.0)
73+
rubocop (1.85.1)
6774
json (~> 2.3)
6875
language_server-protocol (~> 3.17.0.2)
6976
lint_roller (~> 1.1.0)
77+
mcp (~> 0.6)
7078
parallel (~> 1.10)
7179
parser (>= 3.3.0.2)
7280
rainbow (>= 2.2.2, < 4.0)
7381
regexp_parser (>= 2.9.3, < 3.0)
74-
rubocop-ast (>= 1.45.0, < 2.0)
82+
rubocop-ast (>= 1.49.0, < 2.0)
7583
ruby-progressbar (~> 1.7)
7684
unicode-display_width (>= 2.4.0, < 4.0)
77-
rubocop-ast (1.45.0)
85+
rubocop-ast (1.49.0)
7886
parser (>= 3.3.7.2)
79-
prism (~> 1.4)
87+
prism (~> 1.7)
8088
ruby-progressbar (1.13.0)
8189
sawyer (0.9.2)
8290
addressable (>= 2.3.5)
8391
faraday (>= 0.17.3, < 3)
8492
semantic_logger (4.16.1)
8593
concurrent-ruby (~> 1.0)
8694
thor (1.3.2)
87-
unicode-display_width (3.1.4)
88-
unicode-emoji (~> 4.0, >= 4.0.4)
89-
unicode-emoji (4.0.4)
95+
toml-rb (4.1.0)
96+
citrus (~> 3.0, > 3.0)
97+
racc (~> 1.7)
98+
unicode-display_width (3.2.0)
99+
unicode-emoji (~> 4.1)
100+
unicode-emoji (4.2.0)
90101
uri (1.0.3)
91102
websocket (1.2.11)
92103
websocket-client-simple (0.9.0)
@@ -109,6 +120,7 @@ DEPENDENCIES
109120
rubocop (~> 1.76)
110121
semantic_logger (~> 4.16)
111122
thor (~> 1.3)
123+
toml-rb (~> 4.1)
112124
zeitwerk (~> 2.7)
113125

114126
BUNDLED WITH
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
module Pyxis
4+
module Checks
5+
class AggregatedCheck
6+
include Check
7+
8+
attr_reader :check_context, :checks
9+
10+
def initialize(check_context, checks)
11+
@check_context = check_context
12+
@checks = checks
13+
end
14+
15+
def perform_check!
16+
checks.all?(&:pass?)
17+
end
18+
19+
def status_message
20+
message = []
21+
message << if pass?
22+
"#{icon} #{check_context} checks pass"
23+
else
24+
"#{icon} #{check_context} checks fail"
25+
end
26+
checks.each do |check|
27+
message << ''
28+
message << check.status_message
29+
end
30+
31+
message.join("\n")
32+
end
33+
end
34+
end
35+
end

lib/pyxis/checks/canary_release.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module Pyxis
4+
module Checks
5+
class CanaryRelease < AggregatedCheck
6+
def initialize(build_id_to_promote)
7+
info = Pyxis::ManagedVersioning::ComponentInfo.new(build_id: build_id_to_promote)
8+
super(
9+
'Canary release',
10+
[
11+
TucanaVersionMatch.new(info),
12+
OpenIssues.new('release blocking', ['blocks-releases'])
13+
]
14+
)
15+
end
16+
end
17+
end
18+
end

lib/pyxis/checks/check.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# frozen_string_literal: true
2+
3+
module Pyxis
4+
module Checks
5+
module Check
6+
def perform_check!
7+
raise NotImplementedError
8+
end
9+
10+
def status_message
11+
raise NotImplementedError
12+
end
13+
14+
def pass?
15+
return @pass if defined?(@pass)
16+
17+
@pass = perform_check!
18+
end
19+
20+
def icon
21+
if pass?
22+
pass_icon
23+
else
24+
fail_icon
25+
end
26+
end
27+
28+
def pass_icon
29+
'✅' # :white_check_mark:
30+
end
31+
32+
def fail_icon
33+
'❌' # :x:
34+
end
35+
end
36+
end
37+
end

lib/pyxis/checks/open_issues.rb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
3+
module Pyxis
4+
module Checks
5+
class OpenIssues
6+
include Check
7+
8+
attr_reader :check_context, :labels
9+
10+
def initialize(check_context, labels)
11+
@check_context = check_context
12+
@labels = labels
13+
end
14+
15+
def perform_check!
16+
issues.empty?
17+
end
18+
19+
def status_message
20+
return "#{icon} No open #{check_context} issues" if pass?
21+
22+
message = []
23+
message << "#{icon} Open #{check_context} issues"
24+
issues.each do |issue|
25+
message << "- [#{issue.title}](#{issue.html_url})"
26+
end
27+
28+
message.join("\n")
29+
end
30+
31+
private
32+
33+
def issues
34+
@issues ||= GithubClient.octokit.search_issues(
35+
"org:#{GithubClient::ORGANIZATION_NAME} is:open is:issue #{labels.map { |l| "label:#{l}" }.join(' ')}"
36+
).items
37+
end
38+
end
39+
end
40+
end
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# frozen_string_literal: true
2+
3+
module Pyxis
4+
module Checks
5+
class TucanaVersionMatch
6+
include Check
7+
8+
attr_reader :component_info
9+
10+
def initialize(component_info)
11+
@component_info = component_info
12+
end
13+
14+
def perform_check!
15+
[sagittarius_version, aquila_version, draco_version, taurus_version].uniq.size == 1
16+
end
17+
18+
def status_message
19+
return "#{icon} Components use the same tucana version" if pass?
20+
21+
message = []
22+
message << "#{icon} Components use different tucana versions"
23+
message << ''
24+
message << "sagittarius: #{sagittarius_version}"
25+
message << "aquila: #{aquila_version}"
26+
message << "draco: #{draco_version}"
27+
message << "taurus: #{taurus_version}"
28+
29+
message.join("\n")
30+
end
31+
32+
private
33+
34+
def sagittarius_version
35+
return @sagittarius_version if defined?(@sagittarius_version)
36+
37+
gemfile_content = Base64.decode64 GithubClient.octokit.contents(
38+
Project::Sagittarius.github_path,
39+
path: 'Gemfile.lock',
40+
ref: executed_component_info[:sagittarius]
41+
).content
42+
43+
@sagittarius_version = Bundler::LockfileParser.new(gemfile_content)
44+
.specs
45+
.find { |spec| spec.name == 'tucana' }
46+
.version
47+
.to_s
48+
end
49+
50+
def aquila_version
51+
@aquila_version ||= from_cargo_lockfile(
52+
Base64.decode64(
53+
GithubClient.octokit.contents(
54+
Project::Aquila.github_path,
55+
path: 'Cargo.lock',
56+
ref: executed_component_info[:aquila]
57+
).content
58+
)
59+
)
60+
end
61+
62+
def draco_version
63+
@draco_version ||= from_cargo_lockfile(
64+
Base64.decode64(
65+
GithubClient.octokit.contents(
66+
Project::Draco.github_path,
67+
path: 'Cargo.lock',
68+
ref: executed_component_info[:draco]
69+
).content
70+
)
71+
)
72+
end
73+
74+
def taurus_version
75+
@taurus_version ||= from_cargo_lockfile(
76+
Base64.decode64(
77+
GithubClient.octokit.contents(
78+
Project::Taurus.github_path,
79+
path: 'Cargo.lock',
80+
ref: executed_component_info[:taurus]
81+
).content
82+
)
83+
)
84+
end
85+
86+
def from_cargo_lockfile(lockfile)
87+
toml = TomlRB.parse(lockfile, symbolize_keys: true)
88+
toml[:package].find { |package| package[:name] == 'tucana' }[:version]
89+
end
90+
91+
def executed_component_info
92+
@executed_component_info ||= component_info.execute
93+
end
94+
end
95+
end
96+
end

0 commit comments

Comments
 (0)