diff --git a/Cargo.toml b/Cargo.toml index b64c19e6..ea324fbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-make" -version = "0.3.55" +version = "0.3.56" authors = ["Sagie Gur-Ari "] description = "Rust task runner and build tool." license = "Apache-2.0" diff --git a/README.md b/README.md index 4c02c042..b513be44 100644 --- a/README.md +++ b/README.md @@ -452,7 +452,15 @@ Environment variables can also be defined in the command line using the --env/-e cargo make --env ENV1=VALUE1 --env ENV2=VALUE2 -e ENV3=VALUE3 ```` -In addition, cargo-make will also add few environment variables that can be helpful when running task scripts/commands: +Environment variables can also be defined inside tasks, so when a task is invoked (after its dependencies), the environment variables will be set, for example: + +````yaml +[tasks.test-flow] +env = { "SOME_ENV_VAR" = "value" } +run_task = "actual-task" +```` + +In addition, cargo-make will also automatically add few environment variables that can be helpful when running task scripts, commands, conditions, etc: * **CARGO_MAKE** - Set to "true" to help sub processes identify they are running from cargo make. * **CARGO_MAKE_TASK** - Holds the name of the main task being executed. @@ -615,7 +623,7 @@ For faster cargo-make installation as part of the build, you can also pull the b ````yml script: - - wget -O ~/.cargo/bin/cargo-make https://bintray.com/sagiegurari/cargo-make/download_file?file_path=cargo-make_v0.3.55 + - wget -O ~/.cargo/bin/cargo-make https://bintray.com/sagiegurari/cargo-make/download_file?file_path=cargo-make_v0.3.56 - chmod 777 ~/.cargo/bin/cargo-make - cargo-make make ci-flow ```` @@ -623,7 +631,7 @@ script: The specific version of cargo-make requested is defined in the suffix of the cargo-make file name in the form of: cargo-make_v[VERSION], for example ````sh -https://bintray.com/sagiegurari/cargo-make/download_file?file_path=cargo-make_v0.3.55 +https://bintray.com/sagiegurari/cargo-make/download_file?file_path=cargo-make_v0.3.56 ```` In order to pull the latest prebuild cargo-make binary, use the following example: @@ -908,6 +916,8 @@ pub struct Task { pub condition_script: Option>, /// if true, any error while executing the task will be printed but will not break the build pub force: Option, + /// The env vars to setup before running the task commands + pub env: Option>, /// if defined, task points to another task and all other properties are ignored pub alias: Option, /// acts like alias if runtime OS is Linux (takes precedence over alias) @@ -952,6 +962,8 @@ pub struct PlatformOverrideTask { pub condition_script: Option>, /// if true, any error while executing the task will be printed but will not break the build pub force: Option, + /// The env vars to setup before running the task commands + pub env: Option>, /// if defined, the provided crate will be installed (if needed) before running the task pub install_crate: Option, /// if defined, the provided script will be executed before running the task @@ -1073,7 +1085,7 @@ See [contributing guide](.github/CONTRIBUTING.md) | Date | Version | Description | | ----------- | ------- | ----------- | -| 2017-08-15 | v0.3.55 | Update executable name in help/version output | +| 2017-08-18 | v0.3.56 | Set environment variables during task invocation | | 2017-08-09 | v0.3.53 | Added new condition types: env, env_set and env_not_set | | 2017-08-09 | v0.3.51 | Added experimental cli arg to enable access unsupported experimental predefined tasks | | 2017-08-08 | v0.3.49 | Added condition attribute | diff --git a/docs/_config.yml b/docs/_config.yml index 6ba9e6dc..9562854e 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,4 +2,4 @@ theme: jekyll-theme-cayman title: cargo-make description: Rust task runner and build tool. show_downloads: false -version: 0.3.55 \ No newline at end of file +version: 0.3.56 \ No newline at end of file diff --git a/docs/_includes/content.md b/docs/_includes/content.md index 5fae212c..7c0bb216 100644 --- a/docs/_includes/content.md +++ b/docs/_includes/content.md @@ -412,7 +412,15 @@ Environment variables can also be defined in the command line using the --env/-e cargo make --env ENV1=VALUE1 --env ENV2=VALUE2 -e ENV3=VALUE3 ```` -In addition, cargo-make will also add few environment variables that can be helpful when running task scripts/commands: +Environment variables can also be defined inside tasks, so when a task is invoked (after its dependencies), the environment variables will be set, for example: + +````yaml +[tasks.test-flow] +env = { "SOME_ENV_VAR" = "value" } +run_task = "actual-task" +```` + +In addition, cargo-make will also automatically add few environment variables that can be helpful when running task scripts, commands, conditions, etc: * **CARGO_MAKE** - Set to "true" to help sub processes identify they are running from cargo make. * **CARGO_MAKE_TASK** - Holds the name of the main task being executed. @@ -868,6 +876,8 @@ pub struct Task { pub condition_script: Option>, /// if true, any error while executing the task will be printed but will not break the build pub force: Option, + /// The env vars to setup before running the task commands + pub env: Option>, /// if defined, task points to another task and all other properties are ignored pub alias: Option, /// acts like alias if runtime OS is Linux (takes precedence over alias) @@ -912,6 +922,8 @@ pub struct PlatformOverrideTask { pub condition_script: Option>, /// if true, any error while executing the task will be printed but will not break the build pub force: Option, + /// The env vars to setup before running the task commands + pub env: Option>, /// if defined, the provided crate will be installed (if needed) before running the task pub install_crate: Option, /// if defined, the provided script will be executed before running the task @@ -1033,7 +1045,7 @@ See [contributing guide](https://github.com/sagiegurari/cargo-make/blob/master/. | Date | Version | Description | | ----------- | ------- | ----------- | -| 2017-08-15 | v0.3.55 | Update executable name in help/version output | +| 2017-08-18 | v0.3.56 | Set environment variables during task invocation | | 2017-08-09 | v0.3.53 | Added new condition types: env, env_set and env_not_set | | 2017-08-09 | v0.3.51 | Added experimental cli arg to enable access unsupported experimental predefined tasks | | 2017-08-08 | v0.3.49 | Added condition attribute | diff --git a/docs/api/cargo_make/types/index.html b/docs/api/cargo_make/types/index.html index d58df062..4404ed14 100644 --- a/docs/api/cargo_make/types/index.html +++ b/docs/api/cargo_make/types/index.html @@ -48,7 +48,7 @@

