Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions .github/workflows/CI-workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,48 @@ on:
paths:
- '.github/workflows/**'
jobs:
test-workflows:
runs-on: ubuntu-latest
defaults:
run:
shell: pwsh
steps:
- name: Placeholder
run: echo "Placeholder for testing workflows"
test-authorize-user:
name: authorized actor
uses: ./.github/workflows/authorize-user.yml
with:
actor: test-authorized-user
authorized-users: test-authorized-user, another-user

test-generate-release-notes:
name: valid version
uses: ./.github/workflows/generate-release-notes.yml
with:
version: 1.2.3
dry-run: true

test-publish-release-notes:
name: valid version
uses: ./.github/workflows/publish-release-notes.yml
with:
version: 1.2.3
dry-run: true

test-push-powershell-packages:
name: valid version
uses: ./.github/workflows/push-powershell-packages.yml
with:
version: 1.2.3
package-pattern: '*.nupkg'
dry-run: true

test-push-release-info-to-aws-s3:
name: valid version
uses: ./.github/workflows/push-release-info-to-aws-s3.yml
with:
version: 1.2.3
product: TestProduct
bucket: test-bucket
dry-run: true

validate-workflow-tests:
# So we can add new tests without having to update branch protection rules
name: Validate workflow test results
needs: [test-workflows]
needs: [test-authorize-user, test-generate-release-notes, test-publish-release-notes, test-push-powershell-packages, test-push-release-info-to-aws-s3]
if: always()
runs-on: ubuntu-latest
defaults:
Expand Down
30 changes: 28 additions & 2 deletions .github/workflows/authorize-user.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
name: Check Authorized User
on:
workflow_call:
inputs:
actor:
required: false
type: string
default: ''
description: >
Test-only override for the actor to check. Only usable within the Particular/deployment-workflows
repository - set anywhere else, this fails the workflow.
authorized-users:
required: false
type: string
default: ''
description: >
Test-only override for the comma-separated authorized users list. Only usable within the
Particular/deployment-workflows repository - set anywhere else, this fails the workflow.
jobs:
check-authorized-user:
runs-on: ubuntu-latest
Expand All @@ -10,8 +25,19 @@ jobs:
steps:
- name: Verify authorized user
run: |
$actor = "${{ github.actor }}"
$authorizedUsers = "${{ vars.AUTHORIZED_RELEASE_USERS }}" -split ',' | ForEach-Object { $_.Trim() }
$actorOverride = "${{ inputs.actor }}"
$authorizedUsersOverride = "${{ inputs.authorized-users }}"
$repository = "${{ github.repository }}"

if (($actorOverride -or $authorizedUsersOverride) -and $repository -ne 'Particular/deployment-workflows')
{
throw "The 'actor' and 'authorized-users' inputs are test-only overrides and may only be used within the Particular/deployment-workflows repository. This run is in '$repository'."
}

$actor = if ($actorOverride) { $actorOverride } else { "${{ github.actor }}" }
$authorizedUsersRaw = if ($authorizedUsersOverride) { $authorizedUsersOverride } else { "${{ vars.AUTHORIZED_RELEASE_USERS }}" }
$authorizedUsers = $authorizedUsersRaw -split ',' | ForEach-Object { $_.Trim() }

