-
-
Notifications
You must be signed in to change notification settings - Fork 624
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
A way to enforce required variables #1204
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work @benc-uk! 👏 👏 👏 This is going to be useful.
I added a few simple adjustments to be made before this is ready to be merged. This PR also needs a rebase or merge from main
.
In the meantime, I'll also ask a review from @pd93 just to get a second opinion on the syntax.
requires
looks great. The only disadvantage I can think of is that we may want to implement the very same thing for envs as well. In that case, maybe we could go with...
requires:
vars: [FOO, BAR]
env: [BAZ]
Opinions are welcome.
I've spent most of my career checking for unset env variables at the start of bash scripts so I'd concur it's a common pattern worth applying to binaries as well as environment variables. |
My issue with requires:
vars: [] ...fulfils both the need for specificity, allows us to require other things (like |
Co-authored-by: Andrey Nering <andrey@nering.com.br>
Do you mean checking that various binaries are in the system path? I was considering adding this too, as I've also spent far too much time doing I wanted to see how this initial proposal and change went before adding more features like this |
PR updated with all suggestions, and docs, schema, error codes updated too. The current implementation matches the suggestion, e.g. requires:
vars: [] As for separating check for env vs vars, I'm not sure there's much reason or advantage, as tasks blend the two into a "bag" of variables that can be referenced interchangeably. That's what I'm checking against e.g. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note some reformatting crept in when I saved the file due to my VSCode settings, but the changes looked pretty sensible So I kept them
There's been a lot of confusion in the past over the fact that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked out the code and everything seems to work well. I'm happy with the changes that have been made. It might be nice to add a test either in task_test.go
or create a requires_test.go
, but other than that, it LGTM.
Yes this confused me when I first started using Task, I didn't realize it was a by-product of Go templating. I actually like the flexibility it provides. For example GitHub Actions has very specific syntax I guess what I'm saying is, this is surprisingly hard to get right and find the balance between verbosity and clarity |
Has there been any thought into defining optionality within variable definitions themselves? version: '3'
vars:
NAME:
required: true You could actually take it slightly further and include a version: '3'
vars:
NAME:
required: true
VERSION:
required: false
default: latest (Granted, you can already use the It could also pair nicely with dynamic variables to require that the shell command actually outputs something: version: '3'
vars:
NAME:
sh: find . -type f -name package.json | head -n 1
required: true |
@treybrisbane I actually do quite like your proposed syntax. The only disadvantage I can see is that its quite a bit more verbose (in terms of lines consumed): version: '3'
vars:
FOO:
required: true
BAR:
required: true
tasks:
foo:
cmds:
- ... As opposed to: version: '3'
tasks:
foo:
requires:
vars: ['FOO', 'BAR']
cmds:
- ... However, being able to set variable requirements at a global-level and at task-level is quite powerful and it does keep related stuff together in the definition. I think this is worth considering before releasing. @andreynering @benc-uk WDYT? |
I think this is potentially a good idea, but it doesn't replace the "per task" level required vars, as a project often needs a mix. For example if I'm running Personally I'd add taskfile or global level required vars as a separate PR |
To be clear, I think the syntax proposed by @treybrisbane could be used at a global and a task-level: version: '3'
vars:
FOO:
required: true
BAR:
required: true
tasks:
task-a:
vars:
BAZ:
required: true
cmds:
- ... This Taskfile would always require |
Hi guys, sorry for the long time to respond. I may have some time this week to review and merge. I think I prefer I think this is probably easier to implement as well, and less likely to be a shoot in the foot when v4 comes and we're going to change some things about how variables and envs work. Regarding requiring for all tasks, nothing stops us to allow Looks good @pd93? |
@andreynering Yeah, I'm still fine with this as it is. Just worth considering the alternatives before merging. I do think that adding this at a global-level will be useful at some point, but doesn't need to be now. |
@andreynering Thanks for considering. 🙂 If I may, I'd like to make some final arguments in favour of the approach I suggested: ConsistencyScoping To that point, let's look at vars:
NAME:
sh: whoami It's not a sibling: vars: {}
sh:
NAME: whoami Similarly, we have tasks:
print-full-name:
cmds:
- cmd: echo 'Hayley'
silent: false
- cmd: echo 'Williams'
silent: true
silent: true It's not a sibling: tasks:
print-full-name:
cmds:
- echo 'Hayley'
- echo 'Williams'
silent: [false, true]
silent:
print-full-name: true To me, it naturally follows that vars:
NAME:
required: true Not a sibling: vars: {}
requires:
vars: ['NAME'] ComplexityTask currently has two ways of declaring variables: Introducing In contrast, introducing FlexibilityScoping To that point, I'd like to present the following concepts: vars:
VERSION:
required: false
default: latest vars:
PACKAGE_JSON_PATH:
sh: find . -type f -name package.json | head -n 1
required: true vars:
REQUIRED_BOOLEAN:
type: boolean
required: true
OPTIONAL_NON_NEGATIVE_INTEGER:
type: integer
minimum: 0
required: false
default: 0
REQUIRED_DOUBLE_ARRAY:
type: array
items:
type: double
required: true
OPTIONAL_OBJECT_REQUIRED_FIELDS:
type: object
properties:
name:
type: string
required: true
age:
type: integer
required: true
required: false I want to stress that these are only concepts (not proposals), but my hope is that they illustrate that nesting Ultimately, I think either approach will be a net win for Task. I do feel like the nested approach will be better both now and in the long run, but I won't be sad if you decide to go with the sibling approach. Either way, it'll be nice to declare required variables without needing to use Go templates! 😄 |
As always, there are different opinions on the different possible paths to accomplish something. I value everyone's input, but I'm going to proceed with how it was implemented here. Thanks @benc-uk for your contribution and patience! 🙌 |
Summary
This is an implementation of this proposal #1203
Which is a way for tasks to validate and check required variables prior to running
Adds
A new field called
requires
with a sub-fieldvars
is added to the task struct, this field is an array of strings. These strings should be variable names, and these variables are checked for existence before the task is run. If one or more is found to be missing, the task will not run and an error describing the missing variable(s) is returned.e.g.
I basically copied a lot of what I saw happening in
precondition.go
so this does add another top level filerequires.go
to the project. It only has a single function, so this function could moved elsewhere.Documentation has also been updated