Module cargo_make< [] - [src]

+ [src]

types

Defines the various types and aliases used by cargo-make.

diff --git a/docs/api/cargo_make/types/struct.Config.html b/docs/api/cargo_make/types/struct.Config.html index 4267526b..cdffe466 100644 --- a/docs/api/cargo_make/types/struct.Config.html +++ b/docs/api/cargo_make/types/struct.Config.html @@ -48,7 +48,7 @@

Struct cargo_make< [] - [src]

+ [src]
pub struct Config {
     pub config: ConfigSection,
     pub env: HashMap<String, String>,
@@ -66,10 +66,10 @@ 

Struct cargo_make< HashMap<String, Task>

All task definitions

-

Trait Implementations

impl Debug for Config
[src]

+

Trait Implementations

impl Debug for Config
[src]

Formats the value using the given formatter.

-

impl Clone for Config
[src]

+

impl Clone for Config
[src]

Returns a copy of the value. Read more

diff --git a/docs/api/cargo_make/types/struct.ConfigSection.html b/docs/api/cargo_make/types/struct.ConfigSection.html index 11c3ab76..afcedbb0 100644 --- a/docs/api/cargo_make/types/struct.ConfigSection.html +++ b/docs/api/cargo_make/types/struct.ConfigSection.html @@ -48,7 +48,7 @@

Struct cargo_make< [] - [src]

+ [src]
pub struct ConfigSection {
     pub init_task: Option<String>,
     pub end_task: Option<String>,
@@ -61,7 +61,7 @@ 

Struct cargo_make< Option<String>

End task name which will be invoked at the end of every run

-

Methods

impl ConfigSection
[src]

+

Methods

impl ConfigSection
[src]

Creates and returns a new instance.

@@ -71,10 +71,10 @@

Arguments

  • task - The task to copy from
  • -

    Trait Implementations

    impl Debug for ConfigSection
    [src]

    +

    Trait Implementations

    impl Debug for ConfigSection
    [src]

    Formats the value using the given formatter.

    -

    impl Clone for ConfigSection
    [src]

    +

    impl Clone for ConfigSection
    [src]

    Returns a copy of the value. Read more

    diff --git a/docs/api/cargo_make/types/struct.ExecutionPlan.html b/docs/api/cargo_make/types/struct.ExecutionPlan.html index bdabd9ae..5290f533 100644 --- a/docs/api/cargo_make/types/struct.ExecutionPlan.html +++ b/docs/api/cargo_make/types/struct.ExecutionPlan.html @@ -48,7 +48,7 @@

    Struct cargo_make< [] - [src]

    + [src]
    pub struct ExecutionPlan {
         pub steps: Vec<Step>,
     }

    Execution plan which defines all steps to run and the order to run them

    @@ -56,7 +56,7 @@

    Struct cargo_make< Vec<Step>

    A list of steps to execute

    -

    Trait Implementations

    impl Debug for ExecutionPlan
    [src]

    +

    Trait Implementations

    impl Debug for ExecutionPlan
    [src]

    Formats the value using the given formatter.

    diff --git a/docs/api/cargo_make/types/struct.ExternalConfig.html b/docs/api/cargo_make/types/struct.ExternalConfig.html index 9af927d1..521dd7e7 100644 --- a/docs/api/cargo_make/types/struct.ExternalConfig.html +++ b/docs/api/cargo_make/types/struct.ExternalConfig.html @@ -48,7 +48,7 @@

    Struct cargo_make< [] - [src]

    + [src]
    pub struct ExternalConfig {
         pub extend: Option<String>,
         pub config: Option<ConfigSection>,
    @@ -71,10 +71,10 @@ 

    Struct cargo_make< Option<HashMap<String, Task>>

