use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use tempfile::TempDir;
#[test]
fn doctor_reports_the_active_actor_and_redacts_the_token() {
let fixture = DoctorFixture::new("WRITE");
Command::cargo_bin("release-tool")
.unwrap()
.current_dir(fixture.project.path())
.env("PATH", fixture.path())
.arg("doctor")
.assert()
.success()
.stdout(predicate::str::contains("VERIFIED Git repository"))
.stdout(predicate::str::contains(
"VERIFIED GitHub account: release-bot",
))
.stdout(predicate::str::contains(
"VERIFIED repository permission: WRITE",
))
.stdout(predicate::str::contains(
"UNVERIFIABLE destination write permission",
))
.stdout(predicate::str::contains("super-secret-token").not());
}
#[test]
fn doctor_rejects_an_account_without_repository_write_permission() {
let fixture = DoctorFixture::new("READ");
Command::cargo_bin("release-tool")
.unwrap()
.current_dir(fixture.project.path())
.env("PATH", fixture.path())
.arg("doctor")
.assert()
.failure()
.stderr(predicate::str::contains(
"GitHub account only has READ permission for computed-parameter/example",
));
}
#[test]
fn doctor_checks_target_commands_before_the_release_starts() {
let fixture = DoctorFixture::new("WRITE");
fs::write(
fixture.project.path().join("release.toml"),
r#"required_version = "0.1.0"
[repository]
github = "computed-parameter/example"
branch = "main"
[publishers.release]
kind = "github_release"
title = "Example {version}"
prerelease = true
[[targets]]
name = "app"
kind = "docker_archive"
publisher = "release"
default = true
platform = "linux/amd64"
image = "example:{version}"
asset = "example-{version}.tar.xz"
build = ["definitely-missing-release-command", "{image}"]
local_check = ["gh", "--version"]
"#,
)
.unwrap();
Command::cargo_bin("release-tool")
.unwrap()
.current_dir(fixture.project.path())
.env("PATH", fixture.path())
.arg("doctor")
.assert()
.failure()
.stderr(predicate::str::contains(
"required command `definitely-missing-release-command` was not found",
));
}
#[test]
fn doctor_checks_oci_buildx_capabilities_without_a_registry_publisher_table() {
let fixture = DoctorFixture::new("WRITE");
fs::write(
fixture.project.path().join("release.toml"),
r#"required_version = "0.3.0"
[repository]
github = "computed-parameter/example"
branch = "main"
[[targets]]
name = "image"
kind = "oci_image"
default = true
image = "ghcr.io/computed-parameter/example:{version}"
platform = "linux/amd64"
reuse_check = ["gh", "--version"]
build = ["gh", "--version"]
"#,
)
.unwrap();
executable(
&fixture.bin.join("docker"),
r#"#!/usr/bin/env bash
set -eu
case "$*" in
"buildx version") printf 'buildx test\n' ;;
"buildx imagetools inspect --help") printf '%s\n' '--format --raw' ;;
"buildx imagetools create --help") printf '%s\n' '--prefer-index' ;;
*) printf 'unexpected fake docker args: %s\n' "$*" >&2; exit 2 ;;
esac
"#,
);
Command::cargo_bin("release-tool")
.unwrap()
.current_dir(fixture.project.path())
.env("PATH", fixture.path())
.arg("doctor")
.assert()
.success()
.stdout(predicate::str::contains(
"VERIFIED Docker buildx and OCI target commands",
))
.stdout(predicate::str::contains(
"UNVERIFIABLE OCI registry single-writer or immutable-tag enforcement",
));
}
struct DoctorFixture {
project: TempDir,
bin: std::path::PathBuf,
}
impl DoctorFixture {
fn new(permission: &str) -> Self {
let project = tempfile::tempdir().unwrap();
let bin = project.path().join("bin");
fs::create_dir(&bin).unwrap();
fs::write(
project.path().join("release.toml"),
r#"required_version = "0.1.0"
[repository]
github = "computed-parameter/example"
branch = "main"
"#,
)
.unwrap();
executable(
&bin.join("git"),
r#"#!/usr/bin/env bash
set -eu
case "$*" in
"status --porcelain --untracked-files=all") exit 0 ;;
"branch --show-current") printf 'main\n' ;;
"rev-parse HEAD") printf 'commit01\n' ;;
"ls-remote origin refs/heads/main") printf 'commit01\trefs/heads/main\n' ;;
"ls-remote --tags origin") exit 0 ;;
"remote get-url origin") printf 'https://github.com/computed-parameter/example.git\n' ;;
"--version") printf 'git version test\n' ;;
*) printf 'unexpected fake git args: %s\n' "$*" >&2; exit 2 ;;
esac
"#,
);
executable(
&bin.join("gh"),
&format!(
r#"#!/usr/bin/env bash
set -eu
case "$*" in
"--version") printf 'gh version test\n' ;;
"auth status --hostname github.com") exit 0 ;;
"auth token --hostname github.com") printf 'super-secret-token\n' ;;
"api --hostname github.com user --jq .login") printf 'release-bot\n' ;;
"repo view computed-parameter/example --json nameWithOwner,viewerPermission")
printf '{{"nameWithOwner":"computed-parameter/example","viewerPermission":"{permission}"}}\n' ;;
*) printf 'unexpected fake gh args: %s\n' "$*" >&2; exit 2 ;;
esac
"#
),
);
Self { project, bin }
}
fn path(&self) -> String {
let inherited = std::env::var("PATH").unwrap();
format!("{}:{inherited}", self.bin.display())
}
}
fn executable(path: &std::path::Path, source: &str) {
fs::write(path, source).unwrap();
let mut permissions = fs::metadata(path).unwrap().permissions();
permissions.set_mode(0o755);
fs::set_permissions(path, permissions).unwrap();
}