Skip to content
This repository has been archived by the owner on Sep 27, 2023. It is now read-only.

feat: implement paths for Pipeline #53

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 8,10 @@
"editor.defaultFormatter": "denoland.vscode-deno"
},
// Rust
"rust-analyzer.cargo.features": "all"
"rust-analyzer.cargo.features": "all",
"[rust]": {
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.detectIndentation": false
}
}
35 changes: 34 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 42,7 @@ dirs = "5.0.0"
dotenvy = "0.15.7"
flate2 = { version = "1.0.25", optional = true, features = ["zlib"]}
futures = "0.3.28"
globset = "0.4.10"
humansize = "2.1.3"
indicatif = "0.17.3"
oci-spec = "0.6.0"
Expand Down
40 changes: 40 additions & 0 deletions crates/cli/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 9,46 @@ pub struct Origin {
pub url: String,
}

pub async fn git_uncommitted_files() -> Result<Vec<String>> {
let output = Command::new("git")
.args(["status", "--ignored=no", "--short"])
.output()
.await?;

if !output.status.success() {
return Err(anyhow::anyhow!(
"Failed to get git uncommitted files: {}",
String::from_utf8_lossy(&output.stderr)
));
};

let changed_files = String::from_utf8(output.stdout)?
.lines()
.map(|row| row.trim().split(' ').last().unwrap().to_string())
.collect();

Ok(changed_files)
}

pub async fn git_changed_files(base: String, head: String) -> Result<Vec<String>> {
let output = Command::new("git")
.args(["--no-pager", "diff", &base, &head, "--name-only"])
.output()
.await?;

if !output.status.success() {
return Err(anyhow::anyhow!(
"Failed to get git changed files: {}",
String::from_utf8_lossy(&output.stderr)
));
};

Ok(String::from_utf8(output.stdout)?
.lines()
.map(|s| s.to_string())
.collect())
}

pub async fn git_remotes() -> Result<Vec<Origin>> {
let output = Command::new("git").args(["remote", "-v"]).output().await?;

Expand Down
2 changes: 2 additions & 0 deletions crates/cli/src/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 80,8 @@ pub enum Trigger {
Options {
push: Option<TriggerOn>,
pull_request: Option<TriggerOn>,
#[serde(default)]
paths: Vec<String>,
},
DenoFunction,
}
Expand Down
74 changes: 54 additions & 20 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 32,14 @@ use url::Url;

use ahash::{HashMap, HashMapExt};
use clap::Parser;
use globset::{Glob, GlobSetBuilder};
use owo_colors::{OwoColorize, Stream};
use tokio::{io::AsyncWriteExt, process::Command};

use crate::{
bin_deps::{buildctl_exe, deno_exe, BUILDKIT_VERSION},
dag::{invert_graph, topological_sort, Node},
git::github_repo,
git::{git_changed_files, git_uncommitted_files, github_repo},
job::{CicadaType, InspectInfo, JobResolved, OnFail, Pipeline, TriggerOn},
};

Expand Down Expand Up @@ -467,35 468,68 @@ impl Commands {
std::env::var("CICADA_BASE_REF"),
) {
(Ok(git_event), Ok(base_ref)) => match pipeline.on {
Some(job::Trigger::Options { push, pull_request }) => match &*git_event {
"pull_request" => {
if let Some(TriggerOn::Branches { branches }) = &pull_request {
if !branches.contains(&base_ref) {
info!(
"Skipping pipeline because branch {} is not in {}: {:?}",
base_ref.bold(),
"pull_request".bold(),
pull_request
);
std::process::exit(2);
Some(job::Trigger::Options {
push,
pull_request,
paths,
}) => {
match &*git_event {
"pull_request" => {
if let Some(TriggerOn::Branches { branches }) = &pull_request {
if !branches.contains(&base_ref) {
info!(
"Skipping pipeline because branch {} is not in {}: {:?}",
base_ref.bold(),
"pull_request".bold(),
pull_request
);
std::process::exit(2);
}
}
}
}
"push" => {
if let Some(TriggerOn::Branches { branches }) = &push {
if !branches.contains(&base_ref) {
info!(
"push" => {
if let Some(TriggerOn::Branches { branches }) = &push {
if !branches.contains(&base_ref) {
info!(
"Skipping pipeline because branch {} is not in {}: {:?}",
base_ref.bold(),
"push".bold(),
push
);
std::process::exit(2);
std::process::exit(2);
}
}
}
_ => (),
}
_ => {}
},

if !paths.is_empty() {
let globset = {
let mut builder = GlobSetBuilder::new();
for path in paths.iter() {
builder.add(Glob::new(path)?);
}
builder.build()?
};
let changed_files = match (
std::env::var("CICADA_GIT_BASE"),
std::env::var("CICADA_GIT_HEAD"),
Comment on lines 515 to 516
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two new variables should address the problem. The CICADA_GIT_BASE should contain the hash of the latest commit on which cicada was run (for the same branch/pr), while CICADA_GIT_HEAD should be the hash of the commit that triggered the run.

) {
(Ok(base), Ok(head)) => git_changed_files(base, head).await?,
_ => git_uncommitted_files().await?,
};
let matching_files =
changed_files.iter().any(|f| globset.is_match(f));

if !matching_files {
info!(
"Skipping pipeline because no changed file is matching paths: {:?}",
paths
);
std::process::exit(2);
}
}
}
Some(job::Trigger::DenoFunction) => {
anyhow::bail!("TypeScript trigger functions are unimplemented")
}
Expand Down
14 changes: 14 additions & 0 deletions lib/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 37,16 @@ import { DockerImages } from "https://deno.land/x/cicada/types/dockerImages.ts";
*/
export type FilePath = string;

/**
* A glob representing more or one path.
*
* @example
* ```ts
* const glob: Glob = "src/*.ts"
* ```
*/
export type Glob = string;

/**
* Options for a cached directory
*
Expand Down Expand Up @@ -284,6 294,10 @@ export interface TriggerOptions {
* Use `'all'` if you'd like for any branch to trigger the pipeline.
*/
pullRequest?: Branch[] | "all";
/**
* Which paths should trigger the pipeline on a push or pullRequest.
*/
paths?: Glob[];
}

/**
Expand Down