GithubHelp home page GithubHelp logo

adamralph / bullseye Goto Github PK

View Code? Open in Web Editor NEW
826.0 826.0 38.0 1.85 MB

๐ŸŽฏ A .NET library for running a target dependency graph.

License: Apache License 2.0

C# 97.11% Batchfile 1.51% Shell 1.28% Dockerfile 0.09%

bullseye's Introduction

Hi there ๐Ÿ‘‹

bullseye's People

Contributors

adamralph avatar alibresco avatar biohazard999 avatar blairconrad avatar bymyslf avatar damianh avatar dependabot-preview[bot] avatar dependabot[bot] avatar foobit avatar haga-rak avatar moientajik avatar paralexm avatar thefringeninja 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

bullseye's Issues

ForEach<string> doesn't fit with overloads without dependencies

I realised this as I was writing the new README.md. ๐Ÿ˜ฟ

Target(
    "eat-biscuits",
    ForEach("digestives", "chocolate hob nobs"),
    biscuits => Console.WriteLine($"Mmm...{biscuits}! Nom nom."));

In this case the name, dependsOn, action overload is being called, and obviously targets named "digestives" and "chocolate hob nobs" are not found.

The fix is to add the parameter name (ugly):

Target(
    "eat-biscuits",
    forEach: ForEach("digestives", "chocolate hob nobs"),
    action: biscuits => Console.WriteLine($"Mmm...{biscuits}! Nom nom."));

And then it's better not to use ForEach, and use an array initializer instead (less ugly):

Target(
    "eat-biscuits",
    forEach: new[] {"digestives", "chocolate hob nobs"},
    action: biscuits => Console.WriteLine($"Mmm...{biscuits}! Nom nom."));

This issue may become "Deprecate DependsOn and ForEach". They were only added because C# doesn't have a pretty array initializer. I had a feeling they might come and bite me eventually.

Unknown options are not reported properly

Run Bullseye with an unknown option flag, e.g. -b. The error that spews out is akin to

Unknown options {unknownOptions.Quote()}. "--help" for usage.

This is less than ideal.

Support for known exceptions that don't report their full stacktrace

Bare with me @adamralph I am just throwing tickets at you without fully knowing what I want ๐Ÿ˜ธ

Here I am running .NET tests by calling dotnet test through https://github.com/nullean/proc which throws an exception on an unknown exitCode (defaulting to anything not 0).

The result is a bit noisy:

image

I am only interested in the first stracktrace from the failing tests.

It would be nice if I could mark ProcExecException somehow to only display the ex.Message.

Better log messages

Before

Success

Failure

Problems

  • In both cases, the escaping of ", /, and : is flawed. It's easy to construct target names which make the resulting string ambiguous.
  • In the failure case, the last line is confusing, since hell"o actually succeeded.

After

Success

Failure

Solutions

  • The escaping has been removed. If people want to use weird target names that screw up the output, it's their prerogative.
  • In the failure case, the confusion is lessened, since the message format follows that of the "Starting..." message. ๐Ÿคทโ€โ™‚๏ธ

And some extra colour to boot. ๐ŸŒˆ

Running via Linqpad

Hi. Just thought I'd give bullseye a very quick whirl in Linqpad and I see a couple of (cosmetic) issues:

image

  1. the display is a bit odd, I guess there's some encoding/decoding difference. Do you know what it is, and I can see if I can get Linqpad to output correctly?
  2. you get a "Query ended unexpectedly" message - I can avoid this by using RunTargets(args) but I see that's being deprecated...

I appreciate Linqpad's not been targeted for support, but if the problems are easy to fix then it would be neat to be able to use it with bullseye.

[Question] Debugging Bullseye project

This is not an issue, but a question.
I have created a console project in dotnet core 2.2 to build a bunch of projects. As per the documentation and examples, I use

            Target("default", DependsOn(_targetNames.ToArray()));
            RunTargetsAndExit(args);

When debugging in my IDE (visual studio in this case) the command line window disappears too fast to see the errors or the reporting on each task. This is expected behaviour of RunTargetsAndExit. However, how can I prevent the commandline window to close so that I can see all the errors?

