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

WIP: input tracking #5496

Draft
wants to merge 46 commits into
base: main
Choose a base branch
from
Draft

WIP: input tracking #5496

wants to merge 46 commits into from

Conversation

stefreak
Copy link
Member

@stefreak stefreak commented Nov 29, 2023

What this PR does / why we need it:

  • Input tracking, to allow excluding inputs in a future PR
  • Separate parsing template strings from evaluating template strings by generating an AST in the parser
  • Implement lazy evaluation
  • implement a proxy so we avoid changing too much existing code that uses templates

Todo:

  • Integrate all that with the existing code base (Parsing, validating and processing configs)

Special notes for your reviewer:

value: v.value,
inputs: {
// key might be something like ["var", "foo", "bar"]
// We also add the keypath to get separate keys for ever
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// We also add the keypath to get separate keys for ever
// We also add the keypath to get separate keys for every leaf

}
}

relevantValues.forEach((r) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should see if we can add this linter rule to our setup: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/array-foreach.md

The reasons for why are well explained in the link.

constructor(
loc: Location,
public readonly condition: TemplateExpression,
public ifTrue: TemplateExpression,
Copy link
Member Author

@stefreak stefreak Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ifTrue is also optional actually, for example for this expression it would be undefined: ${if ...}{else}Hello world{endif} (It would be undefined because there are no expressions for the then case between the if and the else)

Would be good to add tests for these cases

)
}

return mergeInputs(transformed, left, right)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to merge inputs for concatenating arrays. We likely should skip this step for collections.

})
}

return new TemplateLeaf({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wipes the inputs of the inner expression;
We need to actually:

Suggested change
return new TemplateLeaf({
return inner

if (v instanceof LazyValue) {
return new MergeInputsLazily(this.source, v, unwrappedRelevantValues)
}
return mergeInputs(this.source, v satisfies TemplateLeaf<TemplateLeafValue>, ...unwrappedRelevantValues)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible infinite recursion if unwrappedRelevantValues is a collection that contains lazy values?

} else if (allowInvalid) {
return spec
// we shouldn't throw
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need allowInvalid? Why does it exist?

@@ -335,8 +336,7 @@ export const projectSchema = createSchema({
),
defaultEnvironment: joi
.environment()
.allow("")
.default("")
.default((parent) => parent.environments[0].name)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.default((parent) => parent.environments[0].name)
.default((parent) => parent.environments?.[0]?.name || "")

stefreak and others added 2 commits December 13, 2023 15:28
Co-authored-by: Thorarinn Sigurdsson <thorarinnsigurdsson@gmail.com>
Co-authored-by: Tim Beyer <TimBeyer@users.noreply.github.com>
Co-authored-by: Tim Beyer <TimBeyer@users.noreply.github.com>
Co-authored-by: Thorarinn Sigurdsson <thorarinnsigurdsson@gmail.com>
defaultPath: defaultVarfilePath,
})

const environmentConfigContextVariables = new LayeredContext(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need tests for some edge cases here:
e.g.

variables:
  my
    deep:
      structure: foo

with override
variables.other.deep.structure: bar

message = res.message
partial = !!res.partial
} else {
// TODO: improve error message
throw new ConfigurationError({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of error, it should just result in a plain object with all the values the context contains.

opts: {
...opts,
// Throw an error if we can't find the value in the last layer, unless allowPartial is set
allowPartial: isLastLayer ? opts.allowPartial : false,
Copy link
Member Author

@stefreak stefreak Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary; If we do not find anything, we return CONTEXT_RESOLVE_KEY_NOT_FOUND instead of throwing.

Comment on lines +16 to +18
// In the future we might
// const varsFromFirstConfig = firstConfig.atPath("var") // can contain lazy values
// const actionConfigWithVars = actionConfig.merge(firstConfig)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// In the future we might
// const varsFromFirstConfig = firstConfig.atPath("var") // can contain lazy values
// const actionConfigWithVars = actionConfig.merge(firstConfig)

abstract visitAll(): TemplateExpressionGenerator
}

export class OverrideKeyPathLazily extends LazyValue {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially not needed?

stefreak and others added 2 commits December 14, 2023 13:25
Co-authored-by: Thorarinn Sigurdsson <thorarinnsigurdsson@gmail.com>
Co-authored-by: Tim Beyer <TimBeyer@users.noreply.github.com>
context: ConfigContext,
opts: ContextResolveOpts
): Record<string, CollectionOrValue<TemplateValue>> {
// Resolve $merge keys, depth-first, leaves-first
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Resolve $merge keys, depth-first, leaves-first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants