From aa93724f51dd52ac62b89545fa12fa27fd676672 Mon Sep 17 00:00:00 2001 From: Ole Wunschmenn Date: Wed, 19 Nov 2025 20:19:48 +0100 Subject: [PATCH 01/10] Add event 'workflow_call' to workflow 'UpdateGitHubGoSystemFiles' for reusability --- .../workflows/UpdateGitHubGoSystemFiles.yaml | 24 +++++++++++++++++-- .../workflows/UpdateGitHubGoSystemFiles.yaml | 24 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Templates/AppSource App/.github/workflows/UpdateGitHubGoSystemFiles.yaml b/Templates/AppSource App/.github/workflows/UpdateGitHubGoSystemFiles.yaml index ef3ea471bf..93569d88a3 100644 --- a/Templates/AppSource App/.github/workflows/UpdateGitHubGoSystemFiles.yaml +++ b/Templates/AppSource App/.github/workflows/UpdateGitHubGoSystemFiles.yaml @@ -19,6 +19,26 @@ on: description: Specify a comma-separated list of branches to update. Wildcards are supported. The AL-Go settings will be read for every branch. Leave empty to update the current branch only. required: false default: '' + workflow_call: + inputs: + templateUrl: + description: Template Repository URL (current is {TEMPLATEURL}) + type: string + required: false + default: '' + downloadLatest: + description: Download latest from template repository + type: boolean + default: true + directCommit: + description: Direct Commit? + type: boolean + default: false + includeBranches: + description: Specify a comma-separated list of branches to update. Wildcards are supported. The AL-Go settings will be read for every branch. Leave empty to update the current branch only. + type: string + required: false + default: '' permissions: actions: read @@ -117,8 +137,8 @@ jobs: downloadLatest: '${{ github.event.inputs.downloadLatest }}' run: | $errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0 - if('${{ github.event_name }}' -eq 'workflow_dispatch') { - Write-Host "Using inputs from workflow_dispatch event" + if('${{ github.event_name }}' -in 'workflow_dispatch', 'workflow_call') { + Write-Host "Using inputs from ${{ github.event_name }} event" $directCommit = $env:directCommit $downloadLatest = $env:downloadLatest } diff --git a/Templates/Per Tenant Extension/.github/workflows/UpdateGitHubGoSystemFiles.yaml b/Templates/Per Tenant Extension/.github/workflows/UpdateGitHubGoSystemFiles.yaml index ef3ea471bf..93569d88a3 100644 --- a/Templates/Per Tenant Extension/.github/workflows/UpdateGitHubGoSystemFiles.yaml +++ b/Templates/Per Tenant Extension/.github/workflows/UpdateGitHubGoSystemFiles.yaml @@ -19,6 +19,26 @@ on: description: Specify a comma-separated list of branches to update. Wildcards are supported. The AL-Go settings will be read for every branch. Leave empty to update the current branch only. required: false default: '' + workflow_call: + inputs: + templateUrl: + description: Template Repository URL (current is {TEMPLATEURL}) + type: string + required: false + default: '' + downloadLatest: + description: Download latest from template repository + type: boolean + default: true + directCommit: + description: Direct Commit? + type: boolean + default: false + includeBranches: + description: Specify a comma-separated list of branches to update. Wildcards are supported. The AL-Go settings will be read for every branch. Leave empty to update the current branch only. + type: string + required: false + default: '' permissions: actions: read @@ -117,8 +137,8 @@ jobs: downloadLatest: '${{ github.event.inputs.downloadLatest }}' run: | $errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0 - if('${{ github.event_name }}' -eq 'workflow_dispatch') { - Write-Host "Using inputs from workflow_dispatch event" + if('${{ github.event_name }}' -in 'workflow_dispatch', 'workflow_call') { + Write-Host "Using inputs from ${{ github.event_name }} event" $directCommit = $env:directCommit $downloadLatest = $env:downloadLatest } From a2dd4f63301dae60cf9ce1e7eaf6a57ea015107e Mon Sep 17 00:00:00 2001 From: Ole Wunschmenn Date: Wed, 19 Nov 2025 20:54:41 +0100 Subject: [PATCH 02/10] Add event 'workflow_call' to workflow 'UpdateGitHubGoSystemFiles' for reusability --- RELEASENOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2481179bb9..072b98a9d6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -7,6 +7,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 1855 Add trigger 'workflow_call' to workflow 'UpdateGitHubGoSystemFiles' for reusability ## v8.0 From 563a90fe0b0afc9b30de5ec464e12ed5a8f7b534 Mon Sep 17 00:00:00 2001 From: Ole Wunschmann <44057549+OleWunschmann@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:06:36 +0100 Subject: [PATCH 03/10] Apply workflow default inputs to workflow_call inputs (#1) * Apply workflow default inputs to call inputs with matching dispatch inputs * Update teste for action CheckForUpdates * Updated documentation for "workflowDefaultInputs" --- .../CheckForUpdates.HelperFunctions.ps1 | 238 +++--- Scenarios/settings.md | 2 +- Tests/CheckForUpdates.Action.Test.ps1 | 724 +++++++++--------- 3 files changed, 498 insertions(+), 466 deletions(-) diff --git a/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 b/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 index 82a8d5d22e..81a4a89472 100644 --- a/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 +++ b/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 @@ -330,6 +330,9 @@ function ApplyWorkflowDefaultInputs { return } + # Get workflow_call inputs + $workflowCallInputs = $yaml.Get('on:/workflow_call:/inputs:/') + # Apply defaults to matching inputs foreach ($default in $repoSettings.workflowDefaultInputs) { $inputName = $default.name @@ -342,134 +345,161 @@ function ApplyWorkflowDefaultInputs { 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() + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $defaultValue + + # Update the inputs section with the modified input + $inputs.Replace("$($inputName):/", $inputSection.content) + + # Apply the default to workflow_call inputs if present + if ($workflowCallInputs) { + # Check if this input exists in the workflow_call section + $inputSection = $workflowCallInputs.Get("$($inputName):/") + if ($inputSection) { + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $defaultValue + + # Update the workflow_call inputs section with the modified input + $workflowCallInputs.Replace("$($inputName):/", $inputSection.content) } } + } - # 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." - } + # 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) + + # Update workflow_call inputs if present + if ($workflowCallInputs) { + # Update the workflow_call section with modified inputs + $yaml.Replace('on:/workflow_call:/inputs:/', $workflowCallInputs.content) + } +} + +function ApplyWorkflowInputDefaultValue { + Param( + [Yaml] $inputSection, + [object] $defaultValue + ) + + # 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)." - } + } + '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)." - } + } + '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() - } + } + '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 ', ')." - } + 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." - } + } + 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 - } + 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'" - } + # 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 - # 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") + if ($inputSection.Find('type:', [ref] $typeLine, [ref] $typeCount)) { + $insertAfter = $typeLine + $typeCount } - 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 ($inputSection.Find('required:', [ref] $requiredLine, [ref] $requiredCount)) { + if (($requiredLine + $requiredCount) -gt $insertAfter) { + $insertAfter = $requiredLine + $requiredCount } - - if ($insertAfter -eq -1) { - # No other properties, insert at position 1 (after the input name) - $insertAfter = 1 + } + if ($inputSection.Find('description:', [ref] $descLine, [ref] $descCount)) { + if (($descLine + $descCount) -gt $insertAfter) { + $insertAfter = $descLine + $descCount } + } - $inputSection.Insert($insertAfter, "default: $yamlValue") + if ($insertAfter -eq -1) { + # No other properties, insert at position 1 (after the input name) + $insertAfter = 1 } - # Update the inputs section with the modified input - $inputs.Replace("$($inputName):/", $inputSection.content) + $inputSection.Insert($insertAfter, "default: $yamlValue") } - - # 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 { diff --git a/Scenarios/settings.md b/Scenarios/settings.md index 193e548780..78f9897d46 100644 --- a/Scenarios/settings.md +++ b/Scenarios/settings.md @@ -83,7 +83,7 @@ The repository settings are only read from the repository settings file (.github | 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. | | 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:
**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.
`createPullRequest` : A boolean defining whether AL-Go should create a pull request or attempt to push directly in the branch.
**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.
**pullRequestMergeMethod** = A string defining which merge method to use when auto-merging pull requests. Valid values are "merge" and "squash". Default is "squash".
**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.
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). | | 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:
**onPush** = Determines whether incremental builds is enabled in CI/CD triggered by a merge/push event. Default is **false**.
**onPull_Request** = Determines whether incremental builds is enabled in Pull Requests. Default is **true**.
**onSchedule** = Determines whether incremental builds is enabled in CI/CD when running on a schedule. Default is **false**.
**retentionDays** = Number of days a successful build is good (and can be used for incremental builds). Default is **30**.
**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.
**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). | -| 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:
  **name** = The name of the workflow input
  **value** = The default value (can be string, boolean, or number)
