From d0cde662ec34c484e0143415e8b760476563366c Mon Sep 17 00:00:00 2001 From: "bestia.dev" Date: Mon, 22 Apr 2024 01:25:12 +0000 Subject: [PATCH] template checking --- Cargo.toml | 2 +- README.md | 8 +- automation_tasks_rs/src/main.rs | 6 +- .../src/secrets_always_local_mod.rs | 44 +- src/outside_of_rust_project_mod.rs | 23 +- src/template_new_auto_mod.rs | 11 +- src/template_new_cli_mod.rs | 407 ++++---------- src/template_new_pwa_wasm_mod.rs | 524 ++++++------------ src/template_new_wasm_mod.rs | 440 +++++---------- template_new_auto/rustfmt.toml | 2 +- .../src/secrets_always_local_mod.rs | 44 +- .../.github/workflows/clear_all_cache.yml | 51 ++ template_new_cli/.vscode/settings.json | 20 +- template_new_cli/README.md | 18 +- template_new_cli/RELEASES.md | 4 +- .../automation_tasks_rs/src/main.rs | 8 +- .../src/secrets_always_local_mod.rs | 44 +- template_new_cli/rustfmt.toml | 1 + .../.github/workflows/clear_all_cache.yml | 51 ++ template_new_pwa_wasm/Cargo.toml | 4 +- template_new_pwa_wasm/README.md | 2 +- .../automation_tasks_rs/src/main.rs | 26 +- .../src/secrets_always_local_mod.rs | 46 +- .../publish_script/hello_world_publish.sh | 4 +- template_new_pwa_wasm/src/main_mod.rs | 2 +- .../pwa_short_name/index.html | 2 +- .../pwa_short_name/service_worker.js | 2 +- .../.github/workflows/clear_all_cache.yml | 51 ++ template_new_wasm/Cargo.toml | 4 +- template_new_wasm/README.md | 14 +- template_new_wasm/RELEASES.md | 2 +- .../automation_tasks_rs/src/main.rs | 34 +- .../src/secrets_always_local_mod.rs | 46 +- .../publish_script/hello_world_publish.sh | 4 +- .../cargo_auto_template_new_wasm/index.html | 2 +- 35 files changed, 812 insertions(+), 1141 deletions(-) create mode 100644 template_new_cli/.github/workflows/clear_all_cache.yml create mode 100644 template_new_cli/rustfmt.toml create mode 100644 template_new_pwa_wasm/.github/workflows/clear_all_cache.yml create mode 100644 template_new_wasm/.github/workflows/clear_all_cache.yml diff --git a/Cargo.toml b/Cargo.toml index 72ed6d2c..b1fe0812 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-auto" -version = "2024.419.1824" +version = "2024.422.15" authors = ["bestia.dev"] homepage = "https://bestia.dev" edition = "2021" diff --git a/README.md b/README.md index 1c44faf3..ddfa20f4 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [//]: # (auto_cargo_toml_to_md start) **Automation tasks coded in Rust language for the workflow of Rust projects** -***version: 2024.419.1824 date: 2024-04-19 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo-auto)*** +***version: 2024.422.15 date: 2024-04-22 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo-auto)*** ![maintained](https://img.shields.io/badge/maintained-green) ![ready-for-use](https://img.shields.io/badge/ready_for_use-green) @@ -28,11 +28,11 @@ ![cargo-auto](https://bestia.dev/webpage_hit_counter/get_svg_image/959103982.svg) [//]: # (auto_lines_of_code start) -[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-3106-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) +[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-3142-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) [![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-1191-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-699-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) +[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-704-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) [![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-10704-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) +[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-10869-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) [//]: # (auto_lines_of_code end) diff --git a/automation_tasks_rs/src/main.rs b/automation_tasks_rs/src/main.rs index 734ee01d..2ccf50db 100644 --- a/automation_tasks_rs/src/main.rs +++ b/automation_tasks_rs/src/main.rs @@ -277,7 +277,7 @@ fn task_release() { {YELLOW}1. Check if the template `new_cli` is working. Open a new terminal in VSCode and run:{RESET} {GREEN}cd ~/rustprojects{RESET} -{GREEN}./cargo-auto/target/release/{package_name} new_cli hello_world;{RESET} +{GREEN}./cargo-auto/target/release/{package_name} new_cli hello_world bestia.dev;{RESET} {GREEN}code hello_world{RESET} {YELLOW}In the new VSCODE window terminal, first change in Cargo.toml/repository from "github_owner" to your github username.{RESET} {YELLOW} Then try the workflow: cargo auto build, cargo auto release, cargo auto doc,... all to the end.{RESET} @@ -286,7 +286,7 @@ fn task_release() { {YELLOW}2. Check if the template `new_wasm` is working. Open a new terminal in VSCode and run:{RESET} {GREEN}cd ~/rustprojects{RESET} -{GREEN}./cargo-auto/target/release/{package_name} new_wasm hello_world{RESET} +{GREEN}./cargo-auto/target/release/{package_name} new_wasm hello_world bestia.dev luciano_bestia;{RESET} {GREEN}code hello_world{RESET} {YELLOW}In the new VSCODE window terminal, first change in Cargo.toml/repository from "github_owner" to your github username.{RESET} {YELLOW} Then try the workflow: cargo auto build, cargo auto release, cargo auto doc,... all to the end.{RESET} @@ -295,7 +295,7 @@ fn task_release() { {YELLOW}3. Check if the template `new_pwa_wasm` is working. Open a new terminal in VSCode and run:{RESET} {GREEN}cd ~/rustprojects{RESET} -{GREEN}./cargo-auto/target/release/{package_name} new_pwa_wasm hello_world{RESET} +{GREEN}./cargo-auto/target/release/{package_name} new_pwa_wasm{RESET} {YELLOW}Follow the instructions{RESET} {YELLOW}If ok, close the VSCode window.{RESET} diff --git a/automation_tasks_rs/src/secrets_always_local_mod.rs b/automation_tasks_rs/src/secrets_always_local_mod.rs index a732226d..78d7b84a 100644 --- a/automation_tasks_rs/src/secrets_always_local_mod.rs +++ b/automation_tasks_rs/src/secrets_always_local_mod.rs @@ -236,18 +236,7 @@ pub(crate) mod ssh_mod { ) } - let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); - if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { - eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); - eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); - if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"github api token\"{RESET}"#); - } else if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"crates io token\"{RESET}"#); - } - eprintln!(" "); - panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); - } + let identity_private_file_path_expanded = expand_path_check_private_key_exists(identity_private_file_path); let fingerprint_from_file = cargo_auto_encrypt_secret_lib::get_fingerprint_from_file(&identity_private_file_path_expanded); @@ -282,6 +271,24 @@ pub(crate) mod ssh_mod { } } } + /// Expand path and check if identity file exists + /// + /// Inform the user how to generate identity file. + pub fn expand_path_check_private_key_exists(identity_private_file_path: &camino::Utf8Path) -> camino::Utf8PathBuf { + let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); + if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { + eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); + eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); + if identity_private_file_path_expanded.as_str().contains("github_api") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "github api token"{RESET}"#); + } else if identity_private_file_path_expanded.as_str().contains("crates_io") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "crates io token"{RESET}"#); + } + eprintln!(" "); + panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); + } + identity_private_file_path_expanded + } } pub(crate) mod github_mod { @@ -365,7 +372,9 @@ pub(crate) mod github_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the GitHub API token encrypted with an SSH key? (y/n){RESET}"); @@ -377,7 +386,7 @@ pub(crate) mod github_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return GitHubClient read_token_and_decrypt_return_github_client(ssh_context, encrypted_string_file_path) } @@ -553,7 +562,10 @@ pub(crate) mod crate_io_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the crates.io token encrypted with an SSH key? (y/n){RESET}"); @@ -565,7 +577,7 @@ pub(crate) mod crate_io_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return CratesIoClient read_token_and_decrypt_return_crate_io_client(ssh_context, encrypted_string_file_path) } diff --git a/src/outside_of_rust_project_mod.rs b/src/outside_of_rust_project_mod.rs index f4df4741..4b91b83d 100644 --- a/src/outside_of_rust_project_mod.rs +++ b/src/outside_of_rust_project_mod.rs @@ -42,9 +42,9 @@ fn print_help_from_cargo_auto() { This program automates your custom tasks when developing a Rust project.{RESET} {YELLOW}Outside of a Rust project, cargo-auto can create a new Rust project:{RESET} -{GREEN}cargo auto new_cli project_name{RESET}{YELLOW} - a simple yet complete CLI application, better then `cargo new`{RESET} -{GREEN}cargo auto new_wasm project_name{RESET}{YELLOW} - a complete wasm application that works inside the browser{RESET} -{GREEN}cargo auto new_pwa_wasm project_name{RESET}{YELLOW} - On first call, it will create the `pwa.json5` and `icon512x512.png` files.{RESET} +{GREEN}cargo auto new_cli project_name github_owner{RESET}{YELLOW} - a simple yet complete CLI application, better then `cargo new`{RESET} +{GREEN}cargo auto new_wasm project_name github_owner web_server_domain server_username{RESET}{YELLOW} - a complete wasm application that works inside the browser{RESET} +{GREEN}cargo auto new_pwa_wasm {RESET}{YELLOW} - On first call, it will create the `pwa.json5` and `icon512x512.png` files.{RESET} {YELLOW}Modify them with the required data for your pwa project and then repeat the same command.{RESET} {YELLOW}© 2024 bestia.dev MIT License github.com/automation-tasks-rs/cargo-auto{RESET} @@ -58,14 +58,23 @@ fn match_first_argument(task: &str, args: &mut std::env::Args) { if task == "completion" { completion(); } else if task == "new_cli" { + // project_name let arg_2 = args.next(); - crate::template_new_cli_mod::new_cli(arg_2); + // github_owner + let arg_3 = args.next(); + crate::template_new_cli_mod::new_cli(arg_2, arg_3); } else if task == "new_wasm" { + // project_name let arg_2 = args.next(); - crate::template_new_wasm_mod::new_wasm(arg_2); + // github_owner + let arg_3 = args.next(); + // web server URL + let arg_4 = args.next(); + // web server username + let arg_5 = args.next(); + crate::template_new_wasm_mod::new_wasm(arg_2, arg_3, arg_4, arg_5); } else if task == "new_pwa_wasm" { - let arg_2 = args.next(); - crate::template_new_pwa_wasm_mod::new_pwa_wasm(arg_2); + crate::template_new_pwa_wasm_mod::new_pwa_wasm(); } else { print_help_from_cargo_auto(); } diff --git a/src/template_new_auto_mod.rs b/src/template_new_auto_mod.rs index b2ce94a0..74104cfa 100644 --- a/src/template_new_auto_mod.rs +++ b/src/template_new_auto_mod.rs @@ -67,7 +67,8 @@ pub fn get_vec_file() -> Vec { // region: files copied into strings by automation tasks vec_file.push(crate::FileItem { file_name: "rustfmt.toml", - file_content: r###"max_width = 200"###, + file_content: r###"max_width = 200 +"###, }); vec_file.push(crate::FileItem { file_name: ".gitignore", @@ -140,8 +141,8 @@ pub fn tracing_init() { // Unset the environment variable RUST_LOG // unset RUST_LOG let filter = tracing_subscriber::EnvFilter::from_default_env() - .add_directive("hyper_util=error".parse().unwrap()) - .add_directive("reqwest=error".parse().unwrap()); + .add_directive("hyper_util=error".parse().unwrap_or_else(|e| panic!("{e}"))) + .add_directive("reqwest=error".parse().unwrap_or_else(|e| panic!("{e}"))); tracing_subscriber::fmt() .with_file(true) @@ -258,12 +259,14 @@ fn print_help() { /// all example commands in one place fn print_examples_cmd() { +/* println!( r#" {YELLOW}run examples:{RESET} {GREEN}cargo run --example plantuml1{RESET} "# ); +*/ } /// sub-command for bash auto-completion of `cargo auto` using the crate `dev_bestia_cargo_completion` @@ -360,7 +363,7 @@ fn task_doc() { .run().unwrap_or_else(|e| panic!("{e}")); // pretty html - cl::auto_doc_tidy_html().unwrap(); + cl::auto_doc_tidy_html().unwrap_or_else(|e| panic!("{e}")); cl::run_shell_command_static("cargo fmt").unwrap_or_else(|e| panic!("{e}")); // message to help user with next move println!( diff --git a/src/template_new_cli_mod.rs b/src/template_new_cli_mod.rs index f265f8db..3bafc358 100644 --- a/src/template_new_cli_mod.rs +++ b/src/template_new_cli_mod.rs @@ -7,30 +7,36 @@ use crate::{GREEN, RED, RESET, YELLOW}; -pub fn new_cli(arg_2: Option) { - match arg_2 { - None => println!("{RED}Error: Project name argument is missing: `cargo auto new_cli project_name`{RESET}"), - Some(project_name) => { - copy_to_files(&project_name); - println!(""); - println!(" {YELLOW}The command `cargo auto new_cli` generated the directory `{project_name}`{RESET}"); - println!(" {YELLOW}You can open this new Rust project `{project_name}` in a new Rust editor.{RESET}",); - println!(" {YELLOW}For example VSCode:{RESET}"); - println!("{GREEN}code {project_name}{RESET}"); - println!(" {YELLOW}Then build inside the VSCode terminal with:{RESET}"); - println!("{GREEN}cargo auto build{RESET}"); - println!(" {YELLOW}and follow the detailed instructions.{RESET}"); - } +pub fn new_cli(arg_2: Option, arg_3: Option) { + if arg_2.is_none() { + println!("{RED}Error: Project name argument is missing: `cargo auto new_cli project_name github_owner`{RESET}"); + return; + } + if arg_3.is_none() { + println!("{RED}Error: Github owner argument is missing: `cargo auto new_cli project_name github_owner`{RESET}"); + return; } + let project_name = arg_2.unwrap(); + let github_owner = arg_3.unwrap(); + + copy_to_files(&project_name, &github_owner); + println!(""); + println!(" {YELLOW}The command `cargo auto new_cli` generated the directory `{project_name}`.{RESET}"); + println!(" {YELLOW}You can open this new Rust project in VSCode:{RESET}",); + println!("{GREEN}code {project_name}{RESET}"); + println!(" {YELLOW}Then build inside the VSCode terminal with:{RESET}"); + println!("{GREEN}cargo auto build{RESET}"); + println!(" {YELLOW}and follow the detailed instructions.{RESET}"); } -pub fn copy_to_files(project_name: &str) { +pub fn copy_to_files(project_name: &str, github_owner: &str) { let folder_path = std::path::Path::new(project_name); std::fs::create_dir_all(folder_path).unwrap(); for file_item in get_vec_file() { // rename/replace the project_name let file_name = file_item.file_name.replace("cargo_auto_template_new_cli", project_name); let file_content = file_item.file_content.replace("cargo_auto_template_new_cli", project_name); + let file_content = file_content.replace("/github_owner/", &format!("/{github_owner}/")); // create directory if needed std::fs::create_dir_all(folder_path.join(&file_name).parent().unwrap()).unwrap(); @@ -42,6 +48,11 @@ pub fn get_vec_file() -> Vec { let mut vec_file = vec![]; // region: files copied into strings by automation tasks + vec_file.push(crate::FileItem { + file_name: "rustfmt.toml", + file_content: r###"max_width = 200 +"###, + }); vec_file.push(crate::FileItem { file_name: ".gitattributes", file_content: r###"# Specific git config for the project @@ -73,8 +84,7 @@ LICENSE text eol=lf **/*.rs.bk # not needed in commits, but also not a problem if they are committed -/.automation_tasks_rs_file_hashes.json -/.auto_version_from_date.json"###, +/.automation_tasks_rs_file_hashes.json"###, }); vec_file.push(crate::FileItem { file_name: "automation_tasks_rs/rustfmt.toml", @@ -151,8 +161,8 @@ pub fn tracing_init() { // Unset the environment variable RUST_LOG // unset RUST_LOG let filter = tracing_subscriber::EnvFilter::from_default_env() - .add_directive("hyper_util=error".parse().unwrap()) - .add_directive("reqwest=error".parse().unwrap()); + .add_directive("hyper_util=error".parse().unwrap_or_else(|e| panic!("{e}"))) + .add_directive("reqwest=error".parse().unwrap_or_else(|e| panic!("{e}"))); tracing_subscriber::fmt() .with_file(true) @@ -269,12 +279,14 @@ fn print_help() { /// all example commands in one place fn print_examples_cmd() { +/* println!( r#" {YELLOW}run examples:{RESET} {GREEN}cargo run --example plantuml1{RESET} "# ); +*/ } /// sub-command for bash auto-completion of `cargo auto` using the crate `dev_bestia_cargo_completion` @@ -371,7 +383,7 @@ fn task_doc() { .run().unwrap_or_else(|e| panic!("{e}")); // pretty html - cl::auto_doc_tidy_html().unwrap(); + cl::auto_doc_tidy_html().unwrap_or_else(|e| panic!("{e}")); cl::run_shell_command_static("cargo fmt").unwrap_or_else(|e| panic!("{e}")); // message to help user with next move println!( @@ -476,7 +488,7 @@ fn task_github_new_release() { // take care of tags let tag_name_version = cl::git_tag_sync_check_create_push(&version); - let owner = cargo_toml.github_owner().unwrap(); + let github_owner = cargo_toml.github_owner().unwrap(); let repo_name = cargo_toml.package_name(); let now_date = cl::now_utc_date_iso(); let release_name = format!("Version {} ({})", &version, now_date); @@ -487,7 +499,7 @@ fn task_github_new_release() { let body_md_text = cl::body_text_from_releases_md().unwrap(); let github_client = github_mod::GitHubClient::new_with_stored_token(); - let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); + let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&github_owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); // early exit on error if let Some(error_message) = json_value.get("message") { eprintln!("{RED}{error_message}{RESET}"); @@ -528,7 +540,7 @@ fn task_github_new_release() { .run().unwrap_or_else(|e| panic!("{e}")); // upload asset - cgl::github_api_upload_asset_to_release(&github_client, &owner, &repo_name, &release_id, &tar_name); + cgl::github_api_upload_asset_to_release(&github_client, &github_owner, &repo_name, &release_id, &tar_name); cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) @@ -544,7 +556,7 @@ fn task_github_new_release() { println!( r#" -{GREEN}https://github.com/{owner}/{repo_name}/releases{RESET} +{GREEN}https://github.com/{github_owner}/{repo_name}/releases{RESET} "# ); } @@ -1253,8 +1265,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm The library releases will be published on crates.io. The cargo-auto automation task will use the content of the section `## Unreleased` to create the GitHub release consistently with this file. -The ongoing changes that are not released, are visible in the git commits and github pull requests. -The TODO section is part of the [README.md](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli). +The ongoing changes that are not released, are visible in the git commits and GitHub pull requests. +The TODO section is part of the [README.md](https://github.com/github_owner/cargo_auto_template_new_cli). ## Unreleased @@ -1358,255 +1370,7 @@ fn upper_greet_name(greet_name: &str) -> anyhow::Result<()> { // and it has some global stuff like the Error enum. // region: auto_md_to_doc_comments include README.md A //! -//! # cargo-auto -//! -//! **Automation tasks coded in Rust language for the workflow of Rust projects** -//! ***version: 2024.419.1824 date: 2024-04-19 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo-auto)*** -//! -//! ![maintained](https://img.shields.io/badge/maintained-green) -//! ![ready-for-use](https://img.shields.io/badge/ready_for_use-green) -//! ![rustlang](https://img.shields.io/badge/rustlang-orange) -//! ![automation](https://img.shields.io/badge/automation-orange) -//! ![workflow](https://img.shields.io/badge/workflow-orange) -//! -//! ![logo](https://raw.githubusercontent.com/automation-tasks-rs/cargo-auto/main/images/logo/logo_cargo_auto.svg) -//! cargo-auto is part of the [automation_tasks_rs](https://github.com/automation-tasks-rs) project -//! -//! [![crates.io](https://img.shields.io/crates/v/cargo-auto.svg)](https://crates.io/crates/cargo-auto) -//! [![Documentation](https://docs.rs/cargo-auto/badge.svg)](https://docs.rs/cargo-auto/) -//! [![crev reviews](https://web.crev.dev/rust-reviews/badge/crev_count/cargo-auto.svg)](https://web.crev.dev/rust-reviews/crate/cargo-auto/) -//! [![Lib.rs](https://img.shields.io/badge/Lib.rs-rust-orange.svg)](https://lib.rs/crates/cargo-auto/) -//! [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/blob/master/LICENSE) -//! [![Rust](https://github.com/automation-tasks-rs/cargo-auto/workflows/rust_fmt_auto_build_test/badge.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Newest docs](https://img.shields.io/badge/newest_docs-blue.svg)](https://automation-tasks-rs.github.io/cargo-auto/cargo_auto/index.html) -//! ![cargo-auto](https://bestia.dev/webpage_hit_counter/get_svg_image/959103982.svg) -//! -//! [![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-3106-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-1191-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-699-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in tests](https://img.shields.io/badge/Lines_in_tests-10704-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! -//! Hashtags: #maintained #ready-for-use #rustlang #automation #workflow -//! My projects on GitHub are more like a tutorial than a finished product: [bestia-dev tutorials](https://github.com/bestia-dev/tutorials_rust_wasm). -//! I recommend using the [CRUSTDE - Containerized Rust Development Environment](https://github.com/CRUSTDE-ContainerizedRustDevEnvrustde_cnt_img_pod) to write Rust projects on Linux, isolated from your system. -//! -//! ## Try it -//! -//! First, we will use `cargo-auto` to create a new empty CLI Rust project similar to `cargo new`, but with a more complete project structure. -//! -//! ```bash -//! cargo install cargo-auto -//! cargo auto new_cli my_hello_project -//! cd my_hello_project -//! cargo auto -//! # it lists all the prepared automation tasks -//! # try a few -//! cargo auto build -//! cargo auto release -//! cargo auto doc -//! cargo auto test -//! ``` -//! -//! We can also add `automation tasks` to an existing Rust project. -//! Inside your Rust project directory (the one with Cargo.toml) run: -//! -//! ```bash -//! cargo auto new_auto -//! cargo auto -//! # it lists all the prepared automation tasks -//! # try to build -//! cargo auto build -//! ``` -//! -//! Congratulations! You are already using `cargo-auto`. Simple as that. -//! Now you can modify the tasks to your needs. It is all Rust language. -//! -//! ## Motivation -//! -//! Cargo is a great tool for building Rust projects. It has all the basics: `cargo build`, `cargo build --release`, `cargo fmt`, `cargo test`, `cargo doc`,... -//! But sometimes we need to do more things like copying some files, publishing to FTP, or entering long commands. These repetitive tasks must be automated. -//! Task automation makes work easier and faster, and simplifies the workflow while improving the consistency and accuracy of workflows. -//! This is also sometimes referred to as "workflow automation." -//! There are many different build systems and task runners there: `make`, `cmake`, `shell scripts`, `cargo-xtask`, `cargo-make`, `cargo-task`, `cargo-script`, `cargo-run-script`, `runner`, `python scripts`, `powershell scripts`, `cmd prompt scripts`, ... -//! Sadly there is no standard in the Rust community for now. -//! I want something similar to [build.rs](https://doc.rust-lang.org/cargo/reference/build-scripts.html), so I can write my "tasks" in pure Rust I don't want to learn another meta language with weird syntax and difficulty to debug. So I will make something really simple, easy, rusty, and extensible. -//! -//! ## cargo auto subcommand -//! -//! The command `cargo install cargo-auto` will add a new subcommand to cargo: -//! -//! ```bash -//! cargo auto -//! ``` -//! -//! This binary is super simple. It has only 1 trivial dependency: `lazy_static`. -//! The binary only reads the CLI arguments and runs the `automation_tasks_rs` binary with them. If needed it will compile `automation_tasks_rs` first. -//! The code-flow of the source code of `cargo-auto` is simple, fully commented, and straightforward to audit. -//! The source code is on [GitHub](https://github.com/automation-tasks-rs/cargo-auto) with MIT open-source licensing. -//! -//! ## bash auto-completion -//! -//! With the help of the crate [dev_bestia_cargo_completion](https://crates.io/crates/dev_bestia_cargo_completion), the commands `cargo` and `cargo auto` get bash auto-completion. Try it! -//! -//! ## cargo auto new_cli -//! -//! I like very much that Rust has the command `cargo new project_name`. It creates a super simple Rust Hello project that can be built and run immediately. But this example is too simple. It lacks the basic file structures of a serious CLI program. -//! I composed an opinionated template for a Rust CLI project. It is easy to run: -//! -//! ```bash -//! cargo auto new_cli project_name -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## cargo auto new_wasm -//! -//! I composed an opinionated template for a simple Rust WASM project for a browser. It is very similar to the new_cli template but for WASM. -//! It is easy to run: -//! -//! ```bash -//! cargo auto new_wasm project_name -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## cargo auto new_pwa_wasm -//! -//! I composed an opinionated template for a simple Rust PWA-WASM project for a browser. It is very similar to the new_cli template but for WASM. It adds the PWA standard functionality to work as an offline app. -//! The template needs the title, name, long name, and description inside a `pwa.json5` file and the `icon512x512.png` file for the icons. -//! It is easy to run: -//! -//! ```bash -//! cargo auto new_pwa_wasm -//! # on first run it will just create the `pwa.json5` and `icon512x512.png` files -//! # modify these files with data for your new app and then repeat -//! cargo auto new_pwa_wasm -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## scripting with rust -//! -//! Rust is a compiled language. It is not really a scripting or interpreted language. But the compilation of small projects is really fast and can be ignored. Subsequent calls will use the already-built binary so the speed will be even faster. -//! This tool `cargo-auto` is meant for Rust projects, so it means that all the Rust infrastructure is already in place. -//! -//! ## automation_tasks_rs Rust sub-project -//! -//! The command `cargo auto new_auto` will create a new Rust sub-project`automation_tasks_rs` inside your `Rust project`. It should not interfere with the main Rust project. This directory will be added to git commits and pushed to remote repositories as part of the main project. It has its own `.gitignore` to avoid committing to its target directory. -//! The `automation_tasks_rs` helper project contains user-defined tasks in Rust code. Your tasks. This helper project should be opened in a new editor starting from the `automation_tasks_rs` directory. It does not share dependencies with the main project. It is completely separate and independent. -//! You can edit it and add your dependencies and Rust code. No limits. Freedom of expression. -//! This is now your code, your tasks, and your helper Rust project! -//! Because only you know what you want to automate and how to do it. -//! Never write secrets, passwords, passphrases, or tokens inside your Rust code. Because then it is pushed to GitHub and the whole world can read it in the next second! -//! Basic example (most of the useful functions are already there): -//! -//! ```rust ignore -//! /// match arguments and call tasks functions -//! fn match_arguments_and_call_tasks(mut args: std::env::Args){ -//! // the first argument is the user defined task: (no argument for help), build, release,... -//! let arg_1 = args.next(); -//! match arg_1 { -//! None => print_help(), -//! Some(task) => { -//! println!("Running auto task: {}", &task); -//! if &task == "build"{ -//! task_build(); -//! } else if &task == "release" { -//! task_release(); -//! } else if &task == "doc" { -//! task_doc(); -//! } else { -//! println!("Task {} is unknown.", &task); -//! print_help(); -//! } -//! } -//! } -//! } -//! -//! /// write a comprehensible help for user defined tasks -//! fn print_help() { -//! println!(r#" -//! User defined tasks in automation_tasks_rs: -//! cargo auto build - builds the crate in debug mode -//! cargo auto release - builds the crate in release mode -//! cargo auto docs - builds the docs -//! "#); -//! } -//! -//! // region: tasks -//! -//! /// cargo build -//! fn task_build() { -//! run_shell_command("cargo fmt"); -//! run_shell_command("cargo build"); -//! } -//! -//! /// cargo build --release -//! fn task_release() { -//! run_shell_command("cargo fmt"); -//! run_shell_command("cargo build --release"); -//! } -//! -//! /// cargo doc, then copies to /docs/ folder, because this is a github standard folder -//! fn task_doc() { -//! run_shell_command("cargo doc --no-deps --document-private-items"); -//! // copy target/doc into docs/ because it is github standard -//! run_shell_command("rsync -a --info=progress2 --delete-after target/doc/ docs/"); -//! // Create simple index.html file in docs directory -//! run_shell_command(&format!( -//! "printf \"\\n\" > docs/index.html", -//! cargo_toml.package_name().replace("-","_") -//! )); -//! run_shell_command("cargo fmt"); -//! } -//! -//! // endregion: tasks -//! -//! ``` -//! -//! ## more complex tasks -//! -//! You can write more complex tasks in Rust language. -//! For example in this project I use automation to create GitHub Releases: -//! Here is a pretty complex workspace with more sub-projects: -//! -//! There is no end to your imagination. If you write something that looks like it can help other developers, please share it with me and I will add it here. -//! -//! ## Development details -//! -//! Read the development details in a separate md file: -//! [DEVELOPMENT.md](https://github.com/automation-tasks-rs/cargo-auto/blob/main/DEVELOPMENT.md) -//! -//! ## Releases changelog -//! -//! Read the changelog in a separate md file: -//! [RELEASES.md](https://github.com/automation-tasks-rs/cargo-auto/blob/main/RELEASES.md) -//! -//! ## TODO -//! -//! Nothing big in the near future. -//! -//! ## Open-source and free as a beer -//! -//! My open-source projects are free as a beer (MIT license). -//! I just love programming. -//! But I need also to drink. If you find my projects and tutorials helpful, please buy me a beer by donating to my [PayPal](https://paypal.me/LucianoBestia). -//! You know the price of a beer in your local bar ;-) -//! So I can drink a free beer for your health :-) -//! [Na zdravje!](https://translate.google.com/?hl=en&sl=sl&tl=en&text=Na%20zdravje&op=translate) [Alla salute!](https://dictionary.cambridge.org/dictionary/italian-english/alla-salute) [Prost!](https://dictionary.cambridge.org/dictionary/german-english/prost) [Nazdravlje!](https://matadornetwork.com/nights/how-to-say-cheers-in-50-languages/) 🍻 -//! -//! [//bestia.dev](https://bestia.dev) -//! [//github.com/automation-tasks-rs](https://github.com/automation-tasks-rs) -//! [//bestiadev.substack.com](https://bestiadev.substack.com) -//! [//youtube.com/@bestia-dev-tutorials](https://youtube.com/@bestia-dev-tutorials) -//! + // endregion: auto_md_to_doc_comments include README.md A //! // access to modules @@ -1693,6 +1457,61 @@ mod test { assert_eq!(make_uppercase("čšž"), "ČŠŽ"); } } +"###, + }); + vec_file.push(crate::FileItem { + file_name: ".github/workflows/clear_all_cache.yml", + file_content: r###"name: cleanup caches on main + +# Configure Manual Trigger with workflow_dispatch +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + printf "$REPO\n" + BRANCH=main + printf "$BRANCH\n" + + # loop until the list is empty, because it deletes only 30 per page + has_items=true + while [ "$has_items" = true ] + do + printf "\033[0;33m Fetching list of cache key\n\033[0m\n" + printf "\033[0;32m gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 \n\033[0m\n" + cache_keys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + # printf "$cache_keys\n" + if [ -z "$cache_keys" ]; then + printf "\033[0;35m gh actions-cache list returned nothing.\n\033[0m\n" + has_items=false + fi + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cache_keys + do + # printf "\033[0;32m gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n\033[0m\n" + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + done + printf "\033[0;33m Done\n\033[0m\n" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + "###, }); vec_file.push(crate::FileItem { @@ -1984,20 +1803,20 @@ SOFTWARE. [//]: # (auto_cargo_toml_to_md start) **Basic Rust project template for CLI and library, more than just `cargo new hello`** -***version: 1.0.4 date: 2024-04-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli)*** +***version: 1.0.4 date: 2024-04-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/github_owner/cargo_auto_template_new_cli)*** [//]: # (auto_cargo_toml_to_md end) - [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli/blob/main/LICENSE) - [![Rust](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli/workflows/RustAction/badge.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli/) + [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/blob/main/LICENSE) + [![Rust](https://github.com/github_owner/cargo_auto_template_new_cli/workflows/RustAction/badge.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) [//]: # (auto_lines_of_code start) -[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-89-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-13-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-36-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-19-yellow.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-30-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) +[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-89-green.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-13-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-36-purple.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-19-yellow.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-30-orange.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) [//]: # (auto_lines_of_code end) @@ -2013,7 +1832,7 @@ Just like `cargo new` makes a soft and gentle introduction to Rust projects and cargo auto new_cli project_name ``` -Extremely simple, just the basic moving parts and use-cases. +Extremely simple, just the basic moving parts and use cases. ## Development details @@ -2086,22 +1905,22 @@ fn integration_test_02_error_check() { }, "rust-analyzer.showUnlinkedFileNotification": false, "cSpell.words": [ - "zdravje", - "zcvf", - "thiserror", - "substack", - "struct", - "Prost", - "Nazdravlje", - "CRUSTDE", - "bestiadev", "Alla", "bestia", + "bestiadev", + "CRUSTDE", "endregion", + "Nazdravlje", "plantuml", + "Prost", "rustdevuser", + "rustlang", "rustprojects", - "zcvf" + "struct", + "substack", + "thiserror", + "zcvf", + "zdravje" ] }"###, }); diff --git a/src/template_new_pwa_wasm_mod.rs b/src/template_new_pwa_wasm_mod.rs index 55b7d354..c2c951e9 100644 --- a/src/template_new_pwa_wasm_mod.rs +++ b/src/template_new_pwa_wasm_mod.rs @@ -14,68 +14,62 @@ struct PwaJson5 { pwa_short_name: String, pwa_name: String, pwa_description: String, - project_author: String, project_homepage: String, project_repository: String, -} - -pub fn new_pwa_wasm(arg_2: Option) { - match arg_2 { - None => println!("{RED}Error: Project name argument is missing: `cargo auto new_pwa_wasm project_name`{RESET}"), - Some(rust_project_name) => { - if std::path::Path::new("pwa.json5").exists() && std::path::Path::new("icon512x512.png").exists() { - // both exist, read the json5 and run the generator - let pwa_json5: PwaJson5 = json5::from_str(&std::fs::read_to_string("pwa.json5").unwrap()).unwrap(); - // the rust_project_name must be equal - if rust_project_name != pwa_json5.rust_project_name { - panic!("{RED}Error: rust_project_name in pwa.json5 is different!{RESET}") - } - copy_to_files(&pwa_json5); - - // region: png with various sizes for: favicon png, pwa Android and pwa iOS - // 32, 72, 96, 120, 128, 144, 152, 167, 180, 192, 196, 512 - let img = std::fs::read("icon512x512.png").unwrap(); - let img = decode_png(img); - - resize_image(&img, 32, "icon-032.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 72, "icon-072.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 96, "icon-096.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 120, "icon-120.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 128, "icon-128.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 144, "icon-144.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 152, "icon-152.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 167, "icon-167.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 180, "icon-180.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 192, "icon-192.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - resize_image(&img, 196, "icon-196.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - // overwrite the default with the new - resize_image(&img, 512, "icon-512.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - - // maskable icon 192 - resize_image(&img, 192, "icon-maskable.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - - // favicon.ico with 16, 32 and 48 icons - encode_to_favicon_ico(&img, &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); - - // endregion - println!( - r#" - {YELLOW}On second run, the command `crate auto new_pwa_wasm {package_name}` generated the project directory `{package_name}`{RESET} + web_server_domain: String, + server_username: String, +} + +pub fn new_pwa_wasm() { + if std::path::Path::new("pwa.json5").exists() && std::path::Path::new("icon512x512.png").exists() { + // both exist, read the json5 and run the generator + let pwa_json5: PwaJson5 = json5::from_str(&std::fs::read_to_string("pwa.json5").unwrap()).unwrap(); + copy_to_files(&pwa_json5); + + // region: png with various sizes for: favicon png, pwa Android and pwa iOS + // 32, 72, 96, 120, 128, 144, 152, 167, 180, 192, 196, 512 + let img = std::fs::read("icon512x512.png").unwrap(); + let img = decode_png(img); + + resize_image(&img, 32, "icon-032.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 72, "icon-072.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 96, "icon-096.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 120, "icon-120.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 128, "icon-128.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 144, "icon-144.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 152, "icon-152.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 167, "icon-167.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 180, "icon-180.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 192, "icon-192.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + resize_image(&img, 196, "icon-196.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + // overwrite the default with the new + resize_image(&img, 512, "icon-512.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + + // maskable icon 192 + resize_image(&img, 192, "icon-maskable.png", &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + + // favicon.ico with 16, 32 and 48 icons + encode_to_favicon_ico(&img, &pwa_json5.rust_project_name, &pwa_json5.pwa_short_name); + + // endregion + println!( + r#" + {YELLOW}On second run, the command `crate auto new_pwa_wasm` generated the project directory `{package_name}`{RESET} {YELLOW}You can open this new Rust project `{package_name}` in VSCode:{RESET} {GREEN}code {package_name}{RESET} {YELLOW}Then build with:{RESET} {GREEN}cargo auto build{RESET} {YELLOW}and follow the detailed instructions.{RESET} "#, - package_name = rust_project_name - ); - } else { - // On first run - // They don't exist, create the default ones and return instructions to the user. - if !std::path::Path::new("pwa.json5").exists() { - std::fs::write( - "pwa.json5", - r#" + package_name = &pwa_json5.rust_project_name + ); + } else { + // On first run + // They don't exist, create the default ones and return instructions to the user. + if !std::path::Path::new("pwa.json5").exists() { + std::fs::write( + "pwa.json5", + r#" { // modify the values in this json5 file accordingly to your new project @@ -83,37 +77,35 @@ pub fn new_pwa_wasm(arg_2: Option) { pwa_short_name: "hello_world", pwa_name: "hello_world", pwa_description: "Template for a minimal pwa wasm project for browser", - project_author: "luciano_bestia", project_homepage: "bestia.dev", project_repository: "https://github.com/bestia-dev/hello_world", + web_server_domain: "bestia.dev", + server_username: "luciano_bestia", } "#, - ) - .unwrap(); - } - if !std::path::Path::new("icon512x512.png").exists() { - // decode the icon-512 - for file_item in get_vec_file() { - if file_item.file_name.ends_with("icon-512.png") { - let file_content = file_item.file_content; - let file_content = ::decode_vec(&file_content).unwrap(); - std::fs::write("icon512x512.png", file_content).unwrap(); - break; - } - } + ) + .unwrap(); + } + if !std::path::Path::new("icon512x512.png").exists() { + // decode the icon-512 + for file_item in get_vec_file() { + if file_item.file_name.ends_with("icon-512.png") { + let file_content = file_item.file_content; + let file_content = ::decode_vec(&file_content).unwrap(); + std::fs::write("icon512x512.png", file_content).unwrap(); + break; } - println!( - r#" - {YELLOW}On first run, the command `crate auto new_pwa_wasm {package_name}` generated the files `pwa.json5` and `icon512x512.png`.{RESET} + } + } + println!( + r#" + {YELLOW}On first run, the command `crate auto new_pwa_wasm` generated the files `pwa.json5` and `icon512x512.png`.{RESET} {YELLOW}Modify these files accordingly. This step is very important:{RESET} {GREEN}code pwa.json5{RESET} {YELLOW}Finally, repeat the same command to generate the project directory.{RESET} -{GREEN}crate auto new_pwa_wasm {package_name}{RESET} -"#, - package_name = rust_project_name - ); - } - } +{GREEN}crate auto new_pwa_wasm {RESET} +"# + ); } } @@ -191,9 +183,10 @@ fn copy_to_files(pwa_json5: &PwaJson5) { .replace("pwa_short_name", &pwa_json5.pwa_short_name) .replace("pwa_name", &pwa_json5.pwa_name) .replace("pwa_description", &pwa_json5.pwa_description) - .replace("project_author", &pwa_json5.project_author) .replace("project_homepage", &pwa_json5.project_homepage) - .replace("project_repository", &pwa_json5.project_repository); + .replace("project_repository", &pwa_json5.project_repository) + .replace("web_server_domain", &pwa_json5.web_server_domain) + .replace("server_username", &pwa_json5.server_username); std::fs::write(folder_path.join(&file_name), file_content.as_bytes()).unwrap(); } } @@ -234,8 +227,8 @@ printf "\033[0;33m RUN ON WEB SERVER: Bash script to publish web site \033[0m printf "\n" printf "\033[0;33m First the development files are copied over SSH to the folder 'transfer_folder'. \033[0m\n" printf "\033[0;33m Then copy the files from 'transfer_folder' to the web server folder. \033[0m\n" -printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/hello_world /var/www/bestia.dev/hello_world \033[0m\n" -rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/hello_world/ /var/www/bestia.dev/hello_world/ +printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/hello_world /var/www/web_server_domain/hello_world \033[0m\n" +rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/hello_world/ /var/www/web_server_domain/hello_world/ printf "\033[0;33m Completed. \033[0m\n" printf "\n" @@ -259,7 +252,6 @@ printf "\n" # not needed in commits, but also not a problem if they are committed /.automation_tasks_rs_file_hashes.json -/.auto_version_from_date.json "###, }); vec_file.push(crate::FileItem { @@ -336,8 +328,8 @@ pub fn tracing_init() { // Unset the environment variable RUST_LOG // unset RUST_LOG let filter = tracing_subscriber::EnvFilter::from_default_env() - .add_directive("hyper_util=error".parse().unwrap()) - .add_directive("reqwest=error".parse().unwrap()); + .add_directive("hyper_util=error".parse().unwrap_or_else(|e| panic!("{e}"))) + .add_directive("reqwest=error".parse().unwrap_or_else(|e| panic!("{e}"))); tracing_subscriber::fmt() .with_file(true) @@ -453,9 +445,12 @@ fn print_help() { /// all example commands in one place fn print_examples_cmd() { /* - println!(r#"{YELLOW}run examples:{RESET} -{GREEN}cargo run --example example1{RESET} -"#); + println!( + r#" + {YELLOW}run examples:{RESET} +{GREEN}cargo run --example plantuml1{RESET} +"# + ); */ } @@ -564,7 +559,7 @@ fn task_doc() { .run().unwrap_or_else(|e| panic!("{e}")); // pretty html - cl::auto_doc_tidy_html().unwrap(); + cl::auto_doc_tidy_html().unwrap_or_else(|e| panic!("{e}")); cl::run_shell_command_static("cargo fmt").unwrap_or_else(|e| panic!("{e}")); // message to help user with next move println!( @@ -646,40 +641,40 @@ fn task_publish_to_web() { // rsync to copy to server over ssh into a temporary installation folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{project_author}@{project_homepage}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{server_username}@{web_server_domain}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // rsync to copy to server over ssh the installation script cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/hello_world_publish.sh" "{project_author}@{project_homepage}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/hello_world_publish.sh" "{server_username}@{web_server_domain}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); //make the bash script executable cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" chmod +x "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" chmod +x "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // run installation script over ssh on the server to copy from the installation folder to production folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); println!( r#" {YELLOW}After `cargo auto publish_to_web`check {RESET} -{GREEN}https://bestia.dev/{package_name}{RESET} +{GREEN}https://web_server_domain/{package_name}{RESET} {YELLOW} {YELLOW}If all is fine, run{RESET} {GREEN}cargo auto github_new_release{RESET} "#, @@ -740,16 +735,16 @@ fn task_github_new_release() { // compress files tar.gz let tar_name = format!("{repo_name}-{tag_name_version}-x86_64-unknown-linux-gnu.tar.gz"); - cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"tar -zcvf "{tar_name_sanitized_for_double_quote}" "target/release/{repo_name_sanitized_for_double_quote}" "#) - .arg("{tar_name_sanitized_for_double_quote}", &tar_name) - .arg("{repo_name_sanitized_for_double_quote}", &repo_name) + cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"tar -zcvf "{tar_name_sanitized_for_double_quote}" "target/release/{repo_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) + .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) + .arg("{repo_name_sanitized_for_double_quote}", &repo_name).unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // upload asset cgl::github_api_upload_asset_to_release(&github_client, &owner, &repo_name, &release_id, &tar_name); - cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#) - .arg("{tar_name_sanitized_for_double_quote}", &tar_name) + cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) + .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); println!( @@ -1669,7 +1664,7 @@ fn page_with_inputs() { let mut fragment = wsm::HtmlSourceCode::new(r#"

