main.rs
1 //! # xtask 2 //! This crate is the way we do CI; it is used to build, run, format, and check the code. 3 //! 4 //! --- 5 //! 6 //! ```md 7 //! Copyright (C) 2025 Crypts of the Lost Team 8 //! 9 //! This program is free software: you can redistribute it and/or modify 10 //! it under the terms of the GNU Affero General Public License as 11 //! published by the Free Software Foundation, either version 3 of the 12 //! License, or (at your option) any later version. 13 //! 14 //! This program is distributed in the hope that it will be useful, 15 //! but WITHOUT ANY WARRANTY; without even the implied warranty of 16 //! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 //! GNU Affero General Public License for more details. 18 //! 19 //! You should have received a copy of the GNU Affero General Public License 20 //! along with this program. If not, see <https://www.gnu.org/licenses/>. 21 //! ``` 22 23 use clap::{Parser, Subcommand}; 24 use std::process::Command; 25 26 #[derive(Parser, Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)] 27 struct Cli { 28 #[clap(subcommand)] 29 sub_commands: SubCommands, 30 } 31 32 #[derive(Subcommand, Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)] 33 enum SubCommands { 34 // Builds the server in *debug* 35 Build, 36 // This does all formatting checks, including toml files and the like 37 Check, 38 // Formats all code, including toml files 39 Fmt, 40 // Runs tests using nextest 41 Test, 42 } 43 44 #[expect(clippy::print_stdout)] 45 fn main() -> Result<(), Box<dyn std::error::Error>> { 46 let args = Cli::parse(); 47 48 // Can be unsafe in multithreaded programs, but this won't be multithreaded, so it's good 49 #[expect(unsafe_code)] 50 unsafe { 51 std::env::set_var("TAPLO_CONFIG", "./.config/taplo.toml"); 52 }; 53 54 // keeping it for later use 55 #[expect(unused)] 56 let is_ci: bool = std::env::var("IS_CI").is_ok(); 57 58 match args.sub_commands { 59 SubCommands::Build => { 60 let status = Command::new("cargo") 61 .args([ 62 "build", 63 "--release", 64 "--bin", 65 "server", 66 "--locked", 67 "--color=always", 68 "--quiet", 69 ]) 70 .status()?; 71 72 if !status.success() { 73 std::process::exit(101); 74 } 75 } 76 SubCommands::Check => { 77 let commands: Vec<(&str, &[&str])> = vec![ 78 ("cargo", &["clippy", "--workspace", "--", "-Dwarnings"]), 79 ("taplo", &["lint"]), 80 ("cargo", &["fmt", "--", "--check"]), 81 ("typos", &["--color", "always"]), 82 ]; 83 84 for command in commands { 85 let status = Command::new(command.0).args(command.1).status()?; 86 87 if !status.success() { 88 std::process::exit(101); 89 } 90 } 91 92 println!("\n\x1b[32;1m{:>12}\x1b[0m all checks", "Passed"); 93 } 94 SubCommands::Fmt => { 95 let fmt = Command::new("cargo") 96 .args(["fmt", "--all", "--", "--"]) 97 .status()?; 98 99 if !fmt.success() { 100 std::process::exit(101); 101 } 102 103 let taplo = Command::new("taplo").args(["fmt"]).status()?; 104 105 if !taplo.success() { 106 std::process::exit(101); 107 } 108 } 109 SubCommands::Test => { 110 let nextest = Command::new("cargo") 111 .args([ 112 "nextest", 113 "run", 114 "--profile", 115 "ci", 116 "--release", 117 "--no-tests", 118 "pass", 119 ]) 120 .status()?; 121 122 if !nextest.success() { 123 std::process::exit(101); 124 } 125 } 126 } 127 128 Ok(()) 129 }