#2165: interactive template variables - #2179
Conversation
Coverage Report for CI Build 29803149984Coverage decreased (-0.04%) to 72.439%Details
Uncovered ChangesNo uncovered changes found. Coverage Regressions144 previously-covered lines in 6 files lost coverage.
Coverage Stats
💛 - Coveralls |
| */ | ||
| private String resolveAskExpression(String variableName, boolean secret, AbstractEnvironmentVariables resolvedVars, Object src) { | ||
|
|
||
| if ((this.context == null) || this.context.isBatchMode()) { |
There was a problem hiding this comment.
this.context is set in the constructor: ( line 63)
if (context == null) {
this.context = parent.context; // can be null if the root parent is also null
}
If parent is null and context is null → throw IllegalArgumentException. If parent is not null but parent.context is null... the chain might be null. However, in practice, AbstractEnvironmentVariables is always created via AbstractIdeContext.createVariables() → so a context always exists. While this scenario is unlikely, it is best to include a guard. 👍
| } | ||
|
|
||
| @Override | ||
| public String askForSecret(String message) { |
There was a problem hiding this comment.
In AbstractIdeContext.askForSecret(), an empty input repeats the loop with no feedback. askForInput() has the same behaviour but at least the user can see what they typed. For masked input the user has no idea if they typed nothing or if the terminal swallowed their input. Consider logging a hint like "Empty input — please enter a value" before the next iteration. :)
There was a problem hiding this comment.
@Paras14 and @QuangAnhLe this issue seems to be in team-review for quite a while.
As you already commented in the PR and we discussed in the daily your idea to implement this via #989 as according functions would make more sense and allow a generic and more future-proof solution.
I would really like to avoid that we and potential IDEasy projects start using this ask and secret syntax and we later deprecated it replacing it with @ask function as already suggested and fully making sense.
Maybe it was a misunderstanding in the daily but I thought that someone had already implemented the function syntax and we should therefore use that... I could not find any PR implementing #989 so it seems I got something wrong.
Would you agree that it makes sense to update your PR to implement #989 and using the function syntax @ask (or @ask-variable / @ask-secret if we want to simplify usage and prevent that the secret flag needs to be passed as parameter).
This way almost no work in this PR would be in vain. Most changes are needed anyway.
UPDATE: I have refined #989 and set it as read-to-implement.
| while (true) { | ||
| if (!message.isBlank()) { | ||
| IdeLogLevel.INTERACTION.log(LOG, message); | ||
| } | ||
| if (isBatchMode()) { | ||
| if (isForceMode()) { | ||
| return null; | ||
| } else { | ||
| throw new CliAbortException(); | ||
| } | ||
| } | ||
| String input = readSecretLine().trim(); | ||
| if (!input.isEmpty()) { | ||
| return input; | ||
| } | ||
| } |
There was a problem hiding this comment.
I am not sure if a secret value MUST NOT be empty.
It may be odd but in some test/dev scenarios empty passwords may be used for convenience.
| * "$[ask:MY_VARIABLE]" or "$[secret:MY_VARIABLE]" that will interactively ask the user for the value if the variable is undefined. | ||
| */ | ||
| SQUARE("\\$\\[([a-zA-Z0-9_-]+)\\]") { | ||
| SQUARE("\\$\\[(?:([a-zA-Z0-9_-]+)|(ask|secret):([a-zA-Z0-9_-]+))\\]") { |
There was a problem hiding this comment.
BTW: It is better to have the prefix/function as an optional group without duplicating the variable group like this (and our convention is also to mark opening parenthesis with the according group index for readability):
// ...........1.2...........3
SQUARE("\\$\\[(@([a-z-]+):)?([a-zA-Z0-9_-]+)\\]") {
|
@hohwille Agreed, reworking this around the generic function syntax is the better, more future-proof approach. Most of the existing implementation can still be reused, so the work will not be lost. @QuangAnhLe My suggestion would be to keep #2165 open for now and revisit it once the generic function syntax in #989 is implemented. |
I would implement both #2164 and #989 in this PR so merging it, will close both stories. |
This PR fixes #2165
Implemented changes:
VariableSyntax.SQUAREto additionally match$[ask:VARIABLE]and$[secret:VARIABLE]expressions.IdeContext.askForSecretfor masked console input viaConsole.readPassword.conf/ide.propertiesso they are not asked again.configurator.adocand added tests inEnvironmentVariablesTest.As discussed with @hohwille, the prefix syntax encodes secret vs. plain in the name instead of using function arguments, which aligns it with the $[secret:name] syntax introduced by #2162. A future @function(args) syntax as proposed in #989 can be added as a further alternative in the same regex. Motivated by #412 to preconfigure AI assistant plugins with a backend URL and API key that must not be committed to the settings repository. See also #987.
Testing instructions
Tested on Windows using PowerShell. Strongly recommended to run an actual PowerShell window, as masking needs System.console(), which is null in IDE consoles and when input is piped, and there the input stays visible
with a warning by design.
Build the branch and dump the classpath, from the repository root:
In a test project create IDEasy\settings\workspace\update\ai-test.properties:
Make sure MY_URL and MY_TOKEN are not yet defined in IDEasy\conf\ide.properties.
From the project directory, run the local build:
You are prompted before any downloads: MY_URL with visible input,
MY_TOKEN with hidden(masked) input. Each prompt names the file requiring it.
with no $[...] left, and that both variables were written to
conf\ide.properties exactly as typed.
Run the same command again. You won't get any input prompts this time, the persisted values are reused.
Add MY_OTHER=https://example.com to conf\ide.properties, then add the line
ai.other=$[ask:MY_OTHER] to IDEasy\settings\workspace\update\ai-test.properties.
Run again. There is no prompt, and IDEasy\workspaces\main\ai-test.properties
contains ai.other=https://example.com.
Remove MY_URL and MY_TOKEN from IDEasy\conf\ide.properties and run with --batch.$[ask:...] and $ [secret:...]
No input prompts, but one warning per expression, and the
text is left untouched in the output.
Checklist for this PR
mvn clean testlocally all tests pass and build is successful#«issue-id»: «brief summary»In Progressand assigned to you