Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,20 @@ $projects | ForEach-Object {
}
else {
Write-Host "Search for $project-$refname-Apps-$buildVersion or $project-$refname-PowerPlatformSolution-$buildVersion"
$artifact = $allArtifacts | Where-Object { $_.name -eq "$project-$refname-Apps-$buildVersion"-or $_.name -eq "$project-$refname-PowerPlatformSolution-$buildVersion" } | Select-Object -First 1
$artifact = $allArtifacts | Where-Object { $_.name -eq "$project-$refname-Apps-$buildVersion" -or $_.name -eq "$project-$refname-PowerPlatformSolution-$buildVersion" } | Select-Object -First 1
}
if ($artifact) {
$startIndex = $artifact.name.LastIndexOf('-') + 1
$artifactsVersion = $artifact.name.SubString($startIndex)
}
else {
# No release artifacts (Apps or PowerPlatformSolution) were found for this project.
# This can happen when a project contains only test apps - in that case, skip the project
# rather than failing the release, as test apps are not part of the release.
if ($allArtifacts | Where-Object { $_.name -like "$project-$refname-*TestApps-*.*.*.*" }) {
Write-Host "::Warning::No release artifacts found for project $project, only test artifacts are available. Skipping project for release."
return
}
Comment thread
mazhelez marked this conversation as resolved.
Comment thread
mazhelez marked this conversation as resolved.
throw "No artifacts found for this project"
}
if ($sha) {
Expand All @@ -84,6 +91,9 @@ $projects | ForEach-Object {
throw "No artifacts found for version $artifactsVersion"
}
}
if ($include.Count -eq 0 -or -not $sha) {
throw "No release artifacts found for any project. Ensure that at least one project produces release artifacts (Apps or PowerPlatformSolution) before creating a release."
}
$artifacts = @{ "include" = $include }
$artifactsJson = $artifacts | ConvertTo-Json -compress
Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "artifacts=$artifactsJson"
Expand Down
1 change: 1 addition & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Incremental builds (`modifiedApps` mode) now correctly identify unmodified apps for projects whose `appFolders` reference paths outside the project directory (e.g. using `../`)
- Issue 2204 - Workspace compilation ignores vsixFile setting
- Issue 2211 - Cannot create a release if a project contains only test apps
- Issue 2214 - Workspace compilation not working with external dependencies

## v9.0
Expand Down
109 changes: 108 additions & 1 deletion Tests/DetermineArtifactsForRelease.Test.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
Get-Module Github-Helper | Remove-Module -Force
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Mock/callback parameters must match function signatures')]
param()

Get-Module Github-Helper | Remove-Module -Force
Import-Module (Join-Path $PSScriptRoot '..\Actions\Github-Helper.psm1' -Resolve)
Get-Module TestActionsHelper | Remove-Module -Force
Import-Module (Join-Path $PSScriptRoot 'TestActionsHelper.psm1')
Expand All @@ -15,6 +18,16 @@ Describe 'DetermineArtifactsForRelease Tests' {
$scriptPath = Join-Path $scriptRoot $scriptName
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'actionScript', Justification = 'False positive.')]
$actionScript = GetActionScript -scriptRoot $scriptRoot -scriptName $scriptName

function MockArtifact {
param([string] $name, [string] $sha = 'abc123')
[PSCustomObject]@{
name = $name
expired = $false
archive_download_url = "https://example.com/artifacts/$name"
workflow_run = [PSCustomObject]@{ head_sha = $sha }
}
}
}

It 'Compile Action' {
Expand All @@ -28,4 +41,98 @@ Describe 'DetermineArtifactsForRelease Tests' {
}
YamlTest -scriptRoot $scriptRoot -actionName $actionName -actionScript $actionScript -outputs $outputs
}

