Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fcff18b
Set default values on workflow_dispatch input #1952
jwikman Oct 16, 2025
b68121a
Move workflowInputDefaults setting documentation
jwikman Oct 16, 2025
9934749
Fixes Copilot comments
jwikman Oct 17, 2025
018b008
Enhance ApplyWorkflowInputDefaults to validate choice input with case…
jwikman Oct 17, 2025
dcc40cb
Merge branch 'main' into w/johwik/1952-Set-default-values-on-workflow…
jwikman Oct 17, 2025
13a6644
Merge remote-tracking branch 'upstream/main' into w/johwik/1952-Set-d…
jwikman Oct 17, 2025
7be5ec9
Merge remote-tracking branch 'upstream/main' into w/johwik/1952-Set-d…
jwikman Oct 17, 2025
de397ec
Remove unnecessary blank lines in ApplyWorkflowInputDefaults function…
jwikman Oct 17, 2025
8e6d97a
Remove unnecessary blank line in RELEASENOTES.md
jwikman Oct 17, 2025
e2fe4f1
Remove unnecessary blank line in CheckForUpdates.Action.Test.ps1
jwikman Oct 17, 2025
6b826f2
Consolidate Export-ModuleMember for ReadSettings and SanitizeWorkflow…
jwikman Oct 20, 2025
84f6b53
Move module import to global scope
jwikman Oct 20, 2025
ac3720c
Merge branch 'main' into w/johwik/1952-Set-default-values-on-workflow…
jwikman Oct 20, 2025
2a862c0
Merge remote-tracking branch 'upstream/main' into w/johwik/1952-Set-d…
jwikman Nov 5, 2025
cada39f
Merge remote-tracking branch 'upstream/main' into w/johwik/1952-Set-d…
jwikman Nov 13, 2025
df27829
Rename workflowInputDefaults to workflowDefaultInputs in settings and…
jwikman Nov 13, 2025
3f02f9d
Simplified workflowDefaultInputs setting
jwikman Nov 17, 2025
29b1cd5
Add tests for merging workflowDefaultInputs with duplicate entries
jwikman Nov 17, 2025
2c4bf3c
Merge remote-tracking branch 'upstream/main' into w/johwik/1952-Set-d…
jwikman Nov 17, 2025
f1cee93
Reorganize and clarify Workflow Name Sanitization section in settings.md
jwikman Nov 17, 2025
2511b24
Set default values for workflow inputs in RELEASENOTES.md and update …
jwikman Nov 17, 2025
a8bd32f
Merge remote-tracking branch 'upstream/main' into w/johwik/1952-Set-d…
jwikman Nov 18, 2025
3b94405
Updates after CR
jwikman Nov 18, 2025
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: 1 addition & 0 deletions Actions/.Modules/ReadSettings.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ function GetDefaultSettings
"gitSubmodulesTokenSecretName" = "gitSubmodulesToken"
"shortLivedArtifactsRetentionDays" = 1 # 0 means use GitHub default
"reportSuppressedDiagnostics" = $false
"workflowDefaultInputs" = @()
}
}

Expand Down
17 changes: 17 additions & 0 deletions Actions/.Modules/settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,23 @@
"reportSuppressedDiagnostics": {
"type": "boolean",
"description": "Report suppressed diagnostics. See https://aka.ms/ALGoSettings#reportsuppresseddiagnostics"
},
"workflowDefaultInputs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The name of the workflow input"
},
"value": {
"description": "The default value for the workflow input (can be string, boolean, or number)"
}
},
"required": ["name", "value"]
},
"description": "An array of workflow input default values. See https://aka.ms/ALGoSettings#workflowDefaultInputs"
}
}
}
172 changes: 172 additions & 0 deletions Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,173 @@ function ModifyUpdateALGoSystemFiles {
$yaml.Replace('jobs:/UpdateALGoSystemFiles:/', $updateALGoSystemFilesJob.content)
}