Thank you in advance for the help and for creating this useful tool.

Attempt to automatically enable console colors in Windows

See https://superuser.com/a/1050078/26617

Virtual terminal processing (including ANSI colours) was added to the console in Windows 10. Unfortunately, it's disabled by default, which means running Bullseye targets in a vanilla console window looks like this (unless the --no-color/-N option is specified):

image

With this enhancement, Bullseye uses the Win32 API (when on Windows) to attempt to switch on virtual terminal processing. Any failure to do so is ignored and logged at the verbose level (--verbose/-v). It works in most cases (i.e. on a developer machine):

image

It fails on Appveyor, but Appveyor already redirects console output and understands ANSI colour codes, so builds on Appveyor are already in glorious colour. ๐ŸŒˆ

Some console apps, such as ConEmu, already enable virtual terminal processing so this change has no observable effect when using those apps.

Parallel targets

-p, --parallel             Run targets in parallel

Note that in a typical build script, this can cause havoc in the console, since the output from the external tools that are run in parallel targets will be interleaved. It is perhaps best used to use this option only to speed up local builds on a developer workstation. Builds on a CI server may better off without it, to preserve the readability of build logs.

BeforeTarget and AfterTarget

I would like to be able to run an action before and after each target run.

My particular use case is that I want to write a TC service message before and after each Task.