    All task definitions

    -

    Methods

    impl ExternalConfig
    [src]

    +

    Methods

    impl ExternalConfig
    [src]

    Creates and returns a new instance.

    -

    Trait Implementations

    impl Debug for ExternalConfig
    [src]

    +

    Trait Implementations

    impl Debug for ExternalConfig
    [src]

    Formats the value using the given formatter.

    diff --git a/docs/api/cargo_make/types/struct.PlatformOverrideTask.html b/docs/api/cargo_make/types/struct.PlatformOverrideTask.html index 1627f4e3..5ef8cb83 100644 --- a/docs/api/cargo_make/types/struct.PlatformOverrideTask.html +++ b/docs/api/cargo_make/types/struct.PlatformOverrideTask.html @@ -48,13 +48,14 @@

    Struct cargo_make< [] - [src]

    + [src]
    pub struct PlatformOverrideTask {
         pub clear: Option<bool>,
         pub disabled: Option<bool>,
         pub condition: Option<TaskCondition>,
         pub condition_script: Option<Vec<String>>,
         pub force: Option<bool>,
    +    pub env: Option<HashMap<String, String>>,
         pub install_crate: Option<String>,
         pub install_script: Option<Vec<String>>,
         pub command: Option<String>,
    @@ -84,6 +85,10 @@ 

    Struct cargo_make< Option<bool>

    if true, any error while executing the task will be printed but will not break the build

    +
    +

    The env vars to setup before running the task commands

    pub struct Step {
         pub name: String,
         pub config: Task,
    @@ -61,7 +61,7 @@ 

    Struct cargo_make< Task

    The task config

    -

    Trait Implementations

    impl Debug for Step
    [src]

    +

    Trait Implementations

    impl Debug for Step
    [src]

    Formats the value using the given formatter.

    diff --git a/docs/api/cargo_make/types/struct.Task.html b/docs/api/cargo_make/types/struct.Task.html index d4e0f232..c40eeeaa 100644 --- a/docs/api/cargo_make/types/struct.Task.html +++ b/docs/api/cargo_make/types/struct.Task.html @@ -48,13 +48,14 @@

    Struct cargo_make< [] - [src]

    + [src]
    pub struct Task {
         pub description: Option<String>,
         pub disabled: Option<bool>,
         pub condition: Option<TaskCondition>,
         pub condition_script: Option<Vec<String>>,
         pub force: Option<bool>,
    +    pub env: Option<HashMap<String, String>>,
         pub alias: Option<String>,
         pub linux_alias: Option<String>,
         pub windows_alias: Option<String>,
    @@ -91,6 +92,10 @@ 

    Struct cargo_make< Option<bool>

    if true, any error while executing the task will be printed but will not break the build

    +
    +

    The env vars to setup before running the task commands

     //! # env
     //!
    @@ -258,23 +269,34 @@
     mod mod_test;
     
     use log::Logger;
    +use std::collections::HashMap;
     use std::env;
     use std::path::PathBuf;
     use types::{Config, CrateInfo, EnvInfo, GitInfo, PackageInfo, RustChannel, RustInfo, Workspace};
     