function ApplyWorkflowDefaultInputs {
Param(
[Yaml] $yaml,
[hashtable] $repoSettings,
[string] $workflowName
)

# Check if workflow_dispatch inputs exist
$workflowDispatch = $yaml.Get('on:/workflow_dispatch:/')
if (-not $workflowDispatch) {
# No workflow_dispatch section, nothing to do
return
}

$inputs = $workflowDispatch.Get('inputs:/')
if (-not $inputs) {
# No inputs section, nothing to do
return
}

if ($repoSettings.workflowDefaultInputs.Count -eq 0) {
# No defaults for this workflow
return
}

# Apply defaults to matching inputs
foreach ($default in $repoSettings.workflowDefaultInputs) {
$inputName = $default.name
$defaultValue = $default.value

# Check if this input exists in the workflow
$inputSection = $inputs.Get("$($inputName):/")
if (-not $inputSection) {
# Input is not present in the workflow
continue
}

# Get the input type from the YAML if specified
$inputType = $null
$typeStart = 0
$typeCount = 0
if ($inputSection.Find('type:', [ref] $typeStart, [ref] $typeCount)) {
$typeLine = $inputSection.content[$typeStart].Trim()
if ($typeLine -match 'type:\s*(.+)') {
$inputType = $matches[1].Trim()
}
}

# Validate that the value type matches the input type
$validationError = $null
if ($inputType) {
switch ($inputType) {
'boolean' {
if ($defaultValue -isnot [bool]) {
$validationError = "Workflow '$workflowName', input '$inputName': Expected boolean value, but got $($defaultValue.GetType().Name). Please use `$true or `$false."
}
}
'number' {
if ($defaultValue -isnot [int] -and $defaultValue -isnot [long] -and $defaultValue -isnot [double]) {
$validationError = "Workflow '$workflowName', input '$inputName': Expected number value, but got $($defaultValue.GetType().Name)."
}
}
'string' {
if ($defaultValue -isnot [string]) {
$validationError = "Workflow '$workflowName', input '$inputName': Expected string value, but got $($defaultValue.GetType().Name)."
}
}
'choice' {
# Choice inputs accept strings and must match one of the available options (case-sensitive)
if ($defaultValue -isnot [string]) {
$validationError = "Workflow '$workflowName', input '$inputName': Expected string value for choice input, but got $($defaultValue.GetType().Name)."
}
else {
# Validate that the value is one of the available options
$optionsStart = 0
$optionsCount = 0
if ($inputSection.Find('options:', [ref] $optionsStart, [ref] $optionsCount)) {
$availableOptions = @()
# Parse the options from the YAML (they are indented list items starting with "- ")
for ($i = $optionsStart + 1; $i -lt ($optionsStart + $optionsCount); $i++) {
$optionLine = $inputSection.content[$i].Trim()
if ($optionLine -match '^-\s*(.+)$') {
$availableOptions += $matches[1].Trim()
}
}

if ($availableOptions.Count -gt 0 -and $availableOptions -cnotcontains $defaultValue) {
$validationError = "Workflow '$workflowName', input '$inputName': Value '$defaultValue' is not a valid choice (case-sensitive match required). Available options: $($availableOptions -join ', ')."
}
}
}
}
}
}
else {
# If no type is specified in the workflow, it defaults to string
if ($defaultValue -isnot [string]) {
OutputWarning "Workflow '$workflowName', input '$inputName': No type specified in workflow (defaults to string), but configured value is $($defaultValue.GetType().Name). This may cause issues."
}
}

if ($validationError) {
throw $validationError
}

# Convert the default value to the appropriate YAML format
$yamlValue = $defaultValue
if ($defaultValue -is [bool]) {
$yamlValue = $defaultValue.ToString().ToLower()
}
elseif ($defaultValue -is [string]) {
# Quote strings and escape single quotes per YAML spec
$escapedValue = $defaultValue.Replace("'", "''")
$yamlValue = "'$escapedValue'"
}

# Find and replace the default: line in the input section
$start = 0
$count = 0
if ($inputSection.Find('default:', [ref] $start, [ref] $count)) {
# Replace existing default value
$inputSection.Replace('default:', "default: $yamlValue")
}
else {
# Add default value - find the best place to insert it
# Insert after type, required, or description (whichever comes last)
$insertAfter = -1
$typeLine = 0
$typeCount = 0
$requiredLine = 0
$requiredCount = 0
$descLine = 0
$descCount = 0

if ($inputSection.Find('type:', [ref] $typeLine, [ref] $typeCount)) {
$insertAfter = $typeLine + $typeCount
}
if ($inputSection.Find('required:', [ref] $requiredLine, [ref] $requiredCount)) {
if (($requiredLine + $requiredCount) -gt $insertAfter) {
$insertAfter = $requiredLine + $requiredCount
}
}
if ($inputSection.Find('description:', [ref] $descLine, [ref] $descCount)) {
if (($descLine + $descCount) -gt $insertAfter) {
$insertAfter = $descLine + $descCount
}
}

if ($insertAfter -eq -1) {
# No other properties, insert at position 1 (after the input name)
$insertAfter = 1
}

$inputSection.Insert($insertAfter, "default: $yamlValue")
}

# Update the inputs section with the modified input
$inputs.Replace("$($inputName):/", $inputSection.content)
}

# Update the workflow_dispatch section with modified inputs
$workflowDispatch.Replace('inputs:/', $inputs.content)

# Update the on: section with modified workflow_dispatch
$yaml.Replace('on:/workflow_dispatch:/', $workflowDispatch.content)
}

