Skip to content
Merged
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
71 changes: 63 additions & 8 deletions .github/workflows/release-psdocs-azure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ on:
push:
tags:
- 'psdocs-azure-v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to simulate (e.g. psdocs-azure-v0.5.0 or psdocs-azure-v0.5.0-preview.1)'
required: true
type: string
dry_run:
description: 'Skip Publish-Module and gh release create (validate + build only).'
required: false
type: boolean
default: true

permissions: {}

Expand All @@ -29,29 +40,73 @@ jobs:
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name InvokeBuild -MinimumVersion 5.4.0 -Scope CurrentUser -Force

- name: Extract version from tag
- name: Parse tag and detect channel
id: version
shell: pwsh
run: |
VERSION=${GITHUB_REF#refs/tags/psdocs-azure-v}
echo "version=$VERSION" >> $GITHUB_OUTPUT

$tagRef = if ('${{ github.event_name }}' -eq 'workflow_dispatch') { '${{ inputs.tag }}' } else { '${{ github.ref_name }}' }
$full = $tagRef -replace '^psdocs-azure-v', ''
$base = ($full -split '-', 2)[0]
$isPrerelease = $full.Contains('-')
$channel = if ($isPrerelease) { 'preview' } else { 'stable' }
"tag=$tagRef" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"full=$full" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"base=$base" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"channel=$channel" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"is_prerelease=$($isPrerelease.ToString().ToLower())" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
Write-Host "Tag: $tagRef -> full=$full base=$base channel=$channel"

- name: Validate version matches manifest
shell: pwsh
run: |
$manifestPath = './packages/psdocs-azure/src/PSDocs.Azure/PSDocs.Azure.psd1'
$manifest = Import-PowerShellDataFile -Path $manifestPath
$expected = '${{ steps.version.outputs.base }}'
if ($manifest.ModuleVersion -ne $expected) {
Write-Error "Manifest ModuleVersion '$($manifest.ModuleVersion)' does not match tag base version '$expected'. Update $manifestPath before tagging."
exit 1
}
Write-Host "Manifest ModuleVersion '$($manifest.ModuleVersion)' matches tag base '$expected'."

- name: Extract release notes
shell: pwsh
run: |
./scripts/extract-release-notes.ps1 `
-ChangelogPath ./CHANGELOG.md `
-Version '${{ steps.version.outputs.full }}' `
-OutputPath ./release-notes.md

- name: Build
shell: pwsh
working-directory: packages/psdocs-azure
run: |
Invoke-Build Build -File ./pipeline.build.ps1 -Build '${{ steps.version.outputs.version }}'
Invoke-Build Build -File ./pipeline.build.ps1 -Build '${{ steps.version.outputs.full }}'

- name: Publish to PSGallery
if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
shell: pwsh
env:
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
run: |
Publish-Module -Path packages/psdocs-azure/out/modules/PSDocs.Azure -NuGetApiKey $env:PSGALLERY_API_KEY

- name: Create GitHub Release
if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
env:
GH_TOKEN: ${{ github.token }}
PRERELEASE_FLAG: ${{ steps.version.outputs.is_prerelease == 'true' && '--prerelease' || '' }}
run: |
gh release create "${{ steps.version.outputs.tag }}" \
--title "PSDocs.Azure v${{ steps.version.outputs.full }}" \
--notes-file ./release-notes.md \
$PRERELEASE_FLAG

- name: Dry-run summary
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run == true }}
shell: pwsh
run: |
gh release create "${{ github.ref_name }}" \
--title "PSDocs.Azure v${{ steps.version.outputs.version }}" \
--notes-file CHANGELOG.md
Write-Host '=== DRY RUN ==='
Write-Host "Would publish PSDocs.Azure v${{ steps.version.outputs.full }} (channel=${{ steps.version.outputs.channel }}) to PSGallery."
Write-Host "Would create GitHub Release for tag ${{ steps.version.outputs.tag }}."
Write-Host '--- release notes ---'
Get-Content ./release-notes.md
72 changes: 64 additions & 8 deletions .github/workflows/release-psdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ on:
push:
tags:
- 'psdocs-v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to simulate (e.g. psdocs-v0.10.0 or psdocs-v0.10.0-preview.1)'
required: true
type: string
dry_run:
description: 'Skip Publish-Module and gh release create (validate + build only).'
required: false
type: boolean
default: true

permissions: {}

Expand All @@ -29,29 +40,74 @@ jobs:
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name InvokeBuild -MinimumVersion 5.4.0 -Scope CurrentUser -Force

- name: Extract version from tag
- name: Parse tag and detect channel
id: version
shell: pwsh
run: |
VERSION=${GITHUB_REF#refs/tags/psdocs-v}
echo "version=$VERSION" >> $GITHUB_OUTPUT

$tagRef = if ('${{ github.event_name }}' -eq 'workflow_dispatch') { '${{ inputs.tag }}' } else { '${{ github.ref_name }}' }
$full = $tagRef -replace '^psdocs-v', ''
$base = ($full -split '-', 2)[0]
$isPrerelease = $full.Contains('-')
$channel = if ($isPrerelease) { 'preview' } else { 'stable' }
"tag=$tagRef" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"full=$full" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"base=$base" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"channel=$channel" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"is_prerelease=$($isPrerelease.ToString().ToLower())" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
Write-Host "Tag: $tagRef -> full=$full base=$base channel=$channel"

- name: Validate version matches manifest
shell: pwsh
run: |
$manifestPath = './packages/psdocs/src/PSDocs/PSDocs.psd1'
$manifest = Import-PowerShellDataFile -Path $manifestPath
$expected = '${{ steps.version.outputs.base }}'
if ($manifest.ModuleVersion -ne $expected) {
Write-Error "Manifest ModuleVersion '$($manifest.ModuleVersion)' does not match tag base version '$expected'. Update $manifestPath before tagging."
exit 1
}
Write-Host "Manifest ModuleVersion '$($manifest.ModuleVersion)' matches tag base '$expected'."

- name: Extract release notes
id: notes
shell: pwsh
run: |
./scripts/extract-release-notes.ps1 `
-ChangelogPath ./packages/psdocs/CHANGELOG.md `
-Version '${{ steps.version.outputs.full }}' `
-OutputPath ./release-notes.md

- name: Build
shell: pwsh
working-directory: packages/psdocs
run: |
Invoke-Build Build -File ./pipeline.build.ps1 -Build '${{ steps.version.outputs.version }}'
Invoke-Build Build -File ./pipeline.build.ps1 -Build '${{ steps.version.outputs.full }}'

- name: Publish to PSGallery
if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
shell: pwsh
env:
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
run: |
Publish-Module -Path packages/psdocs/out/modules/PSDocs -NuGetApiKey $env:PSGALLERY_API_KEY

- name: Create GitHub Release
if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
env:
GH_TOKEN: ${{ github.token }}
PRERELEASE_FLAG: ${{ steps.version.outputs.is_prerelease == 'true' && '--prerelease' || '' }}
run: |
gh release create "${{ steps.version.outputs.tag }}" \
--title "PSDocs v${{ steps.version.outputs.full }}" \
--notes-file ./release-notes.md \
$PRERELEASE_FLAG

- name: Dry-run summary
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run == true }}
shell: pwsh
run: |
gh release create "${{ github.ref_name }}" \
--title "PSDocs v${{ steps.version.outputs.version }}" \
--notes-file packages/psdocs/CHANGELOG.md
Write-Host '=== DRY RUN ==='
Write-Host "Would publish PSDocs v${{ steps.version.outputs.full }} (channel=${{ steps.version.outputs.channel }}) to PSGallery."
Write-Host "Would create GitHub Release for tag ${{ steps.version.outputs.tag }}."
Write-Host '--- release notes ---'
Get-Content ./release-notes.md
98 changes: 85 additions & 13 deletions .github/workflows/release-vscode.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
# Release VS Code Extension (Stable)
# Triggered by vscode-v* tags for stable releases
# Release VS Code Extension
# Stable: tag `vscode-vX.Y.Z` -> extension `vicperdana.psdocs-vscode`
# Preview: tag `vscode-preview-vX.Y.Z` -> extension `vicperdana.psdocs-vscode-preview` (separate Marketplace listing)
#
# VS Code Marketplace does not accept SemVer prerelease suffixes (e.g. -preview.1) in
# the package version, so the channel is encoded in the tag prefix and routed to the
# build pipeline via -Channel. Both channels use plain X.Y.Z versions in package.json.

