/ xtask / src / main.rs
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  }