Context 'Artifact selection behavior' {
BeforeAll {
$env:GITHUB_REPOSITORY = 'org/repo'
$env:GITHUB_API_URL = 'https://api.github.com'
$env:GITHUB_REF_NAME = 'main'
$env:Settings = '{"repoName":"repo","type":"PTE","powerPlatformSolutionFolder":""}'
}

BeforeEach {
$script:githubOutputFile = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
New-Item -Path $script:githubOutputFile -ItemType File | Out-Null
$env:GITHUB_OUTPUT = $script:githubOutputFile
}

AfterEach {
if ($script:githubOutputFile -and (Test-Path $script:githubOutputFile)) {
Remove-Item -Path $script:githubOutputFile -Force
}
}

It 'Mixed projects (apps + test artifacts) produce a non-empty include list' {
$artifacts = @(
(MockArtifact 'proj1-main-Apps-1.0.0.0'),
(MockArtifact 'proj1-main-TestApps-1.0.0.0'),
(MockArtifact 'proj2-main-Apps-1.0.0.0')
)
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*page=1*' } -MockWith {
[PSCustomObject]@{ total_count = $artifacts.Count; Artifacts = $artifacts }
}
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*page=2*' } -MockWith {
[PSCustomObject]@{ total_count = 0; Artifacts = @() }
}
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*/branches/*' } -MockWith {
[PSCustomObject]@{ commit = [PSCustomObject]@{ sha = 'abc123' } }
}

& $scriptPath -buildVersion 'latest' -GITHUB_TOKEN 'tok' -TOKENFORPUSH 'tok' -ProjectsJson '["proj1","proj2"]'

$output = Get-Content $env:GITHUB_OUTPUT -Raw
$output | Should -Match 'commitish=abc123'
$output | Should -Match 'proj1-main-Apps-1\.0\.0\.0'
$output | Should -Match 'proj1-main-TestApps-1\.0\.0\.0'
$output | Should -Match 'proj2-main-Apps-1\.0\.0\.0'
}

It 'Test-only project is skipped with a warning (including build-mode test artifacts)' {
$artifacts = @(
(MockArtifact 'proj1-main-Apps-1.0.0.0'),
(MockArtifact 'proj2-main-CleanTestApps-1.0.0.0')
)
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*page=1*' } -MockWith {
[PSCustomObject]@{ total_count = $artifacts.Count; Artifacts = $artifacts }
}
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*page=2*' } -MockWith {
[PSCustomObject]@{ total_count = 0; Artifacts = @() }
}
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*/branches/*' } -MockWith {
[PSCustomObject]@{ commit = [PSCustomObject]@{ sha = 'abc123' } }
}
Mock Write-Host { } -ParameterFilter { "$Object" -like '::Warning::*proj2*' }

& $scriptPath -buildVersion 'latest' -GITHUB_TOKEN 'tok' -TOKENFORPUSH 'tok' -ProjectsJson '["proj1","proj2"]'

Assert-MockCalled Write-Host -ParameterFilter { "$Object" -like '::Warning::*proj2*' } -Scope It
$output = Get-Content $env:GITHUB_OUTPUT -Raw
$output | Should -Match 'proj1-main-Apps-1\.0\.0\.0'
$output | Should -Not -Match 'proj2-main-CleanTestApps'
}

It 'Throws a clear error when no project has releasable artifacts' {
$artifacts = @(
(MockArtifact 'proj1-main-TestApps-1.0.0.0')
)
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*page=1*' } -MockWith {
[PSCustomObject]@{ total_count = $artifacts.Count; Artifacts = $artifacts }
}
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*page=2*' } -MockWith {
[PSCustomObject]@{ total_count = 0; Artifacts = @() }
}

{ & $scriptPath -buildVersion 'latest' -GITHUB_TOKEN 'tok' -TOKENFORPUSH 'tok' -ProjectsJson '["proj1"]' } |
Should -Throw -ExpectedMessage '*No release artifacts found for any project*'
}

It 'Throws original error when a project has no artifacts of any kind' {
Mock Invoke-RestMethod -ParameterFilter { $Uri -like '*actions/artifacts*' } -MockWith {
[PSCustomObject]@{ total_count = 0; Artifacts = @() }
}

{ & $scriptPath -buildVersion 'latest' -GITHUB_TOKEN 'tok' -TOKENFORPUSH 'tok' -ProjectsJson '["proj1"]' } |
Should -Throw -ExpectedMessage '*No artifacts found for this project*'
}
}
}
Loading