use crate::{error, WorkflowAPIEvent, WorkflowEvent, WorkflowState, WorkflowTriggerEvents};
pub fn is_workflow_finished(state: &WorkflowState) -> bool {
match state {
WorkflowState::Succeeded => true,
WorkflowState::Failed => true,
WorkflowState::Cancelled => true,
WorkflowState::Skipped => true,
_ => false,
}
}
pub fn get_workflow_event_payload(event: WorkflowEvent) -> crate::Result<WorkflowAPIEvent> {
match event {
WorkflowEvent::API(api_event) => Ok(api_event),
WorkflowEvent::PullRequest(event) => {
let api_event = WorkflowAPIEvent {
repo_owner: event.repository.owner.login,
repo_name: event.repository.name,
ref_name: event.pull_request.base.ref_name,
sha: event.pull_request.head.sha,
pr_number: Some(event.pull_request.number),
};
Ok(api_event)
}
WorkflowEvent::Push(event) => {
let api_event = WorkflowAPIEvent {
repo_owner: event.repository.owner.login,
repo_name: event.repository.name,
ref_name: event.ref_name,
sha: event.after,
pr_number: None,
};
Ok(api_event)
}
#[allow(unreachable_patterns)]
_ => Err(error::Error::unsupported_feature(
"Currently only support API events",
)),
}
}
pub fn should_skip_workflow(
on: &WorkflowTriggerEvents,
event: &WorkflowEvent,
changed_files: &Option<Vec<String>>,
) -> anyhow::Result<bool> {
match event {
WorkflowEvent::API(_) => Ok(false),
WorkflowEvent::PullRequest(pull_request) => match &on.pull_request {
Some(pull_request_on) => {
if let Some(types) = &pull_request_on.types {
if !types.contains(&pull_request.action) {
return Ok(true);
}
}
if let (Some(patterns), Some(changed_files)) = (&pull_request_on.paths, changed_files) {
if !is_match_patterns(changed_files, patterns)? {
return Ok(true);
}
}
if let Some(branches) = &pull_request_on.branches {
let ref_name = pull_request
.pull_request
.base
.ref_name
.replace("refs/heads/", "");
if !is_match_patterns(&vec![ref_name], branches)? {
return Ok(true);
}
}
return Ok(false);
}
None => {
return Ok(false);
}
},
WorkflowEvent::Push(push_event) => match &on.push {
Some(push_on) => {
let is_tag = push_event.ref_name.starts_with("refs/tags/");
if is_tag {
if let Some(tags) = &push_on.tags {
let tag_name = push_event.ref_name.replace("refs/tags/", "");
if !is_match_patterns(&vec![tag_name], tags)? {
return Ok(true);
}
}
} else {
if let Some(branches) = &push_on.branches {
let ref_name = push_event.ref_name.replace("refs/heads/", "");
if !is_match_patterns(&vec![ref_name], branches)? {
return Ok(true);
}
}
}
if let (Some(patterns), Some(changed_files)) = (&push_on.paths, changed_files) {
if !is_match_patterns(changed_files, patterns)? {
return Ok(true);
}
}
return Ok(false);
}
None => {
return Ok(false);
}
},
#[allow(unreachable_patterns)]
_ => {
todo!("Only API events are supported for now")
}
}
}
fn is_match_patterns(
values: &Vec<String>,
patterns: &Vec<String>,
) -> Result<bool, glob::PatternError> {
for value in values {
for pattern in patterns {
if glob::Pattern::new(pattern)?.matches(value) {
return Ok(true);
}
}
}
Ok(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_match_workflow_paths() {
let paths = vec![
"src/main.rs".to_string(),
"src/lib.rs".to_string(),
"src/runner/main.rs".to_string(),
"src/runner/lib.rs".to_string(),
];
assert_eq!(
is_match_patterns(&paths, &vec!["src/main.rs".to_string()]).unwrap(),
true
);
assert_eq!(
is_match_patterns(&paths, &vec!["src/runner/main.rs".to_string()]).unwrap(),
true
);
assert_eq!(
is_match_patterns(&paths, &vec!["src/runner/*.rs".to_string()]).unwrap(),
true
);
assert_eq!(
is_match_patterns(&paths, &vec!["src/runner/**/*.rs".to_string()]).unwrap(),
true
);
assert_eq!(
is_match_patterns(&paths, &vec!["src/runner/**/main.rs".to_string()]).unwrap(),
true
);
assert_eq!(
is_match_patterns(&paths, &vec!["src/runner/**/lib.rs".to_string()]).unwrap(),
true
);
assert_eq!(
is_match_patterns(&paths, &vec!["scripts/**/lib.rs".to_string()]).unwrap(),
false
);
assert_eq!(
is_match_patterns(&paths, &vec!["src/runner/**/lib.js".to_string()]).unwrap(),
false
);
}
#[test]
fn is_match_branches() {
let branches = vec!["master".to_string(), "develop".to_string()];
assert_eq!(
is_match_patterns(&vec!["master".to_string()], &branches).unwrap(),
true
);
assert_eq!(
is_match_patterns(&vec!["develop".to_string()], &branches).unwrap(),
true
);
assert_eq!(
is_match_patterns(&vec!["feature/branch".to_string()], &branches).unwrap(),
false
);
}
#[test]
fn is_match_features() {
let features = vec!["feature/*".to_string()];
assert_eq!(
is_match_patterns(&vec!["feature/branch".to_string()], &features).unwrap(),
true
);
assert_eq!(
is_match_patterns(&vec!["feature/branch/branch".to_string()], &features).unwrap(),
true
);
assert_eq!(
is_match_patterns(&vec!["feature".to_string()], &features).unwrap(),
false
);
assert_eq!(
is_match_patterns(&vec!["feature-branch".to_string()], &features).unwrap(),
false
);
}
}