Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: cachix/devenv
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6f60468353040db29c474c04f6edb6ca3aaa96c0
Choose a base ref
..
head repository: cachix/devenv
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: f1011bffe4046573e08df9b31c7dcbf7a4cb2c53
Choose a head ref
4 changes: 4 additions & 0 deletions .github/workflows/buildtest.yml
Original file line number Diff line number Diff line change
@@ -2,11 +2,15 @@ name: "Build & Test"

on:
pull_request:
paths-ignore:
- "docs/**"
push:
branches:
- main
tags:
- v*
paths-ignore:
- "docs/**"

jobs:
build:
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -62,9 +62,9 @@ And ``devenv shell`` activates the environment.

```
$ devenv
https://devenv.sh 1.0.1: Fast, Declarative, Reproducible, and Composable Developer Environments
https://devenv.sh 1.3.1: Fast, Declarative, Reproducible, and Composable Developer Environments
Usage: devenv [OPTIONS] <COMMAND>
Usage: devenv [OPTIONS] [COMMAND]
Commands:
init Scaffold devenv.yaml, devenv.nix, .gitignore and .envrc.
@@ -73,36 +73,51 @@ Commands:
search Search for packages and options in nixpkgs. https://devenv.sh/packages/#searching-for-a-file
info Print information about this developer environment.
up Start processes in the foreground. https://devenv.sh/processes/
processes Start or stop processes.
processes Start or stop processes. https://devenv.sh/processes/
tasks Run tasks. https://devenv.sh/tasks/
test Run tests. http://devenv.sh/tests/
container Build, copy, or run a container. https://devenv.sh/containers/
inputs Add an input to devenv.yaml. https://devenv.sh/inputs/
gc Deletes previous shell generations. See http://devenv.sh/garbage-collection
repl Launch an interactive environment for inspecting the devenv configuration.
gc Delete previous shell generations. See https://devenv.sh/garbage-collection
build Build any attribute in devenv.nix.
direnvrc Print a direnvrc that adds devenv support to direnv. See https://devenv.sh/automatic-shell-activation.
version Print the version of devenv.
help Print this message or the help of the given subcommand(s)
Options:
-V, --version
Print version information
-v, --verbose
Enable debug log level.
Enable additional debug logs.
-q, --quiet
Silence all logs
--log-format <LOG_FORMAT>
Configure the output format of the logs. [default: cli] [possible values: cli, tracing-full]
-j, --max-jobs <MAX_JOBS>
Maximum number of Nix builds at any time. [default: 8]
-j, --cores <CORES>
Maximum number CPU cores being used by a single build.. [default: 2]
Maximum number of Nix builds at any time. [default: 5]
-u, --cores <CORES>
Maximum number CPU cores being used by a single build. [default: 2]
-s, --system <SYSTEM>
[default: x86_64-linux]
[default: aarch64-darwin]
-i, --impure
Relax the hermeticity of the environment.
--eval-cache
Cache the results of Nix evaluation.
--refresh-eval-cache
Force a refresh of the Nix evaluation cache.
--offline
Disable substituters and consider all previously downloaded files up-to-date.
-c, --clean [<CLEAN>...]
Ignore existing environment variables when entering the shell. Pass a list of comma-separated environment variables to let through.
-d, --nix-debugger
Enter Nix debugger on failure.
--nix-debugger
Enter the Nix debugger on failure.
-n, --nix-option <NIX_OPTION> <NIX_OPTION>
Pass additional options to nix commands, see `man nix.conf` for full list.
-o, --override-input <OVERRIDE_INPUT> <OVERRIDE_INPUT>
Override inputs in devenv.yaml.
-h, --help
Print help
Print help (see more with '--help')
```

## Documentation
2 changes: 1 addition & 1 deletion devenv-eval-cache/src/db.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ pub async fn setup_db<P: AsRef<str>>(database_url: P) -> Result<SqlitePool, sqlx

// Delete the database and rerun the migrations
Sqlite::drop_database(database_url.as_ref()).await?;

Sqlite::create_database(database_url.as_ref()).await?;
sqlx::migrate!().run(&pool).await?;
}

