-
Notifications
You must be signed in to change notification settings - Fork 162
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
feat: add low-level expression language support #2826
Conversation
✅ Deploy Preview for docs-kargo-io ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2826 +/- ##
==========================================
+ Coverage 48.79% 49.02% +0.23%
==========================================
Files 270 271 +1
Lines 23962 24010 +48
==========================================
+ Hits 11692 11772 +80
+ Misses 11639 11598 -41
- Partials 631 640 +9 ☔ View full report in Codecov by Sentry. |
Signed-off-by: Kent Rancourt <kent.rancourt@gmail.com>
bb17d72
to
2d44f13
Compare
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.
This looks like you are off to a great start. I have no real objections to anything, and it quite perfectly matches what I had envisioned the functionality to look like.
My only minor nit based on your "future" example would be to consts
-> const
, as I can see myself mistyping the former frequently. The fluent API then also becomes nicer, as you can refer to const.myValue
.
Also: tiny suggestion attached at the bottom.
Co-authored-by: Hidde Beydals <hiddeco@users.noreply.github.com>
This PR adds a new
expressions
package, which currently exports just one useful function --EvaluateJSONTemplate()
. This will take an array of bytes, evaluate them, and return the evaluated bytes.The idea is that as we continue to build out expression language support in promotion steps, this can be called by an
Engine
implementation to pre-process the raw config for each step.This is all accomplished with a combination of fasttemplate and expr-lang, similar to how Argo Workflows does.
Our implementation varies a bit from Argo Workflows' in some key ways.
We use
${{ }}
to offset expressions. This was chosen for the sake of being more similar to GitHub Actions, with which many users are already familiar.We don't process the JSON in one shot because I wished to avoid expressions being used in keys. We unmarshal JSON into a
map[string]any
and recurse over that, treating any string value containing${{
as a mini-template.We can play nicely with all valid JSON types.
For a template to be valid and thus transmissible as a
*apiextensionsv1.JSON
, expressions must be enclosed within quotes. If you do not unmarshal the JSON template into a map first and simply evaluate all${{ }}
in the raw JSON, the surrounding quotes will always remain, making it impossible to use expressions to construct values of other JSON types. i.e. You're stuck with string values only.By unpacking the template into a map, recusing over it as we do, and inspecting the result, we avoid this limitation. This means that an expression like
${{ 42 }}
correctly evaluates as a JSONnumber
and${{ true }}
correctly evaluates as a JSONboolean
. In the event that you wish to force an evaluated expression to be treated like astring
, you can do something like:${{ quote(42) }}
.All of the above should be intuitive to anyone who has worked with YAML before where anything that resembles a number or boolean is inferred to be such unless explicitly quoted.
Intended usage will (after a few follow-ups) be something along these lines:
An interesting dimension to this is that the promotion template begins to look sufficiently generic that it could be useful in the not-too-distant-future to create a top-level
PromotionTemplate
CRD (and maybeClusterPromotionTemplate
, too) so Stages that all follow the same generic recipe can reference that recipe instead of repeating it.