-
-
Notifications
You must be signed in to change notification settings - Fork 634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Roadmap to v4 #703
Comments
Anybody is free to comment here about what you expect for v4. The community feedback was always taken into account in the project. 🙂 Some things are still missing, and even the ones mentioned above won't necessarily be implemented. |
@andreynering please help me understand why you do not want breaking changes on v4. Fundamentally, the point of a major version bump is to allow changes that would otherwise be disruptive to occur. Non-breaking changes can & should continue on |
@ghostsquad It's not that breaking changes are disallowed, but I want to avoid them unless necessary. For example, I noticed you renamed some attributes on your PoC branch ( Please, let me know if you disagree, I'm open to hear opinions! But I think the above is what most users would expect. If users have to rewrite all tasks, that would prevent many of them to upgrade to v4, the kind of situation I want to avoid. |
@ghostsquad Changing a bit the subject... can you describe how to you see the lazy variables working? Maybe a couple of simple examples? I'm curious to see what is coming. 🙂 That's a situation where a slightly different syntax may be allowed if we have big improvements in that area, as variables/envs always had it shortcomings. Even though, if it was possible to keep the syntax mostly the same, that would certainly have the benefit of helping people to upgrade. |
A common misconception is that naming things doesn't matter. In fact, well named fields and values make a ton of difference. So this renaming is a feature. https://levelup.gitconnected.com/how-choosing-better-names-can-improve-your-code-31a0050c6c93 https://blog.thecodewhisperer.com/permalink/a-model-for-improving-names http://arlobelshee.com/tag/naming-is-a-process/
I am thinking about this as well, and in fact, in some cases I have been considering some backwards compatibility (at the expense of not having access to new features without an additional change). Additionally, like with Kubernetes, since task v3 has a yaml schema, I'm looking at a schema translation mechanism, so that I can write a tool to allow a user to rewrite their v3 Taskfile into v4 format automatically.
My initial testing uses a concept of type Lazy[T any] struct {
new func() (T, error)
once sync.Once
value T
err error
}
func (l *Lazy[T]) SetNew(fn func() (T, error)) {
l.new = fn
}
func (l *Lazy[T]) Eval() (T, error) {
l.once.Do(func() {
if l.new != nil {
v, err := l.new()
l.value = v
l.err = err
l.new = nil // so that f can now be GC'ed
}
})
return l.value, l.err
} a Lazy Var looks like this: func newLazyVar(txtVal string, tplData *TplData) *lazy.Lazy[any] {
tpl := template.New("")
template.Must(tpl.Parse(txtVal))
return lazy.New[any](func() (any, error) {
buf := bytes.NewBuffer([]byte{})
err := tpl.Execute(buf, tplData)
if err != nil {
return nil, err
}
return buf.String(), nil
})
} The type TplData struct {
v map[string]*lazy.Lazy[any]
}
func (t *TplData) V(key string) (any, error) {
return t.v[key].Eval()
} and some initial experimental tests looked like this: at 12:31:18 ❯ go run ./cmd/taskv4/main.go '{{printf "%s-%s" (.V "var2") (.V "var2")}}' 'bar'
V: var1
(string) (len=7) "bar-bar"
(interface {}) <nil>
V: var2
(string) (len=3) "bar"
(interface {}) <nil>
at 12:31:32 ❯ go run ./cmd/taskv4/main.go 'bar' '{{printf "%s-%s" (.V "var1") (.V "var1")}}'
V: var1
(string) (len=3) "bar"
(interface {}) <nil>
V: var2
(string) (len=7) "bar-bar"
(interface {}) <nil> There's extra information in this output, because here's the evaluation loop I'm using for my experiments: for k, v := range tplData.v {
fmt.Printf("V: %s\n", k)
spew.Dump(v.Eval())
} Layers are like In this way, a variable can access any other variable adjacent to it (same layer) and any variable in lower layers. Allowing for the same type of functionality we currently have with saying You can see that how variables are called though is slightly different. But if the field, such as Because variables are lazy, they are only ever evaluated if they are actually used. This is actually really great I think for I'm still working on a way to detect circular references in order to avoid a confusing panic: at 12:28:02 ❯ go run ./cmd/taskv4/main.go '{{printf "%s-%s" (.V "var2") (.V "var2")}}' '{{ .V "var1" }}'
V: var1
fatal error: all goroutines are asleep - deadlock!
<and a 100+ line stack trace> |
For further clarification that in fact order of declaration of variables actually doesn't matter, here's another example: for _, v := range []string{"1", "2", "3"} {
varName := "var" + v
fmt.Printf("evaluating %s\n", varName)
spew.Dump(tplData.v[varName].Eval())
} at 13:05:11 ❯ go run ./cmd/taskv4/main.go '{{.V "var3"}}' '{{printf "%s-%s" (.V "var1") (.V "var1")}}' 'hello'
evaluating var1
(string) (len=5) "hello"
(interface {}) <nil>
evaluating var2
(string) (len=11) "hello-hello"
(interface {}) <nil>
evaluating var3
(string) (len=5) "hello"
(interface {}) <nil> Noticing that |
I'm not sure how helpful "I would like these things" is, but given your question, I've made a brief list below. For context, I'm a huge fan of Taskfile; we now use it extensively at my company, and in some of the OSS projects I manage. I've been a sponsor for a few months (with no expectations ofc).
Thank you again! Footnotes
|
There's https://github.com/nektos/act which is designed to run your the GitHub workflow locally. That's probably the closest you are going to get there. Regarding managing complexity/differences in general between GHA and what's in Task... I'm tackling this problem as well, and I've found that it's best to actually treat a GitHub actions workflow just like you would treat a developer sitting next to you. Can you give me some examples of what you find yourself duplicating between GHA and Task?
Me too. The thing to consider with docker is the "environment" changes (inside vs outside of a container) as well as the ability to pass data around. Systems like GHA and ConcourseCI have developed a nice abstraction in the form of an ephemeral filesystem that transparently follows you around. Task is not as sophisticated (yet).
Time to go take a look there to get some more data. Can you describe specifics about what you like with |
This is interesting. I think this is a similar abstraction in fact to running specific tasks in docker. Both of these things kind of feel like we need the decorator design pattern. I'll go take a look at watchexec and the issue specifically you linked. |
Thanks for the response @ghostsquad
Yeah, I've found just mapping the working directory as a volume can solve most problems here (though maybe there are problems I'm less familiar with)
Great —
In the most trivial case, I have a task to build assets that's defined in both the Taskfile and the GHA workflow. (They are slightly different, but that supports my point that the divergence here is awkward!). It's obv not the fault of Taskfile that services like GHA & GitLab have proprietary formats.
Thanks, this looks cool, I'll try it! |
I've been thinking about ways to add wildcards to task calls recently. I don't think it's a breaking change but this could be a good feature candidate in I'm working in a monorepo where we have a lot of different project folders. We try to structure each project's taskfiles so they all have common workflow tasks like version: 4
includes:
backend_proj:
taskfile: "backend/Taskfile.yml"
frontend_proj:
taskfile: "frontend/Taskfile.yml"
tasks:
build:
cmds:
# runs all `build` tasks in all included files
- task: *:build
clean:
cmds:
# runs all `clean` tasks in all included files (recursive)
- task: **:clean To me it would be useful to use an
I think we could do this by refactoring the type
I'm definitely trying this. Thanks for posting!
Renaming things to me feels like a natural progression of the tool. Maybe some criteria can be set around what we choose to rename and why. If there are features we can try to re-frame to be more intuitive I'm all for it. And as @ghostsquad mentioned, there's always the idea of writing a migration tool. |
Why not just call |
I was thinking of doing this similar actually to the way https://web.mit.edu/gnu/doc/html/make_10.html#SEC91
Though, I'm sure there are considerations where, in a Depth-first approach, you want FIFO (so start at the bottom, and work your way towards the current file) or possibly LILO (start closest, and move backwards). I'll have to play around with what makes sense as a default, and how one may choose to configure this. |
Ya I think when I land on something I really like, I can work on a "migration.md" document, that can explain some of the design rationale, and reasons for renaming. I'd like to also just make a |
I'll expand on this a bit:
|
I haven't looked into this in depth, but I've found https://github.com/code-lever/asdf-rust There will be some very minor drift, such as "well how do I install ASDF". On Mac,
Similar to GHA - The solution if you want to save time/bandwidth is by declaring the use of a pre-built image that contains tools pre-installed. This is a time/complexity trade off. Complexity is low if you install at runtime. Complexity goes up when you need to decide to build a new image (your toolset changes), and plumb that new version into the workflow. I'll leave this as an exercise for you decide on.
Sounds like those OSS projects need better documentation. The very nature of
Focus on what you need to do to get up and running on your developer machine. Run those same processes (more or less) on GHA/GitLab. Task becomes your abstraction. You may still end up running specific GHA/Gitlab features, such as |
I don't mean to use this issue to go into lots of detail on my specific issues, but I think about some of these issues differently:
|
@max-sixty I'd like to refocus on the problem that you mentioned.
This problem, and even the possible solution you mention describes that of an https://www.silasreinagel.com/blog/2018/10/30/indirection-is-not-abstraction/ The hard part is to identify the "overlap" that is desirable, and the risk involved in maintaining the disparate parts. **Note: yes, you can run multiple parallel docker containers in your CI without using your CI's If you find yourself keeping duplicating code within your CI |
One last thing to mention, is that you said that you were already using |
Great, I think we agree there are tradeoffs in generalizing from two modes to the intersection's one mode. If we can lower those costs, then great. Those costs are high enough at the moment that I often write everything twice, despite being a loyal cheerleader for Task. Maybe we disagree on those costs — though I notice that task uses native runners for most of its GHA too: 1, 2. I'd be most persuaded by real examples of this done well.
I think I must have been unclear — I mean "very few" like "almost never" :)
|
I do agree that more examples, use cases, best/recommended practices need to be documented. I will be working on that in v4.
Oh, well then, ignore that then! 😄
The introduction of a task runner is a feature, not a bug. Sometimes people don't do this in their own projects, or wait until later to do it because their build is already very simple. Example, if |
I still don't think we should rename attributes without a good reason. These are the suggestions from the PoC branch:
I don't think the suggestions are necessarily better than the current names. Even though I admit some are a slightly improvement over before, the current ones are actually fine (and naming is also a bit of personal preference). Doing that would mean that basically all core attributes would be renamed, and I can see that being a big frustration to users. They would need to rewrite their entire Taskfiles, they would need to re-learn a whole new schema (they are already used to the current one), the entire documentation would need to be rewritten, etc. I see a possible automatic conversion as a non-ideal thing: it could not always work (the variable syntax will be different, and that's something it probably wouldn't be able to fix: It would also make the implementation itself more difficult. If we mostly add new attributes, we can iterate over the current And again, it's not that breaking changes are not allowed, but I really want to avoid them when they don't bring enough benefits. I hope you understand the reasoning. 🙂 My goal is to be practical and to both reduce the amount of work we need to do in order to reach the objective and also reduce the friction for users to upgrade and keep using their Taskfiles. |
I very much agree with Andrey. Please do not rename the attributes to the
ones proposed.
While renaming can be good, it must be better in describing its function
than the original name.
You would normally write down the description first and then decide which
name best describes it.
An example would be the deps attribute vs the needs. Needs does not really
convey some of the contextual or positional information that deps does.
When we say a task needs this VS a task depends on this. A need could be
seen as a task that might be needing something in perhaps the very last command, whereas
a dependancy of a task you just know it must be handled first.
|
Strong agree here. Renaming properties such as Adopting a major version update may require users and tools to handle some number of breaking changes, thats ok, thats why we have major versions. But, I really think it is important that the value a given change gives in the long run should not only match, but outweigh the cost you are forcing the use to pay up front to adopt the change. I quite like some of the new names, I'm just not seeing them make that much of a positive change in my future use of Task that I would be ok with having to commit updated versions of all of my Taskfiles. |
Task1 needs Task2 I suppose Regarding other renames. I suppose I should verbalize why I want to rename them.
Ok but let's assume I don't change the field names, I may still end up changing their value types in order to allow for the functionality I need. I'm still considering how/when to allow the schema to accept just a plain string (as a shortcut) vs object. Regarding the vscode extension, I've already looked that up. Updating the schema here: To include sub-schemas and conditional logic allows vscode and others to continue to work with v3 and v4 schemas based on the value of the https://json-schema.org/understanding-json-schema/reference/conditionals.html Happy to continue talks. I still have the impression that, as Task has grown organically, it is failing to provide consistency, it's hard to use "intuition" to find an answer (I'm constantly referring to the docs), and there features which many people want which are not backwards compatible. Some of the features I'm working on aim to reduce the amount of stuff you have to write in your Taskfile's as well. So though there may be large task files out there, that might be because of limitations with Task itself. Meaning the burden remains in the user. |
My two cents here, mostly in regards to including multiple Taskfile.yml in a large structure:
default:
cmds:
echo foobat And this: includes:
foobar: ./foobar I want |
Just my 2¢, but I definitely prefer keeping the existing attribute naming conventions. A possible compromise is to add aliases for the existing ones so both will work. My most-wanted breaking change would be to change the order of importance in the variable interpolation rules so that variables passed via the command line (eg, environment vars) take precedence over all. The reason for this is so users have the option to override variables at the command line. My most-wanted non-breaking change is to allow users to re-color log lines (or disable coloring) via ENV variables or possibly a Thanks! |
Ya I may just alias the fields. |
With ENV Vars it's more complicated. If you look at Make, there are several rules for setting an an environment variable value. https://www.gnu.org/software/make/manual/html_node/Setting.html#Setting This functionality is something I sorely miss. I don't necessarily want all vars to be overwritten by the outside, I need choices. |
@ghostsquad I wonder if some nested keywords could help enable this feature. Maybe something like (and I'm just spitballing here): vars:
# static var
FIZZ: buzz
# dynamic var
JAZZ:
sh: echo fuzz
# static var (with expansion)
FOO:
default: bar
expand: {recursive,simple,if_unset}
# dynamic var (with expansion)
GOO:
sh: echo zoo
expand: {recursive,simple,if_unset} |
2022-05-02 UpdateThe syntax I'm working on continues to diverge from task v3. The more I think about how things should work, the more I try to simplify & make this intuitive, and the more posted issues I investigate, the more my design diverges. DivergencesHere's some of the major divergences I'm currently experimenting with: There are issues out there for all these things, but it would take me awhile to link to all them, so I may come back and do this.
|
My general thoughts — as a cheerleader but nothing more — are whether we can move in this direction without overhauling things we know have worked well, even though we won't get all the way right now. For example: it would indeed be good to have parallel tasks. But can we do that with (I like the And ofc if you don't think |
Hey everybody! First of all, sorry for being a bit away. I've been indeed kinda busy recently. @ghostsquad I hope you understand I'm looking for the best to the project, so please don't take it personally 🙂. But I'm a bit worried that you're trying to propose too many changes to the project, and this comes with some drawbacks:
Given the big changes proposed, as an alternative, you could consider a fork or even a brand new project (@max-sixty said a moment before me, but I was about to suggest the same 🙂). There's really no problem in doing that, if you feel like putting the effort into. It could actually make it easier for you to implement your ideas with more freedom. If you prefer to work on Task, you're more than welcome 🙂, but smaller steps is what I propose to make it viable. Some of the principles I tried to explain in this issue are connected with this objective: avoiding breaking changes, iterating on existing code instead of re-writing, having proposals on separate and small PRs to make it easier to discuss in isolation, etc. In short: everybody here has a full time job & life and limited time to dedicate to OSS. This means that to make it manageable (and avoid burnout) we need to be practical. In this context, not implementing every idea, and mostly doing small/backward-compatible iterations, is an intentional decision. |
I believe that everything I'm doing here is being done with respect to this principle. The way I solve problems is by looking at what the end result is, not necessarily how you are getting to that end result. Similar in game design, design elements either support the primary objective/theme, or get in the way. It's important to aggressively cull elements which don't support the primary objective/theme. With that said, I'll also re-iterate that words matter, and readability matters, design principles matter, not only when it comes to understanding how something works, but by intuitively being able to use the tool. The tool should ideally should not get in the way of a user. It should not be the primary focus. It should get a job done, and get out of the way. https://99percentinvisible.org/article/norman-doors-dont-know-whether-push-pull-blame-design/
I can easily say that I'd also like to iterate that I started this because I want to leverage all the creative work and interesting use cases that exist from users of Task. A Major Version bump should allow backwards incompatible affordances if they indeed provide value to users, which is why I started this journey as V4. I understand the pain in "migrating", and would absolutely, 100% be willing to make some sort of migration tool, but it likely wouldn't be exact, because in some or many cases it may be impossible to understand intent of the author from the code itself, but I definitely would try. I also absolutely love the Zen of Python. I use it often when I'm designing something.
Trust me when I say, I've put a LOT of thought into this. 😉
Small/backwards-compatible iterations are well-suited for continuing with V3. I've spent a significant amount of time looking at the code base, the issues that come up, and considering what changes could be done that are actually backwards compatible. I can think of many situations (and have posted in several issues) that result in "can't fix/change, it would not be backwards compatible". That sucks. 😞 |
definitely not taking anything personally @andreynering - as I said, I'm here because Anyways, this has become quite a passion project of mine, because it closely aligns to work I do on a day-to-day basis. I'm an infrastructure automation engineer (some people call it |
I would love there to be a distinction between the kind of information I would propose something like:
Thank you, |
What I am deriving from this request, is "show me the human-readable documentation without the code". Is this accurate? |
Correct. With a suggested implementation approach. |
hello! adding my selfish list of requests:
thank y'all! |
@ivotron the way I've gotten around your second point is to keep tasks in users' home directories and reference them there: includes:
example: ~/.task/Taskfile.yml |
thanks @amancevice. I meant sharing at community level, like ansible's galaxy or homebrew's formulas but for tasks |
oh, ha, yeah that's a great idea |
Hey everyone! 👋 I've been struggling to find enough time to make significant development on a next major version. Because of this, and having in my own mental health in mind, I've decided to close this issue for now, to avoid any expectations that we'll see a v4 soon. What this means is that, in the foresable future, I plan to focus mostly on stability and small features that fit the current v3 version (due to not being backwards incompatible). I may still consider a next major version in the future when I decide it's the right time. When it happens, there's a chance that I reduce its scope to make it easier to ship. I'm grateful for all the support from the community. In particular people that have been opening PRs with small changes have been a huge help to me. Others have been helping answering questions on GitHub or Discord, which also helps a lot. Thank you! |
@andreynering ya, I haven't even had very much time to work on my own implementation. |
Perhaps #852 would be a good inclusion for a future major version? Being able to have a DAG of tasks between different includes (modules) would be awesome to bring this more in line with other build tools. |
Hi everybody,
There were some discussions at #694 with regard to ideas of a possible future major release. GitHub discussions are not too good for these discussions so I decided to open this issue to be more centralized and visible (issues can be pinned).
Also, that probably needs some direction and organization, as having more people involved means we now have different opinions we need to reconcile.
@ghostsquad started working on some ideas on his fork, but I consider that to be a Proof of Concept ™️, and things will likely be different in its final version in the repository.
This issue is a WIP and will be iterated as time passes.
Principles
version: '3'
toversion: '4'
and their Taskfile should keep working mostly the same, with minimal changescmds
to something else, for example. Most changes should be for new featuresversion: '3'
everything should keep working as before, with rare exceptionsversion: '2'
workingSteps
Preparation
Implementation
v3
branchsetup:
and hooks proposals: Add a "setup:" setting to allow running setup scripts before any command? #204, Add task hooks #667, Add setup hook #668This is a ongoing document and will be improved...
The text was updated successfully, but these errors were encountered: