GithubHelp home page GithubHelp logo

nightroman / invoke-build Goto Github PK

View Code? Open in Web Editor NEW
617.0 30.0 61.0 1.67 MB

Build Automation in PowerShell

Home Page: https://github.com/nightroman/Invoke-Build/wiki

License: Apache License 2.0

PowerShell 98.54% Batchfile 0.15% Shell 0.11% C# 1.04% Dockerfile 0.16%
powershell build automation build-automation engine

invoke-build's People

Contributors

bforsythe avatar dbroeglin avatar mark-raymond avatar mrhockeymonkey avatar mwallner avatar nightroman avatar nreilingh avatar outlivier avatar schittli avatar sheldonhull avatar szeraax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

invoke-build's Issues

TODO Persistent build: create a checkpoint before running tasks

Currently, a persistent build writes a checkpoint after each completed task. As a result, if the first task fails then a checkpoint is not created and the build cannot be resumed, it should be invoked again. Although it makes some sense (nothing was done yet), a user has to choose an action (repeat vs. resume) depending on a failed task. Ideally, a persistent build should be able to resume on a failure of any task. The idea is to write a checkpoint before running tasks in addition to the current writing after completed tasks.

Incremental tasks should show some information on triggering

Currently, if an incremental task is skipped then it writes a message

Skipping up-to-date output.

Similarly, if an incremental task is triggered due to out of date of missing
outputs then it should write some information about those outputs.

A simple incremental task should tell, for example

Output X is missing or out-of-date.

A partial incremental task should tell, for example

N outputs of M inputs are missing or out-of-date.

Such messages may help on troubleshooting, e.g. see the case mentioned in #48.

For incremental builds, should -Outputs allow empty lists?

Hey Roman, I'm trying to use incremental builds for the PowerShell Editor Services build script and ran across this error:

Build FAILED. 3 tasks, 1 errors, 0 warnings 00:00:00.9779218
C:\Users\daviwil\Documents\WindowsPowerShell\Modules\InvokeBuild\3.2.1\Invoke-Build.ps1 : Outputs must not be empty.
At line:1 char:1
+ Invoke-Build BuildHost
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Outputs must not be empty.:String) [Invoke-Build.ps1], RuntimeExcepti
   on
    + FullyQualifiedErrorId : Outputs must not be empty.,Invoke-Build.ps1

Since I'm using Get-ChildItem in my Outputs list to get the list of potential outputs, that list will be empty if those output files haven't yet been created. Is it possible that this error could be removed, or is there some other way around it?

Thanks!

Support mstest

The use 4.0 msbuild syntax is very nice.

It might be useful to support mstest similarly.

TODO Use event blocks instead of event functions

The build engine supports the following events:

  • Enter-Build, Exit-Build
  • Enter-BuildTask, Exit-BuildTask
  • Enter-BuildJob, Exit-BuildJob
  • Export-Build, Import-Build

Events are currently defined in scripts as functions with special names, e.g.

    function Enter-Build {...}
    function Exit-Build {...}

This notation should be replaced with event blocks with the same names, i.e.

    Enter-Build {...}
    Exit-Build {...}

The new notation is less error prone. A misspelled event block name causes an
error, this is good. A misspelled event function name is not an error, the
function is simply ignored, this is bad.

The new notation with special blocks is less confusing. Functions in a build
script are supposed to be defined for its tasks and invoked by tasks. Events
are defined for the engine and called by the engine. So it is better if they
are defined using a different notation.

The new notation happens to be shorter. This is not the main point, indeed.

The change is going to be backward compatible at this moment.
Eventually, we will retire the old notation function EventName {}.

Invoke build `-if` parameter scriptblock evaluation

Consider the following build script

# c:\tmp\test-invokebuild.build.ps1
task Build1 -Before "Build2" { $script:a = "a" }
task Build2 -if {$script:a} { }
C:\tmp
PS> Invoke-Build build2
Build build2 C:\tmp\test-invokebuild.build.ps1
Task /Build2 skipped.
Build succeeded. 0 tasks, 0 errors, 0 warnings 00:00:00.0300201

C:\tmp
PS> Invoke-Build build1,build2
Build build1, build2 C:\tmp\test-invokebuild.build.
Task /Build1
Done /Build1 00:00:00.0130020
Done /Build2/Build1
Task /Build2
Done /Build2 00:00:00.0160129
Build succeeded. 2 tasks, 0 errors, 0 warnings 00:00:00.0620040

Looks like the conditional in task Build2 is evaluated before invoking task Build1 even though Build2 depends on Build1. Is this by design?