function GetWorkflowContentWithChangesFromSettings {
Param(
[string] $srcFile,
Expand Down Expand Up @@ -394,6 +561,11 @@ function GetWorkflowContentWithChangesFromSettings {
ModifyUpdateALGoSystemFiles -yaml $yaml -repoSettings $repoSettings
}

# Apply workflow input defaults from settings
if ($repoSettings.Keys -contains 'workflowDefaultInputs') {
ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName $workflowName
}

# combine all the yaml file lines into a single string with LF line endings
$yaml.content -join "`n"
}
Expand Down
43 changes: 43 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
### Set default values for workflow inputs

A new setting `workflowDefaultInputs` allows you to configure default values for workflow_dispatch inputs. This makes it easier to run workflows manually with consistent settings across your team.

When you add this setting to your AL-Go settings file and run the "Update AL-Go System Files" workflow, the default values will be automatically applied to the workflow YAML files in your repository.
The default values must match the input types (boolean, number, string, or choice) defined in the workflow YAML files.

Example configuration:

```json
{
"workflowDefaultInputs": [
{ "name": "directCommit", "value": true },
{ "name": "useGhTokenWorkflow", "value": true }
]
}
```

This setting can be used on its own in repository settings to apply defaults to all workflows with matching input names. Alternatively, you can use it within [conditional settings](https://aka.ms/algosettings#conditional-settings) to apply defaults only to specific workflows, branches, or other conditions.

Example using conditional settings to target specific workflows:

```json
{
"conditionalSettings": [
{
"workflows": ["Create Release"],
"settings": {
"workflowDefaultInputs": [
{ "name": "directCommit", "value": true },
{ "name": "releaseType", "value": "Prerelease" }
]
}
}
]
}
```

**Important:** When multiple conditional settings blocks match and both define `workflowDefaultInputs`, the arrays are merged following AL-Go's standard behavior for complex setting types (all entries are kept). If the same input name appears in multiple entries, the last matching entry takes precedence.

Read more at [workflowDefaultInputs](https://aka.ms/algosettings#workflowDefaultInputs).

### Issues

- Issue 1961 KeyVault access in PR pipeline
Expand All @@ -7,6 +49,7 @@
- Use Runner_Temp instead of GetTempFolder whenever possible
- Issue 2016 Running Update AL-Go system files with branches wildcard `*` tries to update _origin_
- Issue 1960 Deploy Reference Documentation fails
- Discussion 1952 Set default values on workflow_dispatch input

## v8.0

Expand Down
11 changes: 10 additions & 1 deletion Scenarios/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ The repository settings are only read from the repository settings file (.github
| <a id="useGitSubmodules"></a>useGitSubmodules | If your repository is using Git Submodules, you can set the `useGitSubmodules` setting to `"true"` or `"recursive"` in order to use these submodules during build workflows. If `useGitSubmodules` is not set, git submodules are not initialized. If the submodules reside in private repositories, you need to define a `gitSubmodulesToken` secret. Read [this](https://aka.ms/algosecrets#gitSubmodulesToken) for more information. |
| <a id="commitOptions"></a>commitOptions | If you want more control over how AL-Go creates pull requests or commits changes to the repository you can define `commitOptions`. It is a structure defining how you want AL-Go to handle automated commits or pull requests coming from AL-Go (e.g. for Update AL-Go System Files). The structure contains the following properties:<br />**messageSuffix** = A string you want to append to the end of commits/pull requests created by AL-Go. This can be useful if you are using the Azure Boards integration (or similar integration) to link commits to work items. <br />`createPullRequest` : A boolean defining whether AL-Go should create a pull request or attempt to push directly in the branch.<br />**pullRequestAutoMerge** = A boolean defining whether you want AL-Go pull requests to be set to auto-complete. This will auto-complete the pull requests once all checks are green and all required reviewers have approved.<br />**pullRequestMergeMethod** = A string defining which merge method to use when auto-merging pull requests. Valid values are "merge" and "squash". Default is "squash".<br />**pullRequestLabels** = A list of labels to add to the pull request. The labels need to be created in the repository before they can be applied.<br />If you want different behavior in different AL-Go workflows you can add the `commitOptions` setting to your [workflow-specific settings files](https://github.com/microsoft/AL-Go/blob/main/Scenarios/settings.md#where-are-the-settings-located). |
| <a id="incrementalBuilds"></a>incrementalBuilds | A structure defining how you want AL-Go to handle incremental builds. When using incremental builds for a build, AL-Go will look for the latest successful CI/CD build, newer than the defined `retentionDays` and only rebuild projects or apps (based on `mode`) which needs to be rebuilt. The structure supports the following properties:<br />**onPush** = Determines whether incremental builds is enabled in CI/CD triggered by a merge/push event. Default is **false**.<br />**onPull_Request** = Determines whether incremental builds is enabled in Pull Requests. Default is **true**.<br />**onSchedule** = Determines whether incremental builds is enabled in CI/CD when running on a schedule. Default is **false**.<br />**retentionDays** = Number of days a successful build is good (and can be used for incremental builds). Default is **30**.<br />**mode** = Specifies the mode for incremental builds. Currently, two values are supported. Use **modifiedProjects** when you want to rebuild all apps in all modified projects and depending projects or **modifiedApps** if you want to rebuild modified apps and all apps with dependencies to this app.<br />**NOTE:** when running incremental builds, it is recommended to also set `workflowConcurrency` for the CI/CD workflow, as defined [here](https://aka.ms/algosettings#workflowConcurrency). |
| <a id="workflowDefaultInputs"></a>workflowDefaultInputs | An array of workflow input default values. This setting allows you to configure default values for workflow_dispatch inputs, making it easier to run workflows manually with consistent settings. Each entry should contain:<br />  **name** = The name of the workflow input<br />  **value** = The default value (can be string, boolean, or number)<br />**Important validation rules:**<br />  • The value type must match the input type defined in the workflow YAML file (boolean, number, string, or choice)<br />  • For choice inputs, the value must be one of the options declared in the workflow<br />  • Choice validation is case-sensitive<br />Type and choice validation is performed when running the "Update AL-Go System Files" workflow to prevent configuration errors.<br />When you run the "Update AL-Go System Files" workflow, these default values will be applied to all workflows that have matching input names.<br />**Usage:** This setting can be used on its own in repository settings to apply defaults to all workflows with matching input names. Alternatively, you can use it within [conditional settings](#conditional-settings) to apply defaults only to specific workflows, branches, or other conditions.<br />**Important:** When multiple conditional settings blocks match and both define `workflowDefaultInputs`, the arrays are merged (all entries are kept). When the defaults are applied to workflows, the last matching entry for each input name wins.<br />**Example:**<br />`"workflowDefaultInputs": [`<br />` { "name": "directCommit", "value": true },`<br />` { "name": "useGhTokenWorkflow", "value": true },`<br />` { "name": "updateVersionNumber", "value": "+0.1" }`<br />`]` |

<a id="advanced"></a>

Expand Down Expand Up @@ -181,7 +182,9 @@ to your [project settings file](#where-are-the-settings-located) will ensure tha
- **workflows** settings will be applied to workflows matching the patterns
- **users** settings will be applied for users matching the patterns

You could imagine that you could have and organizational settings variable containing:
**Note:** You can use `workflowDefaultInputs` within conditional settings to apply workflow input defaults only when certain conditions are met. For example, you could set different default values for specific workflows or branches.

You could imagine that you could have an organizational settings variable containing:

```json
"ConditionalSettings": [
Expand All @@ -204,6 +207,12 @@ Which will ensure that for all repositories named `bcsamples-*` in this organiza
> [!NOTE]
> You can have conditional settings on any level and all conditional settings which has all conditions met will be applied in the order of settings file + appearance.

<a id="workflow-name-sanitization"></a>

### Workflow Name Sanitization

When matching workflow names for conditional settings, AL-Go sanitizes the actual workflow name before comparison. Sanitization removes invalid filename characters such as leading spaces, quotes, colons, slashes, and other special characters. For example, a workflow named `" CI/CD"` would be sanitized to `"CICD"` for matching purposes.

<a id="expert"></a>

# Expert level
Expand Down
Loading
Loading