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

When using an imported user-defined functions that calls other udf and uses ternary ifs, deployment fails #12542

Closed
GABRIELNGBTUC opened this issue Nov 24, 2023 · 1 comment · Fixed by #12575
Assignees
Labels
bug Something isn't working
Milestone

Comments

@GABRIELNGBTUC
Copy link

Bicep version
Bicep CLI version 0.23.1 (b02de2d)
Describe the bug
When using imported user-defined functions calling other functions that are not explicitly imported in the import statement. It seems that the deployment can fail if the nested functions are being used inside a ternary if and that they are not imported

To Reproduce

main.bicep

import {getSubnetNumber, isWindows} from 'types.bicep'

param plan_name string = 'plan-name-001'

var subnet_number = getSubnetNumber(plan_name)

var formatted_subnet_name = '${isWindows(plan_name)}${subnet_number}'

output out string = formatted_subnet_name

types.bicep

@export()
func getPlanNumber(hostingPlanName string) string => substring(hostingPlanName, length(hostingPlanName) - 3)

@export()
func isFirstPlan(planNumber string) bool => planNumber == '001'

@export()
func isOneLeadingZero(planNumber string) bool => substring(planNumber, 0, 1) == '0'

@export()
func isTwoLeadingZeroes(planNumber string) bool => substring(planNumber, 0, 2) == '00'

@export()
func getSubnetNumber(plan_name string) string => isFirstPlan(getPlanNumber(plan_name)) ? '' : (isTwoLeadingZeroes(getPlanNumber(plan_name)) ? substring(getPlanNumber(plan_name), 2, 1) : (isOneLeadingZero(getPlanNumber(plan_name)) ? substring(getPlanNumber(plan_name), 1, 2) : getPlanNumber(plan_name)) ) 

@export()
func isWindows(hostingPlanName string) string => contains('-windows-', hostingPlanName) ? 'ASPWindows' : 'ASP'

When attempting a deployment with the provided main.bicep, the deployment fails with the error:

{"code": "InvalidTemplate", "message": "Deployment template validation failed: 'The template function '__bicep.getPlanNumber' is not found. Please see https://aka.ms/arm-syntax-functions for usage details.'.", "additionalInfo": [{"type": "TemplateViolation", "info": {"lineNumber": 97, "linePosition": 406, "path": "properties.template.functions[1].members.getSubnetNumber.output.value"}}]} 

if you modify the import statement to import all functions that are used by getSubnetNumber and isWindows, attempting to deploy the template will then succeed.

//main.bicep
import {getSubnetNumber, isWindows, getPlanNumber, isFirstPlan, isOneLeadingZero, isTwoLeadingZeroes} from 'test.module.types.bicep'

param plan_name string = 'plan-name-001'

var subnet_number = getSubnetNumber(plan_name)

var formatted_subnet_name = '${isWindows(plan_name)}${subnet_number}'

output out string = formatted_subnet_name

Both templates compile with the build command but only the last works in a deployment.

Additional context
The reason I believe the issue is linked to the ternary if is because I do not get the issue when nesting functions directly

Example:

@export()
func a(input) => b(input)
func b(input) => c(input)
func c(input) => uniqueString(input)

In this situation, calling a(input) does not cause any issues.

@jeskew
Copy link
Contributor

jeskew commented Nov 27, 2023

Thanks for reporting! This should be addressed in the next release.

@jeskew jeskew self-assigned this Nov 27, 2023
@jeskew jeskew added bug Something isn't working and removed Needs: Triage 🔍 labels Nov 27, 2023
@jeskew jeskew added this to the v0.24 milestone Nov 27, 2023
harshpatel17 pushed a commit that referenced this issue Nov 28, 2023
Resolves #12542 

The logic that replaces references in imported types, variables, and
functions is not currently handling UDF calls within UDF calls, e.g.,

```bicep
func foo(input string) => input

@export()
func bar(input string) => foo(foo(input))
```

In the definition of `bar`, the outer `foo` would be migrated (i.e., it
would refer to a UDF in a closure namespace (`_1.foo`)), but the inner
`foo` would not (i.e., it would refer to a UDF in the `__bicep`
namespace).
###### Microsoft Reviewers: [Open in
CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/12575)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants