use crate::{
actions::{Action, ActionSteps},
constants::COODEV_CONTAINER_IMAGE,
error,
user_config::{UserActionStep, UserCommandStep, UserStep},
};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
pub struct GitCheckoutOptions {
pub repository: Option<String>,
#[serde(rename = "ref")]
pub ref_name: Option<String>,
#[serde(rename = "github-server-url")]
pub github_server_url: Option<String>,
pub path: Option<String>,
pub depth: Option<String>,
}
#[derive(Debug, Clone)]
pub struct GitCheckoutAction;
impl GitCheckoutAction {
pub fn new() -> Self {
Self {}
}
}
impl Action for GitCheckoutAction {
fn normalize(&self, step: UserActionStep) -> crate::Result<ActionSteps> {
let with = step.with.clone();
let git_checkout_options = match with {
Some(with) => serde_yaml::from_value::<GitCheckoutOptions>(with).map_err(|_| {
error::Error::workflow_config_error(
"Optional `with` options for `git/checkout` action is not valid.",
)
})?,
None => GitCheckoutOptions::default(),
};
let github_server_url = git_checkout_options
.github_server_url
.clone()
.unwrap_or("".to_string());
let ref_name = git_checkout_options
.ref_name
.clone()
.unwrap_or("".to_string());
let repository = git_checkout_options
.repository
.clone()
.unwrap_or("".to_string());
let path = git_checkout_options.path.clone().unwrap_or(".".to_string());
let depth = git_checkout_options.depth.clone().unwrap_or("".to_string());
let prepare = format!(
"
set -e
echo \"$(git --version)\"
# User arguments
github_server_url={github_server_url}
ref={ref_name}
repository={repository}
path={path}
depth={depth}
"
);
let run = r#"
# Format arguments
default_server_url="https://oauth2:${COODEV_ACCESS_TOKEN}@github.com"
github_server_url=${github_server_url:-$default_server_url}
repository=${repository:-$COODEV_REPOSITORY}
ref=${ref:-$COODEV_REF}
# config default branch
git config --global init.defaultBranch $COODEV_DEFAULT_BRANCH
# colorize output of git commands
git config --global color.ui always
echo "Checking out $ref from $repository..."
# Create path if not exists
if [ ! -d $path ]; then
mkdir -p $path
fi
cd $path
git init .
git remote add origin $github_server_url/$repository.git
git fetch \
$([ -n "$depth" ] && echo "--depth $depth" || echo "") \
origin $ref
git switch -c $ref FETCH_HEAD
echo "Checkout done. Current commit:"
git log -1
"#;
let name = step.name.clone().unwrap_or("git/checkout".to_string());
let continue_on_error = step.continue_on_error.unwrap_or(true);
let timeout = step.timeout.unwrap_or("10m".to_string());
Ok(ActionSteps {
pre: None,
run: UserStep::Command(UserCommandStep {
image: Some(COODEV_CONTAINER_IMAGE.to_string()),
name: Some(name),
run: format!("{}{}", prepare, run),
continue_on_error: Some(continue_on_error),
environments: None,
secrets: None,
volumes: None,
security_opts: None,
timeout: Some(timeout),
}),
post: None,
})
}
}
#[cfg(test)]
mod tests {
use crate::{
utils::test::{create_runner, run_workflow},
CreateWorkflowOptions, WorkflowAPIEvent, WorkflowEvent, WorkflowRunOptions,
};
#[tokio::test]
#[ignore]
async fn test_git_checkout_action() -> anyhow::Result<()> {
let yaml = r#"
jobs:
test-job:
name: Test clone repository
steps:
- name: Checkout
uses: git/checkout
with:
repository: panghu-huang/octocrate
ref: refs/heads/main
"#;
let _res = run_workflow(yaml).await?;
Ok(())
}
#[tokio::test]
#[ignore]
async fn test_checkout_private_repo() -> anyhow::Result<()> {
let runner = create_runner()?;
let yaml = r#"
jobs:
test-job:
name: Test clone repository
steps:
- name: Checkout
uses: git/checkout
"#;
let workflow_runner = runner.create_workflow_runner(CreateWorkflowOptions {
config: yaml.to_string(),
event: WorkflowEvent::API(WorkflowAPIEvent {
repo_owner: "coodevjs".to_string(),
repo_name: "coodev-runner".to_string(),
ref_name: "main".to_string(),
sha: "4c03973fa72b114984c9b6eb14a3b4fb415f3877".to_string(),
pr_number: None,
}),
})?;
let _res = workflow_runner
.run(WorkflowRunOptions {
run_id: "runner".to_string(),
environments: None,
})
.await?;
Ok(())
}
}