Repository: Orange-OpenSource/hurl
File: packages/hurl/src/main.rs (Rust)

Code before:
        if errors.is_empty() {
        } else if errors.iter().filter(|(error, _)| !error.assert).count() == 0 {
            count_errors_assert += 1;
        } else {
            count_errors_runner += 1;
        }
    }
    if count_errors_runner > 0 {
        EXIT_ERROR_RUNTIME
    } else if count_errors_assert > 0 {
        EXIT_ERROR_ASSERT
    } else {
        EXIT_OK
    }
}

/// Export cookies for this run to `filename` file.
///
/// The file format for the cookies is [Netscape cookie format](http://www.cookiecentral.com/faq/#3.5).
fn create_cookies_file(
    runs: &[HurlRun],
    filename: &Path,
    secrets: &[&str],
) -> Result<(), CliError> {
    // We ensure that parent folder is created.
    if let Some(parent) = filename.parent() {
        match std::fs::create_dir_all(parent) {
            Ok(_) => {}
            Err(err) => {
                return Err(CliError::IO(format!(
                    "Issue writing to {}: {err:?}",
                    filename.display()
                )));
            }
        }
    }
    let mut file = match std::fs::File::create(filename) {
        Err(why) => {
            return Err(CliError::IO(format!(
                "Issue writing to {}: {why:?}",
                filename.display()
            )));
        }
        Ok(file) => file,
    };
    let mut s = r#"# Netscape HTTP Cookie File
# This file was generated by Hurl

"#
    .to_string();


Review comment (security):
As we have some similar code now, it's a good time to regroup the common code, as the issue suggested it.

We can try to mutualize this code: for instance, we can add in `hurl/util/path.rs` this new function

```rust
/// TODO: explain the aim of the func
pub fn create_dir_all(filename: &Path) -> Result<(), io::Error> {
    if let Some(parent) = filename.parent() {
        return std::fs::create_dir_all(parent);
    }
    Ok(())
}
```

And use it in `report/junit/mod.rs`:

```rust
pub fn write_report(
    filename: &Path,
    testcases: &[Testcase],
    secrets: &[&str],
) -> Result<(), ReportError> {
    if let Err(err) = path::create_dir_all(filename) {
        return Err(ReportError::from_error(
            err,
            filename,
            "Issue writing Junit report",
        ))
    }
```

There are other instances where you can use this function to like with `--cookie-jar` for instance



Code after:
        if errors.is_empty() {
        } else if errors.iter().filter(|(error, _)| !error.assert).count() == 0 {
            count_errors_assert += 1;
        } else {
            count_errors_runner += 1;
        }
    }
    if count_errors_runner > 0 {
        EXIT_ERROR_RUNTIME
    } else if count_errors_assert > 0 {
        EXIT_ERROR_ASSERT
    } else {
        EXIT_OK
    }
}

/// Export cookies for this run to `filename` file.
///
/// The file format for the cookies is [Netscape cookie format](http://www.cookiecentral.com/faq/#3.5).
fn create_cookies_file(
    runs: &[HurlRun],
    filename: &Path,
    secrets: &[&str],
) -> Result<(), CliError> {
    if let Err(err) = hurl::util::path::create_dir_all(filename) {
        return Err(CliError::IO(format!(
            "Issue creating parent directories for {}: {err:?}",
            filename.display()
        )));
    }

    let mut file = match std::fs::File::create(filename) {
        Err(why) => {
            return Err(CliError::IO(format!(
                "Issue writing to {}: {why:?}",
                filename.display()
            )));
        }
        Ok(file) => file,
    };
    let mut s = r#"# Netscape HTTP Cookie File
# This file was generated by Hurl

"#
    .to_string();

    // TODO: We only serialize the first file. I don't see any valid reason why we're not
    // serializing every file see issue <https://github.com/Orange-OpenSource/hurl/issues/2537>
    match runs.first() {
        None => {
            return Err(CliError::IO("Issue fetching results".to_string()));