    -/// Updates the env for the current execution based on the descriptor.
    -fn set_env(
    +/// Updates the env based on the provided data
    +pub fn set_env(
         logger: &Logger,
    -    config: &Config,
    +    env: HashMap<String, String>,
     ) {
         logger.info::<()>("Setting Up Env.", &[], None);
     
    -    for (key, value) in &config.env {
    +    for (key, value) in &env {
             logger.verbose::<()>("Setting env: ", &[&key, "=", &value], None);
             env::set_var(&key, &value);
         }
     }
     
    +/// Updates the env for the current execution based on the descriptor.
    +fn initialize_env(
    +    logger: &Logger,
    +    config: &Config,
    +) {
    +    logger.info::<()>("Setting Up Env.", &[], None);
    +
    +    set_env(&logger, config.env.clone());
    +}
    +
     fn setup_env_for_crate(logger: &Logger) -> CrateInfo {
         let crate_info = CrateInfo::load(&logger);
         let crate_info_clone = crate_info.clone();
    @@ -396,7 +418,7 @@
         config: &Config,
         task: &str,
     ) -> EnvInfo {
    -    set_env(logger, config);
    +    initialize_env(logger, config);
     
         env::set_var("CARGO_MAKE", "true");
         env::set_var("CARGO_MAKE_TASK", &task);
    diff --git a/docs/api/src/cargo_make/runner.rs.html b/docs/api/src/cargo_make/runner.rs.html
    index 20b80e9c..a3210e90 100644
    --- a/docs/api/src/cargo_make/runner.rs.html
    +++ b/docs/api/src/cargo_make/runner.rs.html
    @@ -321,6 +321,14 @@
     276
     277
     278
    +279
    +280
    +281
    +282
    +283
    +284
    +285
    +286
     
     //! # runner
     //!
    @@ -338,8 +346,10 @@
     
     use command;
     use condition;
    +use environment;
     use installer;
     use log::Logger;
    +use std::collections::HashMap;
     use std::collections::HashSet;
     use std::time::SystemTime;
     use types::{Config, CrateInfo, EnvInfo, ExecutionPlan, FlowInfo, Step, Task};
    @@ -371,6 +381,12 @@
         logger.info::<()>("Running Task: ", &[&step.name], None);
     
         if validate_condition(&logger, &flow_info, &step) {
    +        let env = match step.config.env {
    +            Some(ref env) => env.clone(),
    +            None => HashMap::new(),
    +        };
    +        environment::set_env(&logger, env);
    +
             installer::install(&logger, &step.config);
     
             match step.config.run_task {
    diff --git a/docs/api/src/cargo_make/types.rs.html b/docs/api/src/cargo_make/types.rs.html
    index 285a6b64..a143b988 100644
    --- a/docs/api/src/cargo_make/types.rs.html
    +++ b/docs/api/src/cargo_make/types.rs.html
    @@ -736,6 +736,20 @@
     691
     692
     693
    +694
    +695
    +696
    +697
    +698
    +699
    +700
    +701
    +702
    +703
    +704
    +705
    +706
    +707
     
     //! # types
     //!
    @@ -1013,6 +1027,8 @@
         pub condition_script: Option<Vec<String>>,
         /// if true, any error while executing the task will be printed but will not break the build
         pub force: Option<bool>,
    +    /// The env vars to setup before running the task commands
    +    pub env: Option<HashMap<String, String>>,
         /// if defined, task points to another task and all other properties are ignored
         pub alias: Option<String>,
         /// acts like alias if runtime OS is Linux (takes precedence over alias)
    @@ -1054,6 +1070,7 @@
                 condition: None,
                 condition_script: None,
                 force: None,
    +            env: None,
                 alias: None,
                 linux_alias: None,
                 windows_alias: None,
    @@ -1101,6 +1118,10 @@
                 self.force = task.force.clone();
             }
     
    +        if task.env.is_some() {
    +            self.env = task.env.clone();
    +        }
    +
             if task.alias.is_some() {
                 self.alias = task.alias.clone();
             }
    @@ -1200,6 +1221,7 @@
                         condition: override_task.condition.clone(),
                         condition_script: override_task.condition_script.clone(),
                         force: override_task.force.clone(),
    +                    env: override_task.env.clone(),
                         alias: None,
                         linux_alias: None,
                         windows_alias: None,
    @@ -1265,6 +1287,8 @@
         pub condition_script: Option<Vec<String>>,
         /// if true, any error while executing the task will be printed but will not break the build
         pub force: Option<bool>,
    +    /// The env vars to setup before running the task commands
    +    pub env: Option<HashMap<String, String>>,
         /// if defined, the provided crate will be installed (if needed) before running the task
         pub install_crate: Option<String>,
         /// if defined, the provided script will be executed before running the task
    @@ -1315,6 +1339,10 @@
                     self.force = task.force.clone();
                 }
     
    +            if self.env.is_none() && task.env.is_some() {
    +                self.env = task.env.clone();
    +            }
    +
                 if self.install_crate.is_none() && task.install_crate.is_some() {
                     self.install_crate = task.install_crate.clone();
                 }
    diff --git a/examples/env.toml b/examples/env.toml
    new file mode 100644
    index 00000000..cc79549b
    --- /dev/null
    +++ b/examples/env.toml
    @@ -0,0 +1,14 @@
    +
    +[tasks.echo]
    +script = [
    +    "echo var: ${SKIP_TASK}",
    +    "echo hello"
    +]
    +
    +[tasks.wrapper]
    +condition = { env_not_set = [ "SKIP_TASK" ] }
    +run_task = "echo"
    +
    +[tasks.test-flow]
    +env = { "SKIP_TASK" = "true" }
    +run_task = "wrapper"
    diff --git a/src/Makefile.stable.toml b/src/Makefile.stable.toml
    index b4824503..022fe7b8 100644
    --- a/src/Makefile.stable.toml
    +++ b/src/Makefile.stable.toml
    @@ -48,12 +48,23 @@ dependencies = [
         "post-test"
     ]
     
    -[tasks.publish-flow]
    -description = "Publish flow - First clean the target directory of any old leftovers, package and publish"
    +[tasks.pre-publish-clean-flow]
    +description = "Clears old artifactes before publishing"
     dependencies = [
         "pre-clean",
         "clean",
    -    "post-clean",
    +    "post-clean"
    +]
    +
    +[tasks.pre-publish-conditioned-clean-flow]
    +description = "Clears old artifactes before publishing"
    +condition = { env_not_set = [ "CARGO_MAKE_SKIP_PREPUBLISH_CLEAN" ] }
    +run_task = "pre-publish-clean-flow"
    +
    +[tasks.publish-flow]
    +description = "Publish flow - First clean the target directory of any old leftovers, package and publish"
    +dependencies = [
    +    "pre-publish-conditioned-clean-flow",
         "pre-publish",
         "publish",
         "post-publish"
    @@ -487,6 +498,7 @@ script = [
     [tasks.build-publish-flow]
     description = "Runs full sanity, generates github release and publishes the crate."
     condition = { env_set = [ "COMMIT_MSG", "GITHUB_API_TOKEN", "GITHUB_REPO_NAME" ] }
    +env = { "CARGO_MAKE_SKIP_PREPUBLISH_CLEAN" = "true" }
     run_task = "build-publish-flow-no-validation"
     
     [tasks.build-publish-flow-no-validation]
    diff --git a/src/environment/mod.rs b/src/environment/mod.rs
    index cea247c2..e26d5c20 100644
    --- a/src/environment/mod.rs
    +++ b/src/environment/mod.rs
    @@ -11,23 +11,34 @@ mod rustinfo;
     mod mod_test;
     
     use log::Logger;
    +use std::collections::HashMap;
     use std::env;
     use std::path::PathBuf;
     use types::{Config, CrateInfo, EnvInfo, GitInfo, PackageInfo, RustChannel, RustInfo, Workspace};
     
    -/// Updates the env for the current execution based on the descriptor.
    -fn set_env(
    +/// Updates the env based on the provided data
    +pub fn set_env(
         logger: &Logger,
    -    config: &Config,
    +    env: HashMap,
     ) {
         logger.info::<()>("Setting Up Env.", &[], None);
     
    -    for (key, value) in &config.env {
    +    for (key, value) in &env {
             logger.verbose::<()>("Setting env: ", &[&key, "=", &value], None);
             env::set_var(&key, &value);
         }
     }
     
    +/// Updates the env for the current execution based on the descriptor.
    +fn initialize_env(
    +    logger: &Logger,
    +    config: &Config,
    +) {
    +    logger.info::<()>("Setting Up Env.", &[], None);
    +
    +    set_env(&logger, config.env.clone());
    +}
    +
     fn setup_env_for_crate(logger: &Logger) -> CrateInfo {
         let crate_info = CrateInfo::load(&logger);
         let crate_info_clone = crate_info.clone();
    @@ -149,7 +160,7 @@ pub fn setup_env(
         config: &Config,
         task: &str,
     ) -> EnvInfo {
    -    set_env(logger, config);
    +    initialize_env(logger, config);
     
         env::set_var("CARGO_MAKE", "true");
         env::set_var("CARGO_MAKE_TASK", &task);
    diff --git a/src/runner.rs b/src/runner.rs
    index ac742cd1..b476aab9 100644
    --- a/src/runner.rs
    +++ b/src/runner.rs
    @@ -14,8 +14,10 @@ mod runner_test;
     
     use command;
     use condition;
    +use environment;
     use installer;
     use log::Logger;
    +use std::collections::HashMap;
     use std::collections::HashSet;
     use std::time::SystemTime;
     use types::{Config, CrateInfo, EnvInfo, ExecutionPlan, FlowInfo, Step, Task};
    @@ -47,6 +49,12 @@ fn run_task(
         logger.info::<()>("Running Task: ", &[&step.name], None);
     
         if validate_condition(&logger, &flow_info, &step) {
    +        let env = match step.config.env {
    +            Some(ref env) => env.clone(),
    +            None => HashMap::new(),
    +        };
    +        environment::set_env(&logger, env);
    +
             installer::install(&logger, &step.config);
     
             match step.config.run_task {
    diff --git a/src/runner_test.rs b/src/runner_test.rs
    index 8c22ca1c..2d870d85 100644
    --- a/src/runner_test.rs
    +++ b/src/runner_test.rs
    @@ -122,6 +122,7 @@ fn create_execution_plan_platform_disabled() {
             install_crate: None,
             command: None,
             force: None,
    +        env: None,
             install_script: None,
             args: None,
             script: None,
    @@ -137,6 +138,7 @@ fn create_execution_plan_platform_disabled() {
             install_crate: None,
             command: None,
             force: None,
    +        env: None,
             install_script: None,
             args: None,
             script: None,
    @@ -152,6 +154,7 @@ fn create_execution_plan_platform_disabled() {
             install_crate: None,
             command: None,
             force: None,
    +        env: None,
             install_script: None,
             args: None,
             script: None,
    @@ -371,3 +374,31 @@ fn run_task_valid_run_task_bad_command() {
     
         run_task(&logger, &flow_info, &step);
     }
    +
    +#[test]
    +fn run_task_set_env() {
    +    let logger = log::create("error");
    +
    +    let config = Config { config: ConfigSection::new(), env: HashMap::new(), tasks: HashMap::new() };
    +    let flow_info = FlowInfo {
    +        config,
    +        task: "test".to_string(),
    +        env_info: EnvInfo { rust_info: RustInfo::new(), crate_info: CrateInfo::new(), git_info: GitInfo::new() },
    +        disable_workspace: false
    +    };
    +
    +    let mut env = HashMap::new();
    +    env.insert("TEST_RUN_TASK_SET_ENV".to_string(), "VALID".to_string());
    +
    +    let mut task = Task::new();
    +    task.script = Some(vec!["exit 0".to_string()]);
    +    task.env = Some(env);
    +
    +    let step = Step { name: "test".to_string(), config: task };
    +
    +    env::set_var("TEST_RUN_TASK_SET_ENV", "EMPTY");
    +
    +    run_task(&logger, &flow_info, &step);
    +
    +    assert_eq!(env::var("TEST_RUN_TASK_SET_ENV").unwrap(), "VALID");
    +}
    diff --git a/src/types.rs b/src/types.rs
    index 940954ca..beb95e8c 100644
    --- a/src/types.rs
    +++ b/src/types.rs
    @@ -274,6 +274,8 @@ pub struct Task {
         pub condition_script: Option>,
         /// if true, any error while executing the task will be printed but will not break the build
         pub force: Option,
    +    /// The env vars to setup before running the task commands
    +    pub env: Option>,
         /// if defined, task points to another task and all other properties are ignored
         pub alias: Option,
         /// acts like alias if runtime OS is Linux (takes precedence over alias)
    @@ -315,6 +317,7 @@ impl Task {
                 condition: None,
                 condition_script: None,
                 force: None,
    +            env: None,
                 alias: None,
                 linux_alias: None,
                 windows_alias: None,
    @@ -362,6 +365,10 @@ impl Task {
                 self.force = task.force.clone();
             }
     
    +        if task.env.is_some() {
    +            self.env = task.env.clone();
    +        }
    +
             if task.alias.is_some() {
                 self.alias = task.alias.clone();
             }
    @@ -461,6 +468,7 @@ impl Task {
                         condition: override_task.condition.clone(),
                         condition_script: override_task.condition_script.clone(),
                         force: override_task.force.clone(),
    +                    env: override_task.env.clone(),
                         alias: None,
                         linux_alias: None,
                         windows_alias: None,
    @@ -526,6 +534,8 @@ pub struct PlatformOverrideTask {
         pub condition_script: Option>,
         /// if true, any error while executing the task will be printed but will not break the build
         pub force: Option,
    +    /// The env vars to setup before running the task commands
    +    pub env: Option>,
         /// if defined, the provided crate will be installed (if needed) before running the task
         pub install_crate: Option,
         /// if defined, the provided script will be executed before running the task
    @@ -576,6 +586,10 @@ impl PlatformOverrideTask {
                     self.force = task.force.clone();
                 }
     
    +            if self.env.is_none() && task.env.is_some() {
    +                self.env = task.env.clone();
    +            }
    +
                 if self.install_crate.is_none() && task.install_crate.is_some() {
                     self.install_crate = task.install_crate.clone();
                 }
    diff --git a/src/types_test.rs b/src/types_test.rs
    index 0a1c71c8..b1e3a935 100644
    --- a/src/types_test.rs
    +++ b/src/types_test.rs
    @@ -27,6 +27,7 @@ fn task_new() {
         assert!(task.condition_script.is_none());
         assert!(task.description.is_none());
         assert!(task.force.is_none());
    +    assert!(task.env.is_none());
         assert!(task.alias.is_none());
         assert!(task.linux_alias.is_none());
         assert!(task.windows_alias.is_none());
    @@ -88,6 +89,7 @@ fn task_extend_both_have_misc_data() {
             condition: None,
             condition_script: None,
             force: Some(true),
    +        env: Some(HashMap::new()),
             alias: Some("alias2".to_string()),
             linux_alias: None,
             windows_alias: None,
    @@ -112,6 +114,7 @@ fn task_extend_both_have_misc_data() {
         assert!(base.condition.is_none());
         assert!(base.condition_script.is_none());
         assert!(base.force.is_some());
    +    assert!(base.env.is_some());
         assert!(base.alias.is_some());
         assert!(base.linux_alias.is_none());
         assert!(base.windows_alias.is_none());
    @@ -130,6 +133,7 @@ fn task_extend_both_have_misc_data() {
         assert_eq!(base.command.unwrap(), "test1");
         assert!(base.disabled.unwrap());
         assert!(base.force.unwrap());
    +    assert_eq!(base.env.unwrap().len(), 0);
         assert_eq!(base.alias.unwrap(), "alias2");
         assert_eq!(base.script.unwrap().len(), 2);
     }
    @@ -144,6 +148,7 @@ fn task_extend_extended_have_all_fields() {
             condition: None,
             condition_script: None,
             force: Some(true),
    +        env: Some(HashMap::new()),
             alias: None,
             linux_alias: None,
             windows_alias: None,
    @@ -158,6 +163,9 @@ fn task_extend_extended_have_all_fields() {
             windows: None,
             mac: None
         };
    +
    +    let mut env = HashMap::new();
    +    env.insert("test".to_string(), "value".to_string());
         let extended = Task {
             install_crate: Some("my crate2".to_string()),
             command: Some("test2".to_string()),
    @@ -172,6 +180,7 @@ fn task_extend_extended_have_all_fields() {
             }),
             condition_script: Some(vec!["exit 0".to_string()]),
             force: Some(false),
    +        env: Some(env.clone()),
             alias: Some("alias2".to_string()),
             linux_alias: Some("linux".to_string()),
             windows_alias: Some("windows".to_string()),
    @@ -196,6 +205,7 @@ fn task_extend_extended_have_all_fields() {
                 }),
                 condition_script: Some(vec!["exit 0".to_string()]),
                 force: Some(true),
    +            env: Some(env.clone()),
                 install_script: Some(vec!["i1".to_string(), "i2".to_string()]),
                 args: Some(vec!["a1".to_string(), "a2".to_string()]),
                 script: Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]),
    @@ -217,6 +227,7 @@ fn task_extend_extended_have_all_fields() {
                 }),
                 condition_script: Some(vec!["exit 0".to_string()]),
                 force: Some(true),
    +            env: Some(env.clone()),
                 install_script: Some(vec!["i1".to_string(), "i2".to_string()]),
                 args: Some(vec!["a1".to_string(), "a2".to_string()]),
                 script: Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]),
    @@ -238,6 +249,7 @@ fn task_extend_extended_have_all_fields() {
                 }),
                 condition_script: Some(vec!["exit 0".to_string()]),
                 force: Some(true),
    +            env: Some(env.clone()),
                 install_script: Some(vec!["i1".to_string(), "i2".to_string()]),
                 args: Some(vec!["a1".to_string(), "a2".to_string()]),
                 script: Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]),
    @@ -256,6 +268,7 @@ fn task_extend_extended_have_all_fields() {
         assert!(base.condition.is_some());
         assert!(base.condition_script.is_some());
         assert!(base.force.is_some());
    +    assert!(base.env.is_some());
         assert!(base.alias.is_some());
         assert!(base.linux_alias.is_some());
         assert!(base.windows_alias.is_some());
    @@ -276,6 +289,7 @@ fn task_extend_extended_have_all_fields() {
         assert!(base.disabled.unwrap());
         assert_eq!(base.condition_script.unwrap().len(), 1);
         assert!(!base.force.unwrap());
    +    assert_eq!(base.env.unwrap().len(), 1);
         assert_eq!(base.alias.unwrap(), "alias2");
         assert_eq!(base.linux_alias.unwrap(), "linux");
         assert_eq!(base.windows_alias.unwrap(), "windows");
    @@ -343,6 +357,7 @@ fn task_get_normalized_task_undefined() {
             condition: None,
             condition_script: None,
             force: None,
    +        env: None,
             install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
             args: Some(vec!["1".to_string(), "2".to_string()]),
             script: Some(vec!["a".to_string(), "b".to_string()]),
    @@ -363,6 +378,7 @@ fn task_get_normalized_task_undefined() {
         assert!(normalized_task.condition.is_none());
         assert!(normalized_task.condition_script.is_none());
         assert!(normalized_task.force.is_none());
    +    assert!(normalized_task.env.is_none());
         assert!(normalized_task.alias.is_some());
         assert!(normalized_task.linux_alias.is_some());
         assert!(normalized_task.windows_alias.is_some());
    @@ -398,6 +414,9 @@ fn task_get_normalized_task_undefined() {
     #[test]
     #[cfg(target_os = "linux")]
     fn task_get_normalized_task_with_override_no_clear() {
    +    let mut env = HashMap::new();
    +    env.insert("test".to_string(), "value".to_string());
    +
         let mut task = Task {
             alias: Some("bad".to_string()),
             linux_alias: Some("bad".to_string()),
    @@ -416,6 +435,7 @@ fn task_get_normalized_task_with_override_no_clear() {
             }),
             condition_script: Some(vec!["exit 0".to_string()]),
             force: Some(false),
    +        env: Some(HashMap::new()),
             install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
             args: Some(vec!["1".to_string(), "2".to_string()]),
             script: Some(vec!["a".to_string(), "b".to_string()]),
    @@ -436,6 +456,7 @@ fn task_get_normalized_task_with_override_no_clear() {
                 }),
                 condition_script: Some(vec!["exit 0".to_string()]),
                 force: Some(true),
    +            env: Some(env),
                 install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string(), "D".to_string()]),
                 args: Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]),
                 script: Some(vec!["a".to_string(), "b".to_string(), "c".to_string()]),
    @@ -456,6 +477,7 @@ fn task_get_normalized_task_with_override_no_clear() {
         assert!(normalized_task.condition.is_some());
         assert!(normalized_task.condition_script.is_some());
         assert!(normalized_task.force.is_some());
    +    assert!(normalized_task.env.is_some());
         assert!(normalized_task.alias.is_none());
         assert!(normalized_task.linux_alias.is_none());
         assert!(normalized_task.windows_alias.is_none());
    @@ -476,6 +498,7 @@ fn task_get_normalized_task_with_override_no_clear() {
         assert!(normalized_task.disabled.unwrap());
         assert_eq!(normalized_task.condition_script.unwrap().len(), 1);
         assert!(normalized_task.force.unwrap());
    +    assert_eq!(normalized_task.env.unwrap().len(), 1);
         assert_eq!(normalized_task.install_script.unwrap().len(), 4);
         assert_eq!(normalized_task.args.unwrap().len(), 3);
         assert_eq!(normalized_task.script.unwrap().len(), 3);
    @@ -491,6 +514,9 @@ fn task_get_normalized_task_with_override_no_clear() {
     #[test]
     #[cfg(target_os = "linux")]
     fn task_get_normalized_task_with_override_clear_false() {
    +    let mut env = HashMap::new();
    +    env.insert("test".to_string(), "value".to_string());
    +
         let mut task = Task {
             alias: Some("bad".to_string()),
             linux_alias: Some("bad".to_string()),
    @@ -509,6 +535,7 @@ fn task_get_normalized_task_with_override_clear_false() {
             }),
             condition_script: Some(vec!["exit 0".to_string()]),
             force: Some(false),
    +        env: Some(HashMap::new()),
             install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
             args: Some(vec!["1".to_string(), "2".to_string()]),
             script: Some(vec!["a".to_string(), "b".to_string()]),
    @@ -529,6 +556,7 @@ fn task_get_normalized_task_with_override_clear_false() {
                 }),
                 condition_script: Some(vec!["echo test".to_string(), "exit 1".to_string()]),
                 force: Some(true),
    +            env: Some(env),
                 install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string(), "D".to_string()]),
                 args: Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]),
                 script: Some(vec!["a".to_string(), "b".to_string(), "c".to_string()]),
    @@ -549,6 +577,7 @@ fn task_get_normalized_task_with_override_clear_false() {
         assert!(normalized_task.condition.is_some());
         assert!(normalized_task.condition_script.is_some());
         assert!(normalized_task.force.is_some());
    +    assert!(normalized_task.env.is_some());
         assert!(normalized_task.alias.is_none());
         assert!(normalized_task.linux_alias.is_none());
         assert!(normalized_task.windows_alias.is_none());
    @@ -569,6 +598,7 @@ fn task_get_normalized_task_with_override_clear_false() {
         assert!(normalized_task.disabled.unwrap());
         assert_eq!(normalized_task.condition_script.unwrap().len(), 2);
         assert!(normalized_task.force.unwrap());
    +    assert_eq!(normalized_task.env.unwrap().len(), 1);
         assert_eq!(normalized_task.install_script.unwrap().len(), 4);
         assert_eq!(normalized_task.args.unwrap().len(), 3);
         assert_eq!(normalized_task.script.unwrap().len(), 3);
    @@ -601,6 +631,7 @@ fn task_get_normalized_task_with_override_clear_false_partial_override() {
             }),
             condition_script: Some(vec!["exit 0".to_string()]),
             force: Some(false),
    +        env: Some(HashMap::new()),
             install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
             args: Some(vec!["1".to_string(), "2".to_string()]),
             script: Some(vec!["a".to_string(), "b".to_string()]),
    @@ -616,6 +647,7 @@ fn task_get_normalized_task_with_override_clear_false_partial_override() {
                 condition: None,
                 condition_script: None,
                 force: None,
    +            env: None,
                 install_script: None,
                 args: None,
                 script: None,
    @@ -635,6 +667,7 @@ fn task_get_normalized_task_with_override_clear_false_partial_override() {
         assert!(normalized_task.condition.is_some());
         assert!(normalized_task.condition_script.is_some());
         assert!(normalized_task.force.is_some());
    +    assert!(normalized_task.env.is_some());
         assert!(normalized_task.alias.is_none());
         assert!(normalized_task.linux_alias.is_none());
         assert!(normalized_task.windows_alias.is_none());
    @@ -654,6 +687,7 @@ fn task_get_normalized_task_with_override_clear_false_partial_override() {
         assert_eq!(normalized_task.command.unwrap(), "command");
         assert!(!normalized_task.disabled.unwrap());
         assert!(!normalized_task.force.unwrap());
    +    assert_eq!(normalized_task.env.unwrap().len(), 0);
         assert_eq!(normalized_task.install_script.unwrap().len(), 3);
         assert_eq!(normalized_task.args.unwrap().len(), 2);
         assert_eq!(normalized_task.script.unwrap().len(), 2);
    @@ -682,6 +716,7 @@ fn task_get_normalized_task_with_override_clear_true() {
             }),
             condition_script: Some(vec!["exit 0".to_string()]),
             force: Some(false),
    +        env: Some(HashMap::new()),
             install_script: Some(vec!["A".to_string(), "B".to_string(), "C".to_string()]),
             args: Some(vec!["1".to_string(), "2".to_string()]),
             script: Some(vec!["a".to_string(), "b".to_string()]),
    @@ -697,6 +732,7 @@ fn task_get_normalized_task_with_override_clear_true() {
                 condition: None,
                 condition_script: None,
                 force: None,
    +            env: None,
                 install_script: None,
                 args: None,
                 script: None,
    @@ -716,6 +752,7 @@ fn task_get_normalized_task_with_override_clear_true() {
         assert!(normalized_task.condition.is_none());
         assert!(normalized_task.condition_script.is_none());
         assert!(normalized_task.force.is_none());
    +    assert!(normalized_task.env.is_none());
         assert!(normalized_task.alias.is_none());
         assert!(normalized_task.linux_alias.is_none());
         assert!(normalized_task.windows_alias.is_none());