Skip to content

Commit 6feb282

Browse files
authored
refactor(nns-tools): Turn release-runscript to clap-powered CLI (dfinity#3712)
This will make it simpler to add automation for various steps in the future. It will also enable the person doing the release to start at any step (instead of needing to start at the beginning). As a reminder, the runscript can be run with: ``` bazel run //rs/nervous_system/tools/release-runscript --config=lint ``` In this chain of PRs, I automate the first few steps of the release process in this script. [Next PR →](dfinity#3713)
1 parent ec6e895 commit 6feb282

File tree

4 files changed

+178
-61
lines changed

4 files changed

+178
-61
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rs/nervous_system/tools/release-runscript/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ DEPENDENCIES = [
1212
"//rs/types/base_types",
1313
"@crate_index//:anyhow",
1414
"@crate_index//:candid",
15+
"@crate_index//:clap",
1516
"@crate_index//:colored",
1617
"@crate_index//:futures",
1718
"@crate_index//:ic-agent",

rs/nervous_system/tools/release-runscript/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ path = "src/main.rs"
1313
[dependencies]
1414
anyhow = { workspace = true }
1515
candid = { workspace = true }
16+
clap = { workspace = true }
1617
colored = "2.0.0"
1718
futures = { workspace = true }
1819
ic-agent = { workspace = true }

rs/nervous_system/tools/release-runscript/src/main.rs

Lines changed: 175 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,94 @@
1+
use anyhow::{bail, Result};
2+
use clap::{Parser, Subcommand};
13
use colored::*;
24
use std::io::{self, Write};
35

4-
struct Step {
5-
title: &'static str,
6-
description: &'static str,
6+
#[derive(Debug, Parser)]
7+
struct DetermineTargets;
8+
9+
#[derive(Debug, Parser)]
10+
struct RunTests;
11+
12+
#[derive(Debug, Parser)]
13+
struct CreateProposalTexts;
14+
15+
#[derive(Debug, Parser)]
16+
struct SubmitProposals;
17+
18+
#[derive(Debug, Parser)]
19+
struct CreateForumPost;
20+
21+
#[derive(Debug, Parser)]
22+
struct ScheduleVote;
23+
24+
#[derive(Debug, Parser)]
25+
struct UpdateCanistersJson;
26+
27+
#[derive(Debug, Parser)]
28+
struct UpdateChangelog;
29+
30+
#[derive(Debug, Subcommand)]
31+
enum Step {
32+
#[command(about = "Step 1: Pick Release Candidate Commit")]
33+
PickReleaseCandidateCommit,
34+
#[command(about = "Step 2: Determine Upgrade Targets")]
35+
DetermineTargets(DetermineTargets),
36+
#[command(about = "Step 3: Run NNS Upgrade Tests")]
37+
RunTests(RunTests),
38+
#[command(about = "Step 4: Create Proposal Texts")]
39+
CreateProposalTexts(CreateProposalTexts),
40+
#[command(about = "Step 5: Submit Proposals")]
41+
SubmitProposals(SubmitProposals),
42+
#[command(about = "Step 6: Create Forum Post")]
43+
CreateForumPost(CreateForumPost),
44+
#[command(about = "Step 7: Schedule Trusted Neurons Vote")]
45+
ScheduleVote(ScheduleVote),
46+
#[command(about = "Step 8: Update Mainnet Canisters")]
47+
UpdateCanistersJson(UpdateCanistersJson),
48+
#[command(about = "Step 9: Update Changelog")]
49+
UpdateChangelog(UpdateChangelog),
750
}
851

9-
fn main() {
10-
let steps = vec![
11-
Step {
12-
title: "Pick Release Candidate Commit",
13-
description: "Run `./testnet/tools/nns-tools/cmd.sh latest_commit_with_prebuilt_artifacts`.
52+
#[derive(Debug, Parser)]
53+
#[clap(
54+
name = "release-runscript",
55+
about = "Release NNS and SNS canisters.",
56+
version
57+
)]
58+
struct ReleaseRunscript {
59+
#[command(subcommand)]
60+
step: Option<Step>,
61+
}
62+
63+
fn main() -> Result<()> {
64+
let args = match ReleaseRunscript::try_parse_from(std::env::args()) {
65+
Ok(args) => args,
66+
Err(e) => {
67+
bail!("{}", e);
68+
}
69+
};
70+
71+
print_header();
72+
73+
match args.step {
74+
None | Some(Step::PickReleaseCandidateCommit) => run_pick_commit(),
75+
Some(Step::DetermineTargets(cmd)) => run_determine_targets(cmd),
76+
Some(Step::RunTests(cmd)) => run_run_tests(cmd),
77+
Some(Step::CreateProposalTexts(cmd)) => run_create_proposal_texts(cmd),
78+
Some(Step::SubmitProposals(cmd)) => run_submit_proposals(cmd),
79+
Some(Step::CreateForumPost(cmd)) => run_create_forum_post(cmd),
80+
Some(Step::ScheduleVote(cmd)) => run_schedule_vote(cmd),
81+
Some(Step::UpdateCanistersJson(cmd)) => run_update_canisters_json(cmd),
82+
Some(Step::UpdateChangelog(cmd)) => run_update_changelog(cmd),
83+
}
84+
85+
Ok(())
86+
}
87+
88+
fn run_pick_commit() {
89+
print_step(1,
90+
"Pick Release Candidate Commit",
91+
"Run `./testnet/tools/nns-tools/cmd.sh latest_commit_with_prebuilt_artifacts`.
1492
If you would like to pick a different commit, follow these steps:
1593
2. Go to https://github.com/dfinity/ic/actions/workflows/ci-main.yml?query=branch%3Amaster+event%3Apush+is%3Asuccess
1694
3. Find a recent commit with passing CI Main in the master branch
@@ -19,12 +97,17 @@ If you would like to pick a different commit, follow these steps:
1997
Pre-built artifacts check:
2098
- Install aws tool if needed
2199
- List available files:
22-
aws s3 ls --no-sign-request s3://dfinity-download-public/ic/${COMMIT}/canisters/
100+
aws s3 ls --no-sign-request s3://dfinity-download-public/ic/${COMMIT}/canisters/
23101
- Note: Our tools download from the analogous https://download.dfinity.systems/... URL",
24-
},
25-
Step {
26-
title: "Determine Upgrade Targets",
27-
description: "Determine which NNS canisters and/or SNS WASMs need to be upgraded/published.
102+
);
103+
run_determine_targets(DetermineTargets);
104+
}
105+
106+
fn run_determine_targets(_: DetermineTargets) {
107+
print_step(
108+
2,
109+
"Determine Upgrade Targets",
110+
"Determine which NNS canisters and/or SNS WASMs need to be upgraded/published.
28111
Only those with 'interesting' changes need to be released.
29112
30113
Required checks:
@@ -38,10 +121,14 @@ For SNS ledger suite (ledger, archive, and index canisters):
38121
- FI team should provide the 'Features' section of proposals
39122
- This agreement is new - you may need to remind them
40123
- This applies to ledger, archive, and index canisters",
41-
},
42-
Step {
43-
title: "Run NNS Upgrade Tests",
44-
description: "Verify the commit you chose at the previous step has a green check on this page: https://github.com/dfinity/ic/actions/workflows/ci-main.yml?query=branch:master+event:push+is:success
124+
);
125+
run_run_tests(RunTests);
126+
}
127+
128+
fn run_run_tests(_: RunTests) {
129+
print_step(3,
130+
"Run NNS Upgrade Tests",
131+
"Verify the commit you chose at the previous step has a green check on this page: https://github.com/dfinity/ic/actions/workflows/ci-main.yml?query=branch:master+event:push+is:success
45132
46133
If not, you can also run the upgrade tests manually:
47134
- Follow instructions in: testnet/tools/nns-tools/README.md#upgrade-testing-via-bazel
@@ -50,10 +137,16 @@ If not, you can also run the upgrade tests manually:
50137
- No manual testing needed for SNS
51138
- Covered by sns_release_qualification in CI
52139
- Example: Test at rs/nervous_system/integration_tests/tests/sns_release_qualification.rs",
53-
},
54-
Step {
55-
title: "Create Proposal Texts",
56-
description: "Create proposal text for each canister to be upgraded.
140+
);
141+
142+
run_create_proposal_texts(CreateProposalTexts);
143+
}
144+
145+
fn run_create_proposal_texts(_: CreateProposalTexts) {
146+
print_step(
147+
4,
148+
"Create Proposal Texts",
149+
"Create proposal text for each canister to be upgraded.
57150
This can be done in parallel with the previous testing step.
58151
59152
Instructions:
@@ -65,17 +158,27 @@ Instructions:
65158
- Put all proposal files in a dedicated directory
66159
- Keep directory clean (nothing else in there)
67160
- This will help with forum post generation later",
68-
},
69-
Step {
70-
title: "Submit Proposals",
71-
description: "Submit the proposals on Friday
161+
);
162+
run_submit_proposals(SubmitProposals);
163+
}
164+
165+
fn run_submit_proposals(_: SubmitProposals) {
166+
print_step(
167+
5,
168+
"Submit Proposals",
169+
"Submit the proposals on Friday
72170
73171
Follow detailed instructions at:
74172
testnet/tools/nns-tools/README.md#submit-the-proposals",
75-
},
76-
Step {
77-
title: "Create Forum Post",
78-
description: "Create a forum post with the following specifications:
173+
);
174+
175+
run_create_forum_post(CreateForumPost);
176+
}
177+
178+
fn run_create_forum_post(_: CreateForumPost) {
179+
print_step(6,
180+
"Create Forum Post",
181+
"Create a forum post with the following specifications:
79182
80183
1. Title Format:
81184
'NNS Updates <ISO 8601 DATE>(: <Anything interesting to announce>)'
@@ -117,10 +220,15 @@ testnet/tools/nns-tools/README.md#submit-the-proposals",
117220
- Reply to NNS Updates Aggregation Thread (https://forum.dfinity.org/t/nns-updates-aggregation-thread/23551)
118221
- If SNS canister WASMs were published, update SNS Upgrades Aggregation Thread
119222
(https://forum.dfinity.org/t/sns-upgrade-aggregation-thread/24259/2)",
120-
},
121-
Step {
122-
title: "Schedule Trusted Neurons Vote",
123-
description: "Schedule calendar event for Trusted Neurons to vote the following Monday.
223+
);
224+
225+
run_schedule_vote(ScheduleVote);
226+
}
227+
228+
fn run_schedule_vote(_: ScheduleVote) {
229+
print_step(7,
230+
"Schedule Trusted Neurons Vote",
231+
"Schedule calendar event for Trusted Neurons to vote the following Monday.
124232
125233
Calendar Event Setup:
126234
1. Duplicate a past event from:
@@ -141,10 +249,16 @@ Calendar Event Setup:
141249
- Click 'Save' to create event
142250
- Send email invitations when prompted
143251
- If people don't respond, ping @trusted-neurons in #eng-release channel",
144-
},
145-
Step {
146-
title: "Update Mainnet Canisters",
147-
description: "After proposal execution, update mainnet-canisters.json:
252+
);
253+
254+
run_update_canisters_json(UpdateCanistersJson);
255+
}
256+
257+
fn run_update_canisters_json(_: UpdateCanistersJson) {
258+
print_step(
259+
8,
260+
"Update Mainnet Canisters",
261+
"After proposal execution, update mainnet-canisters.json:
148262
149263
1. Run the sync command:
150264
bazel run //rs/nervous_system/tools/sync-with-released-nevous-system-wasms
@@ -159,10 +273,16 @@ Calendar Event Setup:
159273
3. Note on automation:
160274
- There was a ticket for automating this (NNS1-2201)
161275
- Currently marked as won't do",
162-
},
163-
Step {
164-
title: "Update Changelog",
165-
description: "Update CHANGELOG.md file(s) for each proposal:
276+
);
277+
278+
run_update_changelog(UpdateChangelog);
279+
}
280+
281+
fn run_update_changelog(_: UpdateChangelog) {
282+
print_step(
283+
9,
284+
"Update Changelog",
285+
"Update CHANGELOG.md file(s) for each proposal:
166286
167287
1. For each proposal ID:
168288
```bash
@@ -176,35 +296,29 @@ Calendar Event Setup:
176296
177297
2. Best Practice:
178298
- Combine this change with mainnet-canisters.json update in the same PR",
179-
},
180-
];
299+
);
181300

301+
println!("{}", "\nRelease process complete!".bright_green().bold());
302+
println!("Please verify that all steps were completed successfully.");
303+
}
304+
305+
fn print_header() {
182306
println!("{}", "\nNNS Release Runscript".bright_green().bold());
183307
println!("{}", "===================".bright_green());
184308
println!("This script will guide you through the NNS release process.\n");
185-
186-
for (index, step) in steps.iter().enumerate() {
187-
print_step(index + 1, step);
188-
189-
print!("\nPress Enter to continue to next step...");
190-
io::stdout().flush().unwrap();
191-
let mut input = String::new();
192-
io::stdin().read_line(&mut input).unwrap();
193-
194-
// Clear screen for next step
195-
print!("\x1B[2J\x1B[1;1H");
196-
}
197-
198-
println!("{}", "\nRelease process complete!".bright_green().bold());
199-
println!("Please verify that all steps were completed successfully.");
200309
}
201310

202-
fn print_step(number: usize, step: &Step) {
311+
fn print_step(number: usize, title: &str, description: &str) {
203312
println!(
204313
"{} {}",
205314
format!("Step {}:", number).bright_blue().bold(),
206-
step.title.white().bold()
315+
title.white().bold()
207316
);
208317
println!("{}", "---".bright_blue());
209-
println!("{}\n", step.description);
318+
println!("{}\n", description);
319+
print!("\nPress Enter to continue to next step...");
320+
io::stdout().flush().unwrap();
321+
let mut input = String::new();
322+
io::stdin().read_line(&mut input).unwrap();
323+
print!("\x1B[2J\x1B[1;1H");
210324
}

0 commit comments

Comments
 (0)