zixcel-github 0.1.1

Policy-neutral GitHub API wrapper boundary for Zixcel
Documentation
use crate::boundary::{bounded_text, digest, reference};
use crate::{ConnectorError, GitHubAction, GitHubRemoteExpectation};

impl GitHubAction {
    pub(crate) fn validate(&self) -> Result<(), ConnectorError> {
        use GitHubAction::*;
        match self {
            ObserveRepositoryMetadata => Ok(()),
            ListIssues { maximum_items }
            | ListPullRequests { maximum_items }
            | ListReleases { maximum_items }
            | ListWorkflowRuns { maximum_items } => validate_maximum(*maximum_items),
            ListWorkflowArtifacts {
                workflow_run_id,
                maximum_items,
            } => {
                bounded_text("workflow_run_id", workflow_run_id, 128)?;
                validate_maximum(*maximum_items)
            }
            DownloadWorkflowArtifact {
                workflow_run_id,
                artifact_id,
                expected_digest_sha256,
            } => {
                bounded_text("workflow_run_id", workflow_run_id, 128)?;
                bounded_text("artifact_id", artifact_id, 128)?;
                if let Some(value) = expected_digest_sha256 {
                    digest("expected_digest_sha256", value)?;
                }
                Ok(())
            }
            CreatePrivateRepository { default_branch } => {
                if !crate::artifacts::git_branch(default_branch) {
                    return Err(ConnectorError::new("default_branch", "invalid Git branch"));
                }
                Ok(())
            }
            PushRepositorySnapshot {
                snapshot_ref,
                snapshot_digest_sha256,
                expected_remote,
            } => {
                reference("snapshot_ref", snapshot_ref)?;
                digest("snapshot_digest_sha256", snapshot_digest_sha256)?;
                if let GitHubRemoteExpectation::Exact { commit_sha256 } = expected_remote {
                    digest("commit_sha256", commit_sha256)?;
                }
                Ok(())
            }
            DeleteRepository {
                expected_repository_id,
                backup_digest_sha256,
            } => {
                if expected_repository_id.is_empty()
                    || expected_repository_id.len() > 20
                    || !expected_repository_id.bytes().all(|v| v.is_ascii_digit())
                    || expected_repository_id.starts_with('0')
                {
                    return Err(ConnectorError::new(
                        "expected_repository_id",
                        "expected a positive repository ID",
                    ));
                }
                digest("backup_digest_sha256", backup_digest_sha256)
            }
            CreateIssue {
                title,
                body_artifact_ref,
            } => validate_body(title, body_artifact_ref),
            CreatePullRequest {
                base,
                head,
                title,
                body_artifact_ref,
            } => {
                bounded_text("base", base, 128)?;
                bounded_text("head", head, 128)?;
                validate_body(title, body_artifact_ref)
            }
            DispatchWorkflow {
                workflow_ref,
                git_ref,
                inputs_artifact_ref,
            } => {
                bounded_text("workflow_ref", workflow_ref, 256)?;
                bounded_text("git_ref", git_ref, 256)?;
                if let Some(value) = inputs_artifact_ref {
                    reference("inputs_artifact_ref", value)?;
                }
                Ok(())
            }
        }
    }
}

fn validate_maximum(value: u16) -> Result<(), ConnectorError> {
    if (1..=256).contains(&value) {
        Ok(())
    } else {
        Err(ConnectorError::new("maximum_items", "must be in 1..=256"))
    }
}

fn validate_body(title: &str, body: &str) -> Result<(), ConnectorError> {
    bounded_text("title", title, 256)?;
    reference("body_artifact_ref", body)
}