{ph_text_node_1}

"#); fragment.replace_attribute_value("{ph_attr_class_1}", "small"); - fragment.replace_text_node("{ph_text_node_1}", "bestia.dev"); + fragment.replace_text_node("{ph_text_node_1}", "web_server_domain"); html_source_code.replace_html_source_code("{ph_elem_p_1}", &fragment); dbg!(html_source_code.get_html()); @@ -2008,255 +2003,7 @@ pub const RESET: &str = "\x1b[0m"; // So the structure of the project modules can be similar to a binary CLI executable. // region: auto_md_to_doc_comments include README.md A //! -//! # cargo-auto -//! -//! **Automation tasks coded in Rust language for the workflow of Rust projects** -//! ***version: 2024.419.1824 date: 2024-04-19 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo-auto)*** -//! -//! ![maintained](https://img.shields.io/badge/maintained-green) -//! ![ready-for-use](https://img.shields.io/badge/ready_for_use-green) -//! ![rustlang](https://img.shields.io/badge/rustlang-orange) -//! ![automation](https://img.shields.io/badge/automation-orange) -//! ![workflow](https://img.shields.io/badge/workflow-orange) -//! -//! ![logo](https://raw.githubusercontent.com/automation-tasks-rs/cargo-auto/main/images/logo/logo_cargo_auto.svg) -//! cargo-auto is part of the [automation_tasks_rs](https://github.com/automation-tasks-rs) project -//! -//! [![crates.io](https://img.shields.io/crates/v/cargo-auto.svg)](https://crates.io/crates/cargo-auto) -//! [![Documentation](https://docs.rs/cargo-auto/badge.svg)](https://docs.rs/cargo-auto/) -//! [![crev reviews](https://web.crev.dev/rust-reviews/badge/crev_count/cargo-auto.svg)](https://web.crev.dev/rust-reviews/crate/cargo-auto/) -//! [![Lib.rs](https://img.shields.io/badge/Lib.rs-rust-orange.svg)](https://lib.rs/crates/cargo-auto/) -//! [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/blob/master/LICENSE) -//! [![Rust](https://github.com/automation-tasks-rs/cargo-auto/workflows/rust_fmt_auto_build_test/badge.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Newest docs](https://img.shields.io/badge/newest_docs-blue.svg)](https://automation-tasks-rs.github.io/cargo-auto/cargo_auto/index.html) -//! ![cargo-auto](https://bestia.dev/webpage_hit_counter/get_svg_image/959103982.svg) -//! -//! [![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-3106-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-1191-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-699-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in tests](https://img.shields.io/badge/Lines_in_tests-10704-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! -//! Hashtags: #maintained #ready-for-use #rustlang #automation #workflow -//! My projects on GitHub are more like a tutorial than a finished product: [bestia-dev tutorials](https://github.com/bestia-dev/tutorials_rust_wasm). -//! I recommend using the [CRUSTDE - Containerized Rust Development Environment](https://github.com/CRUSTDE-ContainerizedRustDevEnvrustde_cnt_img_pod) to write Rust projects on Linux, isolated from your system. -//! -//! ## Try it -//! -//! First, we will use `cargo-auto` to create a new empty CLI Rust project similar to `cargo new`, but with a more complete project structure. -//! -//! ```bash -//! cargo install cargo-auto -//! cargo auto new_cli my_hello_project -//! cd my_hello_project -//! cargo auto -//! # it lists all the prepared automation tasks -//! # try a few -//! cargo auto build -//! cargo auto release -//! cargo auto doc -//! cargo auto test -//! ``` -//! -//! We can also add `automation tasks` to an existing Rust project. -//! Inside your Rust project directory (the one with Cargo.toml) run: -//! -//! ```bash -//! cargo auto new_auto -//! cargo auto -//! # it lists all the prepared automation tasks -//! # try to build -//! cargo auto build -//! ``` -//! -//! Congratulations! You are already using `cargo-auto`. Simple as that. -//! Now you can modify the tasks to your needs. It is all Rust language. -//! -//! ## Motivation -//! -//! Cargo is a great tool for building Rust projects. It has all the basics: `cargo build`, `cargo build --release`, `cargo fmt`, `cargo test`, `cargo doc`,... -//! But sometimes we need to do more things like copying some files, publishing to FTP, or entering long commands. These repetitive tasks must be automated. -//! Task automation makes work easier and faster, and simplifies the workflow while improving the consistency and accuracy of workflows. -//! This is also sometimes referred to as "workflow automation." -//! There are many different build systems and task runners there: `make`, `cmake`, `shell scripts`, `cargo-xtask`, `cargo-make`, `cargo-task`, `cargo-script`, `cargo-run-script`, `runner`, `python scripts`, `powershell scripts`, `cmd prompt scripts`, ... -//! Sadly there is no standard in the Rust community for now. -//! I want something similar to [build.rs](https://doc.rust-lang.org/cargo/reference/build-scripts.html), so I can write my "tasks" in pure Rust I don't want to learn another meta language with weird syntax and difficulty to debug. So I will make something really simple, easy, rusty, and extensible. -//! -//! ## cargo auto subcommand -//! -//! The command `cargo install cargo-auto` will add a new subcommand to cargo: -//! -//! ```bash -//! cargo auto -//! ``` -//! -//! This binary is super simple. It has only 1 trivial dependency: `lazy_static`. -//! The binary only reads the CLI arguments and runs the `automation_tasks_rs` binary with them. If needed it will compile `automation_tasks_rs` first. -//! The code-flow of the source code of `cargo-auto` is simple, fully commented, and straightforward to audit. -//! The source code is on [GitHub](https://github.com/automation-tasks-rs/cargo-auto) with MIT open-source licensing. -//! -//! ## bash auto-completion -//! -//! With the help of the crate [dev_bestia_cargo_completion](https://crates.io/crates/dev_bestia_cargo_completion), the commands `cargo` and `cargo auto` get bash auto-completion. Try it! -//! -//! ## cargo auto new_cli -//! -//! I like very much that Rust has the command `cargo new project_name`. It creates a super simple Rust Hello project that can be built and run immediately. But this example is too simple. It lacks the basic file structures of a serious CLI program. -//! I composed an opinionated template for a Rust CLI project. It is easy to run: -//! -//! ```bash -//! cargo auto new_cli project_name -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## cargo auto new_wasm -//! -//! I composed an opinionated template for a simple Rust WASM project for a browser. It is very similar to the new_cli template but for WASM. -//! It is easy to run: -//! -//! ```bash -//! cargo auto new_wasm project_name -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## cargo auto new_pwa_wasm -//! -//! I composed an opinionated template for a simple Rust PWA-WASM project for a browser. It is very similar to the new_cli template but for WASM. It adds the PWA standard functionality to work as an offline app. -//! The template needs the title, name, long name, and description inside a `pwa.json5` file and the `icon512x512.png` file for the icons. -//! It is easy to run: -//! -//! ```bash -//! cargo auto new_pwa_wasm -//! # on first run it will just create the `pwa.json5` and `icon512x512.png` files -//! # modify these files with data for your new app and then repeat -//! cargo auto new_pwa_wasm -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## scripting with rust -//! -//! Rust is a compiled language. It is not really a scripting or interpreted language. But the compilation of small projects is really fast and can be ignored. Subsequent calls will use the already-built binary so the speed will be even faster. -//! This tool `cargo-auto` is meant for Rust projects, so it means that all the Rust infrastructure is already in place. -//! -//! ## automation_tasks_rs Rust sub-project -//! -//! The command `cargo auto new_auto` will create a new Rust sub-project`automation_tasks_rs` inside your `Rust project`. It should not interfere with the main Rust project. This directory will be added to git commits and pushed to remote repositories as part of the main project. It has its own `.gitignore` to avoid committing to its target directory. -//! The `automation_tasks_rs` helper project contains user-defined tasks in Rust code. Your tasks. This helper project should be opened in a new editor starting from the `automation_tasks_rs` directory. It does not share dependencies with the main project. It is completely separate and independent. -//! You can edit it and add your dependencies and Rust code. No limits. Freedom of expression. -//! This is now your code, your tasks, and your helper Rust project! -//! Because only you know what you want to automate and how to do it. -//! Never write secrets, passwords, passphrases, or tokens inside your Rust code. Because then it is pushed to GitHub and the whole world can read it in the next second! -//! Basic example (most of the useful functions are already there): -//! -//! ```rust ignore -//! /// match arguments and call tasks functions -//! fn match_arguments_and_call_tasks(mut args: std::env::Args){ -//! // the first argument is the user defined task: (no argument for help), build, release,... -//! let arg_1 = args.next(); -//! match arg_1 { -//! None => print_help(), -//! Some(task) => { -//! println!("Running auto task: {}", &task); -//! if &task == "build"{ -//! task_build(); -//! } else if &task == "release" { -//! task_release(); -//! } else if &task == "doc" { -//! task_doc(); -//! } else { -//! println!("Task {} is unknown.", &task); -//! print_help(); -//! } -//! } -//! } -//! } -//! -//! /// write a comprehensible help for user defined tasks -//! fn print_help() { -//! println!(r#" -//! User defined tasks in automation_tasks_rs: -//! cargo auto build - builds the crate in debug mode -//! cargo auto release - builds the crate in release mode -//! cargo auto docs - builds the docs -//! "#); -//! } -//! -//! // region: tasks -//! -//! /// cargo build -//! fn task_build() { -//! run_shell_command("cargo fmt"); -//! run_shell_command("cargo build"); -//! } -//! -//! /// cargo build --release -//! fn task_release() { -//! run_shell_command("cargo fmt"); -//! run_shell_command("cargo build --release"); -//! } -//! -//! /// cargo doc, then copies to /docs/ folder, because this is a github standard folder -//! fn task_doc() { -//! run_shell_command("cargo doc --no-deps --document-private-items"); -//! // copy target/doc into docs/ because it is github standard -//! run_shell_command("rsync -a --info=progress2 --delete-after target/doc/ docs/"); -//! // Create simple index.html file in docs directory -//! run_shell_command(&format!( -//! "printf \"\\n\" > docs/index.html", -//! cargo_toml.package_name().replace("-","_") -//! )); -//! run_shell_command("cargo fmt"); -//! } -//! -//! // endregion: tasks -//! -//! ``` -//! -//! ## more complex tasks -//! -//! You can write more complex tasks in Rust language. -//! For example in this project I use automation to create GitHub Releases: -//! Here is a pretty complex workspace with more sub-projects: -//! -//! There is no end to your imagination. If you write something that looks like it can help other developers, please share it with me and I will add it here. -//! -//! ## Development details -//! -//! Read the development details in a separate md file: -//! [DEVELOPMENT.md](https://github.com/automation-tasks-rs/cargo-auto/blob/main/DEVELOPMENT.md) -//! -//! ## Releases changelog -//! -//! Read the changelog in a separate md file: -//! [RELEASES.md](https://github.com/automation-tasks-rs/cargo-auto/blob/main/RELEASES.md) -//! -//! ## TODO -//! -//! Nothing big in the near future. -//! -//! ## Open-source and free as a beer -//! -//! My open-source projects are free as a beer (MIT license). -//! I just love programming. -//! But I need also to drink. If you find my projects and tutorials helpful, please buy me a beer by donating to my [PayPal](https://paypal.me/LucianoBestia). -//! You know the price of a beer in your local bar ;-) -//! So I can drink a free beer for your health :-) -//! [Na zdravje!](https://translate.google.com/?hl=en&sl=sl&tl=en&text=Na%20zdravje&op=translate) [Alla salute!](https://dictionary.cambridge.org/dictionary/italian-english/alla-salute) [Prost!](https://dictionary.cambridge.org/dictionary/german-english/prost) [Nazdravlje!](https://matadornetwork.com/nights/how-to-say-cheers-in-50-languages/) 🍻 -//! -//! [//bestia.dev](https://bestia.dev) -//! [//github.com/automation-tasks-rs](https://github.com/automation-tasks-rs) -//! [//bestiadev.substack.com](https://bestiadev.substack.com) -//! [//youtube.com/@bestia-dev-tutorials](https://youtube.com/@bestia-dev-tutorials) -//! + // endregion: auto_md_to_doc_comments include README.md A //! use wasm_bindgen::prelude::*; @@ -2277,6 +2024,61 @@ pub fn wasm_bindgen_start() -> Result<(), JsValue> { // return Ok(()) } +"###, + }); + vec_file.push(crate::FileItem { + file_name: ".github/workflows/clear_all_cache.yml", + file_content: r###"name: cleanup caches on main + +# Configure Manual Trigger with workflow_dispatch +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + printf "$REPO\n" + BRANCH=main + printf "$BRANCH\n" + + # loop until the list is empty, because it deletes only 30 per page + has_items=true + while [ "$has_items" = true ] + do + printf "\033[0;33m Fetching list of cache key\n\033[0m\n" + printf "\033[0;32m gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 \n\033[0m\n" + cache_keys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + # printf "$cache_keys\n" + if [ -z "$cache_keys" ]; then + printf "\033[0;35m gh actions-cache list returned nothing.\n\033[0m\n" + has_items=false + fi + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cache_keys + do + # printf "\033[0;32m gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n\033[0m\n" + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + done + printf "\033[0;33m Done\n\033[0m\n" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + "###, }); vec_file.push(crate::FileItem { @@ -2393,7 +2195,7 @@ jobs: // but the new service worker will not be activated until all // tabs with this webapp are closed. -const CACHE_NAME = '2024.419.1822'; +const CACHE_NAME = '2024.422.6'; self.addEventListener('install', event => { console.log('event install ', CACHE_NAME); @@ -9298,7 +9100,7 @@ navigator.serviceWorker.addEventListener('controllerchange', function () { pwa_name - + @@ -9368,8 +9170,8 @@ navigator.serviceWorker.addEventListener('controllerchange', function () { file_content: r###"[package] name = "rust_project_name" version = "0.0.1" -authors = ["project_author"] -homepage = "project_homepage" +authors = ["web_server_domain"] +homepage = "https://web_server_domain" edition = "2021" description = "pwa_description" repository = "project_repository" @@ -9520,7 +9322,7 @@ SOFTWARE. [//]: # (auto_cargo_toml_to_md start) **pwa_description** -***version: 0.0.1 date: 2024-02-20 author: [project_author](project_homepage) repository: [GitHub](project_repository)*** +***version: 0.0.1 date: 2024-02-20 author: [web_server_domain](https://web_server_domain) repository: [GitHub](project_repository)*** [//]: # (auto_cargo_toml_to_md end) diff --git a/src/template_new_wasm_mod.rs b/src/template_new_wasm_mod.rs index f1cd9528..8f802d58 100644 --- a/src/template_new_wasm_mod.rs +++ b/src/template_new_wasm_mod.rs @@ -7,30 +7,49 @@ use crate::{GREEN, RED, RESET, YELLOW}; -pub fn new_wasm(arg_2: Option) { - match arg_2 { - None => println!("{RED}Error: Project name argument is missing: `cargo auto new_wasm project_name`{RESET}"), - Some(project_name) => { - copy_to_files(&project_name); - println!(""); - println!(" {YELLOW}The command `crate auto new_wasm` generated the directory `{project_name}`{RESET}"); - println!(" {YELLOW}You can open this new Rust project `{project_name}` in a new Rust editor.{RESET}",); - println!(" {YELLOW}For example VSCode:{RESET}"); - println!("{GREEN}code {project_name}{RESET}"); - println!(" {YELLOW}Then build with:{RESET}"); - println!("{GREEN}cargo auto build{RESET}"); - println!(" {YELLOW}and follow the detailed instructions.{RESET}"); - } +pub fn new_wasm(arg_2: Option, arg_3: Option, arg_4: Option, arg_5: Option) { + if arg_2.is_none() { + println!("{RED}Error: Project name argument is missing: `cargo auto new_wasm project_name github_owner web_server server_username`{RESET}"); + return; + } + if arg_3.is_none() { + println!("{RED}Error: Github owner argument is missing: `cargo auto new_wasm project_name github_owner web_server server_username`{RESET}"); + return; + } + if arg_4.is_none() { + println!("{RED}Error: Web server argument is missing: `cargo auto new_wasm project_name github_owner web_server server_username`{RESET}"); + return; } + if arg_5.is_none() { + println!("{RED}Error: Server username argument is missing: `cargo auto new_wasm project_name github_owner web_server server_username`{RESET}"); + return; + } + let project_name = arg_2.unwrap(); + let github_owner = arg_3.unwrap(); + let web_server_domain = arg_4.unwrap(); + let server_username = arg_5.unwrap(); + + copy_to_files(&project_name, &github_owner, &web_server_domain, &server_username); + println!(""); + println!(" {YELLOW}The command `crate auto new_wasm` generated the directory `{project_name}`{RESET}"); + println!(" {YELLOW}You can open this new Rust project `{project_name}` in a new Rust editor.{RESET}",); + println!(" {YELLOW}For example VSCode:{RESET}"); + println!("{GREEN}code {project_name}{RESET}"); + println!(" {YELLOW}Then build with:{RESET}"); + println!("{GREEN}cargo auto build{RESET}"); + println!(" {YELLOW}and follow the detailed instructions.{RESET}"); } -pub fn copy_to_files(project_name: &str) { +pub fn copy_to_files(project_name: &str, github_owner: &str, web_server_domain: &str, server_username: &str) { let folder_path = std::path::Path::new(project_name); std::fs::create_dir_all(folder_path).unwrap(); for file_item in get_vec_file() { // rename/replace the project_name let file_name = file_item.file_name.replace("cargo_auto_template_new_wasm", project_name); let file_content = file_item.file_content.replace("cargo_auto_template_new_wasm", project_name); + let file_content = file_content.replace("/github_owner/", &format!("/{github_owner}/")); + let file_content = file_content.replace("web_server_domain", web_server_domain); + let file_content = file_content.replace("server_username", server_username); // create directory if needed std::fs::create_dir_all(folder_path.join(&file_name).parent().unwrap()).unwrap(); @@ -74,8 +93,8 @@ printf "\033[0;33m RUN ON WEB SERVER: Bash script to publish web site \033[0m printf "\n" printf "\033[0;33m First the development files are copied over SSH to the folder 'transfer_folder'. \033[0m\n" printf "\033[0;33m Then copy the files from 'transfer_folder' to the web server folder. \033[0m\n" -printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/hello_world /var/www/bestia.dev/hello_world \033[0m\n" -rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/hello_world/ /var/www/bestia.dev/hello_world/ +printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/cargo_auto_template_new_wasm /var/www/web_server/cargo_auto_template_new_wasm \033[0m\n" +rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/cargo_auto_template_new_wasm/ /var/www/web_server/cargo_auto_template_new_wasm/ printf "\033[0;33m Completed. \033[0m\n" printf "\n" @@ -99,7 +118,6 @@ printf "\n" # not needed in commits, but also not a problem if they are committed /.automation_tasks_rs_file_hashes.json -/.auto_version_from_date.json "###, }); vec_file.push(crate::FileItem { @@ -176,8 +194,8 @@ pub fn tracing_init() { // Unset the environment variable RUST_LOG // unset RUST_LOG let filter = tracing_subscriber::EnvFilter::from_default_env() - .add_directive("hyper_util=error".parse().unwrap()) - .add_directive("reqwest=error".parse().unwrap()); + .add_directive("hyper_util=error".parse().unwrap_or_else(|e| panic!("{e}"))) + .add_directive("reqwest=error".parse().unwrap_or_else(|e| panic!("{e}"))); tracing_subscriber::fmt() .with_file(true) @@ -293,9 +311,12 @@ fn print_help() { /// all example commands in one place fn print_examples_cmd() { /* - println!(r#"{YELLOW}run examples:{RESET} -{GREEN}cargo run --example example1{RESET} -"#); + println!( + r#" + {YELLOW}run examples:{RESET} +{GREEN}cargo run --example plantuml1{RESET} +"# + ); */ } @@ -404,7 +425,7 @@ fn task_doc() { .run().unwrap_or_else(|e| panic!("{e}")); // pretty html - cl::auto_doc_tidy_html().unwrap(); + cl::auto_doc_tidy_html().unwrap_or_else(|e| panic!("{e}")); cl::run_shell_command_static("cargo fmt").unwrap_or_else(|e| panic!("{e}")); // message to help user with next move println!( @@ -486,40 +507,40 @@ fn task_publish_to_web() { // rsync to copy to server over ssh into a temporary installation folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{project_author}@{project_homepage}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{server_username}@{web_server_domain}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // rsync to copy to server over ssh the installation script cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/hello_world_publish.sh" "{project_author}@{project_homepage}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/{package_name}_publish.sh" "{server_username}@{web_server_domain}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); //make the bash script executable cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" chmod +x "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" chmod +x "/var/www/scripts/{package_name}/{package_name}_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // run installation script over ssh on the server to copy from the installation folder to production folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" "/var/www/scripts/{package_name}/{package_name}_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); println!( r#" {YELLOW}After `cargo auto publish_to_web`check {RESET} -{GREEN}https://bestia.dev/{package_name}{RESET} +{GREEN}https://web_server/{package_name}{RESET} {YELLOW} {YELLOW}If all is fine, run{RESET} {GREEN}cargo auto github_new_release{RESET} "#, @@ -534,7 +555,7 @@ fn task_github_new_release() { // take care of tags let tag_name_version = cl::git_tag_sync_check_create_push(&version); - let owner = cargo_toml.github_owner().unwrap(); + let github_owner = cargo_toml.github_owner().unwrap(); let repo_name = cargo_toml.package_name(); let now_date = cl::now_utc_date_iso(); let release_name = format!("Version {} ({})", &version, now_date); @@ -545,7 +566,7 @@ fn task_github_new_release() { let body_md_text = cl::body_text_from_releases_md().unwrap(); let github_client = github_mod::GitHubClient::new_with_stored_token(); - let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); + let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&github_owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); // early exit on error if let Some(error_message) = json_value.get("message") { eprintln!("{RED}{error_message}{RESET}"); @@ -580,16 +601,16 @@ fn task_github_new_release() { // compress files tar.gz let tar_name = format!("{repo_name}-{tag_name_version}-x86_64-unknown-linux-gnu.tar.gz"); - cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"tar -zcvf "{tar_name_sanitized_for_double_quote}" "target/release/{repo_name_sanitized_for_double_quote}" "#) - .arg("{tar_name_sanitized_for_double_quote}", &tar_name) - .arg("{repo_name_sanitized_for_double_quote}", &repo_name) + cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"tar -zcvf "{tar_name_sanitized_for_double_quote}" "target/release/{repo_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) + .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) + .arg("{repo_name_sanitized_for_double_quote}", &repo_name).unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // upload asset - cgl::github_api_upload_asset_to_release(&github_client, &owner, &repo_name, &release_id, &tar_name); + cgl::github_api_upload_asset_to_release(&github_client, &github_owner, &repo_name, &release_id, &tar_name); - cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#) - .arg("{tar_name_sanitized_for_double_quote}", &tar_name) + cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) + .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); println!( @@ -603,7 +624,7 @@ fn task_github_new_release() { */ println!( r#" -{GREEN}https://github.com/{owner}/{repo_name}/releases{RESET} +{GREEN}https://github.com/{github_owner}/{repo_name}/releases{RESET} "# ); } @@ -1319,7 +1340,7 @@ The library releases will be published on crates.io. The cargo-auto automation task will use the content of the section `## Unreleased` to create the GitHub release consistently with this file. The ongoing changes that are not released, are visible in the git commits and github pull requests. -The TODO section is part of the [README.md](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm). +The TODO section is part of the [README.md](https://github.com/github_owner/cargo_auto_template_new_wasm). ## Unreleased @@ -1705,255 +1726,7 @@ pub const RESET: &str = "\x1b[0m"; // So the structure of the project modules can be similar to a binary CLI executable. // region: auto_md_to_doc_comments include README.md A //! -//! # cargo-auto -//! -//! **Automation tasks coded in Rust language for the workflow of Rust projects** -//! ***version: 2024.419.1824 date: 2024-04-19 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo-auto)*** -//! -//! ![maintained](https://img.shields.io/badge/maintained-green) -//! ![ready-for-use](https://img.shields.io/badge/ready_for_use-green) -//! ![rustlang](https://img.shields.io/badge/rustlang-orange) -//! ![automation](https://img.shields.io/badge/automation-orange) -//! ![workflow](https://img.shields.io/badge/workflow-orange) -//! -//! ![logo](https://raw.githubusercontent.com/automation-tasks-rs/cargo-auto/main/images/logo/logo_cargo_auto.svg) -//! cargo-auto is part of the [automation_tasks_rs](https://github.com/automation-tasks-rs) project -//! -//! [![crates.io](https://img.shields.io/crates/v/cargo-auto.svg)](https://crates.io/crates/cargo-auto) -//! [![Documentation](https://docs.rs/cargo-auto/badge.svg)](https://docs.rs/cargo-auto/) -//! [![crev reviews](https://web.crev.dev/rust-reviews/badge/crev_count/cargo-auto.svg)](https://web.crev.dev/rust-reviews/crate/cargo-auto/) -//! [![Lib.rs](https://img.shields.io/badge/Lib.rs-rust-orange.svg)](https://lib.rs/crates/cargo-auto/) -//! [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/blob/master/LICENSE) -//! [![Rust](https://github.com/automation-tasks-rs/cargo-auto/workflows/rust_fmt_auto_build_test/badge.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Newest docs](https://img.shields.io/badge/newest_docs-blue.svg)](https://automation-tasks-rs.github.io/cargo-auto/cargo_auto/index.html) -//! ![cargo-auto](https://bestia.dev/webpage_hit_counter/get_svg_image/959103982.svg) -//! -//! [![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-3106-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-1191-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-699-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! [![Lines in tests](https://img.shields.io/badge/Lines_in_tests-10704-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -//! -//! Hashtags: #maintained #ready-for-use #rustlang #automation #workflow -//! My projects on GitHub are more like a tutorial than a finished product: [bestia-dev tutorials](https://github.com/bestia-dev/tutorials_rust_wasm). -//! I recommend using the [CRUSTDE - Containerized Rust Development Environment](https://github.com/CRUSTDE-ContainerizedRustDevEnvrustde_cnt_img_pod) to write Rust projects on Linux, isolated from your system. -//! -//! ## Try it -//! -//! First, we will use `cargo-auto` to create a new empty CLI Rust project similar to `cargo new`, but with a more complete project structure. -//! -//! ```bash -//! cargo install cargo-auto -//! cargo auto new_cli my_hello_project -//! cd my_hello_project -//! cargo auto -//! # it lists all the prepared automation tasks -//! # try a few -//! cargo auto build -//! cargo auto release -//! cargo auto doc -//! cargo auto test -//! ``` -//! -//! We can also add `automation tasks` to an existing Rust project. -//! Inside your Rust project directory (the one with Cargo.toml) run: -//! -//! ```bash -//! cargo auto new_auto -//! cargo auto -//! # it lists all the prepared automation tasks -//! # try to build -//! cargo auto build -//! ``` -//! -//! Congratulations! You are already using `cargo-auto`. Simple as that. -//! Now you can modify the tasks to your needs. It is all Rust language. -//! -//! ## Motivation -//! -//! Cargo is a great tool for building Rust projects. It has all the basics: `cargo build`, `cargo build --release`, `cargo fmt`, `cargo test`, `cargo doc`,... -//! But sometimes we need to do more things like copying some files, publishing to FTP, or entering long commands. These repetitive tasks must be automated. -//! Task automation makes work easier and faster, and simplifies the workflow while improving the consistency and accuracy of workflows. -//! This is also sometimes referred to as "workflow automation." -//! There are many different build systems and task runners there: `make`, `cmake`, `shell scripts`, `cargo-xtask`, `cargo-make`, `cargo-task`, `cargo-script`, `cargo-run-script`, `runner`, `python scripts`, `powershell scripts`, `cmd prompt scripts`, ... -//! Sadly there is no standard in the Rust community for now. -//! I want something similar to [build.rs](https://doc.rust-lang.org/cargo/reference/build-scripts.html), so I can write my "tasks" in pure Rust I don't want to learn another meta language with weird syntax and difficulty to debug. So I will make something really simple, easy, rusty, and extensible. -//! -//! ## cargo auto subcommand -//! -//! The command `cargo install cargo-auto` will add a new subcommand to cargo: -//! -//! ```bash -//! cargo auto -//! ``` -//! -//! This binary is super simple. It has only 1 trivial dependency: `lazy_static`. -//! The binary only reads the CLI arguments and runs the `automation_tasks_rs` binary with them. If needed it will compile `automation_tasks_rs` first. -//! The code-flow of the source code of `cargo-auto` is simple, fully commented, and straightforward to audit. -//! The source code is on [GitHub](https://github.com/automation-tasks-rs/cargo-auto) with MIT open-source licensing. -//! -//! ## bash auto-completion -//! -//! With the help of the crate [dev_bestia_cargo_completion](https://crates.io/crates/dev_bestia_cargo_completion), the commands `cargo` and `cargo auto` get bash auto-completion. Try it! -//! -//! ## cargo auto new_cli -//! -//! I like very much that Rust has the command `cargo new project_name`. It creates a super simple Rust Hello project that can be built and run immediately. But this example is too simple. It lacks the basic file structures of a serious CLI program. -//! I composed an opinionated template for a Rust CLI project. It is easy to run: -//! -//! ```bash -//! cargo auto new_cli project_name -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## cargo auto new_wasm -//! -//! I composed an opinionated template for a simple Rust WASM project for a browser. It is very similar to the new_cli template but for WASM. -//! It is easy to run: -//! -//! ```bash -//! cargo auto new_wasm project_name -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## cargo auto new_pwa_wasm -//! -//! I composed an opinionated template for a simple Rust PWA-WASM project for a browser. It is very similar to the new_cli template but for WASM. It adds the PWA standard functionality to work as an offline app. -//! The template needs the title, name, long name, and description inside a `pwa.json5` file and the `icon512x512.png` file for the icons. -//! It is easy to run: -//! -//! ```bash -//! cargo auto new_pwa_wasm -//! # on first run it will just create the `pwa.json5` and `icon512x512.png` files -//! # modify these files with data for your new app and then repeat -//! cargo auto new_pwa_wasm -//! # then -//! cd project_name -//! cargo auto build -//! # then follow detailed instructions -//! ``` -//! -//! ## scripting with rust -//! -//! Rust is a compiled language. It is not really a scripting or interpreted language. But the compilation of small projects is really fast and can be ignored. Subsequent calls will use the already-built binary so the speed will be even faster. -//! This tool `cargo-auto` is meant for Rust projects, so it means that all the Rust infrastructure is already in place. -//! -//! ## automation_tasks_rs Rust sub-project -//! -//! The command `cargo auto new_auto` will create a new Rust sub-project`automation_tasks_rs` inside your `Rust project`. It should not interfere with the main Rust project. This directory will be added to git commits and pushed to remote repositories as part of the main project. It has its own `.gitignore` to avoid committing to its target directory. -//! The `automation_tasks_rs` helper project contains user-defined tasks in Rust code. Your tasks. This helper project should be opened in a new editor starting from the `automation_tasks_rs` directory. It does not share dependencies with the main project. It is completely separate and independent. -//! You can edit it and add your dependencies and Rust code. No limits. Freedom of expression. -//! This is now your code, your tasks, and your helper Rust project! -//! Because only you know what you want to automate and how to do it. -//! Never write secrets, passwords, passphrases, or tokens inside your Rust code. Because then it is pushed to GitHub and the whole world can read it in the next second! -//! Basic example (most of the useful functions are already there): -//! -//! ```rust ignore -//! /// match arguments and call tasks functions -//! fn match_arguments_and_call_tasks(mut args: std::env::Args){ -//! // the first argument is the user defined task: (no argument for help), build, release,... -//! let arg_1 = args.next(); -//! match arg_1 { -//! None => print_help(), -//! Some(task) => { -//! println!("Running auto task: {}", &task); -//! if &task == "build"{ -//! task_build(); -//! } else if &task == "release" { -//! task_release(); -//! } else if &task == "doc" { -//! task_doc(); -//! } else { -//! println!("Task {} is unknown.", &task); -//! print_help(); -//! } -//! } -//! } -//! } -//! -//! /// write a comprehensible help for user defined tasks -//! fn print_help() { -//! println!(r#" -//! User defined tasks in automation_tasks_rs: -//! cargo auto build - builds the crate in debug mode -//! cargo auto release - builds the crate in release mode -//! cargo auto docs - builds the docs -//! "#); -//! } -//! -//! // region: tasks -//! -//! /// cargo build -//! fn task_build() { -//! run_shell_command("cargo fmt"); -//! run_shell_command("cargo build"); -//! } -//! -//! /// cargo build --release -//! fn task_release() { -//! run_shell_command("cargo fmt"); -//! run_shell_command("cargo build --release"); -//! } -//! -//! /// cargo doc, then copies to /docs/ folder, because this is a github standard folder -//! fn task_doc() { -//! run_shell_command("cargo doc --no-deps --document-private-items"); -//! // copy target/doc into docs/ because it is github standard -//! run_shell_command("rsync -a --info=progress2 --delete-after target/doc/ docs/"); -//! // Create simple index.html file in docs directory -//! run_shell_command(&format!( -//! "printf \"\\n\" > docs/index.html", -//! cargo_toml.package_name().replace("-","_") -//! )); -//! run_shell_command("cargo fmt"); -//! } -//! -//! // endregion: tasks -//! -//! ``` -//! -//! ## more complex tasks -//! -//! You can write more complex tasks in Rust language. -//! For example in this project I use automation to create GitHub Releases: -//! Here is a pretty complex workspace with more sub-projects: -//! -//! There is no end to your imagination. If you write something that looks like it can help other developers, please share it with me and I will add it here. -//! -//! ## Development details -//! -//! Read the development details in a separate md file: -//! [DEVELOPMENT.md](https://github.com/automation-tasks-rs/cargo-auto/blob/main/DEVELOPMENT.md) -//! -//! ## Releases changelog -//! -//! Read the changelog in a separate md file: -//! [RELEASES.md](https://github.com/automation-tasks-rs/cargo-auto/blob/main/RELEASES.md) -//! -//! ## TODO -//! -//! Nothing big in the near future. -//! -//! ## Open-source and free as a beer -//! -//! My open-source projects are free as a beer (MIT license). -//! I just love programming. -//! But I need also to drink. If you find my projects and tutorials helpful, please buy me a beer by donating to my [PayPal](https://paypal.me/LucianoBestia). -//! You know the price of a beer in your local bar ;-) -//! So I can drink a free beer for your health :-) -//! [Na zdravje!](https://translate.google.com/?hl=en&sl=sl&tl=en&text=Na%20zdravje&op=translate) [Alla salute!](https://dictionary.cambridge.org/dictionary/italian-english/alla-salute) [Prost!](https://dictionary.cambridge.org/dictionary/german-english/prost) [Nazdravlje!](https://matadornetwork.com/nights/how-to-say-cheers-in-50-languages/) 🍻 -//! -//! [//bestia.dev](https://bestia.dev) -//! [//github.com/automation-tasks-rs](https://github.com/automation-tasks-rs) -//! [//bestiadev.substack.com](https://bestiadev.substack.com) -//! [//youtube.com/@bestia-dev-tutorials](https://youtube.com/@bestia-dev-tutorials) -//! + // endregion: auto_md_to_doc_comments include README.md A //! use wasm_bindgen::prelude::*; @@ -1974,6 +1747,61 @@ pub fn wasm_bindgen_start() -> Result<(), JsValue> { // return Ok(()) } +"###, + }); + vec_file.push(crate::FileItem { + file_name: ".github/workflows/clear_all_cache.yml", + file_content: r###"name: cleanup caches on main + +# Configure Manual Trigger with workflow_dispatch +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + printf "$REPO\n" + BRANCH=main + printf "$BRANCH\n" + + # loop until the list is empty, because it deletes only 30 per page + has_items=true + while [ "$has_items" = true ] + do + printf "\033[0;33m Fetching list of cache key\n\033[0m\n" + printf "\033[0;32m gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 \n\033[0m\n" + cache_keys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + # printf "$cache_keys\n" + if [ -z "$cache_keys" ]; then + printf "\033[0;35m gh actions-cache list returned nothing.\n\033[0m\n" + has_items=false + fi + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cache_keys + do + # printf "\033[0;32m gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n\033[0m\n" + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + done + printf "\033[0;33m Done\n\033[0m\n" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + "###, }); vec_file.push(crate::FileItem { @@ -2132,7 +1960,7 @@ p{ cargo_auto_template_new_wasm - + @@ -2178,8 +2006,8 @@ p{ file_content: r###"[package] name = "cargo_auto_template_new_wasm" version = "0.0.1" -authors = ["bestia.dev"] -homepage = "https://bestia.dev" +authors = ["web_server_domain"] +homepage = "https://web_server_domain" edition = "2021" description = "Template for a minimal wasm project for browser" repository = "https://github.com/github_owner/cargo_auto_template_new_wasm" @@ -2326,19 +2154,19 @@ SOFTWARE. [//]: # (auto_cargo_toml_to_md start) **template for a minimal wasm project for browser** -***version: 0.0.1 date: 2024-02-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm)*** +***version: 0.0.1 date: 2024-02-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/github_owner/cargo_auto_template_new_wasm)*** [//]: # (auto_cargo_toml_to_md end) - [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/blob/master/LICENSE) + [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/blob/master/LICENSE) [//]: # (auto_lines_of_code start) -[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-264-green.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-28-blue.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-69-purple.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-16-orange.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) +[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-264-green.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-28-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-69-purple.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-16-orange.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) [//]: # (auto_lines_of_code end) diff --git a/template_new_auto/rustfmt.toml b/template_new_auto/rustfmt.toml index 420a4a84..ffc467de 100644 --- a/template_new_auto/rustfmt.toml +++ b/template_new_auto/rustfmt.toml @@ -1 +1 @@ -max_width = 200 \ No newline at end of file +max_width = 200 diff --git a/template_new_auto/src/secrets_always_local_mod.rs b/template_new_auto/src/secrets_always_local_mod.rs index a732226d..78d7b84a 100644 --- a/template_new_auto/src/secrets_always_local_mod.rs +++ b/template_new_auto/src/secrets_always_local_mod.rs @@ -236,18 +236,7 @@ pub(crate) mod ssh_mod { ) } - let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); - if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { - eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); - eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); - if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"github api token\"{RESET}"#); - } else if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"crates io token\"{RESET}"#); - } - eprintln!(" "); - panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); - } + let identity_private_file_path_expanded = expand_path_check_private_key_exists(identity_private_file_path); let fingerprint_from_file = cargo_auto_encrypt_secret_lib::get_fingerprint_from_file(&identity_private_file_path_expanded); @@ -282,6 +271,24 @@ pub(crate) mod ssh_mod { } } } + /// Expand path and check if identity file exists + /// + /// Inform the user how to generate identity file. + pub fn expand_path_check_private_key_exists(identity_private_file_path: &camino::Utf8Path) -> camino::Utf8PathBuf { + let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); + if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { + eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); + eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); + if identity_private_file_path_expanded.as_str().contains("github_api") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "github api token"{RESET}"#); + } else if identity_private_file_path_expanded.as_str().contains("crates_io") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "crates io token"{RESET}"#); + } + eprintln!(" "); + panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); + } + identity_private_file_path_expanded + } } pub(crate) mod github_mod { @@ -365,7 +372,9 @@ pub(crate) mod github_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the GitHub API token encrypted with an SSH key? (y/n){RESET}"); @@ -377,7 +386,7 @@ pub(crate) mod github_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return GitHubClient read_token_and_decrypt_return_github_client(ssh_context, encrypted_string_file_path) } @@ -553,7 +562,10 @@ pub(crate) mod crate_io_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the crates.io token encrypted with an SSH key? (y/n){RESET}"); @@ -565,7 +577,7 @@ pub(crate) mod crate_io_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return CratesIoClient read_token_and_decrypt_return_crate_io_client(ssh_context, encrypted_string_file_path) } diff --git a/template_new_cli/.github/workflows/clear_all_cache.yml b/template_new_cli/.github/workflows/clear_all_cache.yml new file mode 100644 index 00000000..475fd5df --- /dev/null +++ b/template_new_cli/.github/workflows/clear_all_cache.yml @@ -0,0 +1,51 @@ +name: cleanup caches on main + +# Configure Manual Trigger with workflow_dispatch +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + printf "$REPO\n" + BRANCH=main + printf "$BRANCH\n" + + # loop until the list is empty, because it deletes only 30 per page + has_items=true + while [ "$has_items" = true ] + do + printf "\033[0;33m Fetching list of cache key\n\033[0m\n" + printf "\033[0;32m gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 \n\033[0m\n" + cache_keys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + # printf "$cache_keys\n" + if [ -z "$cache_keys" ]; then + printf "\033[0;35m gh actions-cache list returned nothing.\n\033[0m\n" + has_items=false + fi + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cache_keys + do + # printf "\033[0;32m gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n\033[0m\n" + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + done + printf "\033[0;33m Done\n\033[0m\n" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/template_new_cli/.vscode/settings.json b/template_new_cli/.vscode/settings.json index 3222937d..c9459b5c 100644 --- a/template_new_cli/.vscode/settings.json +++ b/template_new_cli/.vscode/settings.json @@ -18,21 +18,21 @@ }, "rust-analyzer.showUnlinkedFileNotification": false, "cSpell.words": [ - "zdravje", - "zcvf", - "thiserror", - "substack", - "struct", - "Prost", - "Nazdravlje", - "CRUSTDE", - "bestiadev", "Alla", "bestia", + "bestiadev", + "CRUSTDE", "endregion", + "Nazdravlje", "plantuml", + "Prost", "rustdevuser", + "rustlang", "rustprojects", - "zcvf" + "struct", + "substack", + "thiserror", + "zcvf", + "zdravje" ] } \ No newline at end of file diff --git a/template_new_cli/README.md b/template_new_cli/README.md index 7c529751..7e3b5cc8 100644 --- a/template_new_cli/README.md +++ b/template_new_cli/README.md @@ -5,20 +5,20 @@ [//]: # (auto_cargo_toml_to_md start) **Basic Rust project template for CLI and library, more than just `cargo new hello`** -***version: 1.0.4 date: 2024-04-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli)*** +***version: 1.0.4 date: 2024-04-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/github_owner/cargo_auto_template_new_cli)*** [//]: # (auto_cargo_toml_to_md end) - [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli/blob/main/LICENSE) - [![Rust](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli/workflows/RustAction/badge.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli/) + [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/blob/main/LICENSE) + [![Rust](https://github.com/github_owner/cargo_auto_template_new_cli/workflows/RustAction/badge.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) [//]: # (auto_lines_of_code start) -[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-89-green.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-13-blue.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-36-purple.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-19-yellow.svg)](https://github.com/automation-tasks-rs/cargo-auto/) -[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-30-orange.svg)](https://github.com/automation-tasks-rs/cargo-auto/) +[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-89-green.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-13-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-36-purple.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-19-yellow.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) +[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-30-orange.svg)](https://github.com/github_owner/cargo_auto_template_new_cli/) [//]: # (auto_lines_of_code end) @@ -34,7 +34,7 @@ Just like `cargo new` makes a soft and gentle introduction to Rust projects and cargo auto new_cli project_name ``` -Extremely simple, just the basic moving parts and use-cases. +Extremely simple, just the basic moving parts and use cases. ## Development details diff --git a/template_new_cli/RELEASES.md b/template_new_cli/RELEASES.md index 0f6a6a24..5dc81456 100644 --- a/template_new_cli/RELEASES.md +++ b/template_new_cli/RELEASES.md @@ -5,8 +5,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm The library releases will be published on crates.io. The cargo-auto automation task will use the content of the section `## Unreleased` to create the GitHub release consistently with this file. -The ongoing changes that are not released, are visible in the git commits and github pull requests. -The TODO section is part of the [README.md](https://github.com/automation-tasks-rs/cargo_auto_template_new_cli). +The ongoing changes that are not released, are visible in the git commits and GitHub pull requests. +The TODO section is part of the [README.md](https://github.com/github_owner/cargo_auto_template_new_cli). ## Unreleased diff --git a/template_new_cli/automation_tasks_rs/src/main.rs b/template_new_cli/automation_tasks_rs/src/main.rs index 34c1fc2d..9bd24f7d 100644 --- a/template_new_cli/automation_tasks_rs/src/main.rs +++ b/template_new_cli/automation_tasks_rs/src/main.rs @@ -382,7 +382,7 @@ fn task_github_new_release() { // take care of tags let tag_name_version = cl::git_tag_sync_check_create_push(&version); - let owner = cargo_toml.github_owner().unwrap(); + let github_owner = cargo_toml.github_owner().unwrap(); let repo_name = cargo_toml.package_name(); let now_date = cl::now_utc_date_iso(); let release_name = format!("Version {} ({})", &version, now_date); @@ -393,7 +393,7 @@ fn task_github_new_release() { let body_md_text = cl::body_text_from_releases_md().unwrap(); let github_client = github_mod::GitHubClient::new_with_stored_token(); - let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); + let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&github_owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); // early exit on error if let Some(error_message) = json_value.get("message") { eprintln!("{RED}{error_message}{RESET}"); @@ -434,7 +434,7 @@ fn task_github_new_release() { .run().unwrap_or_else(|e| panic!("{e}")); // upload asset - cgl::github_api_upload_asset_to_release(&github_client, &owner, &repo_name, &release_id, &tar_name); + cgl::github_api_upload_asset_to_release(&github_client, &github_owner, &repo_name, &release_id, &tar_name); cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) @@ -450,7 +450,7 @@ fn task_github_new_release() { println!( r#" -{GREEN}https://github.com/{owner}/{repo_name}/releases{RESET} +{GREEN}https://github.com/{github_owner}/{repo_name}/releases{RESET} "# ); } diff --git a/template_new_cli/automation_tasks_rs/src/secrets_always_local_mod.rs b/template_new_cli/automation_tasks_rs/src/secrets_always_local_mod.rs index a732226d..78d7b84a 100644 --- a/template_new_cli/automation_tasks_rs/src/secrets_always_local_mod.rs +++ b/template_new_cli/automation_tasks_rs/src/secrets_always_local_mod.rs @@ -236,18 +236,7 @@ pub(crate) mod ssh_mod { ) } - let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); - if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { - eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); - eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); - if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"github api token\"{RESET}"#); - } else if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"crates io token\"{RESET}"#); - } - eprintln!(" "); - panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); - } + let identity_private_file_path_expanded = expand_path_check_private_key_exists(identity_private_file_path); let fingerprint_from_file = cargo_auto_encrypt_secret_lib::get_fingerprint_from_file(&identity_private_file_path_expanded); @@ -282,6 +271,24 @@ pub(crate) mod ssh_mod { } } } + /// Expand path and check if identity file exists + /// + /// Inform the user how to generate identity file. + pub fn expand_path_check_private_key_exists(identity_private_file_path: &camino::Utf8Path) -> camino::Utf8PathBuf { + let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); + if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { + eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); + eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); + if identity_private_file_path_expanded.as_str().contains("github_api") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "github api token"{RESET}"#); + } else if identity_private_file_path_expanded.as_str().contains("crates_io") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "crates io token"{RESET}"#); + } + eprintln!(" "); + panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); + } + identity_private_file_path_expanded + } } pub(crate) mod github_mod { @@ -365,7 +372,9 @@ pub(crate) mod github_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the GitHub API token encrypted with an SSH key? (y/n){RESET}"); @@ -377,7 +386,7 @@ pub(crate) mod github_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return GitHubClient read_token_and_decrypt_return_github_client(ssh_context, encrypted_string_file_path) } @@ -553,7 +562,10 @@ pub(crate) mod crate_io_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the crates.io token encrypted with an SSH key? (y/n){RESET}"); @@ -565,7 +577,7 @@ pub(crate) mod crate_io_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return CratesIoClient read_token_and_decrypt_return_crate_io_client(ssh_context, encrypted_string_file_path) } diff --git a/template_new_cli/rustfmt.toml b/template_new_cli/rustfmt.toml new file mode 100644 index 00000000..ffc467de --- /dev/null +++ b/template_new_cli/rustfmt.toml @@ -0,0 +1 @@ +max_width = 200 diff --git a/template_new_pwa_wasm/.github/workflows/clear_all_cache.yml b/template_new_pwa_wasm/.github/workflows/clear_all_cache.yml new file mode 100644 index 00000000..475fd5df --- /dev/null +++ b/template_new_pwa_wasm/.github/workflows/clear_all_cache.yml @@ -0,0 +1,51 @@ +name: cleanup caches on main + +# Configure Manual Trigger with workflow_dispatch +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + printf "$REPO\n" + BRANCH=main + printf "$BRANCH\n" + + # loop until the list is empty, because it deletes only 30 per page + has_items=true + while [ "$has_items" = true ] + do + printf "\033[0;33m Fetching list of cache key\n\033[0m\n" + printf "\033[0;32m gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 \n\033[0m\n" + cache_keys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + # printf "$cache_keys\n" + if [ -z "$cache_keys" ]; then + printf "\033[0;35m gh actions-cache list returned nothing.\n\033[0m\n" + has_items=false + fi + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cache_keys + do + # printf "\033[0;32m gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n\033[0m\n" + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + done + printf "\033[0;33m Done\n\033[0m\n" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/template_new_pwa_wasm/Cargo.toml b/template_new_pwa_wasm/Cargo.toml index 5940894a..d19ea897 100644 --- a/template_new_pwa_wasm/Cargo.toml +++ b/template_new_pwa_wasm/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "rust_project_name" version = "0.0.1" -authors = ["project_author"] -homepage = "project_homepage" +authors = ["web_server_domain"] +homepage = "https://web_server_domain" edition = "2021" description = "pwa_description" repository = "project_repository" diff --git a/template_new_pwa_wasm/README.md b/template_new_pwa_wasm/README.md index 648ea846..6340e233 100644 --- a/template_new_pwa_wasm/README.md +++ b/template_new_pwa_wasm/README.md @@ -5,7 +5,7 @@ [//]: # (auto_cargo_toml_to_md start) **pwa_description** -***version: 0.0.1 date: 2024-02-20 author: [project_author](project_homepage) repository: [GitHub](project_repository)*** +***version: 0.0.1 date: 2024-02-20 author: [web_server_domain](https://web_server_domain) repository: [GitHub](project_repository)*** [//]: # (auto_cargo_toml_to_md end) diff --git a/template_new_pwa_wasm/automation_tasks_rs/src/main.rs b/template_new_pwa_wasm/automation_tasks_rs/src/main.rs index 464e5192..afb61eea 100644 --- a/template_new_pwa_wasm/automation_tasks_rs/src/main.rs +++ b/template_new_pwa_wasm/automation_tasks_rs/src/main.rs @@ -367,40 +367,40 @@ fn task_publish_to_web() { // rsync to copy to server over ssh into a temporary installation folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{project_author}@{project_homepage}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{server_username}@{web_server_domain}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // rsync to copy to server over ssh the installation script cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/hello_world_publish.sh" "{project_author}@{project_homepage}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/hello_world_publish.sh" "{server_username}@{web_server_domain}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); //make the bash script executable cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" chmod +x "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" chmod +x "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // run installation script over ssh on the server to copy from the installation folder to production folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); println!( r#" {YELLOW}After `cargo auto publish_to_web`check {RESET} -{GREEN}https://bestia.dev/{package_name}{RESET} +{GREEN}https://web_server_domain/{package_name}{RESET} {YELLOW} {YELLOW}If all is fine, run{RESET} {GREEN}cargo auto github_new_release{RESET} "#, diff --git a/template_new_pwa_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs b/template_new_pwa_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs index eb7da817..78d7b84a 100644 --- a/template_new_pwa_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs +++ b/template_new_pwa_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs @@ -236,18 +236,7 @@ pub(crate) mod ssh_mod { ) } - let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); - if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { - eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); - eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); - if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"github api token\"{RESET}"#); - } else if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"crates io token\"{RESET}"#); - } - eprintln!(" "); - panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); - } + let identity_private_file_path_expanded = expand_path_check_private_key_exists(identity_private_file_path); let fingerprint_from_file = cargo_auto_encrypt_secret_lib::get_fingerprint_from_file(&identity_private_file_path_expanded); @@ -282,6 +271,24 @@ pub(crate) mod ssh_mod { } } } + /// Expand path and check if identity file exists + /// + /// Inform the user how to generate identity file. + pub fn expand_path_check_private_key_exists(identity_private_file_path: &camino::Utf8Path) -> camino::Utf8PathBuf { + let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); + if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { + eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); + eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); + if identity_private_file_path_expanded.as_str().contains("github_api") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "github api token"{RESET}"#); + } else if identity_private_file_path_expanded.as_str().contains("crates_io") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "crates io token"{RESET}"#); + } + eprintln!(" "); + panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); + } + identity_private_file_path_expanded + } } pub(crate) mod github_mod { @@ -365,7 +372,9 @@ pub(crate) mod github_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the GitHub API token encrypted with an SSH key? (y/n){RESET}"); @@ -377,7 +386,7 @@ pub(crate) mod github_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return GitHubClient read_token_and_decrypt_return_github_client(ssh_context, encrypted_string_file_path) } @@ -553,7 +562,10 @@ pub(crate) mod crate_io_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the crates.io token encrypted with an SSH key? (y/n){RESET}"); @@ -565,7 +577,7 @@ pub(crate) mod crate_io_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return CratesIoClient read_token_and_decrypt_return_crate_io_client(ssh_context, encrypted_string_file_path) } @@ -578,7 +590,6 @@ pub(crate) mod crate_io_mod { } /// decrypts the secret token in memory - #[allow(dead_code)] pub fn decrypt_token_in_memory(&self) -> secrecy::SecretString { self.encrypted_token.expose_decrypted_secret(&self.session_passcode) } @@ -587,7 +598,6 @@ pub(crate) mod crate_io_mod { /// /// This function encapsulates the secret crates.io token. /// The client can be passed to the library. It will not reveal the secret token. - #[allow(dead_code)] pub fn publish_to_crates_io(&self) { // print command without the token println!("{YELLOW}cargo publish --token [REDACTED]{RESET}"); diff --git a/template_new_pwa_wasm/publish_script/hello_world_publish.sh b/template_new_pwa_wasm/publish_script/hello_world_publish.sh index d2f28868..619f36f3 100644 --- a/template_new_pwa_wasm/publish_script/hello_world_publish.sh +++ b/template_new_pwa_wasm/publish_script/hello_world_publish.sh @@ -4,8 +4,8 @@ printf "\033[0;33m RUN ON WEB SERVER: Bash script to publish web site \033[0m printf "\n" printf "\033[0;33m First the development files are copied over SSH to the folder 'transfer_folder'. \033[0m\n" printf "\033[0;33m Then copy the files from 'transfer_folder' to the web server folder. \033[0m\n" -printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/hello_world /var/www/bestia.dev/hello_world \033[0m\n" -rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/hello_world/ /var/www/bestia.dev/hello_world/ +printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/hello_world /var/www/web_server_domain/hello_world \033[0m\n" +rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/hello_world/ /var/www/web_server_domain/hello_world/ printf "\033[0;33m Completed. \033[0m\n" printf "\n" diff --git a/template_new_pwa_wasm/src/main_mod.rs b/template_new_pwa_wasm/src/main_mod.rs index bb780c27..0097898b 100644 --- a/template_new_pwa_wasm/src/main_mod.rs +++ b/template_new_pwa_wasm/src/main_mod.rs @@ -177,7 +177,7 @@ fn page_with_inputs() { let mut fragment = wsm::HtmlSourceCode::new(r#"

{ph_text_node_1}

"#); fragment.replace_attribute_value("{ph_attr_class_1}", "small"); - fragment.replace_text_node("{ph_text_node_1}", "bestia.dev"); + fragment.replace_text_node("{ph_text_node_1}", "web_server_domain"); html_source_code.replace_html_source_code("{ph_elem_p_1}", &fragment); dbg!(html_source_code.get_html()); diff --git a/template_new_pwa_wasm/web_server_folder/pwa_short_name/index.html b/template_new_pwa_wasm/web_server_folder/pwa_short_name/index.html index 482aa29a..4938cd4e 100644 --- a/template_new_pwa_wasm/web_server_folder/pwa_short_name/index.html +++ b/template_new_pwa_wasm/web_server_folder/pwa_short_name/index.html @@ -5,7 +5,7 @@ pwa_name - + diff --git a/template_new_pwa_wasm/web_server_folder/pwa_short_name/service_worker.js b/template_new_pwa_wasm/web_server_folder/pwa_short_name/service_worker.js index da515ee2..316f4fcf 100644 --- a/template_new_pwa_wasm/web_server_folder/pwa_short_name/service_worker.js +++ b/template_new_pwa_wasm/web_server_folder/pwa_short_name/service_worker.js @@ -7,7 +7,7 @@ // but the new service worker will not be activated until all // tabs with this webapp are closed. -const CACHE_NAME = '2024.419.1824'; +const CACHE_NAME = '2024.422.15'; self.addEventListener('install', event => { console.log('event install ', CACHE_NAME); diff --git a/template_new_wasm/.github/workflows/clear_all_cache.yml b/template_new_wasm/.github/workflows/clear_all_cache.yml new file mode 100644 index 00000000..475fd5df --- /dev/null +++ b/template_new_wasm/.github/workflows/clear_all_cache.yml @@ -0,0 +1,51 @@ +name: cleanup caches on main + +# Configure Manual Trigger with workflow_dispatch +on: + workflow_dispatch: + +jobs: + cleanup: + runs-on: ubuntu-latest + permissions: + # `actions:write` permission is required to delete caches + # See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id + actions: write + contents: read + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + printf "$REPO\n" + BRANCH=main + printf "$BRANCH\n" + + # loop until the list is empty, because it deletes only 30 per page + has_items=true + while [ "$has_items" = true ] + do + printf "\033[0;33m Fetching list of cache key\n\033[0m\n" + printf "\033[0;32m gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 \n\033[0m\n" + cache_keys=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + # printf "$cache_keys\n" + if [ -z "$cache_keys" ]; then + printf "\033[0;35m gh actions-cache list returned nothing.\n\033[0m\n" + has_items=false + fi + ## Setting this to not fail the workflow while deleting cache keys. + set +e + for cacheKey in $cache_keys + do + # printf "\033[0;32m gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm\n\033[0m\n" + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + done + printf "\033[0;33m Done\n\033[0m\n" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/template_new_wasm/Cargo.toml b/template_new_wasm/Cargo.toml index e4b82e1e..51516a1f 100644 --- a/template_new_wasm/Cargo.toml +++ b/template_new_wasm/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "cargo_auto_template_new_wasm" version = "0.0.1" -authors = ["bestia.dev"] -homepage = "https://bestia.dev" +authors = ["web_server_domain"] +homepage = "https://web_server_domain" edition = "2021" description = "Template for a minimal wasm project for browser" repository = "https://github.com/github_owner/cargo_auto_template_new_wasm" diff --git a/template_new_wasm/README.md b/template_new_wasm/README.md index 54d9f348..1639c5dd 100644 --- a/template_new_wasm/README.md +++ b/template_new_wasm/README.md @@ -5,19 +5,19 @@ [//]: # (auto_cargo_toml_to_md start) **template for a minimal wasm project for browser** -***version: 0.0.1 date: 2024-02-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm)*** +***version: 0.0.1 date: 2024-02-21 author: [bestia.dev](https://bestia.dev) repository: [GitHub](https://github.com/github_owner/cargo_auto_template_new_wasm)*** [//]: # (auto_cargo_toml_to_md end) - [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/blob/master/LICENSE) + [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/blob/master/LICENSE) [//]: # (auto_lines_of_code start) -[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-264-green.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-28-blue.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-69-purple.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) -[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-16-orange.svg)](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm/) +[![Lines in Rust code](https://img.shields.io/badge/Lines_in_Rust-264-green.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in Doc comments](https://img.shields.io/badge/Lines_in_Doc_comments-28-blue.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in Comments](https://img.shields.io/badge/Lines_in_comments-69-purple.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in examples](https://img.shields.io/badge/Lines_in_examples-0-yellow.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) +[![Lines in tests](https://img.shields.io/badge/Lines_in_tests-16-orange.svg)](https://github.com/github_owner/cargo_auto_template_new_wasm/) [//]: # (auto_lines_of_code end) diff --git a/template_new_wasm/RELEASES.md b/template_new_wasm/RELEASES.md index 0f1cd7e6..63880e59 100644 --- a/template_new_wasm/RELEASES.md +++ b/template_new_wasm/RELEASES.md @@ -6,7 +6,7 @@ The library releases will be published on crates.io. The cargo-auto automation task will use the content of the section `## Unreleased` to create the GitHub release consistently with this file. The ongoing changes that are not released, are visible in the git commits and github pull requests. -The TODO section is part of the [README.md](https://github.com/automation-tasks-rs/cargo_auto_template_new_wasm). +The TODO section is part of the [README.md](https://github.com/github_owner/cargo_auto_template_new_wasm). ## Unreleased diff --git a/template_new_wasm/automation_tasks_rs/src/main.rs b/template_new_wasm/automation_tasks_rs/src/main.rs index 06862d57..7278104c 100644 --- a/template_new_wasm/automation_tasks_rs/src/main.rs +++ b/template_new_wasm/automation_tasks_rs/src/main.rs @@ -367,40 +367,40 @@ fn task_publish_to_web() { // rsync to copy to server over ssh into a temporary installation folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{project_author}@{project_homepage}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "web_server_folder/{package_name}/" "{server_username}@{web_server_domain}:/var/www/transfer_folder/{package_name}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // rsync to copy to server over ssh the installation script cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/hello_world_publish.sh" "{project_author}@{project_homepage}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) +r#"rsync -e ssh -a --info=progress2 --delete-after "publish_script/{package_name}_publish.sh" "{server_username}@{web_server_domain}:/var/www/scripts/{package_name}/" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); //make the bash script executable cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" chmod +x "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" chmod +x "/var/www/scripts/{package_name}/{package_name}_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); // run installation script over ssh on the server to copy from the installation folder to production folder cl::ShellCommandLimitedDoubleQuotesSanitizer::new( -r#"ssh "{project_author}@{project_homepage}" "/var/www/scripts/{package_name}/hello_world_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) +r#"ssh "{server_username}@{web_server_domain}" "/var/www/scripts/{package_name}/{package_name}_publish.sh" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{package_name}", &cargo_toml.package_name()).unwrap_or_else(|e| panic!("{e}")) - .arg("{project_author}", "luciano_bestia").unwrap_or_else(|e| panic!("{e}")) - .arg("{project_homepage}", "bestia.dev").unwrap_or_else(|e| panic!("{e}")) + .arg("{server_username}", "server_username").unwrap_or_else(|e| panic!("{e}")) + .arg("{web_server_domain}", "web_server_domain").unwrap_or_else(|e| panic!("{e}")) .run().unwrap_or_else(|e| panic!("{e}")); println!( r#" {YELLOW}After `cargo auto publish_to_web`check {RESET} -{GREEN}https://bestia.dev/{package_name}{RESET} +{GREEN}https://web_server/{package_name}{RESET} {YELLOW} {YELLOW}If all is fine, run{RESET} {GREEN}cargo auto github_new_release{RESET} "#, @@ -415,7 +415,7 @@ fn task_github_new_release() { // take care of tags let tag_name_version = cl::git_tag_sync_check_create_push(&version); - let owner = cargo_toml.github_owner().unwrap(); + let github_owner = cargo_toml.github_owner().unwrap(); let repo_name = cargo_toml.package_name(); let now_date = cl::now_utc_date_iso(); let release_name = format!("Version {} ({})", &version, now_date); @@ -426,7 +426,7 @@ fn task_github_new_release() { let body_md_text = cl::body_text_from_releases_md().unwrap(); let github_client = github_mod::GitHubClient::new_with_stored_token(); - let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); + let json_value = github_client.send_to_github_api(cgl::github_api_create_new_release(&github_owner, &repo_name, &tag_name_version, &release_name, branch, &body_md_text)); // early exit on error if let Some(error_message) = json_value.get("message") { eprintln!("{RED}{error_message}{RESET}"); @@ -467,7 +467,7 @@ fn task_github_new_release() { .run().unwrap_or_else(|e| panic!("{e}")); // upload asset - cgl::github_api_upload_asset_to_release(&github_client, &owner, &repo_name, &release_id, &tar_name); + cgl::github_api_upload_asset_to_release(&github_client, &github_owner, &repo_name, &release_id, &tar_name); cl::ShellCommandLimitedDoubleQuotesSanitizer::new(r#"rm "{tar_name_sanitized_for_double_quote}" "#).unwrap_or_else(|e| panic!("{e}")) .arg("{tar_name_sanitized_for_double_quote}", &tar_name).unwrap_or_else(|e| panic!("{e}")) @@ -484,7 +484,7 @@ fn task_github_new_release() { */ println!( r#" -{GREEN}https://github.com/{owner}/{repo_name}/releases{RESET} +{GREEN}https://github.com/{github_owner}/{repo_name}/releases{RESET} "# ); } diff --git a/template_new_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs b/template_new_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs index eb7da817..78d7b84a 100644 --- a/template_new_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs +++ b/template_new_wasm/automation_tasks_rs/src/secrets_always_local_mod.rs @@ -236,18 +236,7 @@ pub(crate) mod ssh_mod { ) } - let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); - if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { - eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); - eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); - if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"github api token\"{RESET}"#); - } else if identity_private_file_path_expanded.as_str().contains("github_api") { - eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f \"{identity_private_file_path_expanded}\" -C \"crates io token\"{RESET}"#); - } - eprintln!(" "); - panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); - } + let identity_private_file_path_expanded = expand_path_check_private_key_exists(identity_private_file_path); let fingerprint_from_file = cargo_auto_encrypt_secret_lib::get_fingerprint_from_file(&identity_private_file_path_expanded); @@ -282,6 +271,24 @@ pub(crate) mod ssh_mod { } } } + /// Expand path and check if identity file exists + /// + /// Inform the user how to generate identity file. + pub fn expand_path_check_private_key_exists(identity_private_file_path: &camino::Utf8Path) -> camino::Utf8PathBuf { + let identity_private_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(identity_private_file_path); + if !camino::Utf8Path::new(&identity_private_file_path_expanded).exists() { + eprintln!("{RED}Identity file {identity_private_file_path_expanded} that contains the SSH private key does not exist! {RESET}"); + eprintln!(" {YELLOW}Create the SSH key manually in bash with this command:{RESET}"); + if identity_private_file_path_expanded.as_str().contains("github_api") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "github api token"{RESET}"#); + } else if identity_private_file_path_expanded.as_str().contains("crates_io") { + eprintln!(r#"{GREEN}ssh-keygen -t ed25519 -f "{identity_private_file_path_expanded}" -C "crates io token"{RESET}"#); + } + eprintln!(" "); + panic!("{RED}Error: File {identity_private_file_path_expanded} does not exist! {RESET}"); + } + identity_private_file_path_expanded + } } pub(crate) mod github_mod { @@ -365,7 +372,9 @@ pub(crate) mod github_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/github_api_token_ssh_1"); + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the GitHub API token encrypted with an SSH key? (y/n){RESET}"); @@ -377,7 +386,7 @@ pub(crate) mod github_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return GitHubClient read_token_and_decrypt_return_github_client(ssh_context, encrypted_string_file_path) } @@ -553,7 +562,10 @@ pub(crate) mod crate_io_mod { let encrypted_string_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_encrypted.txt"); let encrypted_string_file_path_expanded = cargo_auto_encrypt_secret_lib::file_path_home_expand(encrypted_string_file_path); - let identity_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + let identity_private_file_path = camino::Utf8Path::new("~/.ssh/crates_io_token_ssh_1"); + + let _identity_private_file_path_expanded = crate::secrets_always_local_mod::ssh_mod::expand_path_check_private_key_exists(identity_private_file_path); + if !encrypted_string_file_path_expanded.exists() { // ask interactive println!(" {BLUE}Do you want to store the crates.io token encrypted with an SSH key? (y/n){RESET}"); @@ -565,7 +577,7 @@ pub(crate) mod crate_io_mod { // get the passphrase and token interactively let mut ssh_context = super::ssh_mod::SshContext::new(); // encrypt and save the encrypted token - cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_file_path, encrypted_string_file_path); + cargo_auto_encrypt_secret_lib::encrypt_with_ssh_interactive_save_file(&mut ssh_context, identity_private_file_path, encrypted_string_file_path); // read the token and decrypt, return CratesIoClient read_token_and_decrypt_return_crate_io_client(ssh_context, encrypted_string_file_path) } @@ -578,7 +590,6 @@ pub(crate) mod crate_io_mod { } /// decrypts the secret token in memory - #[allow(dead_code)] pub fn decrypt_token_in_memory(&self) -> secrecy::SecretString { self.encrypted_token.expose_decrypted_secret(&self.session_passcode) } @@ -587,7 +598,6 @@ pub(crate) mod crate_io_mod { /// /// This function encapsulates the secret crates.io token. /// The client can be passed to the library. It will not reveal the secret token. - #[allow(dead_code)] pub fn publish_to_crates_io(&self) { // print command without the token println!("{YELLOW}cargo publish --token [REDACTED]{RESET}"); diff --git a/template_new_wasm/publish_script/hello_world_publish.sh b/template_new_wasm/publish_script/hello_world_publish.sh index d2f28868..460d407d 100644 --- a/template_new_wasm/publish_script/hello_world_publish.sh +++ b/template_new_wasm/publish_script/hello_world_publish.sh @@ -4,8 +4,8 @@ printf "\033[0;33m RUN ON WEB SERVER: Bash script to publish web site \033[0m printf "\n" printf "\033[0;33m First the development files are copied over SSH to the folder 'transfer_folder'. \033[0m\n" printf "\033[0;33m Then copy the files from 'transfer_folder' to the web server folder. \033[0m\n" -printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/hello_world /var/www/bestia.dev/hello_world \033[0m\n" -rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/hello_world/ /var/www/bestia.dev/hello_world/ +printf "\033[0;33m rsync -avz --delete-after /var/www/transfer_folder/cargo_auto_template_new_wasm /var/www/web_server/cargo_auto_template_new_wasm \033[0m\n" +rsync -avz --delete-after rsync -avz --delete-after /var/www/transfer_folder/cargo_auto_template_new_wasm/ /var/www/web_server/cargo_auto_template_new_wasm/ printf "\033[0;33m Completed. \033[0m\n" printf "\n" diff --git a/template_new_wasm/web_server_folder/cargo_auto_template_new_wasm/index.html b/template_new_wasm/web_server_folder/cargo_auto_template_new_wasm/index.html index 40135c1e..6fca76d4 100644 --- a/template_new_wasm/web_server_folder/cargo_auto_template_new_wasm/index.html +++ b/template_new_wasm/web_server_folder/cargo_auto_template_new_wasm/index.html @@ -6,7 +6,7 @@ cargo_auto_template_new_wasm - +