I think the conditional in Build2 should be evaluated after the invocation of Build1. Consider the following scenario:

task buildA -before  BuildB,BuildC { $script:invokeBuildB = Test-Something }
task buildB -if {$script:invokeBuildB} -Before BuildD { ... }
task buildC  -if {!$script:invokeBuildB} -Before BuildD { ... }
task BuildD { ... }

I want the build script to take either path A -> B -> D or path A -> C -> D depending on what happens in A. I can add an if statement in B and C to achieve this but having the invokebuild engine do that for me would be nice.

Package is not marked as a development dependency

When installing Invoke-Build into a .NET project using NuGet 3.1, it places the package entry into the project level packages.config file (because solution level packages are no longer supported). This causes NuGet to think that this is a runtime dependency of the package being built with Invoke-Build. This can be fixed by adding <developmentDependency>true</developmentDependency> to the nuspec file.

Additionally, when I tried to do this myself I was unable to build a new package dues to missing files (Markdown.tasks.ps1, Helps.ps1 etc.). Please fix this so that others can also build a new package, or update the readme to explain how to build the package.

Invoke-Build says success but the Appveyor build fails

Recently switched to using Invoke-Build from psake.
Used the ConvertFrom-Psake.ps1 to convert the build script to be used with Invoke-Build.

The invoke-build says that the build succeeded and an exception is thrown which marks the overall build in appveyor as failed.
image

See the Appveryor build failing here and the branch here.
I tried to repro this on a Server2016 VM running WMF5.1 to see where the exception is being thrown but it does not throw it on the VM.

image

Running out of ideas on how to debug this. Is there something, which I am missing here ?

Error "the type name 'IB' already exists" when running back-to-back builds

Hello! I've got several projects that use Invoke-Build and I'd like to run them back-to-back from my own Powershell script. However, when I attempt to do so I get the error:

Cannot add type. The type name 'IB' already exists.

My script looks basically like this:

cd 'C:\BuildA'
& .\Invoke-Build.ps1
cd 'C:\BuildB'
& .\Invoke-Build.ps1

I'm a bit of a Powershell neophyte so the solution is probably quite obvious. What would you recommend to avoid this error?

Greg

Get-Help Invoke-Build -Full doesn't work

I've installed IB from PSGallery and am trying to view the xml-based help with Get-Help Invoke-Build -Full. I am on PS 5.1.

I installed IB with powershellget, so the module is in \Program Files\WindowsPowerShell\Modules. In a fresh console, Get-Help *build* returns about_InvokeBuild, and doing Import-Module InvokeBuild first returns two additional rows for the Invoke-Build[s] aliases.

screen shot 2016-12-17 at 6 27 51 pm

Get-Help Invoke-Build -Full just returns those two alias rows, instead of what's described in README.md. Dot-sourcing Invoke-Build does then add help for the helper functions, but doesn't change the behavior for Invoke-Build.

Based on Naming Help Files, it seems that XML-based help may only be possible for actual functions.

Async tasks or jobs concept

This is a topic for discussing and collecting ideas for specs. If there is not much it may be just closed.

Async tasks or jobs seem to be useful and doable in Invoke-Build. Parallel builds are already is use with Invoke-Builds.ps1 which allows parallel invocation of several build scripts or the same script with different tasks. This approach requires some ceremonies with parameters and an extra script.

A single build script is typical for the majority of projects. In this case, async tasks or jobs would be much easier to program if they are built-in. This is doable but there are several possible ways. There must be some neat syntax and concepts.

Improve result information for easier test failure analyses

v2.10.3 introduced "safe tests" (Invoke-Build ** -Safe). It is now possible
to have multiple test failures. How to analyse test failures, e.g. in order to
produce a report?

The answer is to invoke tests like

Invoke-Build ** -Safe -Result Result

and analyse $Result.Errors after.

But this is not perfect because errors are raw PowerShell errors with no clear
links to tasks (PowerShell does not know them) and even files because errors
may be in external scripts called from tasks.

It is possible to iterate through $Result.Tasks and check for Error. If it
is not null then the task has failed and the task information is available. The
problem is that errors may be out of tasks, e.g. in -If blocks or in build
script top code before tasks. Such errors will not be found in $Result.Tasks.

The documentation says about the result property Errors:

This list will continue to exist but objects may change in the
future. For better analysis iterate through Tasks and check Error.

The future is coming and it is time to think of improving $Result.Errors.
It's more likely that raw error objects will be replaced with objects

