Skip to content
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

Add underscore to js evaluation to allow for use of get() #83

Merged
merged 6 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/backstage/catalog-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ apiVersion: backstage.io/v1alpha1
kind: API
metadata:
description: The incident.io public API
name: api-incident-io
namespace: default
spec:
definition:
Expand Down
8 changes: 4 additions & 4 deletions docs/backstage/pipelines/entries.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,18 @@
type_name: 'Custom["BackstageAPI"]',
source: {
filter: '$.apiVersion == "backstage.io/v1alpha1" && $.kind == "API"',
name: '$.metadata.name',
external_id: '$.metadata.namespace + "/" + $.metadata.name',
name: '_.get($.metadata, "name", "default API name")',
external_id: '_.get($.metadata, "namespace", "default description") + "/" + _.get($.metadata, "name", "default API name")',
aliases: [
'$.metadata.name',
'_.get($.name, "name", "default alias")',
],
},
attributes: [
{
id: 'description',
name: 'Description',
type: 'Text',
source: '$.metadata.description',
source: '_.get($.metadata, "description", "default description")',
},
{
id: 'api_type',
Expand Down
11 changes: 11 additions & 0 deletions docs/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ The following expressions would evaluate to:
- `$.runbooks` → `["https://github.com/incident-io/runbooks/blob/main/website.md"]`
- `$.runbooks[0]` → `https://github.com/incident-io/runbooks/blob/main/website.md`


You can also use `get` to evaluate nested fields that may be null.
For the example entry above, the following expressions would evaluate to:

- `_.get($.metadata, "name")` → `null`
- `_.get($.metadata, "name", "default name")` → `default name`
- `_.get($.details, "alias")` → `null`
- `_.get($.details, "alias", "default alias")` → `default alias`
- `_.get($.details, "description")` → `Marketing website`


## Migrating from CEL

As shown above, the main difference between CEL and JavaScript is that your
Expand Down
23 changes: 18 additions & 5 deletions expr/js_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,23 @@ import (

"github.com/pkg/errors"
"github.com/robertkrimen/otto"
underscore "github.com/robertkrimen/otto/underscore"
)

var vm *otto.Otto

func init() {

underscore.Enable()

// Create a Javascript virtual machine that we'll use for evaluating the source
// expression. We must be very careful: this is executing code on behalf of others, so
// comes with all normal warnings.
vm = otto.New()
vm.Interrupt = make(chan func(), 1)

}

// EvaluateJavascript can evaluate a source Javascript program having set the given
// subject into the `$` variable.
func EvaluateJavascript(ctx context.Context, source string, subject any) (result otto.Value, err error) {
Expand All @@ -24,11 +39,9 @@ func EvaluateJavascript(ctx context.Context, source string, subject any) (result
}
}()

// Create a Javascript virtual machine that we'll use for evaluating the source
// expression. We must be very careful: this is executing code on behalf of others, so
// comes with all normal warnings.
vm := otto.New()
vm.Interrupt = make(chan func(), 1)
if vm == nil {
panic("Javascript virtual machine not initialised")
}

// Start a new function bounded context.
ctx, cancel := context.WithCancel(ctx)
Expand Down
7 changes: 7 additions & 0 deletions expr/js_eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ var _ = Describe("Javascript evaluation", func() {
Expect(evaluatedResult).To(Equal(sourceEntry["metadata"].(map[string]any)["namespace"]))
})

It("handles possible null values with _.get", func() {
nestedSrc := "_.get($.metadata, \"badKey\", \"default value\")"
evaluatedResult, err := EvaluateSingleValue[string](ctx, nestedSrc, sourceEntry)
Expect(err).NotTo(HaveOccurred())
Expect(evaluatedResult).To(Equal("default value"))
})

When("parsing array values", func() {
It("returns an error if the input is not an array", func() {
topLevelSrc := "$.name"
Expand Down
2 changes: 1 addition & 1 deletion reconcile/entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func Entries(ctx context.Context, logger kitlog.Logger, cl EntriesClient, catalo
}
}

logger.Log("msg", fmt.Sprintf("found %d entries that need updated", len(toUpdate)))
logger.Log("msg", fmt.Sprintf("found %d entries that need updating", len(toUpdate)))

g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10)
Expand Down
Loading