if ($authorizedUsers -notcontains $actor) {
Write-Error "User '$actor' is not authorized to run this workflow."
exit 1
Expand Down
14 changes: 13 additions & 1 deletion .github/workflows/generate-release-notes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ on:
version:
required: true
type: string
dry-run:
required: false
type: boolean
default: false
jobs:
generate-release-notes:
runs-on: ubuntu-latest
Expand All @@ -29,6 +33,14 @@ jobs:
- name: Update draft release notes from milestone
run: |
Write-Output "Updating draft release body for ${{ github.event.repository.name }} ${{ inputs.version }} from milestone '${{ inputs.version }}'"
dotnet-gitreleasemanager create --token $env:GITHUB_TOKEN -o "${{ github.repository_owner }}" -r "${{ github.event.repository.name }}" -m "${{ inputs.version }}" -n "${{ inputs.version }}" -d .release

if ('${{ inputs.dry-run }}' -eq 'true')
{
Write-Output "[dry-run] Would run: dotnet-gitreleasemanager create -o ${{ github.repository_owner }} -r ${{ github.event.repository.name }} -m ${{ inputs.version }} -n ${{ inputs.version }} -d .release"
}
else
{
dotnet-gitreleasemanager create --token $env:GITHUB_TOKEN -o "${{ github.repository_owner }}" -r "${{ github.event.repository.name }}" -m "${{ inputs.version }}" -n "${{ inputs.version }}" -d .release
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 changes: 13 additions & 1 deletion .github/workflows/publish-release-notes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ on:
version:
required: true
type: string
dry-run:
required: false
type: boolean
default: false
jobs:
publish-release-notes:
runs-on: ubuntu-latest
Expand All @@ -22,6 +26,14 @@ jobs:
- name: Publish release
run: |
Write-Output "Publishing release ${{ inputs.version }} for ${{ github.event.repository.name }}"
dotnet-gitreleasemanager publish --token $env:GITHUB_TOKEN -o "${{ github.repository_owner }}" -r "${{ github.event.repository.name }}" -t "${{ inputs.version }}"

if ('${{ inputs.dry-run }}' -eq 'true')
{
Write-Output "[dry-run] Would run: dotnet-gitreleasemanager publish -o ${{ github.repository_owner }} -r ${{ github.event.repository.name }} -t ${{ inputs.version }}"
}
else
{
dotnet-gitreleasemanager publish --token $env:GITHUB_TOKEN -o "${{ github.repository_owner }}" -r "${{ github.event.repository.name }}" -t "${{ inputs.version }}"
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30 changes: 24 additions & 6 deletions .github/workflows/push-powershell-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
package-pattern:
required: true
type: string
dry-run:
required: false
type: boolean
default: false
jobs:
push-powershell-packages:
runs-on: ubuntu-latest
Expand All @@ -17,7 +21,14 @@ jobs:
steps:
- name: Download assets from release
run: |
gh release download "${{ inputs.version }}" --repo "${{ github.repository }}" --pattern "${{ inputs.package-pattern }}" --dir powershellModules
if ('${{ inputs.dry-run }}' -eq 'true')
{
Write-Output "[dry-run] Would download assets matching '${{ inputs.package-pattern }}' from release '${{ inputs.version }}'."
}
else
{
gh release download "${{ inputs.version }}" --repo "${{ github.repository }}" --pattern "${{ inputs.package-pattern }}" --dir powershellModules
}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand All @@ -29,10 +40,17 @@ jobs:
{
Register-PSResourceRepository -Name ${{ vars.GALLERY_NAME }} -Uri ${{ vars.GALLERY_SOURCE_LOCATION }} -Trusted
}
$psModules = Get-ChildItem powershellModules -File
Write-Output "Pushing $($psModules.Count) PowerShell module package(s) to ${{ vars.GALLERY_NAME }}:"
$psModules | ForEach-Object { Write-Output " - $($_.Name)" }
foreach ($module in $psModules)
if ('${{ inputs.dry-run }}' -eq 'true')
{
Write-Output "[dry-run] Would push PowerShell module package(s) found under 'powershellModules/' to ${{ vars.GALLERY_NAME }}."
}
else
{
Publish-PSResource -NupkgPath $module.FullName -Repository ${{ vars.GALLERY_NAME }} -ApiKey ${{ secrets.GALLERY_KEY }}
$psModules = Get-ChildItem powershellModules -File
Write-Output "Pushing $($psModules.Count) PowerShell module package(s) to ${{ vars.GALLERY_NAME }}:"
$psModules | ForEach-Object { Write-Output " - $($_.Name)" }
foreach ($module in $psModules)
{
Publish-PSResource -NupkgPath $module.FullName -Repository ${{ vars.GALLERY_NAME }} -ApiKey ${{ secrets.GALLERY_KEY }}
}
}
104 changes: 58 additions & 46 deletions .github/workflows/push-release-info-to-aws-s3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ on:
bucket:
required: true
type: string
dry-run:
required: false
type: boolean
default: false
jobs:
push-release-info-to-aws-s3:
runs-on: ubuntu-latest
Expand All @@ -19,66 +23,74 @@ jobs:
shell: pwsh
steps:
- name: Setup AWS Credentials
if: ${{ !inputs.dry-run }}
uses: aws-actions/configure-aws-credentials@v5.1.1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESSKEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRETKEY }}
aws-region: us-west-2
- name: Push release info to S3
run: |
$product = "${{ inputs.product }}"

try {
$response = Invoke-WebRequest -Uri https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ inputs.version }} -UseBasicParsing
}
catch {
Write-Error "Failed to fetch release ${{ inputs.version }}: $($_.Exception.Message)"
exit 1
if ('${{ inputs.dry-run }}' -eq 'true')
{
Write-Output "[dry-run] Would fetch release '${{ inputs.version }}', validate it, and upload its info to s3://${{ inputs.bucket }}/$('${{ inputs.product }}'.ToLower()).txt."
}
else
{
$product = "${{ inputs.product }}"

# Filter and rework the JSON
$obj = ConvertFrom-Json $response.Content -ErrorAction Stop
try {
$response = Invoke-WebRequest -Uri https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ inputs.version }} -UseBasicParsing
}
catch {
Write-Error "Failed to fetch release ${{ inputs.version }}: $($_.Exception.Message)"
exit 1
}

