From 2f22965396d60d40cbadc631720ff8d95ebfc2e1 Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Fri, 14 Jun 2024 12:16:19 +0200 Subject: [PATCH] feat(#195): `print-spec` and `release-network` commands --- Cargo.toml | 1 + xtask/res/create_network_release.gql | 16 ++++ xtask/res/get_release.gql | 4 +- xtask/src/main.rs | 23 ++++-- xtask/src/release_runtime.rs | 71 ++++++++++++++--- .../release_runtime/create_network_release.rs | 76 +++++++++++++++++++ xtask/src/release_runtime/get_release.rs | 6 +- 7 files changed, 172 insertions(+), 25 deletions(-) create mode 100644 xtask/res/create_network_release.gql create mode 100644 xtask/src/release_runtime/create_network_release.rs diff --git a/Cargo.toml b/Cargo.toml index 4951122c6..fb533ca6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ substrate-build-script-utils = { git = 'https://github.com/duniter/duniter-polka [dev-dependencies] rusty-hook = "^0.11.2" +reqwest = { version = "0.12.0", default-features = false, features = ["rustls-tls"] } # Dependencies for specific targets [target.'cfg(any(target_arch="x86_64", target_arch="aarch64"))'.dependencies] diff --git a/xtask/res/create_network_release.gql b/xtask/res/create_network_release.gql new file mode 100644 index 000000000..694afccf1 --- /dev/null +++ b/xtask/res/create_network_release.gql @@ -0,0 +1,16 @@ +mutation CreateReleaseMutation($branch: String!, $description: String!, $network: String! $links: [ReleaseAssetLinkInput!]!) { + releaseCreate(input: { + clientMutationId: "duniter-v2s-xtask" + description: $description + milestones: [] + name: $network + projectPath: "nodes/rust/duniter-v2s" + ref: $branch + tagName: $network + assets: { + links: $links + } + }) { + errors + } +} diff --git a/xtask/res/get_release.gql b/xtask/res/get_release.gql index 9ca58b82c..7fb7ef667 100644 --- a/xtask/res/get_release.gql +++ b/xtask/res/get_release.gql @@ -1,6 +1,6 @@ -query GetReleaseOfProjectQuery($milestone: String!) { +query GetReleaseOfProjectQuery($tag: String!) { project(fullPath: "nodes/rust/duniter-v2s") { - release(tagName: $milestone) { + release(tagName: $tag) { id tagName assets { diff --git a/xtask/src/main.rs b/xtask/src/main.rs index c6b201b9d..7e4c82382 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -51,10 +51,12 @@ enum DuniterXTaskCommand { /// Raw spec filepath raw_spec: PathBuf, }, + /// Release a new network + ReleaseNetwork { network: String, branch: String }, /// Release a new runtime ReleaseRuntime { milestone: String, branch: String }, - /// Update raw specs locally with the files published on a Release - UpdateRawSpecs { milestone: String }, + /// Print the chainSpec published on given Network Release + PrintSpec { network: String }, /// Create asset in a release CreateAssetLink { tag: String, @@ -79,8 +81,14 @@ async fn main() -> Result<()> { ); std::process::exit(1); } - Command::new("rustc").arg("--version").status()?; - Command::new("cargo").arg("--version").status()?; + + match &args.command { + DuniterXTaskCommand::PrintSpec { .. } => { /* no print */ } + _ => { + Command::new("rustc").arg("--version").status()?; + Command::new("cargo").arg("--version").status()?; + } + } match args.command { DuniterXTaskCommand::Build { production } => build(production), @@ -88,12 +96,13 @@ async fn main() -> Result<()> { DuniterXTaskCommand::InjectRuntimeCode { runtime, raw_spec } => { inject_runtime_code(&raw_spec, &runtime) } + DuniterXTaskCommand::ReleaseNetwork { network, branch } => { + release_runtime::release_network(network, branch).await + } DuniterXTaskCommand::ReleaseRuntime { milestone, branch } => { release_runtime::release_runtime(milestone, branch).await } - DuniterXTaskCommand::UpdateRawSpecs { milestone } => { - release_runtime::update_raw_specs(milestone).await - } + DuniterXTaskCommand::PrintSpec { network } => release_runtime::print_spec(network).await, DuniterXTaskCommand::CreateAssetLink { tag, asset_name, diff --git a/xtask/src/release_runtime.rs b/xtask/src/release_runtime.rs index 53bff4a97..c39f4a441 100644 --- a/xtask/src/release_runtime.rs +++ b/xtask/src/release_runtime.rs @@ -15,6 +15,7 @@ // along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. mod create_asset_link; +mod create_network_release; mod create_release; mod get_changes; mod get_issues; @@ -61,6 +62,50 @@ struct CoreVersion { //transaction_version: u32, } +pub(super) async fn release_network(network: String, branch: String) -> Result<()> { + let mut release_notes = String::from( + " +# Runtime + +", + ); + + // Generate release notes + let currency = network.clone(); + let env_var = "SRTOOL_OUTPUT".to_string(); + + if let Ok(sr_tool_output_file) = std::env::var(env_var) { + let read = fs::read_to_string(sr_tool_output_file); + match read { + Ok(sr_tool_output) => { + release_notes.push_str( + gen_release_notes(currency.to_string(), sr_tool_output) + .with_context(|| { + format!("Fail to generate release notes for {}", currency) + })? + .as_str(), + ); + } + Err(e) => { + eprintln!("srtool JSON output could not be read ({}). Skipped.", e) + } + } + } + + println!("{}", release_notes); + let gitlab_token = + std::env::var("GITLAB_TOKEN").with_context(|| "missing env var GITLAB_TOKEN")?; + create_network_release::create_network_release( + gitlab_token, + branch, + network, + release_notes.to_string(), + ) + .await?; + + Ok(()) +} + pub(super) async fn release_runtime(milestone: String, branch: String) -> Result<()> { // TODO: check spec_version in the code and bump if necessary (with a commit) // TODO: create and push a git tag runtime-{spec_version} @@ -134,20 +179,22 @@ pub(super) async fn release_runtime(milestone: String, branch: String) -> Result Ok(()) } -pub(super) async fn update_raw_specs(milestone: String) -> Result<()> { - let specs = vec!["gdev-raw.json", "gtest-raw.json", "g1-raw.json"]; - println!("Fetching release info…"); - let assets = get_release::get_release(milestone).await?; - for spec in specs { - if let Some(gdev_raw_specs) = assets.iter().find(|asset| asset.ends_with(spec)) { - println!("Downloading {}…", spec); - let client = reqwest::Client::new(); - let res = client.get(gdev_raw_specs).send().await?; - let write_to = format!("./node/specs/{}", spec); - fs::write(write_to, res.bytes().await?)?; +pub(super) async fn print_spec(network: String) -> Result<()> { + let spec_file = match network.clone() { + network if network.starts_with("g1") => "g1.json", + network if network.starts_with("gtest") => "gtest.json", + network if network.starts_with("gdev") => "gdev.json", + _ => { + return Err(anyhow!("Invalid network")); } + }; + let assets = get_release::get_release(network).await?; + if let Some(gdev_spec) = assets.iter().find(|asset| asset.ends_with(spec_file)) { + let client = reqwest::Client::new(); + let res = client.get(gdev_spec).send().await?; + let spec = String::from_utf8(res.bytes().await?.to_vec())?; + println!("{}", spec); } - println!("Done."); Ok(()) } diff --git a/xtask/src/release_runtime/create_network_release.rs b/xtask/src/release_runtime/create_network_release.rs new file mode 100644 index 000000000..6736a94ca --- /dev/null +++ b/xtask/src/release_runtime/create_network_release.rs @@ -0,0 +1,76 @@ +// Copyright 2021 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +use anyhow::{anyhow, Result}; +use graphql_client::{GraphQLQuery, Response}; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "res/schema.gql", + query_path = "res/create_network_release.gql", + response_derives = "Debug" +)] +pub struct CreateReleaseMutation; + +pub(super) async fn create_network_release( + gitlab_token: String, + branch: String, + network: String, + release_notes: String, +) -> Result<()> { + // this is the important line + let request_body = CreateReleaseMutation::build_query(create_release_mutation::Variables { + branch, + description: release_notes, + network, + links: vec![], + }); + + let client = reqwest::Client::new(); + let res = client + .post("https://git.duniter.org/api/graphql") + .header("PRIVATE-TOKEN", gitlab_token) + .json(&request_body) + .send() + .await?; + let response_body: Response<create_release_mutation::ResponseData> = res.json().await?; + + if let Some(data) = response_body.data { + if let Some(release_create) = data.release_create { + if release_create.errors.is_empty() { + Ok(()) + } else { + println!("{} errors:", release_create.errors.len()); + for error in release_create.errors { + println!("{}", error); + } + Err(anyhow!("Logic errors")) + } + } else if let Some(errors) = response_body.errors { + Err(anyhow!("Errors: {:?}", errors)) + } else { + Err(anyhow!("Invalid response: no release_create")) + } + } else if let Some(errors) = response_body.errors { + println!("{} errors:", errors.len()); + for error in errors { + println!("{}", error); + } + Err(anyhow!("GraphQL errors")) + } else { + Err(anyhow!("Invalid response: no data nor errors")) + } +} diff --git a/xtask/src/release_runtime/get_release.rs b/xtask/src/release_runtime/get_release.rs index cec00aba9..238a3504d 100644 --- a/xtask/src/release_runtime/get_release.rs +++ b/xtask/src/release_runtime/get_release.rs @@ -25,12 +25,10 @@ use graphql_client::{GraphQLQuery, Response}; )] pub struct GetReleaseOfProjectQuery; -pub(super) async fn get_release(milestone: String) -> Result<Vec<String>> { +pub(super) async fn get_release(tag: String) -> Result<Vec<String>> { // this is the important line let request_body = - GetReleaseOfProjectQuery::build_query(get_release_of_project_query::Variables { - milestone, - }); + GetReleaseOfProjectQuery::build_query(get_release_of_project_query::Variables { tag }); let client = reqwest::Client::new(); let res = client -- GitLab