[PSCustomObject]@{
    Error = an error object as it is now
    File = a build script, i.e. the test collection
    Task = a task object or null for out of task errors
}

As a result, it will be enough to iterate through $Result.Errors in order to
report all errors with additional information related to scripts and tasks.

This change is potentially incompatible. Code that used to analyse these
objects may fail. But the documentation warned that objects may change.
This issue is a reminder.

It is possible to enhance existing errors by adding two more note properties,
say, BuildFile and BuildTask, PowerShell allows such tricks. This change
would be compatible but the information less discoverable and difficult to
display.

This change investigation is still in progress but so far the first way with
custom error objects looks better.

Thoughts, suggestions, ideas are welcome.

Show-BuildGraph.ps1 - avoid fixed temp file names

See #44

Issue: Generating multiple graphs with default settings will cause PDFs to be generated and opened in your default PDF reader. However, the previous behavior is for the previous PDF files to be overwritten with the new one. Depending on your PDF viewer, this might be visible as multiple windows all open to the same file, that you had expected to be different.

PS Module

Can we get psd1 and psm1 files generated for this project so it is detected as an actual PSModule?

Error when running within Azure deployment

I'm trying to use Invoke-Build during an Azure deployment, however I get the following error:

D:\home\site\repository\Invoke-Build.2.14.2\tools\Invoke-Build.ps1 : Exception setting "ForegroundColor": "The Win32 internal error "The handle is invalid"

I'm assuming that because it's not a regular environment you can't set the ForegroundColor.

Parallel builds scope

Given the script script.ps1

$script:Foo = "This is foo"

and the build script build.ps1

Task Foo {
	$Foo
}

using Invoke-Build I have access to the script scope variable

PS C:\temp> .  .\script.ps1

PS C:\temp> Invoke-Build -File .\build.ps1 -Task Foo
Build Foo C:\temp\build.ps1
Task /Foo
This is foo
Done /Foo 00:00:00.0080051
Build succeeded. 1 tasks, 0 errors, 0 warnings 00:00:00.1170883

while I cannot using Invoke-Builds

PS C:\temp> .  .\script.ps1

PS C:\temp> Invoke-Builds @(@{File=".\build.ps1"; Task='Foo'})
(1/1) C:\temp\build.ps1
Build (1/1) C:\temp\build.ps1:
Build Foo C:\temp\build.ps1
Task /Foo
Done /Foo 00:00:00.0030020
Build succeeded. 1 tasks, 0 errors, 0 warnings 00:00:00.0140088
Build (1/1) C:\temp\build.ps1 succeeded.
Tasks: 1 tasks, 0 errors, 0 warnings
Builds succeeded. 1 builds, 0 failed 00:00:00.1901150

I wonder if the behavior is by design and if there's a way to achieve so.
Consider that for simplicity I have used a variable in my example but my real use case involves script scope functions. I have a script which orchestrate the invocation of builds with common initialization.

EXIT in ib.cmd should use /B

All EXIT commands from ib.cmd wrapper should use /B option to avoid quitting the current CMD.EXE.

Problem:

  1. Open a cmd.exe session in a folder containing Invoke-Build and ib.cmd.

  2. Run ib /?

The current console will close.

Solution:

Replace exit with exit /B 0 in :list and :help sections.

Environment:

Microsoft Windows [Version 10.0.14393]
PSVersion 5.1.14393.693

Task dependency syntax clarity

I've picked up Invoke-Build after considering psake, Cake etc
I like that it supports incremental building which is a key feature of a build orchestration engine. I also like that it isn't a module so it won't pollute my PowerShell runspace or bleed variables back into the caller.

However, I have a minor gripe with the task dependency syntax. Currently I have to define a task and dependencies like so

task Foo Bar, { }

This is very nice and concise, but awkward at the same time. The trailing , to create an array is a bit unfortunate.

Would it be possible at add an optional parameter to specify dependencies like psake has with -depends? I feel this will help other maintainers of my scripts grok them more effectively without the somewhat magical syntax confusing them.

Colored output of IB invoked in background jobs

I am not sure why and how it works but colored output turns out to be possible from PS background jobs. Thus, it should be enabled if it does not introduce issues. To be investigated and enabled if all is fine.

ib.cmd small issue

in ib.cmd it should be '%~dp0Invoke-Build.ps1' not '%~dp0\Invoke-Build.ps1'

%~dp0 already adds trailing slash as part of the path. Adding your own creates a double slash. Windows, in general, correctly ignores the extra slash, so no big deal.

Invoke-Builds.ps1 - type is not found