if ($obj.Draft -or $obj.Prerelease) {
Write-Error "Release $($obj.tag_name) is a draft or prerelease, aborting"
exit 1
}
# Filter and rework the JSON
$obj = ConvertFrom-Json $response.Content -ErrorAction Stop

$release = $obj | Select-Object -Property @{Name="tag";Expression={$_."tag_name"}}, @{Name="release";Expression={$_."html_url"}}, @{Name="published";Expression={$_."published_at"}}, assets
if (-not ($release.tag -match '^\d+\.\d+\.\d+$')) {
Write-Error "Release $($release.tag) has an invalid tag format, aborting"
exit 1
}

$release.assets = @($release.assets | Where-Object name -Like "*.exe" | Select-Object -Property name, size, @{Name="download";Expression={$_."browser_download_url"}})
if ($obj.Draft -or $obj.Prerelease) {
Write-Error "Release $($obj.tag_name) is a draft or prerelease, aborting"
exit 1
}

if (-not $release.assets) {
Write-Error "Release $($release.tag) has no exe assets, aborting"
exit 1
}
$release = $obj | Select-Object -Property @{Name="tag";Expression={$_."tag_name"}}, @{Name="release";Expression={$_."html_url"}}, @{Name="published";Expression={$_."published_at"}}, assets
if (-not ($release.tag -match '^\d+\.\d+\.\d+$')) {
Write-Error "Release $($release.tag) has an invalid tag format, aborting"
exit 1
}

$newobj = @($release)
$json = ConvertTo-Json $newobj -Depth 100 -ErrorAction Stop
$release.assets = @($release.assets | Where-Object name -Like "*.exe" | Select-Object -Property name, size, @{Name="download";Expression={$_."browser_download_url"}})

# Write JSON to S3
$bucket = "${{ inputs.bucket }}"
$key = "{0}.txt" -f $product.ToLower()
$tempFile = New-TemporaryFile
Set-Content -Path $tempFile -Value $json -NoNewline
if (-not $release.assets) {
Write-Error "Release $($release.tag) has no exe assets, aborting"
exit 1
}

aws s3 cp $tempFile "s3://$bucket/$key" --content-type application/json
if ($LASTEXITCODE -ne 0) {
Write-Error "Upload to S3 failed"
exit 1
}
$newobj = @($release)
$json = ConvertTo-Json $newobj -Depth 100 -ErrorAction Stop

# Double check upload
$expectedSize = ([System.Text.Encoding]::UTF8.GetByteCount($json))
$uploadedSize = aws s3api head-object --bucket $bucket --key $key --query ContentLength --output text
if ([int]$uploadedSize -ne $expectedSize) {
Write-Error "Content verification failed"
exit 1
}
else {
Write-Output ("Updated file now be available at http://{0}/{1} (case sensitive URL)" -f $bucket, $key)
# Write JSON to S3
$bucket = "${{ inputs.bucket }}"
$key = "{0}.txt" -f $product.ToLower()
$tempFile = New-TemporaryFile
Set-Content -Path $tempFile -Value $json -NoNewline

aws s3 cp $tempFile "s3://$bucket/$key" --content-type application/json
if ($LASTEXITCODE -ne 0) {
Write-Error "Upload to S3 failed"
exit 1
}

# Double check upload
$expectedSize = ([System.Text.Encoding]::UTF8.GetByteCount($json))
$uploadedSize = aws s3api head-object --bucket $bucket --key $key --query ContentLength --output text
if ([int]$uploadedSize -ne $expectedSize) {
Write-Error "Content verification failed"
exit 1
}
else {
Write-Output ("Updated file now be available at http://{0}/{1} (case sensitive URL)" -f $bucket, $key)
}
}
6 changes: 6 additions & 0 deletions .release/.templates/default/issue-note.sbn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{
if issue.is_pull_request
}}- [__#{{ issue.public_number }}__]({{ issue.html_url }}) {{ issue.title }}
{{ else
}}- [__#{{ issue.public_number }}__]({{ issue.html_url }}) {{ issue.title }}
{{ end -}}
10 changes: 10 additions & 0 deletions .release/GitReleaseManager.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
templates-dir: .templates
create:
include-footer: true
issue-labels-include:
- "Bug"
- "Feature"
- "Improvement"
- "Dependency CVE"
issue-labels-exclude:
- "Refactoring"
9 changes: 9 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"sdk": {
"version": "10.0.100",
"rollForward": "latestFeature"
},
"msbuild-sdks": {
"Microsoft.Build.NoTargets": "3.7.56"
}
}
Loading