Skip to content

Commit

Permalink
Add migration logic
Browse files Browse the repository at this point in the history
  • Loading branch information
paudrow committed Feb 22, 2024
1 parent 7158a43 commit 549fd4c
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 65 deletions.
5 changes: 4 additions & 1 deletion src/common/src/types/requirement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ impl Requirement {
name: "name".to_string(),
description: "description".to_string(),
steps: vec![Step {
name: Some("step name".to_string()),
description: Some("step description".to_string()),
action: vec![
Action::Describe("action".to_string()),
Action::StdIn(Terminal {
Expand Down Expand Up @@ -61,6 +63,8 @@ pub struct Link {

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Step {
pub name: Option<String>,
pub description: Option<String>,
pub action: Vec<Action>,
pub expect: Vec<Expect>,
}
Expand All @@ -75,7 +79,6 @@ pub enum Action {

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Expect {
StdIn(Terminal),
StdOut(Terminal),
StdErr(Terminal),
Image(String),
Expand Down
289 changes: 243 additions & 46 deletions src/migrate_v1_requirements/src/migrate_v1_to_v2.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::requirements_file_v1::{RequirementV1, RequirementsFileV1};
use crate::requirements_file_v1::{CheckV1, RequirementV1, RequirementsFileV1, StepV1};
use anyhow::{Context, Result};
use common::types::{
Action as ActionV2, Expect as ExpectV2, Requirement as RequirementV2,
Expand Down Expand Up @@ -34,55 +34,12 @@ mod tests {
}
}

// TODO: Fix this so that it takes in all of the different cases.
fn convert_v1_to_v2(req_v1: &RequirementV1) -> Result<RequirementV2> {
let steps = req_v1
.checks
.iter()
.map(|check| {
let actions = check
.r#try
.as_ref()
.unwrap_or(&vec![])
.iter()
.filter_map(|try_item| {
try_item.stdin.as_ref().map(|stdin| {
ActionV2::StdIn(TerminalV2 {
number: try_item.terminal.unwrap_or(1), // Default to terminal 1 if not specified
text: stdin.clone(),
})
})
})
.collect();

let expects = check
.expect
.as_ref()
.unwrap_or(&vec![])
.iter()
.map(|expect_item| {
if let Some(stdout) = &expect_item.stdout {
ExpectV2::StdOut(TerminalV2 {
number: expect_item.terminal.unwrap_or(1), // Default to terminal 1 if not specified
text: stdout.clone(),
})
} else if let Some(stdin) = &expect_item.stdin {
ExpectV2::StdIn(TerminalV2 {
number: expect_item.terminal.unwrap_or(1), // Default to terminal 1 if not specified
text: stdin.clone(),
})
} else {
ExpectV2::Describe(expect_item.note.clone().unwrap_or_default())
}
})
.collect();

StepV2 {
action: actions,
expect: expects,
}
})
.collect();
.map(check_v1_to_step_v2)
.collect::<Result<Vec<StepV2>>>()?;

Ok(RequirementV2 {
name: req_v1.name.clone(),
Expand All @@ -92,3 +49,243 @@ fn convert_v1_to_v2(req_v1: &RequirementV1) -> Result<RequirementV2> {
links: req_v1.links.clone(),
})
}

fn check_v1_to_step_v2(check: &CheckV1) -> Result<StepV2> {
let actions = check
.r#try
.as_ref()
.unwrap_or(&vec![])
.iter()
.map(try_v1_to_actions_v2)
.collect::<Result<Vec<Vec<ActionV2>>>>()?
.into_iter()
.flatten()
.collect();

let expects = check
.expect
.as_ref()
.unwrap_or(&vec![])
.iter()
.map(expect_v1_to_expects_v2)
.collect::<Result<Vec<Vec<ExpectV2>>>>()?
.into_iter()
.flatten()
.collect();

Ok(StepV2 {
name: Some(check.name.clone()),
description: check.description.clone(),
action: actions,
expect: expects,
})
}

fn try_v1_to_actions_v2(try_v1: &StepV1) -> Result<Vec<ActionV2>> {
let mut actions = vec![];
if let Some(note) = &try_v1.note {
actions.push(ActionV2::Describe(note.clone()));
}
if let Some(stdin) = &try_v1.stdin {
actions.push(ActionV2::StdIn(TerminalV2 {
number: try_v1.terminal.unwrap_or(1), // Default to terminal 1 if not specified
text: stdin.clone(),
}));
}
if let Some(image_url) = &try_v1.imageUrl {
actions.push(ActionV2::Image(image_url.clone()));
}
if let Some(stdout) = &try_v1.stdout {
actions.push(ActionV2::Describe(format!("Stdout: {:?}", stdout.clone())));
}
if let Some(stderr) = &try_v1.stderr {
actions.push(ActionV2::Describe(format!("Stderr: {:?}", stderr.clone())));
}
if actions.is_empty() {
anyhow::bail!("There should be at least one action")
}
Ok(actions)
}

#[cfg(test)]
mod test_try_v1_to_actions_v2 {
use super::try_v1_to_actions_v2;
use crate::requirements_file_v1::StepV1;
use common::types::{Action as ActionV2, Terminal as TerminalV2};

#[test]
fn test_try_v1_to_actions_v2() {
let try_v1 = StepV1 {
stdin: Some("echo hello".to_string()),
note: Some("This is a note".to_string()),
terminal: Some(2),
imageUrl: Some("http://example.com".to_string()),
stderr: None,
stdout: None,
};
let actions = try_v1_to_actions_v2(&try_v1).expect("Converts to actions");

assert_eq!(actions.len(), 3);
for action in actions {
match action {
ActionV2::StdIn(TerminalV2 { number, text }) => {
assert_eq!(number, 2);
assert_eq!(text, "echo hello");
}
ActionV2::Describe(note) => {
assert_eq!(note, "This is a note");
}
ActionV2::Image(image_url) => {
assert_eq!(image_url, "http://example.com");
}
ActionV2::Url(_) => panic!("No corresponding v1 field"),
}
}
}

#[test]
fn stdout_and_stderr_convert_to_describe() {
let try_v1 = StepV1 {
stdin: None,
note: None,
terminal: None,
imageUrl: None,
stderr: Some("error".to_string()),
stdout: Some("hello".to_string()),
};
let actions = try_v1_to_actions_v2(&try_v1).expect("Converts to actions");

assert_eq!(actions.len(), 2);
for action in actions {
match action {
ActionV2::Describe(note) => {
assert!(note.contains("hello") || note.contains("error"));
}
_ => panic!("No corresponding v1 field"),
}
}
}

#[test]
fn fail_if_no_actions() {
let try_v1 = StepV1 {
stdin: None,
note: None,
terminal: None,
imageUrl: None,
stderr: None,
stdout: None,
};
let result = try_v1_to_actions_v2(&try_v1);
assert!(result.is_err());
}
}

fn expect_v1_to_expects_v2(expect_v1: &StepV1) -> Result<Vec<ExpectV2>> {
let mut expects = vec![];

if let Some(note) = &expect_v1.note {
expects.push(ExpectV2::Describe(note.clone()));
}
if let Some(stdout) = &expect_v1.stdout {
expects.push(ExpectV2::StdOut(TerminalV2 {
number: expect_v1.terminal.unwrap_or(1), // Default to terminal 1 if not specified
text: stdout.clone(),
}));
}
if let Some(stderr) = &expect_v1.stderr {
expects.push(ExpectV2::StdErr(TerminalV2 {
number: expect_v1.terminal.unwrap_or(1), // Default to terminal 1 if not specified
text: stderr.clone(),
}));
}
if let Some(image_url) = &expect_v1.imageUrl {
expects.push(ExpectV2::Image(image_url.clone()));
}
if let Some(stdin) = &expect_v1.stdin {
expects.push(ExpectV2::Describe(format!("Stdin: {:?}", stdin.clone())));
}
if expects.is_empty() {
anyhow::bail!("There should be at least one expect")
}
Ok(expects)
}

#[cfg(test)]
mod test_expect_v1_to_expects_v2 {

use super::expect_v1_to_expects_v2;
use crate::requirements_file_v1::StepV1;
use common::types::{Expect as ExpectV2, Terminal as TerminalV2};

#[test]
fn test_expect_v1_to_expects_v2() {
let expect_v1 = StepV1 {
note: Some("This is a note".to_string()),
imageUrl: Some("http://example.com".to_string()),
stdin: None,
stdout: Some("hello".to_string()),
stderr: Some("".to_string()),
terminal: Some(2),
};
let expects = expect_v1_to_expects_v2(&expect_v1).expect("Converts to expects");

assert_eq!(expects.len(), 4);
for expect in expects {
match expect {
ExpectV2::StdOut(TerminalV2 { number, text }) => {
assert_eq!(number, 2);
assert_eq!(text, "hello");
}
ExpectV2::Describe(note) => {
assert_eq!(note, "This is a note");
}
ExpectV2::Image(url) => {
assert_eq!(url, "http://example.com");
}
ExpectV2::StdErr(TerminalV2 { number, text }) => {
assert_eq!(number, 2);
assert_eq!(text, "");
}
ExpectV2::Url(_) => panic!("No corresponding v1 field"),
}
}
}

#[test]
fn stdin_convert_to_describe() {
let expect_v1 = StepV1 {
note: None,
imageUrl: None,
stdin: Some("echo hello".to_string()),
stdout: None,
stderr: None,
terminal: None,
};
let expects = expect_v1_to_expects_v2(&expect_v1).expect("Converts to expects");

assert_eq!(expects.len(), 1);
for expect in expects {
match expect {
ExpectV2::Describe(note) => {
assert!(note.contains("hello"));
}
_ => panic!("No corresponding v1 field"),
}
}
}

#[test]
fn fail_if_no_expects() {
let expect_v1 = StepV1 {
stdout: None,
stdin: None,
note: None,
terminal: None,
imageUrl: None,
stderr: None,
};
let result = expect_v1_to_expects_v2(&expect_v1);
assert!(result.is_err());
}
}
21 changes: 8 additions & 13 deletions src/migrate_v1_requirements/src/requirements_file_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,24 @@ pub struct CheckV1 {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub r#try: Option<Vec<TryV1>>,
pub r#try: Option<Vec<StepV1>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expect: Option<Vec<ExpectV1>>,
pub expect: Option<Vec<StepV1>>,
}

#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize)]
pub struct TryV1 {
#[serde(skip_serializing_if = "Option::is_none")]
pub stdin: Option<String>,
pub struct StepV1 {
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub terminal: Option<u8>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExpectV1 {
#[serde(skip_serializing_if = "Option::is_none")]
pub stdout: Option<String>,
pub imageUrl: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stdin: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
pub stdout: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stderr: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub terminal: Option<u8>,
}
5 changes: 0 additions & 5 deletions src/yatm_v2/templates/github_issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@
{% endif %}
{% for expect in step.expect -%}
{%- match expect -%}
{% when Expect::StdIn with (terminal) %}
```bash
# StdIn - terminal {{ terminal.number }}
{{ terminal.text }}
```
{% when Expect::StdOut with (terminal) %}
```bash
# StdOut - terminal {{ terminal.number }}
Expand Down

0 comments on commit 549fd4c

Please sign in to comment.