Invoke-Builds.ps1 works only if it is called from a build script or after dot-sourcing the engine. Otherwise, it fails because an internal type defined by the engine is not found.

The culprit is 308bd3dfe5794583b77d4f538ce33d80412ba7d3.

The bug was not caught by tests because they are build scripts.

TODO: Fix the bug and cover by tests that call Invoke-Builds.ps1 directly by PowerShell.exe.

Incorrect sequence of tasks in the summary

IB version: 2.14.6
After executing the build script with task parameter "-After", summary has incorrect order.

Example

# run.ps1

try {
    # Invoke the build and keep results in the variable Result
    Invoke-Build .  -Result Result
}
finally {
    # Show task summary information after the build
    $Result.Tasks | Format-Table Elapsed, Name, Error -AutoSize
}
# test.build.ps1

task Clean {
    Write-Host "Clean"
}
task Build {
    Write-Host "Build"
}

task Build-After -After Build {
    Write-Host "Build-After"
}

task . Clean, Build
# result

> .\run.ps1
Build . test.build.ps1
Task /./Clean
Clean
Done /./Clean 00:00:00.0040157
Task /./Build
Build
Task /./Build/Build-After
Build-After
Done /./Build/Build-After 00:00:00.0035095
Done /./Build 00:00:00.0075210
Done /. 00:00:00.0155475
Build succeeded. 4 tasks, 0 errors, 0 warnings 00:00:00.0260102

Elapsed          Name        Error
-------          ----        -----
00:00:00.0040157 Clean
00:00:00.0035095 Build-After
00:00:00.0075210 Build
00:00:00.0155475 .

What errors should stop safe testing?

In an error happens before the first task (e.g. the top level script code throws, missing tasks, cyclic references, etc.), then something is really wrong. Such errors should be fatal even on Invoke-Build -Safe.

Conditional Task Issue?

I'm not certain if I'm possibly just missing something or what but I cannot get conditional tasks to work. Here is an extremely simple example.

#Synopsis: Validate script requirements are met, load required modules, and load build tools.
task Configure {
    # If we made it this far then we are configured!
    $Script:IsConfigured = $True
        Write-Host 'configured!'
}, TestConfigure

task TestConfigure -If ($Script:IsConfigured -eq $true) {
    Write-Host 'configured...for certain!'
}

If I run invoke-build Configure it will always skip the TestConfigure task.

VSCode tasks: to work around known issues

There are two known issues of tasks generated by New-VSCodeTask.ps1.

Issue 1. Output encoding.

Non ASCII task output may be shown incorrectly in VSCode output window.
See Tasks should support specifying the output encoding

Issue 2. Console is required.

Some tasks may require the console host, for example for interaction (Read-Host, confirmations, etc.)
Some tasks may use colored output, so that in such cases they are better to be invoked in a console.

Another IB-Based Project for your list

I've taken a module build script I created for one of my projects and turned it into a more generic scaffolding for PowerShell module builds. It's capable of setting up the initial module framework, building/combining the module into a single source psm1, running PSScriptAnalyzer, publishing to the powershell gallery, and other such fun. Hopefully I didn't totally bastardize the intended purpose of IB too much :) Anyway, it is fairly usable and reasonably documented at this point. Thanks again for such a useful build engine!

Sharing scripts between projects

