Skip to content

Commit

Permalink
Keep track of workflows and jobs (#89)
Browse files Browse the repository at this point in the history
FlowCrafter now keeps track of generated workflows and their respective
jobs in its configuration file inside the repository. This is the first
step towards a more "hands off" approach, where FlowCrafter is
configured once using `flowcrafter init` and `flowcrafter create`
commands. This enables us to work on commands like `flowcrafter update`,
which will automatically update all workflows to their latest version.
  • Loading branch information
jdno authored Dec 13, 2023
1 parent b05b9f8 commit 882f544
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 8 deletions.
25 changes: 24 additions & 1 deletion .github/flowcrafter.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# This file is managed by FlowCrafter. Manual changes will be overwritten
# the next time you run FlowCrafter.
---
library:
github:
instance: https://api.github.com/
owner: jdno
repository: workflows
workflows:
- name: github
jobs:
- sync-labels
- name: json
jobs:
- style
- name: markdown
jobs:
- lint
- style
- name: rust
jobs:
- features
- lint
- style
- test
- name: yaml
jobs:
- lint
- style
2 changes: 1 addition & 1 deletion .github/workflows/yaml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
uses: tj-actions/changed-files@v40
with:
files: |
**/*.yml
**/*.yaml
**/*.yml
- name: Print changed files
run: |
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async-trait = "0.1.74"
base64 = "0.21.5"
clap = { version = "4.4.11", optional = true, features = ["derive"] }
octocrab = "0.32.0"
indoc = "2.0.4"
serde = { version = "1.0.193", optional = true, features = ["derive"] }
serde_yaml = { version = "0.9.27", optional = true }
thiserror = "1.0.50"
Expand All @@ -39,7 +40,6 @@ typed-builder = "0.18.0"
url = "2.5.0"

[dev-dependencies]
indoc = "2.0.4"
mockito = "1.2.0"
serde_json = "1.0.108"
tempfile = "3.8.1"
Expand Down
31 changes: 27 additions & 4 deletions src/cli/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::ops::Deref;
use anyhow::{Context, Error};
use async_trait::async_trait;

use crate::cli::configuration::WorkflowConfiguration;
use crate::cli::{Command, Configuration, LibraryConfiguration};
use crate::github::GitHubLibrary;
use crate::local::LocalLibrary;
Expand All @@ -25,6 +26,18 @@ impl<'a> Create<'a> {
}
}

async fn download_fragments(
&self,
configuration: &Configuration,
) -> Result<(Fragment, Vec<Fragment>), Error> {
let library = self.init_library(configuration);

let workflow = self.get_workflow(library.deref()).await?;
let jobs = self.get_jobs(library.deref()).await?;

Ok((workflow, jobs))
}

fn init_library(&self, configuration: &'a Configuration) -> Box<dyn FragmentLibrary<'a>> {
match configuration.library() {
LibraryConfiguration::GitHub(github_configuration) => {
Expand Down Expand Up @@ -77,20 +90,30 @@ impl<'a> Create<'a> {

std::fs::write(path, workflow.to_string()).context("failed to write workflow file")
}

fn update_configuration(&self, configuration: &mut Configuration) -> Result<(), Error> {
let workflow = WorkflowConfiguration::builder()
.name(self.workflow)
.jobs(self.jobs.to_vec())
.build();

configuration.add_workflow(workflow);
configuration.save(self.project)
}
}

#[async_trait]
impl<'a> Command for Create<'a> {
async fn run(&self) -> Result<(), Error> {
let configuration = Configuration::load(self.project)?;
let library = self.init_library(&configuration);
let mut configuration = Configuration::load(self.project)?;

let workflow = self.get_workflow(library.deref()).await?;
let jobs = self.get_jobs(library.deref()).await?;
let (workflow, jobs) = self.download_fragments(&configuration).await?;

let rendered_workflow = self.render_workflow(&workflow, &jobs)?;
self.save_workflow(&rendered_workflow)?;

self.update_configuration(&mut configuration)?;

Ok(())
}
}
Expand Down
27 changes: 26 additions & 1 deletion src/cli/configuration/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::{Display, Formatter};

use anyhow::{Context, Error};
use indoc::indoc;
use serde::{Deserialize, Serialize};
use typed_builder::TypedBuilder;

Expand All @@ -13,6 +14,13 @@ mod library;
mod workflow;

const CONFIG_FILE_NAME: &str = "flowcrafter.yml";
const CONFIG_FILE_HEADER: &str = indoc!(
r#"
# This file is managed by FlowCrafter. Manual changes will be overwritten
# the next time you run FlowCrafter.
---
"#
);

#[derive(
Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize, TypedBuilder,
Expand All @@ -25,6 +33,21 @@ pub struct Configuration {
}

impl Configuration {
pub fn workflows(&self) -> &[WorkflowConfiguration] {
&self.workflows
}

pub fn add_workflow(&mut self, workflow: WorkflowConfiguration) {
for existing_workflow in &mut self.workflows {
if existing_workflow.name() == workflow.name() {
existing_workflow.set_jobs(workflow.jobs().to_vec());
return;
}
}

self.workflows.push(workflow);
}

pub fn save(&self, project: &Project) -> Result<(), Error> {
let github_path = project.path().join(".github");
if !github_path.exists() {
Expand All @@ -36,8 +59,10 @@ impl Configuration {

let serialized =
serde_yaml::to_string(self).context("failed to serialize configuration to YAML")?;
let config_with_header = format!("{}{}", CONFIG_FILE_HEADER, serialized);

std::fs::write(config_path, serialized).context("failed to write configuration to file")?;
std::fs::write(config_path, config_with_header)
.context("failed to write configuration to file")?;

Ok(())
}
Expand Down
4 changes: 4 additions & 0 deletions src/cli/configuration/workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ impl WorkflowConfiguration {
pub fn jobs(&self) -> &[String] {
&self.jobs
}

pub fn set_jobs(&mut self, jobs: Vec<String>) {
self.jobs = jobs;
}
}

#[cfg(test)]
Expand Down

0 comments on commit 882f544

Please sign in to comment.