231 changes: 140 additions & 91 deletions devenv-run-tests/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use clap::Parser;
use devenv::{log, Devenv, DevenvOptions};
use std::path::PathBuf;
use std::{env, fs};
use std::{
env, fs,
path::PathBuf,
process::{Command, ExitCode, Stdio},
};

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
@@ -33,140 +36,186 @@ struct TestResult {
async fn run_tests_in_directory(
args: &Args,
) -> Result<Vec<TestResult>, Box<dyn std::error::Error>> {
println!("Running Tests");
eprintln!("Running Tests");

let cwd = std::env::current_dir()?;
let cwd = env::current_dir()?;

let mut test_results = vec![];

for directory in &args.directories {
println!("Running in directory {}", directory.display());
eprintln!("Running in directory {}", directory.display());
let paths = fs::read_dir(directory)?;

for path in paths {
let path = path?.path();
let path = path.as_path();
if path.is_dir() {
let dir_name_path = path.file_name().unwrap();
let dir_name = dir_name_path.to_str().unwrap();

if !args.only.is_empty() {
let mut found = false;
for only in &args.only {
if path.ends_with(only) {
found = true;
break;
}
}
if !found {
continue;
}
} else {
for exclude in &args.exclude {
if path.ends_with(exclude) {
println!("Skipping {}", dir_name);
continue;
}
}
}

let mut config = devenv::config::Config::load_from(path)?;
for input in args.override_input.chunks_exact(2) {
config.add_input(&input[0].clone(), &input[1].clone(), &[]);
}
// Skip files
if !path.is_dir() {
continue;
}

// Override the input for the devenv module
config.add_input(
"devenv",
&format!("path:{:}?dir=src/modules", cwd.to_str().unwrap()),
&[],
);
let dir_name_path = path.file_name().unwrap();
let dir_name = dir_name_path.to_str().unwrap();

let tmpdir = tempdir::TempDir::new_in(path, ".devenv")
.expect("Failed to create temporary directory");
if !args.only.is_empty() {
if !args.only.iter().any(|only| path.ends_with(only)) {
continue;
}
} else if args.exclude.iter().any(|exclude| path.ends_with(exclude)) {
eprintln!("Skipping {}", dir_name);
continue;
}

let options = DevenvOptions {
config,
devenv_root: Some(cwd.join(path)),
devenv_dotfile: Some(tmpdir.path().to_path_buf()),
..Default::default()
};
let mut devenv = Devenv::new(options).await;
let mut config = devenv::config::Config::load_from(path)?;
for input in args.override_input.chunks_exact(2) {
config.add_input(&input[0].clone(), &input[1].clone(), &[]);
}

println!(" Running {}", dir_name);
// Override the input for the devenv module
config.add_input(
"devenv",
&format!("path:{:}?dir=src/modules", cwd.to_str().unwrap()),
&[],
);

let tmpdir = tempdir::TempDir::new(&format!("devenv-run-tests-{}", dir_name))?;
let devenv_root = tmpdir.path().to_path_buf();
let devenv_dotfile = tmpdir.path().join(".devenv");

// Copy the contents of the test directory to the temporary directory
let copy_content_status = Command::new("cp")
.arg("-r")
.arg(format!("{}/.", path.display()))
.arg(&devenv_root)
.status()?;
if !copy_content_status.success() {
return Err("Failed to copy test directory".into());
}

env::set_current_dir(path).expect("failed to set current dir");
env::set_current_dir(&devenv_root)?;

// A script to patch files in the working directory before the shell.
let patch_script = ".patch.sh";
// Initialize a git repository in the temporary directory.
// This helps Nix Flakes and git-hooks find the root of the project.
let git_init_status = Command::new("git")
.arg("init")
.arg("--initial-branch=main")
.status()?;
if !git_init_status.success() {
return Err("Failed to initialize the git repository".into());
}

// Run .patch.sh if it exists
if PathBuf::from(patch_script).exists() {
println!(" Running {patch_script}");
let _ = std::process::Command::new("bash")
.arg(patch_script)
.status()?;
}
let options = DevenvOptions {
config,
devenv_root: Some(devenv_root.clone()),
devenv_dotfile: Some(devenv_dotfile),
global_options: Some(devenv::GlobalOptions {
// Avoid caching between setup and shell.
// Because setup runs inside the shell, we can cache the shell before it's fully set up (e.g. dotenv test)
// TODO(sander): remove once `pathExists` can be cache-busted
eval_cache: false,
..Default::default()
}),
};
let mut devenv = Devenv::new(options).await;

// A script to run inside the shell before the test.
let setup_script = ".setup.sh";
eprintln!(" Running {}", dir_name);

// Run .setup.sh if it exists
if PathBuf::from(setup_script).exists() {
println!(" Running {setup_script}");
devenv
.shell(&Some(format!("./{setup_script}")), &[], false)
.await?;
}
// A script to patch files in the working directory before the shell.
let patch_script = ".patch.sh";

// TODO: wait for processes to shut down before exiting
let status = devenv.test().await;
let result = TestResult {
name: dir_name.to_string(),
passed: status.is_ok(),
};
test_results.push(result);
// Run .patch.sh if it exists
if PathBuf::from(patch_script).exists() {
eprintln!(" Running {patch_script}");
let _ = Command::new("bash").arg(patch_script).status()?;
}

// A script to run inside the shell before the test.
let setup_script = ".setup.sh";

// Restore the current directory
env::set_current_dir(&cwd).expect("failed to set current dir");
// Run .setup.sh if it exists
if PathBuf::from(setup_script).exists() {
eprintln!(" Running {setup_script}");
devenv
.shell(&Some(format!("./{setup_script}")), &[], false)
.await?;
}

// TODO: wait for processes to shut down before exiting
let status = devenv.test().await;
let result = TestResult {
name: dir_name.to_string(),
passed: status.is_ok(),
};
test_results.push(result);

// Restore the current directory
env::set_current_dir(&cwd)?;
}
}

Ok(test_results)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
async fn main() -> Result<ExitCode, Box<dyn std::error::Error>> {
log::init_tracing_default();

let args = Args::parse();
// If DEVENV_RUN_TESTS is set, run the tests.
if env::var("DEVENV_RUN_TESTS") == Ok("1".to_string()) {
let args = Args::parse();
match run(&args).await {
Ok(_) => return Ok(ExitCode::SUCCESS),
Err(err) => {
eprintln!("Error: {}", err);
return Ok(ExitCode::FAILURE);
}
};
}

let executable_path = std::env::current_exe()?;
// Otherwise, run the tests in a subprocess with a fresh environment.
let executable_path = env::current_exe()?;
let executable_dir = executable_path.parent().unwrap();
std::env::set_var(
"PATH",
format!(
"{}:{}",
executable_dir.display(),
std::env::var("PATH").unwrap_or_default()
),
let path = format!(
"{}:{}",
executable_dir.display(),
env::var("PATH").unwrap_or_default()
);

let test_results = run_tests_in_directory(&args).await?;
let mut cmd = Command::new(&executable_path);
cmd.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.args(env::args().skip(1));
cmd.env_clear()
.env("DEVENV_RUN_TESTS", "1")
.env("DEVENV_NIX", env::var("DEVENV_NIX").unwrap_or_default())
.env("PATH", path)
.env("HOME", env::var("HOME").unwrap_or_default());

let output = cmd.output()?;
if output.status.success() {
Ok(ExitCode::SUCCESS)
} else {
Ok(ExitCode::FAILURE)
}
}

async fn run(args: &Args) -> Result<(), Box<dyn std::error::Error>> {
let test_results = run_tests_in_directory(args).await?;
let num_tests = test_results.len();
let num_failed_tests = test_results.iter().filter(|r| !r.passed).count();

println!();
eprintln!();

for result in test_results {
if !result.passed {
println!("{}: Failed", result.name);
eprintln!("{}: Failed", result.name);
};
}

println!();
println!("Ran {} tests, {} failed.", num_tests, num_failed_tests);
eprintln!();
eprintln!("Ran {} tests, {} failed.", num_tests, num_failed_tests);

if num_failed_tests > 0 {
Err("Some tests failed".into())
4 changes: 1 addition & 3 deletions devenv.nix
Original file line number Diff line number Diff line change
@@ -15,9 +15,7 @@
pkgs.watchexec
pkgs.openssl
pkgs.sqlx-cli
] ++ lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk; [
frameworks.SystemConfiguration
]);
];

languages.nix.enable = true;
# for cli
Loading