stages: - build - publish # Only create pipelines automatically when a Git tag is pushed. # Otherwise the pipeline must be started manually (pipeline "Run" / dispatch equivalent). # workflow: # rules: # - if: '$CI_COMMIT_TAG' # when: always # - if: '$CI_PIPELINE_SOURCE == "web"' # when: always # - when: never variables: DOTNET_CLI_TELEMETRY_OPTOUT: "1" DOTNET_SKIP_FIRST_TIME_EXPERIENCE: "1" BUILD_CONFIG: "Release" # NOTE: This project uses repository variables for NuGet auth because secrets # (masked/protected variables) may not be available on your GitLab plan. # Replace the placeholders below with values in the repository, or override # them in your project CI/CD variables when available. # - NUGET_USERNAME : username (can be any value when using a PAT) # - NUGET_PASSWORD : personal access token or project deploy token NUGET_USERNAME: "REPLACE_WITH_USERNAME" NUGET_PASSWORD: "REPLACE_WITH_TOKEN" # Build job for Windows runner (shell executor). Remove 'image' so the runner uses the host environment. build_windows: stage: build tags: - saas-windows-medium-amd64 script: - | powershell -NoProfile -Command { $needsInstall = -not (dotnet --list-sdks 2>$null | Select-String '^10\.') if ($needsInstall) { Write-Host 'Installing .NET 10 SDK using dotnet-install.ps1' Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1 -UseBasicParsing .\dotnet-install.ps1 -Channel 10.0 -InstallDir $env:USERPROFILE\.dotnet $dotnetExe = Join-Path $env:USERPROFILE '.dotnet\dotnet.exe' } else { Write-Host '.NET 10 SDK already present on PATH' $dotnetExe = 'dotnet' } # Configure private NuGet source from GitLab Packages using CI_JOB_TOKEN # Fallback to repository variables NUGET_USERNAME/NUGET_PASSWORD for shared runners $nugetUrl = 'https://gitlab.com/api/v4/projects/79509532/packages/nuget/index.json' $authMode = $null if ($env:CI_JOB_TOKEN) { Write-Host 'Configuring private NuGet source Nuget-GitLab-AIFotoONLUS using CI_JOB_TOKEN...' try { & $dotnetExe nuget remove source Nuget-GitLab-AIFotoONLUS } catch {} & $dotnetExe nuget add source $nugetUrl --name Nuget-GitLab-AIFotoONLUS --username gitlab-ci-token --password $env:CI_JOB_TOKEN --store-password-in-clear-text $authMode = 'JobToken' } elseif ($env:NUGET_USERNAME -and $env:NUGET_PASSWORD) { Write-Host 'Configuring private NuGet source Nuget-GitLab-AIFotoONLUS using NUGET_USERNAME/NUGET_PASSWORD...' try { & $dotnetExe nuget remove source Nuget-GitLab-AIFotoONLUS } catch {} & $dotnetExe nuget add source $nugetUrl --name Nuget-GitLab-AIFotoONLUS --username $env:NUGET_USERNAME --password $env:NUGET_PASSWORD --store-password-in-clear-text $authMode = 'UserCreds' } else { Write-Host 'No credentials available; skipping private NuGet source configuration.' } & $dotnetExe --info # Diagnostic: verify GitLab NuGet feed and package visibility using configured auth if ($authMode) { Write-Host 'Checking GitLab NuGet feed index and project packages for AIFotoONLUS.Core using auth mode:' $authMode try { if ($authMode -eq 'JobToken') { $headers = @{ 'JOB-TOKEN' = $env:CI_JOB_TOKEN } } else { $pair = "$env:NUGET_USERNAME:$env:NUGET_PASSWORD" $b64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($pair)) $headers = @{ Authorization = "Basic $b64" } } Invoke-RestMethod -Uri $nugetUrl -Headers $headers -Method Get | ConvertTo-Json | Write-Host } catch { Write-Host "Failed to fetch feed index: $_" } try { $pkgApi = "https://gitlab.com/api/v4/projects/79509532/packages?package_name=AIFotoONLUS.Core" Invoke-RestMethod -Uri $pkgApi -Headers $headers -Method Get | ConvertTo-Json | Write-Host } catch { Write-Host "Failed to query project packages API: $_" } } else { Write-Host 'Skipping feed diagnostics because no auth configured.' } & $dotnetExe restore & $dotnetExe build "imagecatalog\ImageCatalog 2.csproj" -c $env:BUILD_CONFIG -v minimal } artifacts: paths: - "**/bin/$BUILD_CONFIG/net10.0-windows/**" expire_in: 1 hour # Publish and create GitLab Release when building a tag. This job expects a Windows runner with PowerShell and curl available. publish_release: stage: publish tags: - saas-windows-medium-amd64 needs: - build_windows script: - | powershell -NoProfile -Command { # Ensure .NET 10 SDK is available (install to user folder if missing) and use that dotnet for publish $needsInstall = -not (dotnet --list-sdks 2>$null | Select-String '^10\.') if ($needsInstall) { Write-Host 'Installing .NET 10 SDK using dotnet-install.ps1' Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1 -UseBasicParsing .\dotnet-install.ps1 -Channel 10.0 -InstallDir $env:USERPROFILE\.dotnet $dotnetExe = Join-Path $env:USERPROFILE '.dotnet\dotnet.exe' } else { $dotnetExe = 'dotnet' } & $dotnetExe publish "imagecatalog\ImageCatalog 2.csproj" -c $env:BUILD_CONFIG -r win-x64 --self-contained false -o publish Write-Host "Published to $(pwd)\\publish" # Configure private NuGet source from GitLab Packages using CI_JOB_TOKEN # Fallback to repository variables NUGET_USERNAME/NUGET_PASSWORD for shared runners $nugetUrl = 'https://gitlab.com/api/v4/projects/79509532/packages/nuget/index.json' if ($env:CI_JOB_TOKEN) { Write-Host 'Configuring private NuGet source Nuget-GitLab-AIFotoONLUS using CI_JOB_TOKEN...' try { & $dotnetExe nuget remove source Nuget-GitLab-AIFotoONLUS } catch {} & $dotnetExe nuget add source $nugetUrl --name Nuget-GitLab-AIFotoONLUS --username gitlab-ci-token --password $env:CI_JOB_TOKEN --store-password-in-clear-text } elseif ($env:NUGET_USERNAME -and $env:NUGET_PASSWORD) { Write-Host 'Configuring private NuGet source Nuget-GitLab-AIFotoONLUS using NUGET_USERNAME/NUGET_PASSWORD...' try { & $dotnetExe nuget remove source Nuget-GitLab-AIFotoONLUS } catch {} & $dotnetExe nuget add source $nugetUrl --name Nuget-GitLab-AIFotoONLUS --username $env:NUGET_USERNAME --password $env:NUGET_PASSWORD --store-password-in-clear-text } else { Write-Host 'No credentials available; skipping private NuGet source configuration.' } # Find first file in publish folder $file = Get-ChildItem -Path publish -File | Select-Object -First 1; Write-Host "Uploading $($file.FullName)" # Upload to GitLab project uploads API to get a public URL for the artifact $uploadUrl = "$env:CI_API_V4_URL/projects/$env:CI_PROJECT_ID/uploads" $formData = "file=@$($file.FullName)" $uploadResp = curl --silent --show-error --header "JOB-TOKEN:$env:CI_JOB_TOKEN" --form $formData $uploadUrl $uploadJson = $uploadResp | ConvertFrom-Json $assetUrl = "$env:CI_SERVER_URL$($uploadJson.url)" Write-Host "Uploaded asset url: $assetUrl" # Create the release using uploads URL $body = @{ name = $env:CI_COMMIT_TAG; tag_name = $env:CI_COMMIT_TAG; description = "Automated release from CI"; assets = @{ links = @(@{ name = "$($file.Name)"; url = $assetUrl }) } } | ConvertTo-Json -Depth 10 Invoke-RestMethod -Method Post -Uri "$env:CI_API_V4_URL/projects/$env:CI_PROJECT_ID/releases" -Headers @{ "JOB-TOKEN" = $env:CI_JOB_TOKEN } -Body $body -ContentType "application/json" } artifacts: paths: - publish/* expire_in: 1 day only: - tags # Notes for runner setup: Ensure a GitLab Windows runner with tag 'windows' is registered and has .NET 10 SDK installed. # Use the shell executor on the Windows machine so the job runs in the host PowerShell environment