rust-actions 0.2.1

BDD testing framework with GitHub Actions YAML syntax
Documentation
use crate::parser::{parse_workflows, Workflow};
use crate::{Error, Result};
use std::collections::HashMap;
use std::path::{Path, PathBuf};

const FILE_REF_PREFIX: &str = "@file:";

pub struct WorkflowRegistry {
    base_path: PathBuf,
    workflows: HashMap<PathBuf, Workflow>,
}

impl WorkflowRegistry {
    pub fn build(workflows_path: impl AsRef<Path>) -> Result<Self> {
        let base_path = workflows_path.as_ref().to_path_buf();
        let parsed = parse_workflows(&base_path)?;
        let workflows: HashMap<PathBuf, Workflow> = parsed.into_iter().collect();

        Ok(Self {
            base_path,
            workflows,
        })
    }

    pub fn get(&self, path: &Path) -> Option<&Workflow> {
        self.workflows.get(path)
    }

    pub fn get_by_str(&self, path: &str) -> Option<&Workflow> {
        self.workflows.get(&PathBuf::from(path))
    }

    pub fn is_reusable(&self, path: &Path) -> bool {
        self.workflows
            .get(path)
            .map(|w| w.is_reusable())
            .unwrap_or(false)
    }

    pub fn resolve_file_ref(&self, uses: &str) -> Result<&Workflow> {
        let path = parse_file_ref(uses)?;
        self.get_by_str(path).ok_or_else(|| {
            Error::WorkflowNotFound {
                path: path.to_string(),
            }
        })
    }

    pub fn runnable_workflows(&self) -> impl Iterator<Item = (&PathBuf, &Workflow)> {
        self.workflows.iter().filter(|(_, w)| !w.is_reusable())
    }

    pub fn reusable_workflows(&self) -> impl Iterator<Item = (&PathBuf, &Workflow)> {
        self.workflows.iter().filter(|(_, w)| w.is_reusable())
    }

    pub fn all_workflows(&self) -> impl Iterator<Item = (&PathBuf, &Workflow)> {
        self.workflows.iter()
    }

    pub fn base_path(&self) -> &Path {
        &self.base_path
    }

    pub fn workflow_count(&self) -> usize {
        self.workflows.len()
    }

    pub fn runnable_count(&self) -> usize {
        self.workflows.values().filter(|w| !w.is_reusable()).count()
    }

    pub fn reusable_count(&self) -> usize {
        self.workflows.values().filter(|w| w.is_reusable()).count()
    }
}

pub fn is_file_ref(uses: &str) -> bool {
    uses.starts_with(FILE_REF_PREFIX)
}

pub fn parse_file_ref(uses: &str) -> Result<&str> {
    if !uses.starts_with(FILE_REF_PREFIX) {
        return Err(Error::InvalidFileRef {
            uses: uses.to_string(),
        });
    }
    Ok(&uses[FILE_REF_PREFIX.len()..])
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_is_file_ref() {
        assert!(is_file_ref("@file:setup/user-setup.yaml"));
        assert!(!is_file_ref("user/create"));
        assert!(!is_file_ref("file:something"));
    }

    #[test]
    fn test_parse_file_ref() {
        let path = parse_file_ref("@file:setup/user-setup.yaml").unwrap();
        assert_eq!(path, "setup/user-setup.yaml");
    }

    #[test]
    fn test_parse_file_ref_invalid() {
        let result = parse_file_ref("user/create");
        assert!(result.is_err());
    }
}