**Important validation rules:**
  • The value type must match the input type defined in the workflow YAML file (boolean, number, string, or choice)
  • For choice inputs, the value must be one of the options declared in the workflow
  • Choice validation is case-sensitive
Type and choice validation is performed when running the "Update AL-Go System Files" workflow to prevent configuration errors.
When you run the "Update AL-Go System Files" workflow, these default values will be applied to all workflows that have matching input names.
**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.
**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.
**Example:**
`"workflowDefaultInputs": [`
` { "name": "directCommit", "value": true },`
` { "name": "useGhTokenWorkflow", "value": true },`
` { "name": "updateVersionNumber", "value": "+0.1" }`
`]` | +| 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. If a workflow also has matching `workflow_call` inputs, those will receive the same default values to ensure consistency in reusable workflows. Each entry should contain:
  **name** = The name of the workflow input
  **value** = The default value (can be string, boolean, or number)
**Important validation rules:**
  • The value type must match the input type defined in the workflow YAML file (boolean, number, string, or choice)
  • For choice inputs, the value must be one of the options declared in the workflow
  • Choice validation is case-sensitive
Type and choice validation is performed when running the "Update AL-Go System Files" workflow to prevent configuration errors.
When you run the "Update AL-Go System Files" workflow, these default values will be applied to matching `workflow_dispatch` inputs. If a workflow also defines `workflow_call` inputs with the same names, those inputs will receive the same defaults to ensure consistency between manual and programmatic workflow invocations.
**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.
**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.
**Example:**
`"workflowDefaultInputs": [`
` { "name": "directCommit", "value": true },`
` { "name": "useGhTokenWorkflow", "value": true },`
` { "name": "updateVersionNumber", "value": "+0.1" }`
`]` | diff --git a/Tests/CheckForUpdates.Action.Test.ps1 b/Tests/CheckForUpdates.Action.Test.ps1 index ba31d127cf..328c81ec3e 100644 --- a/Tests/CheckForUpdates.Action.Test.ps1 +++ b/Tests/CheckForUpdates.Action.Test.ps1 @@ -268,11 +268,19 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { $modifiedContent."srcSetting" | Should -Be "value1" $modifiedContent."`$schema" | Should -Be "someSchema" } +} + +Describe "CheckForUpdates Action: ApplyWorkflowDefaultInputs Tests" { + BeforeAll { + $actionName = "CheckForUpdates" + $scriptRoot = Join-Path $PSScriptRoot "..\Actions\$actionName" -Resolve + . (Join-Path -Path $scriptRoot -ChildPath "CheckForUpdates.HelperFunctions.ps1") + } It 'ApplyWorkflowDefaultInputs applies default values to workflow inputs' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with workflow_dispatch inputs + # Create a test workflow YAML with both workflow_dispatch and workflow_call inputs $yamlContent = @( "name: 'Test Workflow'", "on:", @@ -290,6 +298,20 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { " description: Version number", " required: false", " default: ''", + " workflow_call:", + " inputs:", + " directCommit:", + " description: Direct Commit?", + " type: boolean", + " default: false", + " useGhTokenWorkflow:", + " description: Use GhTokenWorkflow?", + " type: boolean", + " default: false", + " updateVersionNumber:", + " description: Version number", + " required: false", + " default: ''", "jobs:", " test:", " runs-on: ubuntu-latest", @@ -311,10 +333,15 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify the defaults were applied + # Verify the defaults were applied to workflow_dispatch $yaml.Get('on:/workflow_dispatch:/inputs:/directCommit:/default:').content -join '' | Should -Be 'default: true' $yaml.Get('on:/workflow_dispatch:/inputs:/useGhTokenWorkflow:/default:').content -join '' | Should -Be 'default: true' $yaml.Get('on:/workflow_dispatch:/inputs:/updateVersionNumber:/default:').content -join '' | Should -Be "default: '+0.1'" + + # Verify the defaults were also applied to workflow_call + $yaml.Get('on:/workflow_call:/inputs:/directCommit:/default:').content -join '' | Should -Be 'default: true' + $yaml.Get('on:/workflow_call:/inputs:/useGhTokenWorkflow:/default:').content -join '' | Should -Be 'default: true' + $yaml.Get('on:/workflow_call:/inputs:/updateVersionNumber:/default:').content -join '' | Should -Be "default: '+0.1'" } It 'ApplyWorkflowDefaultInputs handles empty workflowDefaultInputs array' { @@ -410,7 +437,7 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { It 'ApplyWorkflowDefaultInputs applies multiple defaults to same workflow' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with multiple inputs + # Create a test workflow YAML with multiple inputs in both workflow_dispatch and workflow_call $yamlContent = @( "name: 'Test Workflow'", "on:", @@ -431,6 +458,23 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { " - optionA", " - optionB", " default: optionA", + " workflow_call:", + " inputs:", + " input1:", + " type: boolean", + " default: false", + " input2:", + " type: number", + " default: 0", + " input3:", + " type: string", + " default: ''", + " input4:", + " type: choice", + " options:", + " - optionA", + " - optionB", + " default: optionA", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -451,52 +495,23 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify all defaults were applied + # Verify all defaults were applied to workflow_dispatch $yaml.Get('on:/workflow_dispatch:/inputs:/input1:/default:').content -join '' | Should -Be 'default: true' $yaml.Get('on:/workflow_dispatch:/inputs:/input2:/default:').content -join '' | Should -Be 'default: 5' $yaml.Get('on:/workflow_dispatch:/inputs:/input3:/default:').content -join '' | Should -Be "default: 'test-value'" $yaml.Get('on:/workflow_dispatch:/inputs:/input4:/default:').content -join '' | Should -Be "default: 'optionB'" - } - - It 'ApplyWorkflowDefaultInputs inserts default line when missing' { - . (Join-Path $scriptRoot "yamlclass.ps1") - - # Create a test workflow YAML with input without default line (only description) - $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " myInput:", - " description: 'My input without default'", - " type: string", - "jobs:", - " test:", - " runs-on: ubuntu-latest" - ) - $yaml = [Yaml]::new($yamlContent) - - # Create settings with default value - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "myInput"; "value" = "new-default" } - ) - } - - # Apply the defaults - ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - - # Verify default line was inserted - $defaultLine = $yaml.Get('on:/workflow_dispatch:/inputs:/myInput:/default:') - $defaultLine | Should -Not -BeNullOrEmpty - $defaultLine.content -join '' | Should -Be "default: 'new-default'" + # Verify all defaults were also applied to workflow_call + $yaml.Get('on:/workflow_call:/inputs:/input1:/default:').content -join '' | Should -Be 'default: true' + $yaml.Get('on:/workflow_call:/inputs:/input2:/default:').content -join '' | Should -Be 'default: 5' + $yaml.Get('on:/workflow_call:/inputs:/input3:/default:').content -join '' | Should -Be "default: 'test-value'" + $yaml.Get('on:/workflow_call:/inputs:/input4:/default:').content -join '' | Should -Be "default: 'optionB'" } It 'ApplyWorkflowDefaultInputs is case-insensitive for input names' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with specific casing + # Create a test workflow YAML with specific casing in both workflow_dispatch and workflow_call $yamlContent = @( "name: 'Test Workflow'", "on:", @@ -505,6 +520,11 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { " MyInput:", " type: boolean", " default: false", + " workflow_call:", + " inputs:", + " MyInput:", + " type: boolean", + " default: false", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -522,14 +542,17 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify default WAS applied despite case difference (case-insensitive matching) + # Verify default WAS applied despite case difference (case-insensitive matching) to workflow_dispatch $yaml.Get('on:/workflow_dispatch:/inputs:/MyInput:/default:').content -join '' | Should -Be 'default: true' + + # Verify default WAS also applied to workflow_call + $yaml.Get('on:/workflow_call:/inputs:/MyInput:/default:').content -join '' | Should -Be 'default: true' } It 'ApplyWorkflowDefaultInputs ignores defaults for non-existent inputs' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML + # Create a test workflow YAML with both workflow_dispatch and workflow_call $yamlContent = @( "name: 'Test Workflow'", "on:", @@ -538,6 +561,11 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { " existingInput:", " type: boolean", " default: false", + " workflow_call:", + " inputs:", + " existingInput:", + " type: boolean", + " default: false", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -562,7 +590,7 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { It 'ApplyWorkflowDefaultInputs applies only existing inputs when mixed with non-existent inputs' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML + # Create a test workflow YAML with both workflow_dispatch and workflow_call $yamlContent = @( "name: 'Test Workflow'", "on:", @@ -571,6 +599,11 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { " existingInput:", " type: boolean", " default: false", + " workflow_call:", + " inputs:", + " existingInput:", + " type: boolean", + " default: false", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -590,14 +623,17 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { # Apply the defaults - should not throw { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Not -Throw - # Verify only the existing input was modified + # Verify only the existing input was modified in workflow_dispatch $yaml.Get('on:/workflow_dispatch:/inputs:/existingInput:/default:').content -join '' | Should -Be 'default: true' + + # Verify only the existing input was also modified in workflow_call + $yaml.Get('on:/workflow_call:/inputs:/existingInput:/default:').content -join '' | Should -Be 'default: true' } - It 'ApplyWorkflowDefaultInputs handles special YAML characters in string values' { + It 'ApplyWorkflowDefaultInputs applies last value when multiple entries have same input name' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML + # Create a test workflow YAML with both workflow_dispatch and workflow_call $yamlContent = @( "name: 'Test Workflow'", "on:", @@ -607,11 +643,16 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { " type: string", " default: ''", " input2:", + " type: boolean", + " default: false", + " workflow_call:", + " inputs:", + " input1:", " type: string", " default: ''", - " input3:", - " type: string", - " default: ''", + " input2:", + " type: boolean", + " default: false", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -619,37 +660,50 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { $yaml = [Yaml]::new($yamlContent) - # Create settings with special YAML characters + # Create settings with duplicate entries for input1 - simulating merged conditional settings + # This can happen when multiple conditionalSettings blocks both match and both define the same input $repoSettings = @{ "workflowDefaultInputs" = @( - @{ "name" = "input1"; "value" = "value: with colon" }, - @{ "name" = "input2"; "value" = "value # with comment" }, - @{ "name" = "input3"; "value" = "value with 'quotes' inside" } + @{ "name" = "input1"; "value" = "first-value" }, + @{ "name" = "input2"; "value" = $false }, + @{ "name" = "input1"; "value" = "second-value" }, # Duplicate input1 + @{ "name" = "input1"; "value" = "final-value" } # Another duplicate input1 ) } # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify values are properly quoted and escaped - $yaml.Get('on:/workflow_dispatch:/inputs:/input1:/default:').content -join '' | Should -Be "default: 'value: with colon'" - $yaml.Get('on:/workflow_dispatch:/inputs:/input2:/default:').content -join '' | Should -Be "default: 'value # with comment'" - $yaml.Get('on:/workflow_dispatch:/inputs:/input3:/default:').content -join '' | Should -Be "default: 'value with ''quotes'' inside'" + # Verify "last wins" - the final value for input1 should be applied to workflow_dispatch + $yaml.Get('on:/workflow_dispatch:/inputs:/input1:/default:').content -join '' | Should -Be "default: 'final-value'" + $yaml.Get('on:/workflow_dispatch:/inputs:/input2:/default:').content -join '' | Should -Be 'default: false' + + # Verify "last wins" also applies to workflow_call + $yaml.Get('on:/workflow_call:/inputs:/input1:/default:').content -join '' | Should -Be "default: 'final-value'" + $yaml.Get('on:/workflow_call:/inputs:/input2:/default:').content -join '' | Should -Be 'default: false' } - It 'ApplyWorkflowDefaultInputs handles environment input type' { + It 'ApplyWorkflowDefaultInputs updates workflow_call inputs only when matching workflow_dispatch input exists' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with environment type + # Create a workflow where workflow_call has an input that also exists in workflow_dispatch + # and another input that does NOT exist in workflow_dispatch $yamlContent = @( "name: 'Test Workflow'", "on:", " workflow_dispatch:", " inputs:", - " environmentName:", - " description: Environment to deploy to", - " type: environment", - " default: ''", + " sharedInput:", + " type: string", + " default: 'dispatch-default'", + " workflow_call:", + " inputs:", + " sharedInput:", + " type: string", + " default: 'call-default'", + " callOnlyInput:", + " type: boolean", + " default: false", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -657,107 +711,80 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { $yaml = [Yaml]::new($yamlContent) - # Create settings with environment value (should be treated as string) + # Provide defaults for both inputs $repoSettings = @{ "workflowDefaultInputs" = @( - @{ "name" = "environmentName"; "value" = "production" } + @{ "name" = "sharedInput"; "value" = "new-value" }, + @{ "name" = "callOnlyInput"; "value" = $true } ) } # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify environment value is set as string - $yaml.Get('on:/workflow_dispatch:/inputs:/environmentName:/default:').content -join '' | Should -Be "default: 'production'" - } - - It 'ApplyWorkflowDefaultInputs validates invalid choice value not in options' { - . (Join-Path $scriptRoot "yamlclass.ps1") + # Verify workflow_dispatch: sharedInput should be updated + $yaml.Get('on:/workflow_dispatch:/inputs:/sharedInput:/default:').content -join '' | Should -Be "default: 'new-value'" - # Create a test workflow YAML with choice input - $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " deploymentType:", - " type: choice", - " options:", - " - Development", - " - Staging", - " - Production", - " default: Development", - "jobs:", - " test:", - " runs-on: ubuntu-latest" - ) - - $yaml = [Yaml]::new($yamlContent) - - # Create settings with invalid choice value - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "deploymentType"; "value" = "Testing" } - ) - } + # Verify workflow_call: Only sharedInput should be updated (exists in workflow_dispatch) + $yaml.Get('on:/workflow_call:/inputs:/sharedInput:/default:').content -join '' | Should -Be "default: 'new-value'" - # Apply the defaults - should throw validation error - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Throw "*not a valid choice*" + # Verify workflow_call: callOnlyInput should NOT be updated (doesn't exist in workflow_dispatch) + $yaml.Get('on:/workflow_call:/inputs:/callOnlyInput:/default:').content -join '' | Should -Be 'default: false' } - It 'ApplyWorkflowDefaultInputs handles inputs without existing default' { + It 'ApplyWorkflowDefaultInputs handles workflow with only workflow_call inputs' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with input without default + # Create a workflow that only has workflow_call (no workflow_dispatch) + # Per the rule: workflow_call inputs are only updated when matching workflow_dispatch input exists + # Since there's no workflow_dispatch, no updates should be applied $yamlContent = @( - "name: 'Test Workflow'", + "name: 'Reusable Workflow'", "on:", - " workflow_dispatch:", + " workflow_call:", " inputs:", - " myInput:", - " description: My Input", - " required: false", + " input1:", + " type: string", + " default: ''", + " input2:", + " type: boolean", + " default: false", "jobs:", " test:", " runs-on: ubuntu-latest" ) $yaml = [Yaml]::new($yamlContent) + $originalContent = $yaml.content -join "`n" - # Create settings with workflow input defaults + # Provide defaults $repoSettings = @{ "workflowDefaultInputs" = @( - @{ "name" = "myInput"; "value" = "test-value" } + @{ "name" = "input1"; "value" = "reusable-value" }, + @{ "name" = "input2"; "value" = $true } ) } # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify the default was added - $defaultLine = $yaml.Get('on:/workflow_dispatch:/inputs:/myInput:/default:') - $defaultLine | Should -Not -BeNullOrEmpty - $defaultLine.content -join '' | Should -Be "default: 'test-value'" + # Verify YAML was not modified + $yaml.content -join "`n" | Should -Be $originalContent } - It 'ApplyWorkflowDefaultInputs handles different value types' { + It 'ApplyWorkflowDefaultInputs handles workflow_call without inputs section' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML + # Create a workflow with workflow_call that has an inputs section but no actual inputs $yamlContent = @( "name: 'Test Workflow'", "on:", " workflow_dispatch:", " inputs:", - " boolInput:", - " type: boolean", - " default: false", - " stringInput:", + " dispatchInput:", " type: string", " default: ''", - " numberInput:", - " type: number", - " default: 0", + " workflow_call:", "jobs:", " test:", " runs-on: ubuntu-latest" @@ -765,339 +792,314 @@ Describe "CheckForUpdates Action: CheckForUpdates.HelperFunctions.ps1" { $yaml = [Yaml]::new($yamlContent) - # Create settings with different value types + # Provide defaults $repoSettings = @{ "workflowDefaultInputs" = @( - @{ "name" = "boolInput"; "value" = $true }, - @{ "name" = "stringInput"; "value" = "test" }, - @{ "name" = "numberInput"; "value" = 42 } + @{ "name" = "dispatchInput"; "value" = "test-value" }, + @{ "name" = "nonExistentInput"; "value" = "ignored" } ) } # Apply the defaults ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - # Verify the defaults were applied with correct types - $yaml.Get('on:/workflow_dispatch:/inputs:/boolInput:/default:').content -join '' | Should -Be 'default: true' - $yaml.Get('on:/workflow_dispatch:/inputs:/stringInput:/default:').content -join '' | Should -Be "default: 'test'" - $yaml.Get('on:/workflow_dispatch:/inputs:/numberInput:/default:').content -join '' | Should -Be 'default: 42' + # Verify workflow_dispatch input was updated + $yaml.Get('on:/workflow_dispatch:/inputs:/dispatchInput:/default:').content -join '' | Should -Be "default: 'test-value'" + + # Verify workflow_call remains unchanged (no inputs to update) + $yaml.Get('on:/workflow_call:/inputs:').content -join '' | Should -Be '' + $yaml.Get('on:/workflow_dispatch:/inputs:/dispatchInput:/default:').content -join '' | Should -Be "default: 'test-value'" } +} - It 'ApplyWorkflowDefaultInputs validates boolean type mismatch' { +Describe "CheckForUpdates Action: ApplyWorkflowInputDefaultValue Tests" { + BeforeAll { + $actionName = "CheckForUpdates" + $scriptRoot = Join-Path $PSScriptRoot "..\Actions\$actionName" -Resolve + . (Join-Path -Path $scriptRoot -ChildPath "CheckForUpdates.HelperFunctions.ps1") + } + + It 'ApplyWorkflowInputDefaultValue inserts default line when missing' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with boolean input + # Create just the input section without default line $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " boolInput:", - " type: boolean", - " default: false", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "myInput:", + " description: 'My input without default'", + " type: string" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('myInput:/') - # Create settings with wrong type (string instead of boolean) - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "boolInput"; "value" = "not a boolean" } - ) - } + # Apply default value + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "new-default" - # Apply the defaults - should throw validation error - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Throw "*Expected boolean value*" + # Verify default line was inserted + $inputSection.content -join '' | Should -BeLike "*default: 'new-default'*" } - It 'ApplyWorkflowDefaultInputs validates number type mismatch' { + It 'ApplyWorkflowInputDefaultValue handles special YAML characters in string values' { + . (Join-Path $scriptRoot "yamlclass.ps1") + + # Test colon + $yamlContent = @("input1:", " type: string", " default: ''") + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('input1:/') + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "value: with colon" + $inputSection.Get('default:').content -join '' | Should -Be "default: 'value: with colon'" + + # Test hash/comment + $yamlContent = @("input2:", " type: string", " default: ''") + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('input2:/') + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "value # with comment" + $inputSection.Get('default:').content -join '' | Should -Be "default: 'value # with comment'" + + # Test quotes + $yamlContent = @("input3:", " type: string", " default: ''") + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('input3:/') + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "value with 'quotes' inside" + $inputSection.Get('default:').content -join '' | Should -Be "default: 'value with ''quotes'' inside'" + } + + It 'ApplyWorkflowInputDefaultValue handles environment input type' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with number input $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " numberInput:", - " type: number", - " default: 0", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "environmentName:", + " description: Environment to deploy to", + " type: environment", + " default: ''" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('environmentName:/') - # Create settings with wrong type (string instead of number) - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "numberInput"; "value" = "not a number" } - ) - } + # Apply environment value (should be treated as string) + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "production" - # Apply the defaults - should throw validation error - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Throw "*Expected number value*" + # Verify environment value is set as string + $inputSection.Get('default:').content -join '' | Should -Be "default: 'production'" } - It 'ApplyWorkflowDefaultInputs validates string type mismatch' { + It 'ApplyWorkflowInputDefaultValue validates invalid choice value not in options' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with string input $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " stringInput:", - " type: string", - " default: ''", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "deploymentType:", + " type: choice", + " options:", + " - Development", + " - Staging", + " - Production", + " default: Development" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('deploymentType:/') - # Create settings with wrong type (boolean instead of string) - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "stringInput"; "value" = $true } - ) - } - - # Apply the defaults - should throw validation error - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Throw "*Expected string value*" + # Apply invalid choice value - should throw + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "Testing" } | Should -Throw "*not a valid choice*" } - It 'ApplyWorkflowDefaultInputs validates choice type' { + It 'ApplyWorkflowInputDefaultValue handles different value types' { + . (Join-Path $scriptRoot "yamlclass.ps1") + + # Test boolean + $yamlContent = @("boolInput:", " type: boolean", " default: false") + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('boolInput:/') + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $true + $inputSection.Get('default:').content -join '' | Should -Be 'default: true' + + # Test string + $yamlContent = @("stringInput:", " type: string", " default: ''") + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('stringInput:/') + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "test" + $inputSection.Get('default:').content -join '' | Should -Be "default: 'test'" + + # Test number + $yamlContent = @("numberInput:", " type: number", " default: 0") + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('numberInput:/') + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue 42 + $inputSection.Get('default:').content -join '' | Should -Be 'default: 42' + } + + It 'ApplyWorkflowInputDefaultValue validates boolean type mismatch' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with choice input $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " choiceInput:", - " type: choice", - " options:", - " - option1", - " - option2", - " default: option1", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "boolInput:", + " type: boolean", + " default: false" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('boolInput:/') - # Create settings with correct type (string for choice) - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "choiceInput"; "value" = "option2" } - ) - } - - # Apply the defaults - should succeed - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Not -Throw - $yaml.Get('on:/workflow_dispatch:/inputs:/choiceInput:/default:').content -join '' | Should -Be "default: 'option2'" + # Apply wrong type - should throw + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "not a boolean" } | Should -Throw "*Expected boolean value*" } - It 'ApplyWorkflowDefaultInputs validates choice value is in available options' { + It 'ApplyWorkflowInputDefaultValue validates number type mismatch' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with choice input $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " choiceInput:", - " type: choice", - " options:", - " - option1", - " - option2", - " - option3", - " default: option1", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "numberInput:", + " type: number", + " default: 0" ) - $yaml = [Yaml]::new($yamlContent) - - # Create settings with invalid choice value - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "choiceInput"; "value" = "invalidOption" } - ) - } + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('numberInput:/') - # Apply the defaults - should throw validation error - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Throw "*not a valid choice*" + # Apply wrong type - should throw + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "not a number" } | Should -Throw "*Expected number value*" } - It 'ApplyWorkflowDefaultInputs validates choice value with case-sensitive matching' { + It 'ApplyWorkflowInputDefaultValue validates string type mismatch' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with choice input using mixed case options $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " releaseTypeInput:", - " type: choice", - " options:", - " - Release", - " - Prerelease", - " - Draft", - " default: Release", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "stringInput:", + " type: string", + " default: ''" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('stringInput:/') - # Test 1: Exact case match should succeed - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "releaseTypeInput"; "value" = "Prerelease" } - ) - } + # Apply wrong type - should throw + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $true } | Should -Throw "*Expected string value*" + } - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Not -Throw - $yaml.Get('on:/workflow_dispatch:/inputs:/releaseTypeInput:/default:').content -join '' | Should -Be "default: 'Prerelease'" + It 'ApplyWorkflowInputDefaultValue validates choice type accepts valid option' { + . (Join-Path $scriptRoot "yamlclass.ps1") - # Test 2: Wrong case should fail with case-sensitive error message - $yaml2 = [Yaml]::new($yamlContent) - $repoSettings2 = @{ - "workflowDefaultInputs" = @( - @{ "name" = "releaseTypeInput"; "value" = "prerelease" } - ) - } + $yamlContent = @( + "choiceInput:", + " type: choice", + " options:", + " - option1", + " - option2", + " default: option1" + ) - { ApplyWorkflowDefaultInputs -yaml $yaml2 -repoSettings $repoSettings2 -workflowName "Test Workflow" } | Should -Throw "*case-sensitive match required*" + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('choiceInput:/') - # Test 3: Uppercase version should also fail - $yaml3 = [Yaml]::new($yamlContent) - $repoSettings3 = @{ - "workflowDefaultInputs" = @( - @{ "name" = "releaseTypeInput"; "value" = "PRERELEASE" } - ) - } + # Apply valid choice - should succeed + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "option2" } | Should -Not -Throw + $inputSection.Get('default:').content -join '' | Should -Be "default: 'option2'" + } + + It 'ApplyWorkflowInputDefaultValue validates choice value is in available options' { + . (Join-Path $scriptRoot "yamlclass.ps1") - { ApplyWorkflowDefaultInputs -yaml $yaml3 -repoSettings $repoSettings3 -workflowName "Test Workflow" } | Should -Throw "*case-sensitive match required*" + $yamlContent = @( + "choiceInput:", + " type: choice", + " options:", + " - option1", + " - option2", + " - option3", + " default: option1" + ) + + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('choiceInput:/') + + # Apply invalid choice - should throw + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "invalidOption" } | Should -Throw "*not a valid choice*" } - It 'ApplyWorkflowDefaultInputs handles inputs without type specification' { + It 'ApplyWorkflowInputDefaultValue validates choice value with case-sensitive matching' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML without type (defaults to string) $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " noTypeInput:", - " description: Input without type", - " default: ''", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "releaseTypeInput:", + " type: choice", + " options:", + " - Release", + " - Prerelease", + " - Draft", + " default: Release" ) - $yaml = [Yaml]::new($yamlContent) + # Test 1: Exact case match should succeed + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('releaseTypeInput:/') + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "Prerelease" } | Should -Not -Throw + $inputSection.Get('default:').content -join '' | Should -Be "default: 'Prerelease'" - # Create settings with string value (should work without warning) - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "noTypeInput"; "value" = "string value" } - ) - } + # Test 2: Wrong case should fail + $inputYaml2 = [Yaml]::new($yamlContent) + $inputSection2 = $inputYaml2.Get('releaseTypeInput:/') + { ApplyWorkflowInputDefaultValue -inputSection $inputSection2 -defaultValue "prerelease" } | Should -Throw "*case-sensitive match required*" - # Apply the defaults - should succeed - { ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" } | Should -Not -Throw - $yaml.Get('on:/workflow_dispatch:/inputs:/noTypeInput:/default:').content -join '' | Should -Be "default: 'string value'" + # Test 3: Uppercase should also fail + $inputYaml3 = [Yaml]::new($yamlContent) + $inputSection3 = $inputYaml3.Get('releaseTypeInput:/') + { ApplyWorkflowInputDefaultValue -inputSection $inputSection3 -defaultValue "PRERELEASE" } | Should -Throw "*case-sensitive match required*" } - It 'ApplyWorkflowDefaultInputs escapes single quotes in string values' { + It 'ApplyWorkflowInputDefaultValue handles inputs without type specification' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML with string input $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " nameInput:", - " type: string", - " default: ''", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "noTypeInput:", + " description: Input without type", + " default: ''" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('noTypeInput:/') - # Create settings with string value containing single quote - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "nameInput"; "value" = "O'Brien" } - ) - } + # Apply string value (should work as type defaults to string) + { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "string value" } | Should -Not -Throw + $inputSection.Get('default:').content -join '' | Should -Be "default: 'string value'" + } - # Apply the defaults - ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" + It 'ApplyWorkflowInputDefaultValue escapes single quotes in string values' { + . (Join-Path $scriptRoot "yamlclass.ps1") + + $yamlContent = @( + "nameInput:", + " type: string", + " default: ''" + ) + + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('nameInput:/') + + # Apply value with single quote + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "O'Brien" # Verify single quote is escaped per YAML spec (doubled) - $yaml.Get('on:/workflow_dispatch:/inputs:/nameInput:/default:').content -join '' | Should -Be "default: 'O''Brien'" + $inputSection.Get('default:').content -join '' | Should -Be "default: 'O''Brien'" } - It 'ApplyWorkflowDefaultInputs applies last value when multiple entries have same input name' { + It 'ApplyWorkflowInputDefaultValue replaces existing default value' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create a test workflow YAML $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " input1:", - " type: string", - " default: ''", - " input2:", - " type: boolean", - " default: false", - "jobs:", - " test:", - " runs-on: ubuntu-latest" + "myInput:", + " type: string", + " default: 'old-value'" ) - $yaml = [Yaml]::new($yamlContent) + $inputYaml = [Yaml]::new($yamlContent) + $inputSection = $inputYaml.Get('myInput:/') - # Create settings with duplicate entries for input1 - simulating merged conditional settings - # This can happen when multiple conditionalSettings blocks both match and both define the same input - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "input1"; "value" = "first-value" }, - @{ "name" = "input2"; "value" = $false }, - @{ "name" = "input1"; "value" = "second-value" }, # Duplicate input1 - @{ "name" = "input1"; "value" = "final-value" } # Another duplicate input1 - ) - } + # Apply new value + ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "new-value" - # Apply the defaults - ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - - # Verify "last wins" - the final value for input1 should be applied - $yaml.Get('on:/workflow_dispatch:/inputs:/input1:/default:').content -join '' | Should -Be "default: 'final-value'" - $yaml.Get('on:/workflow_dispatch:/inputs:/input2:/default:').content -join '' | Should -Be 'default: false' + # Verify default was replaced + $inputSection.Get('default:').content -join '' | Should -Be "default: 'new-value'" } } From 52ef2a5eef14fd3965c580c49742d6741da24ae8 Mon Sep 17 00:00:00 2001 From: Ole Wunschmann <44057549+OleWunschmann@users.noreply.github.com> Date: Thu, 11 Dec 2025 20:07:19 +0100 Subject: [PATCH 04/10] Update RELEASENOTES.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ea10efae67..4dd5ce7840 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -65,7 +65,7 @@ Read more at [workflowDefaultInputs](https://aka.ms/algosettings#workflowDefault - 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 -- Discussion 1855 Add trigger 'workflow_call' to workflow 'UpdateGitHubGoSystemFiles' for reusability +- Discussion 1855 Add trigger 'workflow_call' to workflow 'Update AL-Go System Files' for reusability ### Deprecations From fbf40e868ebbfbfab098f44fdecac7ee35f76385 Mon Sep 17 00:00:00 2001 From: Ole Wunschmann Date: Thu, 11 Dec 2025 20:14:10 +0100 Subject: [PATCH 05/10] Update RELEASENOTES.md --- RELEASENOTES.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4dd5ce7840..4aee63d693 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,13 @@ ### Issues - AL-Go repositories with large amounts of projects may run into issues with too large environment variables +- Discussion 1855 Add trigger 'workflow_call' to workflow 'Update AL-Go System Files' for reusability + +### Set default values for workflow inputs + +The setting `workflowDefaultInputs` now also applies the default values to workflow_call inputs if a input with the same name exists for workflow_dispatch. + +Read more at [workflowDefaultInputs](https://aka.ms/algosettings#workflowDefaultInputs). ## AL-Go Telemetry updates @@ -65,7 +72,6 @@ Read more at [workflowDefaultInputs](https://aka.ms/algosettings#workflowDefault - 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 -- Discussion 1855 Add trigger 'workflow_call' to workflow 'Update AL-Go System Files' for reusability ### Deprecations From 9e1d9716605e74934162ebd145231509c96d7a61 Mon Sep 17 00:00:00 2001 From: Ole Wunschmann Date: Thu, 11 Dec 2025 20:16:03 +0100 Subject: [PATCH 06/10] Update RELEASENOTES.md --- RELEASENOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4aee63d693..3bd220bb5c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,7 +5,8 @@ ### Set default values for workflow inputs -The setting `workflowDefaultInputs` now also applies the default values to workflow_call inputs if a input with the same name exists for workflow_dispatch. +The `workflowDefaultInputs` setting now also applies to `workflow_call` inputs when an input with the same name exists for `workflow_dispatch`. +This ensures consistent default values across both manual workflow runs and reusable workflow calls. Read more at [workflowDefaultInputs](https://aka.ms/algosettings#workflowDefaultInputs). From 0cdcde0416817753d6b3644792c0bf2a8b88f487 Mon Sep 17 00:00:00 2001 From: Ole Wunschmann Date: Thu, 11 Dec 2025 22:20:14 +0100 Subject: [PATCH 07/10] Apply workflow default inputs to call inputs with matching dispatch inputs --- .../CheckForUpdates.HelperFunctions.ps1 | 76 +-- Tests/CheckForUpdates.Action.Test.ps1 | 466 +++++++++++------- 2 files changed, 330 insertions(+), 212 deletions(-) diff --git a/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 b/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 index aabac44366..3482ce5d0c 100644 --- a/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 +++ b/Actions/CheckForUpdates/CheckForUpdates.HelperFunctions.ps1 @@ -334,54 +334,52 @@ function ApplyWorkflowDefaultInputs { $workflowCallInputs = $yaml.Get('on:/workflow_call:/inputs:/') # 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 - } - - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $defaultValue - - # Update the inputs section with the modified input - $inputs.Replace("$($inputName):/", $inputSection.content) - - # Apply the default to workflow_call inputs if present - if ($workflowCallInputs) { - # Check if this input exists in the workflow_call section - $inputSection = $workflowCallInputs.Get("$($inputName):/") - if ($inputSection) { - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $defaultValue - - # Update the workflow_call inputs section with the modified input - $workflowCallInputs.Replace("$($inputName):/", $inputSection.content) + $workflowDispatchInputsModified = $false + $workflowCallInputsModified = $false + + foreach ($defaultInput in $repoSettings.workflowDefaultInputs) { + # Apply to workflow_dispatch inputs and only update workflow_call if dispatch was modified + if (ApplyWorkflowDefaultInput -workflowName $workflowName -inputs $inputs -defaultInput $defaultInput) { + $workflowDispatchInputsModified = $true + + # Only apply to workflow_call inputs if the workflow_dispatch input was modified + if ($workflowCallInputs) { + if (ApplyWorkflowDefaultInput -workflowName $workflowName -inputs $workflowCallInputs -defaultInput $defaultInput) { + $workflowCallInputsModified = $true + } } } } - # 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) + # Update the workflow_dispatch section if modified + if ($workflowDispatchInputsModified) { + $workflowDispatch.Replace('inputs:/', $inputs.content) + $yaml.Replace('on:/workflow_dispatch:/', $workflowDispatch.content) + } - # Update workflow_call inputs if present - if ($workflowCallInputs) { - # Update the workflow_call section with modified inputs + # Update workflow_call inputs if modified + if ($workflowCallInputsModified) { $yaml.Replace('on:/workflow_call:/inputs:/', $workflowCallInputs.content) } } -function ApplyWorkflowInputDefaultValue { +function ApplyWorkflowDefaultInput { Param( - [Yaml] $inputSection, - [object] $defaultValue + [string] $workflowName, + [Yaml] $inputs, + [hashtable] $defaultInput ) + $inputName = $defaultInput.name + $defaultValue = $defaultInput.value + + # Check if this input exists in the inputs collection + $inputSection = $inputs.Get("$($inputName):/") + if (-not $inputSection) { + # Input is not present in the workflow + return $false + } + # Get the input type from the YAML if specified $inputType = $null $typeStart = 0 @@ -464,6 +462,7 @@ function ApplyWorkflowInputDefaultValue { # 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") @@ -500,6 +499,11 @@ function ApplyWorkflowInputDefaultValue { $inputSection.Insert($insertAfter, "default: $yamlValue") } + + # Update the inputs collection with the modified input section + $inputs.Replace("$($inputName):/", $inputSection.content) + + return $true } function GetWorkflowContentWithChangesFromSettings { diff --git a/Tests/CheckForUpdates.Action.Test.ps1 b/Tests/CheckForUpdates.Action.Test.ps1 index 654e86f836..35662a16f3 100644 --- a/Tests/CheckForUpdates.Action.Test.ps1 +++ b/Tests/CheckForUpdates.Action.Test.ps1 @@ -508,47 +508,6 @@ Describe "CheckForUpdates Action: ApplyWorkflowDefaultInputs Tests" { $yaml.Get('on:/workflow_call:/inputs:/input4:/default:').content -join '' | Should -Be "default: 'optionB'" } - It 'ApplyWorkflowDefaultInputs is case-insensitive for input names' { - . (Join-Path $scriptRoot "yamlclass.ps1") - - # Create a test workflow YAML with specific casing in both workflow_dispatch and workflow_call - $yamlContent = @( - "name: 'Test Workflow'", - "on:", - " workflow_dispatch:", - " inputs:", - " MyInput:", - " type: boolean", - " default: false", - " workflow_call:", - " inputs:", - " MyInput:", - " type: boolean", - " default: false", - "jobs:", - " test:", - " runs-on: ubuntu-latest" - ) - - $yaml = [Yaml]::new($yamlContent) - - # Create settings with different casing - $repoSettings = @{ - "workflowDefaultInputs" = @( - @{ "name" = "myInput"; "value" = $true } - ) - } - - # Apply the defaults - ApplyWorkflowDefaultInputs -yaml $yaml -repoSettings $repoSettings -workflowName "Test Workflow" - - # Verify default WAS applied despite case difference (case-insensitive matching) to workflow_dispatch - $yaml.Get('on:/workflow_dispatch:/inputs:/MyInput:/default:').content -join '' | Should -Be 'default: true' - - # Verify default WAS also applied to workflow_call - $yaml.Get('on:/workflow_call:/inputs:/MyInput:/default:').content -join '' | Should -Be 'default: true' - } - It 'ApplyWorkflowDefaultInputs ignores defaults for non-existent inputs' { . (Join-Path $scriptRoot "yamlclass.ps1") @@ -812,293 +771,448 @@ Describe "CheckForUpdates Action: ApplyWorkflowDefaultInputs Tests" { } } -Describe "CheckForUpdates Action: ApplyWorkflowInputDefaultValue Tests" { +Describe "CheckForUpdates Action: ApplyWorkflowDefaultInput Tests" { BeforeAll { $actionName = "CheckForUpdates" $scriptRoot = Join-Path $PSScriptRoot "..\Actions\$actionName" -Resolve . (Join-Path -Path $scriptRoot -ChildPath "CheckForUpdates.HelperFunctions.ps1") } - It 'ApplyWorkflowInputDefaultValue inserts default line when missing' { + It 'ApplyWorkflowDefaultInput ignores default when input with same name does not exist' { + . (Join-Path $scriptRoot "yamlclass.ps1") + + # Create workflow with input + $yamlContent = @( + "inputs:", + " myInput:", + " description: 'My input'", + " type: boolean", + " default: false" + ) + + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + + $originalContent = $yaml.content -join "`n" + + # Apply default value + $defaultInput = @{ 'name' = 'otherInput'; 'value' = $true } + $result = ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + + # Verify no changes were made and function returned false + $result | Should -Be $false + $yaml.content -join "`n" | Should -Be $originalContent + } + + It 'ApplyWorkflowDefaultInput updates only input with matching name' { + . (Join-Path $scriptRoot "yamlclass.ps1") + + # Create workflow with input + $yamlContent = @( + "inputs:", + " input1:", + " description: 'Input 1'", + " type: boolean", + " default: false", + " input2:", + " description: 'Input 2'", + " type: boolean", + " default: false" + ) + + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + + # Apply default value + $defaultInput = @{ 'name' = 'input1'; 'value' = $true } + $result = ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + + # Verify no changes were made and function returned false + $result | Should -Be $true + $inputs.Get('input1:/default:').content -join '' | Should -Be "default: true" + $inputs.Get('input2:/default:').content -join '' | Should -Be "default: false" + } + + It 'ApplyWorkflowDefaultInput is case-insensitive for input names' { + . (Join-Path $scriptRoot "yamlclass.ps1") + + # Create workflow with specific casing + $yamlContent = @( + "inputs:", + " MyInput:", + " description: 'My input'", + " type: boolean", + " default: false" + ) + + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + + # Apply default value with different casing + $defaultInput = @{ 'name' = 'myInput'; 'value' = $true } + $result = ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + + # Verify default was applied despite case difference (case-insensitive matching) + $result | Should -Be $true + $inputs.Get('MyInput:/default:').content -join '' | Should -Be 'default: true' + } + + It 'ApplyWorkflowDefaultInput inserts default line when missing' { . (Join-Path $scriptRoot "yamlclass.ps1") - # Create just the input section without default line + # Create workflow with input without default line $yamlContent = @( - "myInput:", - " description: 'My input without default'", - " type: string" + "inputs:", + " myInput:", + " description: 'My input without default'", + " type: string" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('myInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply default value - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "new-default" + $defaultInput = @{ 'name' = 'myInput'; 'value' = 'new-default' } + $result = ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput - # Verify default line was inserted + # Verify default line was inserted and function returned true + $result | Should -Be $true + $inputSection = $inputs.Get('myInput:/') $inputSection.content -join '' | Should -BeLike "*default: 'new-default'*" } - It 'ApplyWorkflowInputDefaultValue handles special YAML characters in string values' { + It 'ApplyWorkflowDefaultInput handles special YAML characters in string values' { . (Join-Path $scriptRoot "yamlclass.ps1") # Test colon - $yamlContent = @("input1:", " type: string", " default: ''") - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('input1:/') - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "value: with colon" + $yamlContent = @( + "inputs:", + " input1:", + " type: string", + " default: ''" + ) + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'input1'; 'value' = 'value: with colon' } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + $inputSection = $inputs.Get('input1:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'value: with colon'" # Test hash/comment - $yamlContent = @("input2:", " type: string", " default: ''") - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('input2:/') - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "value # with comment" + $yamlContent = @( + "inputs:", + " input2:", + " type: string", + " default: ''" + ) + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'input2'; 'value' = 'value # with comment' } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + $inputSection = $inputs.Get('input2:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'value # with comment'" # Test quotes - $yamlContent = @("input3:", " type: string", " default: ''") - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('input3:/') - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "value with 'quotes' inside" + $yamlContent = @( + "inputs:", + " input3:", + " type: string", + " default: ''" + ) + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'input3'; 'value' = "value with 'quotes' inside" } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + $inputSection = $inputs.Get('input3:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'value with ''quotes'' inside'" } - It 'ApplyWorkflowInputDefaultValue handles environment input type' { + It 'ApplyWorkflowDefaultInput handles environment input type' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "environmentName:", - " description: Environment to deploy to", - " type: environment", - " default: ''" + "inputs:", + " environmentName:", + " description: Environment to deploy to", + " type: environment", + " default: ''" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('environmentName:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply environment value (should be treated as string) - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "production" + $defaultInput = @{ 'name' = 'environmentName'; 'value' = 'production' } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput # Verify environment value is set as string + $inputSection = $inputs.Get('environmentName:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'production'" } - It 'ApplyWorkflowInputDefaultValue validates invalid choice value not in options' { + It 'ApplyWorkflowDefaultInput validates invalid choice value not in options' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "deploymentType:", - " type: choice", - " options:", - " - Development", - " - Staging", - " - Production", - " default: Development" + "inputs:", + " deploymentType:", + " type: choice", + " options:", + " - Development", + " - Staging", + " - Production", + " default: Development" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('deploymentType:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply invalid choice value - should throw - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "Testing" } | Should -Throw "*not a valid choice*" + $defaultInput = @{ 'name' = 'deploymentType'; 'value' = 'Testing' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Throw "*not a valid choice*" } - It 'ApplyWorkflowInputDefaultValue handles different value types' { + It 'ApplyWorkflowDefaultInput handles different value types' { . (Join-Path $scriptRoot "yamlclass.ps1") # Test boolean - $yamlContent = @("boolInput:", " type: boolean", " default: false") - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('boolInput:/') - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $true + $yamlContent = @( + "inputs:", + " boolInput:", + " type: boolean", + " default: false" + ) + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'boolInput'; 'value' = $true } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + $inputSection = $inputs.Get('boolInput:/') $inputSection.Get('default:').content -join '' | Should -Be 'default: true' # Test string - $yamlContent = @("stringInput:", " type: string", " default: ''") - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('stringInput:/') - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "test" + $yamlContent = @( + "inputs:", + " stringInput:", + " type: string", + " default: ''" + ) + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'stringInput'; 'value' = 'test' } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + $inputSection = $inputs.Get('stringInput:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'test'" # Test number - $yamlContent = @("numberInput:", " type: number", " default: 0") - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('numberInput:/') - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue 42 + $yamlContent = @( + "inputs:", + " numberInput:", + " type: number", + " default: 0" + ) + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'numberInput'; 'value' = 42 } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput + $inputSection = $inputs.Get('numberInput:/') $inputSection.Get('default:').content -join '' | Should -Be 'default: 42' } - It 'ApplyWorkflowInputDefaultValue validates boolean type mismatch' { + It 'ApplyWorkflowDefaultInput validates boolean type mismatch' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "boolInput:", - " type: boolean", - " default: false" + "inputs:", + " boolInput:", + " type: boolean", + " default: false" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('boolInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply wrong type - should throw - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "not a boolean" } | Should -Throw "*Expected boolean value*" + $defaultInput = @{ 'name' = 'boolInput'; 'value' = 'not a boolean' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Throw "*Expected boolean value*" } - It 'ApplyWorkflowInputDefaultValue validates number type mismatch' { + It 'ApplyWorkflowDefaultInput validates number type mismatch' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "numberInput:", - " type: number", - " default: 0" + "inputs:", + " numberInput:", + " type: number", + " default: 0" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('numberInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply wrong type - should throw - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "not a number" } | Should -Throw "*Expected number value*" + $defaultInput = @{ 'name' = 'numberInput'; 'value' = 'not a number' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Throw "*Expected number value*" } - It 'ApplyWorkflowInputDefaultValue validates string type mismatch' { + It 'ApplyWorkflowDefaultInput validates string type mismatch' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "stringInput:", - " type: string", - " default: ''" + "inputs:", + " stringInput:", + " type: string", + " default: ''" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('stringInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply wrong type - should throw - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue $true } | Should -Throw "*Expected string value*" + $defaultInput = @{ 'name' = 'stringInput'; 'value' = $true } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Throw "*Expected string value*" } - It 'ApplyWorkflowInputDefaultValue validates choice type accepts valid option' { + It 'ApplyWorkflowDefaultInput validates choice type accepts valid option' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "choiceInput:", - " type: choice", - " options:", - " - option1", - " - option2", - " default: option1" + "inputs:", + " choiceInput:", + " type: choice", + " options:", + " - option1", + " - option2", + " default: option1" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('choiceInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply valid choice - should succeed - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "option2" } | Should -Not -Throw + $defaultInput = @{ 'name' = 'choiceInput'; 'value' = 'option2' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Not -Throw + $inputSection = $inputs.Get('choiceInput:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'option2'" } - It 'ApplyWorkflowInputDefaultValue validates choice value is in available options' { + It 'ApplyWorkflowDefaultInput validates choice value is in available options' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "choiceInput:", - " type: choice", - " options:", - " - option1", - " - option2", - " - option3", - " default: option1" + "inputs:", + " choiceInput:", + " type: choice", + " options:", + " - option1", + " - option2", + " - option3", + " default: option1" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('choiceInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply invalid choice - should throw - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "invalidOption" } | Should -Throw "*not a valid choice*" + $defaultInput = @{ 'name' = 'choiceInput'; 'value' = 'invalidOption' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Throw "*not a valid choice*" } - It 'ApplyWorkflowInputDefaultValue validates choice value with case-sensitive matching' { + It 'ApplyWorkflowDefaultInput validates choice value with case-sensitive matching' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "releaseTypeInput:", - " type: choice", - " options:", - " - Release", - " - Prerelease", - " - Draft", - " default: Release" + "inputs:", + " releaseTypeInput:", + " type: choice", + " options:", + " - Release", + " - Prerelease", + " - Draft", + " default: Release" ) # Test 1: Exact case match should succeed - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('releaseTypeInput:/') - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "Prerelease" } | Should -Not -Throw + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') + $defaultInput = @{ 'name' = 'releaseTypeInput'; 'value' = 'Prerelease' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Not -Throw + $inputSection = $inputs.Get('releaseTypeInput:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'Prerelease'" # Test 2: Wrong case should fail - $inputYaml2 = [Yaml]::new($yamlContent) - $inputSection2 = $inputYaml2.Get('releaseTypeInput:/') - { ApplyWorkflowInputDefaultValue -inputSection $inputSection2 -defaultValue "prerelease" } | Should -Throw "*case-sensitive match required*" + $yaml2 = [Yaml]::new($yamlContent) + $inputs2 = $yaml2.Get('inputs:/') + $defaultInput2 = @{ 'name' = 'releaseTypeInput'; 'value' = 'prerelease' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs2 -defaultInput $defaultInput2 } | Should -Throw "*case-sensitive match required*" # Test 3: Uppercase should also fail - $inputYaml3 = [Yaml]::new($yamlContent) - $inputSection3 = $inputYaml3.Get('releaseTypeInput:/') - { ApplyWorkflowInputDefaultValue -inputSection $inputSection3 -defaultValue "PRERELEASE" } | Should -Throw "*case-sensitive match required*" + $yaml3 = [Yaml]::new($yamlContent) + $inputs3 = $yaml3.Get('inputs:/') + $defaultInput3 = @{ 'name' = 'releaseTypeInput'; 'value' = 'PRERELEASE' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs3 -defaultInput $defaultInput3 } | Should -Throw "*case-sensitive match required*" } - It 'ApplyWorkflowInputDefaultValue handles inputs without type specification' { + It 'ApplyWorkflowDefaultInput handles inputs without type specification' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "noTypeInput:", - " description: Input without type", - " default: ''" + "inputs:", + " noTypeInput:", + " description: Input without type", + " default: ''" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('noTypeInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply string value (should work as type defaults to string) - { ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "string value" } | Should -Not -Throw + $defaultInput = @{ 'name' = 'noTypeInput'; 'value' = 'string value' } + { ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput } | Should -Not -Throw + $inputSection = $inputs.Get('noTypeInput:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'string value'" } - It 'ApplyWorkflowInputDefaultValue escapes single quotes in string values' { + It 'ApplyWorkflowDefaultInput escapes single quotes in string values' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "nameInput:", - " type: string", - " default: ''" + "inputs:", + " nameInput:", + " type: string", + " default: ''" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('nameInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply value with single quote - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "O'Brien" + $defaultInput = @{ 'name' = 'nameInput'; 'value' = "O'Brien" } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput # Verify single quote is escaped per YAML spec (doubled) + $inputSection = $inputs.Get('nameInput:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'O''Brien'" } - It 'ApplyWorkflowInputDefaultValue replaces existing default value' { + It 'ApplyWorkflowDefaultInput replaces existing default value' { . (Join-Path $scriptRoot "yamlclass.ps1") $yamlContent = @( - "myInput:", - " type: string", - " default: 'old-value'" + "inputs:", + " myInput:", + " type: string", + " default: 'old-value'" ) - $inputYaml = [Yaml]::new($yamlContent) - $inputSection = $inputYaml.Get('myInput:/') + $yaml = [Yaml]::new($yamlContent) + $inputs = $yaml.Get('inputs:/') # Apply new value - ApplyWorkflowInputDefaultValue -inputSection $inputSection -defaultValue "new-value" + $defaultInput = @{ 'name' = 'myInput'; 'value' = 'new-value' } + ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput # Verify default was replaced + $inputSection = $inputs.Get('myInput:/') $inputSection.Get('default:').content -join '' | Should -Be "default: 'new-value'" } } From 71cb8ebb9ab923653b4db1bf755d6a50b4dce1fe Mon Sep 17 00:00:00 2001 From: Ole Wunschmann <44057549+OleWunschmann@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:28:11 +0100 Subject: [PATCH 08/10] Update Tests/CheckForUpdates.Action.Test.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Tests/CheckForUpdates.Action.Test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/CheckForUpdates.Action.Test.ps1 b/Tests/CheckForUpdates.Action.Test.ps1 index 35662a16f3..e867154dba 100644 --- a/Tests/CheckForUpdates.Action.Test.ps1 +++ b/Tests/CheckForUpdates.Action.Test.ps1 @@ -827,7 +827,7 @@ Describe "CheckForUpdates Action: ApplyWorkflowDefaultInput Tests" { $defaultInput = @{ 'name' = 'input1'; 'value' = $true } $result = ApplyWorkflowDefaultInput -workflowName 'TestWorkflow' -inputs $inputs -defaultInput $defaultInput - # Verify no changes were made and function returned false + # Verify changes were made and function returned true $result | Should -Be $true $inputs.Get('input1:/default:').content -join '' | Should -Be "default: true" $inputs.Get('input2:/default:').content -join '' | Should -Be "default: false" From ecda769c8ed35fdf3b1e101fc23285367d7e0b8d Mon Sep 17 00:00:00 2001 From: Ole Wunschmann <44057549+OleWunschmann@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:09:47 +0100 Subject: [PATCH 09/10] Update Tests/CheckForUpdates.Action.Test.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Tests/CheckForUpdates.Action.Test.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/CheckForUpdates.Action.Test.ps1 b/Tests/CheckForUpdates.Action.Test.ps1 index e867154dba..9ef52b2f13 100644 --- a/Tests/CheckForUpdates.Action.Test.ps1 +++ b/Tests/CheckForUpdates.Action.Test.ps1 @@ -767,7 +767,6 @@ Describe "CheckForUpdates Action: ApplyWorkflowDefaultInputs Tests" { # Verify workflow_call remains unchanged (no inputs to update) $yaml.Get('on:/workflow_call:/inputs:').content -join '' | Should -Be '' - $yaml.Get('on:/workflow_dispatch:/inputs:/dispatchInput:/default:').content -join '' | Should -Be "default: 'test-value'" } } From 61e21affd99b9210238fb1b0f725cf7613576713 Mon Sep 17 00:00:00 2001 From: Ole Wunschmann Date: Fri, 12 Dec 2025 15:17:42 +0100 Subject: [PATCH 10/10] Update Tests for strict mode --- Tests/CheckForUpdates.Action.Test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/CheckForUpdates.Action.Test.ps1 b/Tests/CheckForUpdates.Action.Test.ps1 index 9ef52b2f13..be6cfa9b98 100644 --- a/Tests/CheckForUpdates.Action.Test.ps1 +++ b/Tests/CheckForUpdates.Action.Test.ps1 @@ -766,7 +766,7 @@ Describe "CheckForUpdates Action: ApplyWorkflowDefaultInputs Tests" { $yaml.Get('on:/workflow_dispatch:/inputs:/dispatchInput:/default:').content -join '' | Should -Be "default: 'test-value'" # Verify workflow_call remains unchanged (no inputs to update) - $yaml.Get('on:/workflow_call:/inputs:').content -join '' | Should -Be '' + $yaml.Get('on:/workflow_call:').content -join '' | Should -Be 'workflow_call:' } }