From 527bbaf988b73f9d506b252cbeb57f8eafd1b619 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 27 Nov 2024 16:48:12 -0800 Subject: [PATCH 1/2] add add_needs operator on job --- .github/workflows/ci.yml | 3 +- Cargo.lock | 2 +- src/event.rs | 64 ++++++++++++------------ src/generate.rs | 41 ++++++++++++++- src/workflow.rs | 83 ++++++++++++++++++++----------- tests/ci.rs | 2 +- tests/fixtures/workflow-bench.yml | 2 +- tests/fixtures/workflow-ci.yml | 2 +- 8 files changed, 131 insertions(+), 68 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67910a6..9ec6ecf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,8 @@ jobs: - name: Cargo Clippy run: cargo +nightly clippy --all-features --workspace -- -D warnings release: - needs: build + needs: + - build name: Release runs-on: ubuntu-latest permissions: diff --git a/Cargo.lock b/Cargo.lock index 5beb26c..983ae09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,7 +146,7 @@ version = "0.1.0" dependencies = [ "heck", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] diff --git a/src/event.rs b/src/event.rs index 65dcf52..5ce9989 100644 --- a/src/event.rs +++ b/src/event.rs @@ -10,7 +10,7 @@ use crate::is_default; /// Represents all possible webhook events that can trigger a workflow /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows -#[derive(Default, Debug, Clone, Deserialize, Serialize, Merge, Setters)] +#[derive(Default, Debug, Clone, Deserialize, Serialize, Merge, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Event { #[serde(skip_serializing_if = "Option::is_none")] @@ -93,7 +93,7 @@ pub enum BranchProtectionRuleType { } /// Configuration for branch protection rule events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct BranchProtectionRule { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -123,7 +123,7 @@ pub enum CheckRunType { RequestedAction, } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct CheckRun { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -149,7 +149,7 @@ pub enum CheckSuiteType { /// Configuration for check suite events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct CheckSuite { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -166,7 +166,7 @@ impl CheckSuite { /// Configuration for create events (branch or tag creation) /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#create -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Create { /// Filter on specific branch names @@ -193,7 +193,7 @@ impl Create { /// Configuration for delete events (branch or tag deletion) /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#delete -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Delete { /// Filter on specific branch names @@ -221,7 +221,7 @@ impl Delete { /// Types of deployment events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#deployment -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Deployment { /// Filter on specific branch names @@ -240,7 +240,7 @@ impl Deployment { /// Types of deployment status events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#deployment_status -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct DeploymentStatus { /// Filter on specific deployment states @@ -291,7 +291,7 @@ pub enum DiscussionType { /// Configuration for discussion events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] pub struct Discussion { /// Filter on specific discussion event types #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -321,7 +321,7 @@ pub enum DiscussionCommentType { /// Configuration for discussion comment events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] pub struct DiscussionComment { /// Filter on specific discussion comment event types #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -338,7 +338,7 @@ impl DiscussionComment { /// Configuration for issue comment events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] pub struct IssueComment { /// Filter on specific issue comment event types #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -406,7 +406,7 @@ pub enum IssuesType { /// Configuration for issue events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Issues { /// Filter on specific issue event types @@ -437,7 +437,7 @@ pub enum LabelType { /// Configuration for label events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Label { /// Filter on specific label event types @@ -459,7 +459,7 @@ pub enum MergeGroupType { ChecksRequested, } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct MergeGroup { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -483,7 +483,7 @@ pub enum MilestoneType { Deleted, } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Milestone { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -516,7 +516,7 @@ pub enum PullRequestType { ReviewRequestRemoved, } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct PullRequest { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -559,7 +559,7 @@ pub enum PullRequestReviewType { /// Configuration for pull request review events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct PullRequestReview { /// Filter on specific pull request review event types @@ -589,7 +589,7 @@ pub enum PullRequestReviewCommentType { } /// Configuration for pull request review comment events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct PullRequestReviewComment { /// Filter on specific pull request review comment event types @@ -607,7 +607,7 @@ impl PullRequestReviewComment { /// Configuration for pull request target events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct PullRequestTarget { /// Filter on specific pull request event types @@ -634,7 +634,7 @@ impl PullRequestTarget { /// Configuration for push events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Push { /// Filter on specific branch names @@ -672,7 +672,7 @@ pub enum RegistryPackageType { /// Configuration for registry package events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct RegistryPackage { /// Filter on specific registry package event types @@ -711,7 +711,7 @@ pub enum ReleaseType { /// Configuration for release events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Release { /// Filter on specific release event types @@ -727,7 +727,7 @@ impl Release { } } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct RepositoryDispatch { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -741,7 +741,7 @@ impl RepositoryDispatch { } } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Schedule { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -755,7 +755,7 @@ impl Schedule { } } -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct Watch { #[serde(default, skip_serializing_if = "Vec::is_empty")] @@ -771,7 +771,7 @@ impl Watch { /// Configuration for workflow call events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_call -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct WorkflowCall { /// Inputs for the workflow call @@ -786,7 +786,7 @@ pub struct WorkflowCall { } /// Configuration for workflow call input -#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Setters, Eq)] #[setters(strip_option, into)] pub struct WorkflowCallInput { /// Description of the input @@ -804,7 +804,7 @@ pub struct WorkflowCallInput { } /// Configuration for workflow call output -#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Setters, Eq)] #[setters(strip_option, into)] pub struct WorkflowCallOutput { /// Description of the output @@ -816,7 +816,7 @@ pub struct WorkflowCallOutput { } /// Configuration for workflow call secret -#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Setters, Eq)] #[setters(strip_option, into)] pub struct WorkflowCallSecret { /// Description of the secret @@ -830,7 +830,7 @@ pub struct WorkflowCallSecret { /// Configuration for workflow dispatch events /// See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct WorkflowDispatch { /// Inputs for the workflow dispatch @@ -839,7 +839,7 @@ pub struct WorkflowDispatch { } /// Configuration for workflow dispatch input -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct WorkflowDispatchInput { /// Description of the input @@ -870,7 +870,7 @@ pub enum WorkflowRunType { } /// Configuration for workflow run events -#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, Setters, PartialEq, Eq)] #[setters(strip_option, into)] pub struct WorkflowRun { /// Filter on specific workflow run event types diff --git a/src/generate.rs b/src/generate.rs index 4bac5b6..4c775fe 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -3,9 +3,10 @@ use std::path::PathBuf; use std::process::Command; use derive_setters::Setters; +use indexmap::IndexMap; use crate::error::{Error, Result}; -use crate::Workflow; +use crate::{Job, Jobs, Workflow}; #[derive(Setters, Clone)] #[setters(into)] @@ -16,6 +17,7 @@ pub struct Generate { impl Generate { pub fn new(workflow: Workflow) -> Self { + let workflow = organize_job_dependency(workflow); Self { workflow, name: "ci.yml".to_string() } } @@ -78,3 +80,40 @@ impl Generate { } } } + +fn organize_job_dependency(mut workflow: Workflow) -> Workflow { + let mut job_id = 0; + let mut new_jobs = IndexMap::::new(); + + // Iterate over all jobs + for (id, mut job) in workflow.jobs.clone().unwrap_or_default().0.into_iter() { + // If job has dependencies + if let Some(dep_jobs) = &job.tmp_needs { + // Prepare the job_ids + let mut job_ids = Vec::::new(); + for dep_job in dep_jobs.into_iter() { + // If the job is already defined in the workflow + if let Some(id) = workflow.get_id(&dep_job) { + job_ids.push(id.to_string()); + } else { + // Create a job-id for the job + let id = format!("job-{}", job_id); + job_id += 1; + + // Add job id as the dependency + job_ids.push(id.clone()); + + // Insert the missing job into the new_jobs + new_jobs.insert(format!("job-{}", job_id), dep_job.clone()); + } + } + job.needs = Some(job_ids); + } + + new_jobs.insert(id.clone(), job.clone()); + } + + workflow.jobs = Some(Jobs(new_jobs)); + + workflow +} diff --git a/src/workflow.rs b/src/workflow.rs index 939fe34..a2f8db2 100644 --- a/src/workflow.rs +++ b/src/workflow.rs @@ -15,7 +15,7 @@ use crate::{private, Event}; #[derive(Debug, Default, Serialize, Deserialize, Clone)] #[serde(transparent)] -pub struct Jobs(IndexMap); +pub struct Jobs(pub(crate) IndexMap); impl Jobs { pub fn insert(&mut self, key: String, value: Job) { self.0.insert(key, value); @@ -78,7 +78,7 @@ pub struct Workflow { } /// Represents an action that can be triggered by an event in the workflow. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct EventAction { /// A list of branches that trigger the action. @@ -141,10 +141,20 @@ impl Workflow { self.env = Some(env); self } + + /// Performs a reverse lookup to get the ID of a job. + pub fn get_id(&self, job: &Job) -> Option<&str> { + self.jobs + .as_ref()? + .0 + .iter() + .find(|(_, j)| *j == job) + .map(|(id, _)| id.as_str()) + } } /// Represents the type of activity in the workflow. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub enum ActivityType { Created, @@ -153,7 +163,7 @@ pub enum ActivityType { } /// Represents the environment in which a job runs. -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(transparent)] pub struct RunsOn(Value); @@ -168,12 +178,17 @@ where } /// Represents a job in the workflow. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Job { #[serde(skip_serializing_if = "Option::is_none")] - pub needs: Option, + #[setters(skip)] + pub(crate) needs: Option>, + + #[serde(skip)] + pub(crate) tmp_needs: Option>, + #[serde(skip_serializing_if = "Option::is_none", rename = "if")] pub cond: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -240,10 +255,18 @@ impl Job { self.env = Some(env); self } + + pub fn add_needs>(mut self, needs: J) -> Self { + let job: Job = needs.into(); + let mut needs = self.tmp_needs.unwrap_or_default(); + needs.push(job); + self.tmp_needs = Some(needs); + self + } } /// Represents a step in the workflow. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(transparent)] pub struct Step { /// The value of the step. @@ -267,11 +290,11 @@ impl From> for StepValue { } /// Represents a step that uses an action. -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Use; /// Represents a step that runs a command. -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Run; /// A trait to convert `Step` and `Step` to `StepValue`. @@ -298,7 +321,7 @@ impl StepType for Use { } /// Represents environment variables in the workflow. -#[derive(Default, Debug, Serialize, Deserialize, Clone)] +#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(transparent)] pub struct Env(IndexMap); @@ -333,7 +356,7 @@ impl Env { } /// Represents input parameters for a step. -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(transparent)] pub struct Input(#[serde(skip_serializing_if = "IndexMap::is_empty")] IndexMap); @@ -366,7 +389,7 @@ impl Input { /// Represents a step value in the workflow. #[allow(clippy::duplicated_attributes)] -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters( strip_option, @@ -524,7 +547,7 @@ impl From<(S1, S2)> for Env { } /// Represents the runner environment for jobs. -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub enum Runner { #[default] @@ -535,7 +558,7 @@ pub enum Runner { } /// Represents a container configuration for jobs. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Container { @@ -568,7 +591,7 @@ pub struct Container { } /// Represents credentials for accessing a container. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Credentials { @@ -580,7 +603,7 @@ pub struct Credentials { } /// Represents a network port. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub enum Port { /// A port specified by its number. @@ -591,7 +614,7 @@ pub enum Port { } /// Represents a volume configuration for containers. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Volume { @@ -618,7 +641,7 @@ impl Volume { } /// Represents concurrency settings for workflows. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Concurrency { @@ -635,7 +658,7 @@ pub struct Concurrency { } /// Represents permissions for the `GITHUB_TOKEN`. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Permissions { @@ -681,7 +704,7 @@ pub struct Permissions { } /// Represents the level of permissions. -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub enum Level { Read, @@ -691,7 +714,7 @@ pub enum Level { } /// Represents the strategy for running jobs. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Strategy { @@ -709,7 +732,7 @@ pub struct Strategy { } /// Represents an environment for jobs. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Environment { @@ -722,7 +745,7 @@ pub struct Environment { } /// Represents default settings for jobs. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Defaults { @@ -740,7 +763,7 @@ pub struct Defaults { } /// Represents default settings for running commands. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct RunDefaults { @@ -754,7 +777,7 @@ pub struct RunDefaults { } /// Represents default settings for retries. -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct RetryDefaults { /// The maximum number of retry attempts. @@ -763,7 +786,7 @@ pub struct RetryDefaults { } /// Represents an expression used in conditions. -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] pub struct Expression(String); impl Expression { @@ -774,7 +797,7 @@ impl Expression { } /// Represents a secret required for the workflow. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Secret { @@ -787,7 +810,7 @@ pub struct Secret { } /// Represents a strategy for retrying jobs. -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct RetryStrategy { /// The maximum number of retry attempts. @@ -796,7 +819,7 @@ pub struct RetryStrategy { } /// Represents artifacts produced by jobs. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Artifacts { @@ -810,7 +833,7 @@ pub struct Artifacts { } /// Represents an artifact produced by a job. -#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Setters, Serialize, Deserialize, Clone, Default, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[setters(strip_option, into)] pub struct Artifact { diff --git a/tests/ci.rs b/tests/ci.rs index 2a2a0b0..06a3e5b 100644 --- a/tests/ci.rs +++ b/tests/ci.rs @@ -49,7 +49,7 @@ fn generate() { .contents(Level::Write); let release = Job::new("Release") - .needs("build") + .add_needs(build.clone()) .add_env(Env::github()) .add_env(Env::new( "CARGO_REGISTRY_TOKEN", diff --git a/tests/fixtures/workflow-bench.yml b/tests/fixtures/workflow-bench.yml index 80d7357..118723c 100644 --- a/tests/fixtures/workflow-bench.yml +++ b/tests/fixtures/workflow-bench.yml @@ -61,7 +61,7 @@ jobs: path: bench*.txt analyze: - needs: build + needs: [build] runs-on: benchmarking-runner steps: - name: Checkout (GitHub) diff --git a/tests/fixtures/workflow-ci.yml b/tests/fixtures/workflow-ci.yml index 5ba9090..4582503 100644 --- a/tests/fixtures/workflow-ci.yml +++ b/tests/fixtures/workflow-ci.yml @@ -112,7 +112,7 @@ jobs: test: name: Run Tests on ${{ matrix.build }} runs-on: ${{ matrix.os || 'ubuntu-latest' }} - needs: setup_build_matrix + needs: [setup_build_matrix] strategy: fail-fast: false matrix: ${{ fromJson(needs.setup_build_matrix.outputs.matrix) }} From 87bd194c640f5a20d129e7a6fb6890bedb427e97 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 27 Nov 2024 16:53:06 -0800 Subject: [PATCH 2/2] add docs --- src/generate.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/generate.rs b/src/generate.rs index 4c775fe..b604a47 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -81,6 +81,14 @@ impl Generate { } } +/// Organizes job dependencies within a given `Workflow`. +/// +/// This function iterates over all jobs in the provided `Workflow` and ensures that +/// each job's dependencies are correctly set up. If a job has dependencies specified +/// in `tmp_needs`, it checks if those dependencies are already defined in the workflow. +/// If not, it creates new job IDs for the missing dependencies and inserts them into +/// the workflow. The function then updates the `needs` field of each job with the +/// appropriate job IDs. fn organize_job_dependency(mut workflow: Workflow) -> Workflow { let mut job_id = 0; let mut new_jobs = IndexMap::::new();