I have a simple build script (https://gitlab.com/snippets/25985) and I will use it in many projects without any changes. I would like to share it between projects. One way is to download the build script from somewhere and it would be nice if Invoke-Build could do this.

InvokeBuild -Url "https://gitlab.com/snippets/25985/raw"

It will download and execute the build script. But of course, I can also do it that way.

Invoke-WebRequest "https://gitlab.com/snippets/25985/raw" -OutFile ".build.ps1"
Invoke-Build

Write-Warning fails when it is called from a trap

The function Write-Warning defined by IB fails when it is called from a trap:

task Write-Warning-in-trap {
    trap {
        Write-Warning $_
        continue
    }
    1/$null
}

This line fails:

$PSCmdlet.WriteWarning($Message)

because $PSCmdlet is null in this scenario. IB incorrectly assumed that $PSCmdlet is defined in a parent scope.

TODO: Make Write-Warning an advanced function to ensure its $PSCmdlet.

Announcement: v3.0.0 will use script parameters specified for Invoke-Build

Starting from v2.7.0 (2014-05-03), build script parameters may be specified in
two ways:

  1. Directly for Invoke-Build (thanks to dynamic parameters)
  2. As a hashtable argument of the original parameter Parameters.

Dynamic parameters are much easier to use, read, and supported by TabExpansion
right away.

The original parameter Parameters was kept for compatibility at first and then
as a backup for a case of problems with dynamics. For two years problems were
not found. It is time to get rid of the obsolete Parameters and use only
parameters specified directly for Invoke-Build as if they were its own.

This is a breaking change in some cases. The migration steps are easy, though.
There is no need to wait for v3.0.0, migration may be gradually performed now.

Rename prohibited build script parameters

The inevitable loss: build scripts cannot use parameters used by Invoke-Build:
Task, File, Result, Safe, Summary, Checkpoint, Resume, WhatIf.

And Log if a script is going to be used in parallel builds (Invoke-Builds).

Unwrap and remove Parameters in Invoke-Build commands

Commands like

Invoke-Build Build -Parameters @{Configuration='Release'; Platform='x64'}

should be replaced with

Invoke-Build Build -Configuration Release -Platform x64

Ditto for parallel builds (Invoke-Builds)

Commands like

Invoke-Builds @(
    @{Task='Build'; Parameters=@{Configuration='Release'; Platform='x64'}}
    ...
}

should be replaced with

Invoke-Builds @(
    @{Task='Build'; Configuration='Release'; Platform='x64'}
    ...
}

Use splatting for dynamically created parameters

Scenarios like

$param = @{...}
Invoke-Build Build -Parameters $param

should be replaced with

$param = @{...}
Invoke-Build Build @param

Objections, please

The change will happen soon. It is done locally and being tested. It looks good.

If you see potential drawbacks or have any concerns, let's discuss here.

Nuget package as module

Hi,

I would like suggest to make include in nuget package also the module definition files.
Most of the nuget packages, with powershell, available at nuget.org have the psm1 and psd1 files in tools folder. As example look at 7Zip4PowerShell or psake.

The change is not invasive and allow to handle powershell packages in consistent way.

Code a little difficult to read.

Is there a reason that the code is as compact as it is? The complexity per line is very high. It's going to make interpreting diffs very hard is it not?
e.g.:

${private:-o}=${-}.Outputs
if(${-}.Partial){
    ${-o}=@(if(${-o} -is [scriptblock]){${-p}|& ${-o}; *SL}else{${-o}})
    if(${-p}.Count -ne ${-o}.Count){throw "Different input/output: $(${-p}.Count)/$(${-o}.Count)."}
    $k=-1; ${-}.Inputs=$i=[System.Collections.ArrayList]@(); ${-}.Outputs=$o=[System.Collections.ArrayList]@()
    foreach($_ in ${-i}){if($_.LastWriteTime -gt [System.IO.File]::GetLastWriteTime((*FP ($p=${-o}[++$k])))){$null=$i.Add(${-p}[$k]), $o.Add($p)}}
    if($i){return}
}else{
    if(${-o} -is [scriptblock]){${-}.Outputs=${-o}=& ${-o}; *SL}
    if(!${-o}){throw 'Empty output.'}
    ${-}.Inputs=${-p}
    $m=(${-i}|.{process{$_.LastWriteTime.Ticks}}|Measure-Object -Maximum).Maximum
    foreach($_ in ${-o}){if($m -gt [System.IO.File]::GetLastWriteTime((*FP $_)).Ticks){return}}

Invoke-BuildExec propagates exit code

Explicitly define valid exit codes does not stop the overall script to fail.

Task . {
    # Arrange
    if (Test-Path src) { Remove-Item -Path src -Recurse -Force }
    if (Test-Path dest) { Remove-Item -Path dest -Recurse -Force }
    $src = New-Item -Name src -ItemType Directory
    $dest = New-Item -Name dest -ItemType Directory
    Set-Content -Path (Join-Path $src "foo.txt") -Value "foo content"

    # Act
    Exec { Robocopy src dest foo.txt /256 /XO /NP /NFL /NDL /NJH /NJS } (0..7)

    # Assert
    "LASTEXITCODE is $LASTEXITCODE"
}

In this case, Invoke-Build succeed but the global exit code is 1 due to Robocopy, therefore the overall script fails. This is the case on my CI server which expect the PowerShell script executed to exit 0

Perhaps Invoke-BuildExec should return 0 if the exit code is within the valid range?

The workaround is having $global:LastExitCode = $null after each Exec { Robocopy ... } which is not ideal

Exception Missing default script thrown when no task is specified

Calling Invoke-Build without specifying a task throws the following exception:
‘Missing default script.’
I expected Invoke-Build would run the default task if no task is specified.

This is my build script:

task Build {
    Write-Host "Build..."
}

task Clean {
    Write-Host "Clean..."
}

task . Build, Clean

And this is how I start the script:

.\packages\Invoke-Build\tools\Invoke-Build .\.build\Build.ps1

Why does Invoke-Build not run the default task?

Improve result warnings for easier analysis

It makes sense to do the same as proposed in #10 for Result.Warnings. Right now warnings are just plain test messages. Especially on testing such information is not enough. It is difficult to guess what test file and task emitted a warning.

TODO: Fix persistent builds with cmdlet binding parameters

If a build script uses cmdlet binding parameters then persistent builds fail on saving a checkpoint due to not defined common parameters.

TODO: Ignore common parameters on saving a checkpoint file. This should fix the problem. The fix is presumably safe because common parameters are not supposed to be used in build scripts.

`-Before/-After` are not honoured if the referenced task has no jobs

I've been putting together a little project built around Invoke-Build. The intention is to define a standard lifecycle of tasks that can then be hooked into using -Before and -After.
I've found an issue where should the task being targeted with -Before/After have an empty job list, then the tasks fire in what looks like alphabetical order rather than honouring the expected arrangement,

Repro

if I define a .build.ps1 as follows

# Import features
. .\alpha.ps1
. .\beta.ps1

# Default Task
Task . -Jobs Build

# Lifecycle
Task Clean
Task Build -Jobs Clean
Task Pack -Jobs Build

And I create alpha.ps1

task Clean.Alpha -Jobs { Write-Build 10 "alpha" } -After Clean

and beta.ps1

task Clean.Beta -Jobs { Write-Build 10 "beta" } -Before Clean

When the build is executed, I would expect the tasks to fire in the order: Clean.Beta, Clean, Clean.Alpha. However the tasks fire in the order Clean.Alpha, Clean.Beta, Clean.

C:\Users\Kieranties\Desktop\repro
> .\Invoke-Build.ps1
Build . C:\Users\Kieranties\Desktop\repro\.build.ps1
Task /./Build/Clean/Clean.Alpha
alpha
Done /./Build/Clean/Clean.Alpha 00:00:00.0080036
Task /./Build/Clean/Clean.Beta
beta
Done /./Build/Clean/Clean.Beta 00:00:00.0069889
Done /./Build/Clean 00:00:00.0210044
Done /./Build 00:00:00.0250046
Done /. 00:00:00.0290171
Build succeeded. 5 tasks, 0 errors, 0 warnings 00:00:00.0610152

Workaround

To work around the issue, the task being targeted with -Before/-After must declare a job. This job can be empty. E.g. Declaring the Clean task as task Clean -Jobs {} and running the build again gives the expected result

C:\Users\Kieranties\Desktop\repro
> .\Invoke-Build.ps1
Build . C:\Users\Kieranties\Desktop\repro\.build.ps1
Task /./Build/Clean/Clean.Beta
beta
Done /./Build/Clean/Clean.Beta 00:00:00.0060157
Task /./Build/Clean
Task /./Build/Clean/Clean.Alpha
alpha
Done /./Build/Clean/Clean.Alpha 00:00:00.0059994
Done /./Build/Clean 00:00:00.0250031
Done /./Build 00:00:00.0290026
Done /. 00:00:00.0330021
Build succeeded. 5 tasks, 0 errors, 0 warnings 00:00:00.0570023

Review how errors are recorded in tasks and added to the result Errors

Currently (2.10.3 and before) any task error is added to the result Errors, including an error of a referenced task. As a result, the same error can be added to the list several times.

It still makes sense perhaps to store an error to the property Error of a task, it is failed after all, even though not itself but due to a child task. But repeating the same error in the result list does not look practically useful.

Get rid of Out-String

Out-String fails in the strict mode with "Default Host". This is a rare use case. So Out-String is fine in tests or even build scripts if they are not designed for this problematic scenario. But it is better to get rid of Out-String in the Invoke-Build core. It should work in this scenario.

Discovering Build Task from module, and import them

I really like Invoke-Build and the way you can split tasks in different files, use parameters and the property keyword to propagate them across dot sourced Build tasks files, providing defaults or overriding values.

I think some PS Modules should export tasks generic but relevant to their subject (say PSDepend could expose some tasks like those here), and then a user can import and compose them in a single .build.ps1 file, overriding variables as needed.

This would allow much more re-usability from Build scripts, instead of everyone 'making their own'.

Then it would be good to have Invoke-Build providing some helper functions for discovering those Build tasks/file from other installed modules or from the gallery.

To implement that function, I think Plaster has a very neat way of doing exactly that for PlasterTemplates.

In short, the module needs to 'expose' an extension in its metadata, then the Plaster module can find the extension and list its Templates.

What do you think?

/cc @RamblingCookieMonster

ArgumentCompleters not working on Task argument

Hi!

Invoke-Build.ArgumentCompleters seems to have problem with completing Task argument values.
Invoke-Build and was installed under CurrentUser with Install-Module. Tried using Invoke-Build.ArgumentCompleters both with Install-Script and Save-Script but didn't work either way.

Quick fix is to modify Invoke-Build.ArgumentCompleters.ps1 and change first call to Register-ArgumentCompleter to use Invoke-Build instead of $commandName to find completions:

Register-ArgumentCompleter -CommandName Invoke-Build.ps1 -ParameterName Task -ScriptBlock {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $boundParameters)
    $commandName = "Invoke-Build"
    (& $commandName ?? -File ($boundParameters['File'])).Keys -like "$wordToComplete*" | .{process{
        New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', $_
    }}
}

Best regards and keep up good work!

Egon

OSS Posh: ConsoleColor Assembly Issues

In answer to a comment you left on my blog here is the error I get when I try to run Invoke-Build.ps1 on Powershell 6.0 on my linux test server. I cannot dig into this just right now to find the equivalent .Net Core namespaces but I'll try to take a peek a bit later.

Add-Type : (9) : The type or namespace name 'ConsoleColor' could not be found (are you missing a using directive or an assembly reference?)
(8) : static public void RC() {if (_u != null) {try {_u.ForegroundColor = _c;} catch {}}}
(9) : >>> static public void SC(ConsoleColor c) {if (_u != null) {try {_c = _u.ForegroundColor; _u.ForegroundColor = c;} catch {_u = null;}}}
(10) : static public object List() {return new List();}
At /vagrant/Invoke-Build/Invoke-Build.ps1:204 char:1

  • Add-Type @'
  • - CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    - FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
    

Add-Type : (5) : The type or namespace name 'ConsoleColor' could not be found (are you missing a using directive or an assembly reference?)
(4) : public class IB {
(5) : >>> [ThreadStatic] static ConsoleColor _c;
(6) : [ThreadStatic] static PSHostRawUserInterface _u;
At /vagrant/Invoke-Build/Invoke-Build.ps1:204 char:1

  • Add-Type @'
  • - CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    - FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
    
    

Add-Type : (8) : The type 'ConsoleColor' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Console, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a'.
(7) : static public void Init(PSHost h) {if (h.UI != null) _u = h.UI.RawUI;}
(8) : >>> static public void RC() {if (_u != null) {try {_u.ForegroundColor = _c;} catch {}}}
(9) : static public void SC(ConsoleColor c) {if (_u != null) {try {_c = _u.ForegroundColor; _u.ForegroundColor = c;} catch {_u = null;}}}
At /vagrant/Invoke-Build/Invoke-Build.ps1:204 char:1

  • Add-Type @'
  • - CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    - FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
    
    

Add-Type : (9) : The type 'ConsoleColor' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Console, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a'.
(8) : static public void RC() {if (_u != null) {try {_u.ForegroundColor = _c;} catch {}}}
(9) : >>> static public void SC(ConsoleColor c) {if (_u != null) {try {_c = _u.ForegroundColor; _u.ForegroundColor = c;} catch {_u = null;}}}
(10) : static public object List() {return new List();}
At /vagrant/Invoke-Build/Invoke-Build.ps1:204 char:1

  • Add-Type @'
  • - CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    - FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
    
    

Add-Type : (9) : The type 'ConsoleColor' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Console, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a'.
(8) : static public void RC() {if (_u != null) {try {_u.ForegroundColor = _c;} catch {}}}
(9) : >>> static public void SC(ConsoleColor c) {if (_u != null) {try {_c = _u.ForegroundColor; _u.ForegroundColor = c;} catch {_u = null;}}}
(10) : static public object List() {return new List();}
At /vagrant/Invoke-Build/Invoke-Build.ps1:204 char:1

  • Add-Type @'
  • - CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeCompilerError) [Add-Type], Exception
    - FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
    
    

Add-Type : Cannot add type. Compilation errors occurred.
At /vagrant/Invoke-Build/Invoke-Build.ps1:204 char:1

  • Add-Type @'
  • - CategoryInfo          : InvalidData: (:) [Add-Type], InvalidOperationException
    - FullyQualifiedErrorId : COMPILER_ERRORS,Microsoft.PowerShell.Commands.AddTypeCommand
    
    

Unable to find type IB.
At /vagrant/Invoke-Build/Invoke-Build.ps1:217 char:1

  • - CategoryInfo          : InvalidOperation: (IB:TypeName) [], RuntimeException
    - FullyQualifiedErrorId : TypeNotFound
    
    

/vagrant/Invoke-Build/Invoke-Build.ps1 : Unable to find type IB.
At line:1 char:1

  • ./Invoke-Build.ps1
  • - CategoryInfo          : InvalidOperation: (IB:TypeName) [Invoke-Build.ps1], RuntimeException
    - FullyQualifiedErrorId : TypeNotFound,Invoke-Build.ps1
    

Conflict between dynamic switch parameters and positional parameters

The problem

It turns out that switch parameters in build scripts may cause problems when
used as dynamic parameters of Invoke-Build before its positional parameters.

Example build script:

    param(
        [switch]$Switch
    )

    task task1 {"1 $Switch"}
    task task2 {"2 $Switch"}

This command works fine, it calls task2:

    Invoke-Build task2 -Switch

But this seemingly same command calls task1 instead:

    Invoke-Build -Switch task2

Why? Presumably PowerShell on calling the DynamicParam block does not know
yet that -Switch is a dynamic switch (i.e. not requiring an argument) and
assigns the argument task2 to it. Thus, the positional parameter Task gets
nothing at this point instead of task2 (and the default task is used which is
task1 in this case).

Things are even worse if the positional parameter File is affected:

    Invoke-Build task2 -Switch path/.build.ps1

because File (path/.build.ps1) should be used in DynamicParam for getting
the dynamic parameters (including the troublesome -Switch). But -Switch eats
path/.build.ps1 and File gets nothing, so that the default build script is
assumed instead, potentially not the same as specified.

Solutions?

One possible way to resolve this properly is to allow dynamic parameters only
if Task and File are explicitly defined, i.e. not accidentally swallowed by
a dynamic switch for sure.

But this requirement seems to be too strong because switches are often
used after positional parameters and do not cause such issues.

So the proposal is to keep things as they are and just document this as a known issue
in help and wiki. It's a minor issue, after all. Other thoughts?

Incremental Outputs block should always receive piped Inputs

Currently, this is the case only for partial incremental tasks.

It looks like there may be cases when this convention may help with composing
outputs of simple incremental tasks, too. See the discussion of #48.

It should be possible to write a task inputs and outputs like this:

    $param = @{
        Inputs = {Get-ChildItem -Filter *.csproj -Recurse}
        Outputs = {process{ Join-Path (Split-Path $_) obj/project.assets.json }}
    }

    task test @param {
        $Inputs
        $Outputs
    }

Note how the Outputs block processes the piped paths evaluated from Inputs.

Invoke-Build ** -- to propagate -Safe to all *.test.ps1

Invoke-Build ** invokes tasks in *.test.ps1 files. This feature is used for testing. The testing stops on the first failed task and in most cases this is fine. Invoke-Build is not a sophisticated test engine.

Still, with many test files sometimes it would be useful to continue testing and invoke some more test files, perhaps with more failures, and then decide how to proceed.

I propose to use the existing switch Safe in order to make failures stopping individual test files, not the whole testing. In other words, the command Invoke-Build ** -Safe will propagate -Safe to invocation of test files and collect all errors instead of just the first.

One potential flaw. It will not be possible to tell Invoke-Build to not throw and yet stop testing at the first failed test. But try/catch without Safe solves this. Also, Safe normally makes sense with some analysis after invocation. And analysis of multiple test failures looks more practically useful.

Any objections or other ideas?

Watch command?

I'm hoping to replace gulp and I think the only thing missing that I need is a "watch" command. I want to be able to give a list of files to watch, and a command to run with the intention of running webpack when scripts are updated.

Thoughts?

A default build script should support *not* starting with dot

It's a little weird to use the dotfile convention for a default build script. On Windows, it looks weird, on *nix, the file is hidden from ls without an option.

I'd suggest allow at least one other default filename as a default. One obvious possibility - if the script is in foo\bar\project, then project.build.ps1 is considered a default build script. In other words, if the filename is directoryname.build.ps1, it's the default build script.

Is $WhatIf check really needed in *UC?

Is $WhatIf check really needed in the internal function*UC? If it is not remove it. Presumably this function should not be called on $WhatIf.

function *UC($_) {
    if (!$WhatIf) {
        *SL
        . $_ @args
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.