Comments (12)
I'm not sure if I understand what you mean :/
Normally when you declare dependencies you write:
Task("Clean")
.Does(() =>
{
});
Task("UpdateAssemblyInfo")
.WithCriteria(() => !isLocalBuild)
.IsDependentOn("Clean")
.Does(() =>
{
});
Task("Build")
.IsDependentOn("A")
.Does(() =>
{
});
What I'm proposing is another way of declaring the dependency graph:
Task("Clean")
.Does(() =>
{
});
Task("UpdateAssemblyInfo")
.Does(() =>
{
});
Task("Build")
.Does(() =>
{
});
// Declare dependencies.
Graph("Clean")
.Then("Build");
.Then("OtherTask1");
.Then("OtherTask2");
if(!isLocalBuild)
{
Graph("Clean")
.Then("UpdateAssemblyInfo");
}
With a model like this, you could theoretically tell Cake to run tasks is parallel:
Graph("Clean")
.Then("Build");
.ThenInParallel("OtherTask1", "OtherTask2");
This is just an example. I find the Graph
method name a little confusing.
This would (like I've said many times before) need some more thought 😄
from cake.
While graph is correct, wouldn't Target("Default")
be more technically appropriate? Or am I misunderstanding this issue?
from cake.
Ahh, I think I was misunderstanding this slightly. I was assuming this as a secondary way to define targets for building. Like:
Task("Clean")
.Does(() =>
{
/* Clean Things */
});
Task("UpdateAssemblyInfo")
.Does(() =>
{
/* Update CommonAssemblyInfo.cs */
});
Task("Build")
.Does(() =>
{
/* Build the project. */
});
// Declare dependencies.
if(!isLocalBuild)
{
Target("Default")
.Do("Clean");
.Then("UpdateAssemblyInfo")
.Then("Build")
.Then("Package");
}
else
{
Target("Default")
.Do("Clean")
.Then("Build");
}
RunTarget("Default");
NVM then ^_^
from cake.
What's the status of this feature? Looks appealing to me 👍
from cake.
I'm not sure if this should be implemented (therefore the investigate label). It seemed like a good idea at the time, but I'm not that sure that it would contribute anything except introducing more complexity.
I might be wrong and I'm not 100% against it, but I think the API should be discussed a little bit more before doing anything since it affects how Cake behaves.
Any good use cases for this functionality?
from cake.
I agree that it hardly adds any value to the project, but as a "syntactic sugar" - looks nice 😋
In proposed example the workflow is all at a glance, so if build order is changed it is much easier to move couple of lines up/down, rather than fixing IsDependentOn
and WithCriteria
calls. As the complexity of the build process grows, so does value of such syntax model.
And to me, semantically it also looks like better way to. First you define tasks as granular units of work; next - you combine them in a workflow (or multiple workflows).
Specifying execution criteria for the task makes it stick to the task. So, say if you want to execute same task, but in another workflow/build configuration where that criteria doesn't apply you have 2 options: write a new task with different criteria, or update the criteria itself with some conditional logic depending to context of execution.
Example
Current way
Task("A")
.WithCriteria( ()=> !someCondition)
.Does(()=>
{
// some actions here
});
Task("B")
.IsDependentOn("A")
.Does(()=>
{
// some actions here
});
Task("C")
.Does(()=>
{
// some actions here
});
// this wants task A to execute only if !someCondition
Target("Build_Config_A")
.IsDependentOn("B")
.IsDependentOn("C");
// this wants task A to execute regardless of 'someCondition',
Target("Build_Config_B")
.IsDependentOn("B")
.IsDependentOn("C");
// so to be able to acheive that, will have to duplicate task but exclude condition
// or update the condition itself to tak execution context into account somehow.
// Even more, we might have a config that, wants task B to be executed, but not w/o Task A
// being executed before it
Target("Build_Config_C")
.IsDependentOn("B") // just B! not dep. on task "A"
.IsDependentOn("C");
Now a better way (in my opinion 😄 )
var config = Argument<string>("config", "Build_Config_B");
Task("A")
.Does(()=>
{
// some actions here
});
Task("B")
.Does(()=>
{
// some actions here
});
Task("C")
.Does(()=>
{
// some actions here
});
Workflow("Build_Config_A").
Do("A", If (() => !someCondition))
.Then("B")
.Then("C");
Workflow("Build_Config_B")
.Do("A")
.Then("B")
.Then("C");
Workflow("Build_Config_C")
.Do("B")
.Then("C");
RunWorkflow(config);
As you mentioned above, this style also gives credit to possible parallel execution (in future), and passing a some sort of "execution result" object to the next task (which is "piping" in a nutshell, some already mentioned that in other discussion)
from cake.
Great feedback.
I would say that workflows as you suggest (great name suggestion btw) is something else than what's proposed in this issue. Although I like the idea.
Since the simplified graph configuration i proposed above is more like a way of adding dependencies in reverse, have I understood this correctly if I say that workflows is a way to compose tasks - also in reverse - but in many different ways and isolated from other workflows?
Some questions that pop up:
- Can a workflow be dependent on a workflow?
- Can a task be dependent on a workflow?
- What happens if task
A
have a dependency on taskX
? Would task specific dependencies be respected when executing a workflow with a dependency onA
? - Given that task
A
already have a condition, would a condition for taskA
in the workflow be evaluated after the original condition?
from cake.
if I say that workflows is a way to compose tasks - also in reverse - but in many different ways and isolated from other workflows?
Yes. I consider "workflow" as single unique path to accomplish build.
Can a workflow be dependent on a workflow?
I had troubles trying to come-up with a good use case for that, so - no, workflow should not be dependent on other workflow(s).
Can a task be dependent on a workflow?
No again. My vision here is that task, actually should not have dependencies (so as conditions) at all. That is, there should be no Task.IsDependentOn
and Task.WithCriteria
methods. You declare those on level of workflow. So, this actually answers last 2 questions as well.
I understand, that what I wrote above "hurts" a bit at first, because removing aforementioned methods is a huge breaking change, but we're just talking it out loud, anyway, right? 😉 And the conversation topic has drifted from original one, cause now I realize I speak more about alternative Cake API.
What-if
We would have an experimental namespace Cake.Core.Workflows
which would hold definitions for Workflow
and Job
(Job
is a twin-brother of Task
, It has same interface except it does not allow user to declare dependencies and conditions right on it). This would give us 2 alternative API's to execute build, which will not interfere with each other.
from cake.
I've been thinking about this today and I cannot see that we would remove task dependencies or criteria from Cake. I appreciate the ideas, but I'm extremely reluctant to include two execution models that are not compatible with each other.
I like the idea of workflows though, and I can see a benefit from them if they respect task dependencies and criteria, which would make them a new kind of mechanism for task execution. This way we could accomplish what you propose simply by not specifying dependencies or criteria for a task. This is the only option I see since we don't want to deprecate the current functionality or ignore it.
I'm sorry if I sound negative, but it's so easy to add stuff and so difficult to remove them. I've already made that mistake in this project so I'm trying to avoid another one. Especially something that would affect core functionality.
We could add a new issue for this and continue the discussion since this issue has been a little bit derailed 😄
from cake.
Rather than baking a different workflow in you could simply create a ExecuteTask
alias. Then
Target("Default")
.Do("Clean");
.Then("UpdateAssemblyInfo")
.Then("Build")
.Then("Package");
Would be
Task("Default")
.Does(() => {
ExecuteTask("UpdateAssemblyInfo");'
ExecuteTask("Build");
ExecuteTask("Package");
}
I am not sure, but if Does have an overload which accepts a task you can do parallel with:
Task("Default")
.Does(async () => {
ExecuteTask("UpdateAssemblyInfo");'
await Task.WhenAll(ExecuteTaskAsync("Build"), ExecuteTaskAsync("Build"));
ExecuteTask("Package");
}
I agree that cake should not move away from the graph approach it has now, that way the engine can add parallelism down the track without changing build scripts.
from cake.
I ran into a bug today in my project that is related to the way the dependency graph works today. It is a great point of contention for me and my team on how to write scripts because of this.
For example I have a script that has the following targets:
Task("restore").Does(() => { //restore code });
Task("build-sources").Does(() => { //build code });
Task("get-translations").Does(() => { // get translation code} );
Task("run-tests").Does(() => { //run tests });
Task("zip-artifacts").Does(() => { // zipping code });
I then have 2 rollup tasks to generate the graph:
Target("build")
.IsDependentOn("restore")
.IsDependentOn("get-translations")
.IsDependentOn("build-sources")
.IsDependentOn("run-tests")
.IsDependentOn("zip-artifacts");
Target("cc")
.IsDependentOn("restore")
.IsDependentOn("get-translations")
.IsDependentOn("build-sources")
.IsDependentOn("run-tests");
The problem came in when somebody on my team asked "Why don't the core tasks have IsDependentOn() calls?". And, then went about adding them into the tasks. During this he added a
Task("get-translations")
.IsDependentOn("build-sources")
.Does(() => { //some stuff here });
This changed the call order from:
restore -> get-translations -> build-sources -> run-tests -> zip-artifacts
To:
restore -> build-sources -> get-translations -> run-tests -> zip-artifacts
Which caused builds for the last 2 weeks to go out the door with stale translations. What I expected should happen was a cyclical dependency error, but I suppose cake doesn't get that info from the IsDependentOn() calls for the build target.
TLDR; I would prefer a cleaner dependency graph solution to whats offered now. And, many of the ideas floating in this issue remind me of how FAKE does it. I think Cake would benefit greatly from ripping out the old system and replacing it with a clear dependency structure.
from cake.
@rbutcher We will not change this behavior.
First it would be a massive breaking change and second is that FAKE is actually the tool that does this differently. The "normal" way that people coming from a Make, Rake or MSBuild background would expect is to define targets and their dependencies, not the explicit execution order.
I opened this issue to provide an alternative to the default way of building the dependency graph, for simple scenarios.
from cake.
Related Issues (20)
- Bug with InspectCodeSettings parsing in InspectCodeRunner on Linux (and probably MacOS)
- Cake.Build doesn't generate description for nuget and non-sdk projecs HOT 1
- MSBuild properties are incorrectly formatted HOT 2
- SignTool error when /fd parameter is not provided
- Update NuGet.Packaging to 6.8.1 HOT 1
- Update NuGet.* to 6.9.1
- Update xunit to 2.7.0
- Update Verify.Xunit to 23.5.2
- Update Microsoft.NET.Test.Sdk to 17.9.0
- Update Basic.Reference.Assemblies.* to 1.5.0
- Update Microsoft.CodeAnalysis.CSharp.Scripting to 4.9.2
- Update Autofac to 8.0.0
- Github action with sparse checkout causes cake Gitversion to crash
- Update Cake.Tool to support running on FreeBSD HOT 2
- `InspectCode` calls the exe file even on Linux, where it doesn't work HOT 1
- Unhandled exception: System.IO.IOException: Access to the path '...\build\tools\.store\.stage\ftb2snwd.f5x' is denied. HOT 1
- IProcess WaitForExit(int) does not just observe whether the process has exited, it will kill a running process HOT 3
- FakeFileSystem throws on linux, when it is created on a Windows FakeEnvironment HOT 1
- When running multiple targets, common dependent tasks are executed twice HOT 1
- Github Actions: UploadArtifact does not result in uploaded artifact HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cake.