BeforeTarget((targetName) => Console.WriteLine($"##teamcity[blockOpened name='{targetName}']");
AfterTarget((targetName) => Console.WriteLine($"##teamcity[blockClosed name='{targetName}']");

Happy to attempt a PR if agreeable. My current workaround is to have my own TargetTC methods that wrap Target and it's a bit meh

private static void TargetTC(string name, Action action)
{
    Target(name, () =>
    {
        Console.WriteLine($"##teamcity[blockOpened name='{name}']");
        action();
        Console.WriteLine($"##teamcity[blockClosed name='{name}']");
    });
}

Use dependencies to determine target execution order, even when skipping dependencies

This may be an uncommon use case, but I find myself running a local build, and skipping dependencies (because I don't want to run a restore target, or something that calculates the next released version number), but executing targets that depend on others, such as a build and a test target. In such cases, I must take pains to order the targets properly, or they will be executed in the wrong order. Consider:

Target("build", DoesNothing);                     
Target("subtest1", DependsOn("build"));           
Target("subtest2", DependsOn("build"));           
Target("test", DependsOn("subtest1", "subtest2"));
Target("default", DependsOn("test"));             

When I run with Bullseye 2.0.0-rc.2+build.115:

ฮป  dotnet run -s build test
Bullseye: Starting... (build test) (skip dependencies)
Bullseye/build: Starting...
Bullseye/build: Succeeded. (4.57 ms)
Bullseye/test: Succeeded.
Bullseye: Succeeded. (build test) (skip dependencies) (19.6 ms)
D:\Sandbox\try-bullseye

ฮป  dotnet run -s test build
Bullseye: Starting... (test build) (skip dependencies)
Bullseye/test: Succeeded.
Bullseye/build: Starting...
Bullseye/build: Succeeded. (3.51 ms)
Bullseye: Succeeded. (test build) (skip dependencies) (15.7 ms)

But I would've hoped the order of execution would be the same. Just because I don't want to run (unasked-for) dependencies, I don't want to throw my usual target-ordering rules out the window.

@adamralph, if you've interest in this change (or at least are not opposed), I'd be happy to work on a PR.

More forgiving command line parsing exception reporting.

> build.cmd drink-tea
Bullseye: Starting... (drink-tea)
Bullseye: Failed! (drink-tea) (3.96 ms)

Unhandled Exception: System.Exception: The following target was not found: drink-te
a.
   at Bullseye.Internal.TargetCollection.Validate(List`1 names) in C:\projects\bull
seye\Bullseye\Internal\TargetCollection.cs:line 150
   at Bullseye.Internal.TargetCollection.RunAsync(List`1 names, Boolean skipDepende
ncies, Boolean dryRun, Boolean parallel, Logger log) in C:\projects\bullseye\Bullse
ye\Internal\TargetCollection.cs:line 30
   at Bullseye.Internal.TargetCollection.RunAsync(List`1 names, Boolean skipDepende
ncies, Boolean dryRun, Boolean parallel, Logger log) in C:\projects\bullseye\Bullse
ye\Internal\TargetCollection.cs:line 47
   at Bullseye.Internal.TargetCollectionExtensions.RunAsync(TargetCollection target
s, List`1 args, IConsole console) in C:\projects\bullseye\Bullseye\Internal\TargetC
ollectionExtensions.cs:line 171
   at targets.Program.Main(String[] args) in C:\Projects\elastic\net-master\build\t
argets\Program.cs:line 26
   at targets.Program.<Main>(String[] args)

Is rather verbose and panicky, a smaller output for these validation failure cases would make for a smoother CLI experience in my opinion.

> build.cmd drink-tea
Bullseye: Starting... (drink-tea)
Bullseye: Failed! (drink-tea) The following target was not found: drink-tea. (3.96 ms)

Similarly the reporting of unknown command line switches do not need to yield a full stacktrace IMHO.

Targets not build if name is not default and with custom arguments

  1. Using following gist published
    https://gist.github.com/adamralph/d6a3167c8fe0d4e24721d8d2b9c02989
  2. Just change the name of default target to something else (say default1 )
  3. run following
    dotnet run -- default1 --foo=bar

Expected : I was expecting it to execute default1 target

Actual : "Bullseye: Unknown option --foo=bar. "--help" for usage."

Same can be tried without changing name , just specify target name , say default it will throw same error.

RunTargetsAndExit() and RunTargetsAndExitAsync()

These method groups will run the targets and then call Environment.Exit.

  • The current RunTargets() and RunTargetsAsync will be deprecated.
  • The .NET Standard 1.3 assembly will be removed, since Environment.Exit() does not exist in .NET Standard 1.3.

The advantage is that when a target fails, or when invalid arguments are supplied, or when the targets are badly defined (circular dependencies, missing dependencies, etc), the exception message will be logged and the process will exit with an appropriate exit code. Currently, the process exits with an unhandled exception, which results in the stack trace being written to the console, and an application error being written to the OS event log (at least on Windows) which usually results in a significant delay before control is returned to the console.

Comparison

RunTargets(args)

And three entries in the OS event logs! Notice that two seconds elapsed between the first and last entry, and this seems to be the delay in control being returned to the console after the process exits.

RunTargetsAndExit(args)

And nothing in the OS event logs, and no delay.

Overloads

Accepting a predicate that is called when an exception is thrown, which should returns true if only the exception message should be displayed.

RunTargetsAndExit(IEnumerable<string> args, Func<Exception, bool> messageOnly)
RunTargetsAndExitAsync(IEnumerable<string> args, Func<Exception, bool> messageOnly)

Log exceptions inside targets

Benefits

  • Less scrolling to see the last target which failed (as mentioned below)
  • Smaller stack traces, since the exception is being logged further down the stack
  • When running with --parallel, all exception details are shown.

Before

image

After

image

Original text by @Mpdreamz Currently exceptions bubble out of `RunTargets(Async)()`
C:\Projects\elastic\net-master>build.cmd walkdog
Bullseye: Starting... (walkdog)
Bullseye/walkdog: Starting...
Bullseye/walkdog: Failed! boom! (8.34 ms)
Bullseye: Failed! (walkdog) (23.4 ms)

Unhandled Exception: System.Exception: boom!
   at targets.WalkDogTarget.Exec() in C:\Projects\elastic\net-master\build\targets\Progra
m.cs:line 40
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, Co
ntextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
   at Bullseye.Internal.ActionTarget.RunAsync(Boolean dryRun, Boolean parallel, Logger lo
g) in C:\projects\bullseye\Bullseye\Internal\ActionTarget.cs:line 25
   at Bullseye.Internal.ActionTarget.RunAsync(Boolean dryRun, Boolean parallel, Logger lo
g) in C:\projects\bullseye\Bullseye\Internal\ActionTarget.cs:line 31
   at Bullseye.Internal.TargetCollection.RunAsync(String name, List`1 explicitTargets, Bo
olean skipDependencies, Boolean dryRun, Boolean parallel, ConcurrentDictionary`2 targetsR
an, Logger log, Stack`1 targets) in C:\projects\bullseye\Bullseye\Internal\TargetCollecti
on.cs:line 83
   at Bullseye.Internal.TargetCollection.RunAsync(List`1 names, Boolean skipDependencies,
 Boolean dryRun, Boolean parallel, Logger log) in C:\projects\bullseye\Bullseye\Internal\
TargetCollection.cs:line 38
   at Bullseye.Internal.TargetCollection.RunAsync(List`1 names, Boolean skipDependencies,
 Boolean dryRun, Boolean parallel, Logger log) in C:\projects\bullseye\Bullseye\Internal\
TargetCollection.cs:line 47
   at Bullseye.Internal.TargetCollectionExtensions.RunAsync(TargetCollection targets, Lis
t`1 args, IConsole console) in C:\projects\bullseye\Bullseye\Internal\TargetCollectionExt
ensions.cs:line 171
   at targets.Program.Main(String[] args) in C:\Projects\elastic\net-master\build\targets
\Program.cs:line 26
   at targets.Program.<Main>(String[] args)

C:\Projects\elastic\net-master>

If the order were different:

C:\Projects\elastic\net-master>build.cmd walkdog
Bullseye: Starting... (walkdog)
Bullseye/walkdog: Starting...

Unhandled Exception: System.Exception: boom!
   at targets.WalkDogTarget.Exec() in C:\Projects\elastic\net-master\build\targets\Progra
m.cs:line 40
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, Co
ntextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
   at Bullseye.Internal.ActionTarget.RunAsync(Boolean dryRun, Boolean parallel, Logger lo
g) in C:\projects\bullseye\Bullseye\Internal\ActionTarget.cs:line 25
   at Bullseye.Internal.ActionTarget.RunAsync(Boolean dryRun, Boolean parallel, Logger lo
g) in C:\projects\bullseye\Bullseye\Internal\ActionTarget.cs:line 31
   at Bullseye.Internal.TargetCollection.RunAsync(String name, List`1 explicitTargets, Bo
olean skipDependencies, Boolean dryRun, Boolean parallel, ConcurrentDictionary`2 targetsR
an, Logger log, Stack`1 targets) in C:\projects\bullseye\Bullseye\Internal\TargetCollecti
on.cs:line 83
   at Bullseye.Internal.TargetCollection.RunAsync(List`1 names, Boolean skipDependencies,
 Boolean dryRun, Boolean parallel, Logger log) in C:\projects\bullseye\Bullseye\Internal\
TargetCollection.cs:line 38
   at Bullseye.Internal.TargetCollection.RunAsync(List`1 names, Boolean skipDependencies,
 Boolean dryRun, Boolean parallel, Logger log) in C:\projects\bullseye\Bullseye\Internal\
TargetCollection.cs:line 47
   at Bullseye.Internal.TargetCollectionExtensions.RunAsync(TargetCollection targets, Lis
t`1 args, IConsole console) in C:\projects\bullseye\Bullseye\Internal\TargetCollectionExt
ensions.cs:line 171
   at targets.Program.Main(String[] args) in C:\Projects\elastic\net-master\build\targets
\Program.cs:line 26
   at targets.Program.<Main>(String[] args)

Bullseye/walkdog: Failed! boom! (8.34 ms)
Bullseye: Failed! (walkdog) (23.4 ms)


C:\Projects\elastic\net-master>

The last lines would always indicate the faulty target and a user does not have to scroll their terminal.

Better help line in help

Before

-h, --help                 Show this help (case insensitive) (or -?)

After

-h, --help, -?             Show this help, then exit (case insensitive)

Case-insensitive target names

Right now target is case sensitive, it would be nice if this was case insensitive allowing you to use nameof(Method) but pass method on the command line

Provide a way to create dependency chain in isolation

One thing I love about FAKE is that it promotes the separation of defining targets and defining dependency chains.

e.g part of our current build that I am converting over to BullsEye

"Start"
    =?> ("Clean", Commandline.needsClean )
    =?> ("Version", hasBuildParam "version")
    ==> "Restore"
    =?> ("FullBuild", Commandline.needsFullBuild)
    =?> ("Test", (not Commandline.skipTests && Commandline.target <> "canary"))
    =?> ("InternalizeDependencies", (not isMono))
    ==> "InheritDoc"
    =?> ("Documentation", (not Commandline.skipDocs))
    ==> "Build"

=?> denotes a conditional target which will only run if the predicate is true.

Not sure how to work this into the current DSL but I found there was a bit of cognitive overload on my end trying to rework this as arguments to the target creation.

Enriched verbose output

When running with (-v/--verbose):

  • Bullseye version (.NET Standard 2.0+ only)
  • Host (Unknown/Appveyor/Travis/TeamCity) (detected/forced)
  • OS (Unknown/Linux,MacOS,Windows)
  • Args
  • Dependency walking
  • Target awaiting
  • Ignoring non-existent dependencies (when running with -s/--skip-dependencies)

Provide an alternative to Environment.Exit

Calling Environment.Exit from RunTargetsAndExit prevents us from doing anything after we run the targets.

Could RunTargets (or some other method like RunTargetsAndReturn) do the same thing as RunTargetsAndExit, except return the exit code that should be returned from Main, instead of calling Environment.Exit?

Switch palettes for CI environments

With support for Appveyor, Travis CI, and TeamCity.

For reference, this is how the output looks in a local console:

And these are the various colour palettes:

Local console Appveyor - Windows Appveyor - Linux Travis CI TeamCity

AppVeyor - Windows

Before

After

AppVeyor - Linux

Before

After

Travis CI

Before

After

TeamCity

Before

After

Support custom command line arguments

Currently there's no easy way to pass custom command line arguments to a Bullseye-based program.

  1. Parsing has to be done manually
  2. Custom arguments have to be removed before passing the args to Bullseye

I suggest:

  1. Adding a string GetArgument(string argumentName), which would allow passing arguments in the form --foo=bar
  2. Ignoring unknown arguments passed to RunTargets (or adding an overload with a bool ignoreUnknownArguments parameter)

Summary reporting

E.g.

original description What I want is a way to print a summary as the very last thing on the command line

e.g from a FAKE build script:

---------------------------------------------------------------------
Build Time Report
---------------------------------------------------------------------
Target                    Duration
------                    --------
Clean                     00:00:01.5973051
ChangeVersion             00:00:00.0216123
Version                   00:00:00.0449321
Restore                   00:00:02.5392854
FullBuild                 00:00:06.7928622
Test                      00:00:26.2444011
InternalizeDependencies   00:00:08.4346894
Build                     00:00:00.0017516
Release                   00:00:04.1651395
Total:                    00:00:49.9985537
---------------------------------------------------------------------
Status:                   Ok
---------------------------------------------------------------------

I really like having this be the last thing printed consistently as I often keep an eye out on task running times.

New `Target()` and `RunTargets()` API

using static Bullseye.Targets;
...
Target("default", () => System.Console.WriteLine("Hello, world!"));
RunTargets(args);

With Add() and Run() deprecated.

Feedback from @blairconrad and @thomaslevesque was that Add() and Run() are too general in their bare forms when using static. An alternative is AddTargets() and RunTargets(), although that is a little verbose when you consider Targets.AddTarget(), Targets.RunTargets(). Ideally it would be great to have an API which looks great in both scenarios although I'm not sure that's possible.

This would include a deprecation of the previous methods, and their removal in 2.0.

Final decision was Target() and RunTargets().

Initial version

2.3.0 release

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.