Skip to content

Commit

Permalink
Merge pull request #164 from DeterminateSystems/edolstra/local-testing
Browse files Browse the repository at this point in the history
Make it easier to test without GitHub or a local FlakeHub
  • Loading branch information
cole-h authored Sep 13, 2024
2 parents 8c17c5f + 4024285 commit 41a7d04
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 221 deletions.
14 changes: 14 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,17 @@ cargo run -- \
--jwt-issuer-uri http://localhost:8081/jwt/token \
--host http://localhost:8080
```

To test evaluation of a local flake without fetching anything from
GitHub, and writing the tarball and metadata to a local directory
instead of FlakeHub, do:

```bash
cargo run -- \
--visibility public \
--repository foo/bar \
--tag v0.0.1 \
--git-root /path/to/repo \
--directory /path/to/repo/flake \
--dest-dir /tmp/out
```
105 changes: 104 additions & 1 deletion src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
mod instrumentation;

use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::str::FromStr as _;

use color_eyre::eyre::{eyre, Context as _, Result};

use crate::git_context::GitContext;
use crate::push_context::ExecutionEnvironment;
use crate::{Visibility, DEFAULT_ROLLING_PREFIX};

#[derive(Debug, clap::Parser)]
#[clap(version)]
Expand Down Expand Up @@ -118,6 +125,10 @@ pub(crate) struct FlakeHubPushCli {
default_value_t = false
)]
pub(crate) disable_rename_subgroups: bool,

/// Write the tarball to a directory instead of pushing it to FlakeHub.
#[clap(long, env = "FLAKEHUB_DEST_DIR", value_parser = PathBufToNoneParser, default_value = "")]
pub(crate) dest_dir: OptionPathBuf,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -320,4 +331,96 @@ impl FlakeHubPushCli {
}
}
}

pub(crate) fn execution_environment(&self) -> ExecutionEnvironment {
if std::env::var("GITHUB_ACTION").ok().is_some() {
ExecutionEnvironment::GitHub
} else if std::env::var("GITLAB_CI").ok().is_some() {
ExecutionEnvironment::GitLab
} else {
ExecutionEnvironment::LocalGitHub
}
}

pub(crate) fn visibility(&self) -> Result<Visibility> {
match (self.visibility_alt, self.visibility) {
(Some(v), _) => Ok(v),
(None, Some(v)) => Ok(v),
(None, None) => Err(color_eyre::eyre::eyre!(
"Could not determine the flake's desired visibility. Use `--visibility` to set this to one of the following: public, unlisted, private.",
)),
}
}

pub(crate) fn resolve_local_git_root(&self) -> Result<PathBuf> {
let maybe_git_root = match &self.git_root.0 {
Some(gr) => Ok(gr.to_owned()),
None => std::env::current_dir().map(PathBuf::from),
};

let local_git_root = maybe_git_root.wrap_err("Could not determine current `git_root`. Pass `--git-root` or set `FLAKEHUB_PUSH_GIT_ROOT`, or run `flakehub-push` with the git root as the current working directory")?;
let local_git_root = local_git_root
.canonicalize()
.wrap_err("Failed to canonicalize `--git-root` argument")?;

Ok(local_git_root)
}

pub(crate) fn subdir_from_git_root(&self, local_git_root: &Path) -> Result<PathBuf> {
let subdir =
if let Some(directory) = &self.directory.0 {
let absolute_directory = if directory.is_absolute() {
directory.clone()
} else {
local_git_root.join(directory)
};
let canonical_directory = absolute_directory
.canonicalize()
.wrap_err("Failed to canonicalize `--directory` argument")?;

PathBuf::from(canonical_directory.strip_prefix(local_git_root).wrap_err(
"Specified `--directory` was not a directory inside the `--git-root`",
)?)
} else {
PathBuf::new()
};

Ok(subdir)
}

pub(crate) fn release_version(&self, git_ctx: &GitContext) -> Result<String> {
let rolling_prefix_or_tag = match (self.rolling_minor.0.as_ref(), &self.tag.0) {
(Some(_), _) if !self.rolling => {
return Err(eyre!(
"You must enable `rolling` to upload a release with a specific `rolling-minor`."
));
}
(Some(minor), _) => format!("0.{minor}"),
(None, _) if self.rolling => DEFAULT_ROLLING_PREFIX.to_string(),
(None, Some(tag)) => {
let version_only = tag.strip_prefix('v').unwrap_or(tag);
// Ensure the version respects semver
semver::Version::from_str(version_only).wrap_err_with(|| eyre!("Failed to parse version `{tag}` as semver, see https://semver.org/ for specifications"))?;
tag.to_string()
}
(None, None) => {
return Err(eyre!("Could not determine tag or rolling minor version, `--tag`, `GITHUB_REF_NAME`, or `--rolling-minor` must be set"));
}
};

let Some(commit_count) = git_ctx.revision_info.commit_count else {
return Err(eyre!("Could not determine commit count, this is normally determined via the `--git-root` argument or via the GitHub API"));
};

let rolling_minor_with_postfix_or_tag = if self.rolling_minor.0.is_some() || self.rolling {
format!(
"{rolling_prefix_or_tag}.{}+rev-{}",
commit_count, git_ctx.revision_info.revision
)
} else {
rolling_prefix_or_tag.to_string() // This will always be the tag since `self.rolling_prefix` was empty.
};

Ok(rolling_minor_with_postfix_or_tag)
}
}
44 changes: 39 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,45 @@ async fn main() -> Result<std::process::ExitCode> {
}

async fn execute() -> Result<std::process::ExitCode> {
let ctx = {
let mut cli = cli::FlakeHubPushCli::parse();
cli.instrumentation.setup()?;
PushContext::from_cli_and_env(&mut cli).await?
};
let mut cli = cli::FlakeHubPushCli::parse();
cli.instrumentation.setup()?;

// NOTE(cole-h): If --dest-dir is passed, we're intentionally avoiding doing any actual
// networking (i.e. for FlakeHub and GitHub)
if let Some(dest_dir) = &cli.dest_dir.0 {
let local_git_root = cli.resolve_local_git_root()?;
let local_rev_info = revision_info::RevisionInfo::from_git_root(&local_git_root)?;
let git_ctx = git_context::GitContext {
spdx_expression: cli.spdx_expression.0.clone(),
repo_topics: vec![],
revision_info: local_rev_info,
};

let release_version = cli.release_version(&git_ctx)?;
let release_tarball_name = format!("{release_version}.tar.gz");
let release_json_name = format!("{release_version}.json");

let (release_metadata, tarball) =
release_metadata::ReleaseMetadata::new(&cli, &git_ctx, None).await?;

std::fs::create_dir_all(dest_dir)?;

{
let dest_file = dest_dir.join(release_tarball_name);
tracing::info!("Writing tarball to {}", dest_file.display());
std::fs::write(dest_file, tarball.bytes)?;
}

{
let dest_file = dest_dir.join(release_json_name);
tracing::info!("Writing release metadata to {}", dest_file.display());
std::fs::write(dest_file, serde_json::to_string(&release_metadata)?)?;
}

return Ok(ExitCode::SUCCESS);
}

let ctx = PushContext::from_cli_and_env(&mut cli).await?;

let fhclient = FlakeHubClient::new(ctx.flakehub_host, ctx.auth_token)?;

Expand Down
Loading

0 comments on commit 41a7d04

Please sign in to comment.