chore: stop sharing a cache with the binary the audit job runs
This commit is contained in:
32
.gitignore
vendored
32
.gitignore
vendored
@@ -8,3 +8,35 @@ target/
|
|||||||
|
|
||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
*.pdb
|
*.pdb
|
||||||
|
|
||||||
|
# the cargo home CI keeps inside the project so it lands in the cache
|
||||||
|
.cargo/
|
||||||
|
|
||||||
|
# where the completions build writes when it is not given a directory
|
||||||
|
completions/
|
||||||
|
|
||||||
|
# os
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# editors
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
.ignore
|
||||||
|
|
||||||
|
# ai
|
||||||
|
CLAUDE.local.md
|
||||||
|
.claude
|
||||||
|
|
||||||
|
# languages
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# nix
|
||||||
|
.nix-venv
|
||||||
|
.envrc
|
||||||
|
.direnv/
|
||||||
|
|
||||||
|
# project-local
|
||||||
|
TODO.md
|
||||||
|
# database dumps, which this tool exists to keep out of a repository
|
||||||
|
dumps
|
||||||
|
*.partial
|
||||||
|
|||||||
@@ -5,30 +5,38 @@ default:
|
|||||||
files:
|
files:
|
||||||
- Cargo.lock
|
- Cargo.lock
|
||||||
paths:
|
paths:
|
||||||
|
# no .cargo/bin here: the audit job runs what is in it, and this cache is
|
||||||
|
# shared by every branch and merge request, so a pipeline could otherwise
|
||||||
|
# leave behind the binary a later scheduled audit executes
|
||||||
- .cargo/registry
|
- .cargo/registry
|
||||||
# so the audit job does not rebuild cargo-audit on every schedule
|
|
||||||
- .cargo/bin
|
|
||||||
- target
|
- target
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
# keep the registry inside the project so it lands in the cache
|
# keep the registry inside the project so it lands in the cache
|
||||||
CARGO_HOME: $CI_PROJECT_DIR/.cargo
|
CARGO_HOME: $CI_PROJECT_DIR/.cargo
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
# pinned, rather than whatever version exists on the night this runs
|
||||||
|
CARGO_AUDIT_VERSION: "0.21.2"
|
||||||
|
|
||||||
# without this a push to a branch with an open merge request runs twice
|
# without this a push to a branch with an open merge request runs twice
|
||||||
workflow:
|
workflow:
|
||||||
rules:
|
rules:
|
||||||
|
# first, because a scheduled pipeline sets CI_COMMIT_BRANCH as well and so
|
||||||
|
# would be matched by the branch rule below, or vetoed by the one above it
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
|
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
|
||||||
when: never
|
when: never
|
||||||
- if: $CI_COMMIT_BRANCH
|
- if: $CI_COMMIT_BRANCH
|
||||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
||||||
|
|
||||||
check:
|
check:
|
||||||
script:
|
script:
|
||||||
- rustup component add rustfmt clippy
|
- rustup component add rustfmt clippy
|
||||||
- cargo fmt --check
|
- cargo fmt --check
|
||||||
- cargo clippy --all-targets -- -D warnings
|
# --locked on the first cargo invocation too: without it clippy resolves the
|
||||||
|
# dependencies and rewrites a Cargo.lock that has drifted from Cargo.toml,
|
||||||
|
# and the --locked commands after it then pass against what it just wrote
|
||||||
|
- cargo clippy --locked --all-targets -- -D warnings
|
||||||
- cargo test --locked
|
- cargo test --locked
|
||||||
- cargo build --release --locked
|
- cargo build --release --locked
|
||||||
rules:
|
rules:
|
||||||
@@ -39,19 +47,33 @@ check:
|
|||||||
# runs only from a pipeline schedule, so set one up in the project settings
|
# runs only from a pipeline schedule, so set one up in the project settings
|
||||||
audit:
|
audit:
|
||||||
script:
|
script:
|
||||||
- cargo install cargo-audit --locked
|
- cargo install cargo-audit --version $CARGO_AUDIT_VERSION --locked
|
||||||
- cargo audit
|
- cargo audit
|
||||||
# reports dependencies that have drifted behind, without changing the lockfile
|
# reports dependencies that have drifted behind, without changing the lockfile
|
||||||
- cargo update --dry-run
|
- cargo update --dry-run
|
||||||
|
# its own cache, so the audit tool is not rebuilt on every schedule while
|
||||||
|
# still being written only by this schedule-only job. the pinned version is
|
||||||
|
# part of the key, so a bump fetches rather than reusing the old binary
|
||||||
|
cache:
|
||||||
|
key: audit-tools-$CARGO_AUDIT_VERSION
|
||||||
|
paths:
|
||||||
|
- .cargo/bin
|
||||||
|
- .cargo/registry
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
# the msrv declared in Cargo.toml, so it fails when something needs a newer rustc
|
# the msrv declared in Cargo.toml, so it fails when something needs a newer rustc
|
||||||
msrv:
|
msrv:
|
||||||
image: rust:1.85
|
image: rust:1.85
|
||||||
script:
|
script:
|
||||||
- cargo build --locked
|
- cargo build --locked
|
||||||
|
# its own key: artifacts built by another rustc are of no use to this job, and
|
||||||
|
# sharing one only has the two toolchains taking turns overwriting it
|
||||||
|
cache:
|
||||||
|
key: msrv-$CI_COMMIT_REF_SLUG
|
||||||
|
paths:
|
||||||
|
- .cargo/registry
|
||||||
|
- target
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||||
when: never
|
when: never
|
||||||
|
|||||||
21
build.rs
21
build.rs
@@ -25,6 +25,14 @@ fn install_dir(shell: Shell) -> Option<(PathBuf, bool)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
|
// naming any rerun-if condition replaces cargo's default of re-running the
|
||||||
|
// script whenever anything in the package changed, so everything that
|
||||||
|
// shapes a completion script has to be named here. without them an
|
||||||
|
// installed script goes stale against the binary it completes
|
||||||
|
println!("cargo::rerun-if-changed=build.rs");
|
||||||
|
println!("cargo::rerun-if-changed=src/cli");
|
||||||
|
println!("cargo::rerun-if-changed=Cargo.toml");
|
||||||
|
|
||||||
println!("cargo::rerun-if-env-changed=SHELL_COMPLETIONS_DIR");
|
println!("cargo::rerun-if-env-changed=SHELL_COMPLETIONS_DIR");
|
||||||
for shell in Shell::value_variants() {
|
for shell in Shell::value_variants() {
|
||||||
println!(
|
println!(
|
||||||
@@ -40,7 +48,18 @@ fn main() -> Result<(), Error> {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::create_dir_all(&dir)?;
|
// a build script's working directory is the package root, so a relative
|
||||||
|
// dir would quietly install into the source tree and one holding `..`
|
||||||
|
// somewhere else again. only a path that says where it means is taken
|
||||||
|
if requested && !dir.is_absolute() {
|
||||||
|
return Err(Error::other(format!(
|
||||||
|
"the completions directory must be an absolute path, not {}",
|
||||||
|
dir.display()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::create_dir_all(&dir)
|
||||||
|
.map_err(|e| Error::other(format!("creating {}: {e}", dir.display())))?;
|
||||||
let path = generate_to(*shell, &mut cmd, env!("CARGO_PKG_NAME"), &dir)?;
|
let path = generate_to(*shell, &mut cmd, env!("CARGO_PKG_NAME"), &dir)?;
|
||||||
|
|
||||||
if requested {
|
if requested {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub enum Django {
|
|||||||
/// Start a bash session in a fresh django container
|
/// Start a bash session in a fresh django container
|
||||||
Bash,
|
Bash,
|
||||||
|
|
||||||
/// Prepare empty management command 'command' in app 'app'
|
/// Prepare an empty management command NAME in the app at APP
|
||||||
MakeCommand { app: PathBuf, name: String },
|
MakeCommand { app: PathBuf, name: String },
|
||||||
|
|
||||||
/// Run Django's manage.py makemigrations
|
/// Run Django's manage.py makemigrations
|
||||||
|
|||||||
@@ -27,15 +27,24 @@ fn script(shell: Shell) -> Vec<u8> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Shell, script};
|
use super::{Ahab, Shell, script};
|
||||||
use clap::ValueEnum;
|
use clap::{CommandFactory, ValueEnum};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn every_shell_gets_a_script_covering_the_subcommands() {
|
fn every_shell_gets_a_script_covering_the_subcommands() {
|
||||||
|
// asked of the parser rather than listed here, which is a list that
|
||||||
|
// silently stops covering the newest command
|
||||||
|
let subcommands: Vec<String> = Ahab::command()
|
||||||
|
.get_subcommands()
|
||||||
|
.map(|sub| sub.get_name().to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert!(subcommands.len() > 1, "{subcommands:?}");
|
||||||
|
|
||||||
for shell in Shell::value_variants() {
|
for shell in Shell::value_variants() {
|
||||||
let out = String::from_utf8(script(*shell)).expect("script is utf8");
|
let out = String::from_utf8(script(*shell)).expect("script is utf8");
|
||||||
|
|
||||||
for subcommand in ["django", "postgres", "link", "completions"] {
|
for subcommand in &subcommands {
|
||||||
assert!(
|
assert!(
|
||||||
out.contains(subcommand),
|
out.contains(subcommand),
|
||||||
"{shell:?} script never mentions {subcommand}"
|
"{shell:?} script never mentions {subcommand}"
|
||||||
|
|||||||
Reference in New Issue
Block a user