name: Release VS Code Extension

on:
push:
tags:
- 'vscode-v*'
- 'vscode-preview-v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to simulate (e.g. vscode-v0.4.0 or vscode-preview-v0.4.0)'
required: true
type: string
dry_run:
description: 'Skip vsce publish and gh release create (validate + build only).'
required: false
type: boolean
default: true

permissions:
contents: write

jobs:
release:
name: Release Stable
name: Release
runs-on: ubuntu-latest
environment: release

Expand All @@ -34,22 +51,61 @@ jobs:
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name InvokeBuild -MinimumVersion 5.4.0 -Scope CurrentUser -Force

- name: Extract version from tag
- name: Parse tag and detect channel
id: version
shell: pwsh
run: |
VERSION=${GITHUB_REF#refs/tags/vscode-v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Releasing version: $VERSION"
$tag = if ('${{ github.event_name }}' -eq 'workflow_dispatch') { '${{ inputs.tag }}' } else { '${{ github.ref_name }}' }
if ($tag -match '^vscode-preview-v(.+)$') {
$version = $Matches[1]
$channel = 'preview'
$isPrerelease = $true
} elseif ($tag -match '^vscode-v(.+)$') {
$version = $Matches[1]
$channel = 'stable'
$isPrerelease = $false
} else {
Write-Error "Tag '$tag' does not match expected pattern vscode-v* or vscode-preview-v*"
exit 1
}
if ($version -notmatch '^\d+\.\d+\.\d+$') {
Write-Error "Version '$version' must be plain SemVer (X.Y.Z) — VS Code Marketplace does not accept prerelease suffixes."
exit 1
}
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"channel=$channel" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
"is_prerelease=$($isPrerelease.ToString().ToLower())" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
Write-Host "Tag: $tag -> version=$version channel=$channel"

- name: Validate version matches package.json
shell: pwsh
run: |
$pkg = Get-Content ./packages/vscode-extension/package.json -Raw | ConvertFrom-Json
$expected = '${{ steps.version.outputs.version }}'
if ($pkg.version -ne $expected) {
Write-Error "package.json version '$($pkg.version)' does not match tag version '$expected'. Update packages/vscode-extension/package.json before tagging."
exit 1
}
Write-Host "package.json version '$($pkg.version)' matches tag '$expected'."

- name: Extract release notes
shell: pwsh
run: |
./scripts/extract-release-notes.ps1 `
-ChangelogPath ./packages/vscode-extension/CHANGELOG.md `
-Version '${{ steps.version.outputs.version }}' `
-OutputPath ./release-notes.md

- name: Install dependencies
working-directory: packages/vscode-extension
run: npm ci

- name: Build stable channel
- name: Build (${{ steps.version.outputs.channel }})
shell: pwsh
working-directory: packages/vscode-extension
run: |
Invoke-Build Build -Channel 'stable' -Build '${{ steps.version.outputs.version }}'
Invoke-Build Build -Channel '${{ steps.version.outputs.channel }}' -Build '${{ steps.version.outputs.version }}'

- name: Find VSIX file
id: vsix
Expand All @@ -65,17 +121,33 @@ jobs:
echo "Found VSIX: $VSIX_FILE"

- name: Publish to VS Marketplace
if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
working-directory: packages/vscode-extension/out/package
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
PRE_RELEASE_FLAG: ${{ steps.version.outputs.is_prerelease == 'true' && '--pre-release' || '' }}
run: |
npx @vscode/vsce publish --packagePath "${{ steps.vsix.outputs.file }}" --pat "$VSCE_PAT"
npx @vscode/vsce publish --packagePath "${{ steps.vsix.outputs.file }}" --pat "$VSCE_PAT" $PRE_RELEASE_FLAG

- name: Create GitHub Release
if: ${{ github.event_name != 'workflow_dispatch' || inputs.dry_run != true }}
env:
GH_TOKEN: ${{ github.token }}
PRERELEASE_FLAG: ${{ steps.version.outputs.is_prerelease == 'true' && '--prerelease' || '' }}
TITLE_SUFFIX: ${{ steps.version.outputs.is_prerelease == 'true' && ' (Preview)' || '' }}
run: |
gh release create "${{ github.ref_name }}" \
--title "VS Code Extension v${{ steps.version.outputs.version }}" \
--notes-file packages/vscode-extension/CHANGELOG.md \
gh release create "${{ steps.version.outputs.tag }}" \
--title "VS Code Extension v${{ steps.version.outputs.version }}$TITLE_SUFFIX" \
--notes-file ./release-notes.md \
$PRERELEASE_FLAG \
"${{ steps.vsix.outputs.path }}"

- name: Dry-run summary
if: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run == true }}
shell: pwsh
run: |
Write-Host '=== DRY RUN ==='
Write-Host "Would publish VS Code extension v${{ steps.version.outputs.version }} (channel=${{ steps.version.outputs.channel }}) to VS Marketplace."
Write-Host "Would create GitHub Release for tag ${{ steps.version.outputs.tag }} with VSIX ${{ steps.vsix.outputs.file }}."
Write-Host '--- release notes ---'
Get-Content ./release-notes.md
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ Check out the links below to get started.

### Release Process

Refer to [release process](docs/release.md)
See [RELEASING.md](RELEASING.md) for the full release runbook covering all three packages
(PSDocs, PSDocs.Azure, VS Code extension), tag conventions, and the pre-release flow.

## Thank You!

Expand Down
14 changes: 14 additions & 0 deletions MONOREPO_MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@ git subtree pull --prefix=packages/psdocs https://github.com/microsoft/PSDocs.gi
git subtree pull --prefix=packages/vscode-extension https://github.com/microsoft/PSDocs-vscode.git main --squash
```

> **After any subtree pull**, audit the result and remove anything we don't
> want to inherit from upstream:
>
> - `packages/*/.azure-pipelines/` and `packages/*/azure-pipelines*.yaml` —
> the monorepo uses GitHub Actions (`/.github/workflows/`); upstream ADO
> pipelines are not active here and should be deleted to avoid confusion.
> - `packages/*/.github/workflows/` — workflows nested inside packages do
> not run on GitHub. Either delete them or, if a workflow is genuinely
> wanted, move and adapt it under root `.github/workflows/` with
> appropriate path filters.
> - Any upstream `.github/dependabot.yml` / `.github/CODEOWNERS` etc. —
> monorepo policy lives at the repo root and should not be shadowed by
> per-package copies.

## Workflow Migration

The following legacy workflows were removed as part of the monorepo migration, replaced by new workflows with path-based filtering:
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ For a list of module changes please see the [change log](CHANGELOG.md).
> Pre-release versions should be considered experimental.
> Modules and change log details for pre-releases will be removed as standard releases are made available.

For maintainers cutting a release, see [RELEASING.md](RELEASING.md).

## Contributing

This project welcomes contributions and suggestions.
Expand Down
Loading
Loading