Skip to content

Commit 4412b4b

Browse files
committed
refactor: streamline PowerShell module publishing workflow and enhance pre-publish checks
1 parent ab8e07a commit 4412b4b

File tree

4 files changed

+385
-58
lines changed

4 files changed

+385
-58
lines changed
Lines changed: 26 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,37 @@
1-
# This is a basic workflow to help you get started with Actions
2-
3-
name: Publish to PowerShell Gallery
4-
5-
# Controls when the action will run.
1+
name: publish to powershell gallery
62
on:
73
push:
8-
branches: [ master ]
4+
branches: [master]
95
paths:
10-
- "**.psd1" # run when manifest changes (usually when version bumps)
6+
- "**.psd1"
7+
118
workflow_dispatch:
129

13-
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
1410
jobs:
15-
publish:
16-
runs-on: ubuntu-latest
11+
publishmodule:
12+
runs-on: windows-latest
1713
steps:
18-
- name: Checkout
19-
uses: actions/checkout@v4
20-
21-
- name: Set up PowerShellGet
14+
- uses: actions/checkout@v4
15+
- uses: dlemstra/code-sign-action@v1
16+
with:
17+
certificate: ${{ secrets.CERTIFICATE }}
18+
password: ${{ secrets.CERTIFICATE_PASSWORD }}
19+
folder: .
20+
recursive: true
21+
files: |
22+
*.ps1
23+
*.psm1
24+
- name: publish to powershell gallery
2225
shell: pwsh
23-
run: |
24-
$ErrorActionPreference = 'Stop'
25-
# Avoid prompts and ensure we can install to the current user on hosted runners
26-
if (-not (Get-PSRepository -Name 'PSGallery' -ErrorAction SilentlyContinue)) {
27-
Register-PSRepository -Name 'PSGallery' -SourceLocation 'https://www.powershellgallery.com/api/v2' -InstallationPolicy Trusted
28-
} else {
29-
Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
30-
}
31-
# Ensure NuGet package provider is available without interactive prompts
32-
$null = Get-PackageProvider -Name NuGet -ForceBootstrap -ErrorAction Stop
33-
Import-Module PowerShellGet -ErrorAction Stop
34-
35-
- name: Publish module (skip if version exists)
3626
env:
37-
NUGET_API_KEY: ${{ secrets.NUGETKEY }}
38-
shell: pwsh
27+
nugetkey: ${{secrets.NUGETKEY}}
3928
run: |
40-
$ErrorActionPreference = 'Stop'
41-
$moduleFolder = Join-Path $PWD 'code365scripts.openai'
42-
if (-not (Test-Path $moduleFolder)) {
43-
throw "Module folder not found: $moduleFolder"
29+
Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
30+
$data = Import-PowerShellDataFile .\code365scripts.openai\code365scripts.openai.psd1
31+
if($data.RequiredModules) {
32+
$data.RequiredModules | Foreach-Object {Install-Module -Name $_.ModuleName -RequiredVersion $_.ModuleVersion }
4433
}
45-
46-
$manifest = Get-ChildItem -Path $moduleFolder -Filter *.psd1 | Select-Object -First 1
47-
if (-not $manifest) { throw "No module manifest (*.psd1) found under $moduleFolder" }
48-
49-
# Parse manifest without validating RequiredModules to avoid CI dependency failures
50-
$data = Import-PowerShellDataFile -Path $manifest.FullName
51-
$localVersion = [version]$data.ModuleVersion
52-
# Use manifest base name as module name (matches folder and PSGallery name)
53-
$moduleName = $manifest.BaseName
54-
55-
Write-Host "Local module: $moduleName v$localVersion"
56-
$published = Find-Module -Name $moduleName -Repository PSGallery -ErrorAction SilentlyContinue
57-
if ($published -and ([version]$published.Version -ge $localVersion)) {
58-
Write-Host "A version ($($published.Version)) already exists on PSGallery for $moduleName. Skipping publish."
59-
exit 0
60-
}
61-
62-
if (-not $env:NUGET_API_KEY) { throw 'NuGet API key is not set. Configure secrets.NUGETKEY in the repository settings.' }
63-
64-
# CI safety: ensure any lightweight dependency listed in RequiredModules is present
65-
try {
66-
Install-Module -Name PowerShellExtension -Scope CurrentUser -Force -ErrorAction Stop
67-
} catch { Write-Host 'Optional dependency install failed; continuing...' }
68-
69-
Publish-Module -Path $moduleFolder -Repository 'PSGallery' -NuGetApiKey $env:NUGET_API_KEY -Verbose
34+
Remove-Item -Path ".git" -Recurse -Force
35+
Remove-Item -Path ".github" -Recurse -Force
36+
Remove-Item -Path ".vscode" -Recurse -Force
37+
Publish-PSResource -ApiKey $env:nugetkey -Path .\code365scripts.openai\code365scripts.openai.psd1 -Repository PSGallery

PUBLISH_GUIDE.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# PowerShell Module Publishing Guide
2+
3+
This guide will walk you through publishing the `code365scripts.openai` module to the PowerShell Gallery.
4+
5+
## 📋 Prerequisites
6+
7+
1. **PowerShell Gallery Account**
8+
- Visit [PowerShell Gallery](https://www.powershellgallery.com/)
9+
- Sign in with your Microsoft account
10+
- Go to `Account Settings``API Keys`
11+
- Create a new API Key with "Push new packages and package versions" permission
12+
13+
2. **PowerShellGet Module**
14+
```powershell
15+
# Check if already installed
16+
Get-Module -ListAvailable PowerShellGet
17+
18+
# Install or update if needed
19+
Install-Module -Name PowerShellGet -Force -AllowClobber
20+
```
21+
22+
## 🚀 Publishing Steps
23+
24+
### Step 1: Run Pre-publish Check
25+
```powershell
26+
.\pre-publish-check.ps1
27+
```
28+
29+
### Step 2: Test Publishing (Optional)
30+
```powershell
31+
# Use WhatIf parameter to preview the publishing process
32+
.\publish.ps1 -NuGetApiKey 'your-api-key-here' -WhatIf
33+
```
34+
35+
### Step 3: Official Publishing
36+
```powershell
37+
# Replace with your actual API Key
38+
.\publish.ps1 -NuGetApiKey 'your-api-key-here'
39+
```
40+
41+
## ✅ Post-publishing Verification
42+
43+
1. **Check PowerShell Gallery**
44+
- Visit: https://www.powershellgallery.com/packages/code365scripts.openai
45+
- Confirm the new version has been uploaded
46+
47+
2. **Test Installation**
48+
```powershell
49+
# Test in a new PowerShell session
50+
Install-Module -Name code365scripts.openai -Force
51+
Get-Module -ListAvailable code365scripts.openai
52+
```
53+
54+
3. **Test Functionality**
55+
```powershell
56+
Import-Module code365scripts.openai
57+
Get-Command -Module code365scripts.openai
58+
```
59+
60+
## 🔄 Version Management
61+
62+
For each new version release:
63+
64+
1. **Update Version Number**
65+
- Edit `ModuleVersion` in `code365scripts.openai.psd1`
66+
- Follow Semantic Versioning (SemVer)
67+
68+
2. **Update CHANGELOG.md**
69+
- Document new features, fixes, and breaking changes
70+
71+
3. **Run Tests**
72+
```powershell
73+
# If you have test scripts
74+
.\_tests_\test.ps1
75+
```
76+
77+
## 🛠️ Troubleshooting
78+
79+
### Common Errors
80+
81+
1. **Version Number Issue**
82+
```
83+
Error: The specified version 'x.x.x.x' of module 'ModuleName' cannot be published as the current version 'x.x.x.x' is already available
84+
```
85+
**Solution**: Increment the version number
86+
87+
2. **Invalid API Key**
88+
```
89+
Error: The specified API key is invalid
90+
```
91+
**Solution**: Check if API Key is correct and has sufficient permissions
92+
93+
3. **Module Manifest Error**
94+
```
95+
Error: The module manifest could not be validated
96+
```
97+
**Solution**: Run `Test-ModuleManifest` to check syntax
98+
99+
### Validation Commands
100+
101+
```powershell
102+
# Validate module manifest
103+
Test-ModuleManifest .\code365scripts.openai\code365scripts.openai.psd1
104+
105+
# Check module import
106+
Import-Module .\code365scripts.openai -Force
107+
Get-Module code365scripts.openai
108+
109+
# Verify function exports
110+
Get-Command -Module code365scripts.openai
111+
```
112+
113+
## 📞 Support
114+
115+
If you encounter issues:
116+
1. Check [PowerShell Gallery documentation](https://docs.microsoft.com/en-us/powershell/scripting/gallery/)
117+
2. Review [PowerShellGet documentation](https://docs.microsoft.com/en-us/powershell/module/powershellget/)
118+
3. Report issues in GitHub Issues
119+
120+
## 🎉 After Successful Publishing
121+
122+
1. **Update README.md** badges
123+
2. **Create GitHub Release**
124+
3. **Notify users** about the new version
125+
4. **Monitor** download statistics and user feedback
126+
127+
---
128+
129+
**Note**: First-time publishing may take a few minutes to appear in the PowerShell Gallery.

pre-publish-check.ps1

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# Pre-publish check script
2+
# Validates module integrity and best practices before publishing
3+
4+
$ModulePath = ".\code365scripts.openai"
5+
$ModuleName = "code365scripts.openai"
6+
7+
Write-Host "🔍 PowerShell Module Pre-publish Check" -ForegroundColor Green
8+
Write-Host "Module path: $ModulePath" -ForegroundColor Cyan
9+
Write-Host ""
10+
11+
$issues = @()
12+
$warnings = @()
13+
14+
# 1. Check module manifest
15+
Write-Host "1️⃣ Checking module manifest (.psd1)" -ForegroundColor Yellow
16+
try {
17+
$manifest = Test-ModuleManifest -Path "$ModulePath\$ModuleName.psd1" -ErrorAction Stop
18+
Write-Host " ✅ Module manifest syntax is correct" -ForegroundColor Green
19+
Write-Host " 📊 Module version: $($manifest.Version)" -ForegroundColor Cyan
20+
Write-Host " 📊 PowerShell version requirement: $($manifest.PowerShellVersion)" -ForegroundColor Cyan
21+
Write-Host " 📊 Compatible editions: $($manifest.CompatiblePSEditions -join ', ')" -ForegroundColor Cyan
22+
}
23+
catch {
24+
$issues += "Module manifest validation failed: $_"
25+
Write-Host " ❌ Module manifest validation failed" -ForegroundColor Red
26+
}
27+
28+
# 2. Check required files
29+
Write-Host "`n2️⃣ Checking required files" -ForegroundColor Yellow
30+
$requiredFiles = @(
31+
"$ModulePath\$ModuleName.psd1",
32+
"$ModulePath\$ModuleName.psm1"
33+
)
34+
35+
foreach ($file in $requiredFiles) {
36+
if (Test-Path $file) {
37+
Write-Host "$($file | Split-Path -Leaf) exists" -ForegroundColor Green
38+
}
39+
else {
40+
$issues += "Missing required file: $file"
41+
Write-Host "$($file | Split-Path -Leaf) missing" -ForegroundColor Red
42+
}
43+
}
44+
45+
# 3. Check public functions
46+
Write-Host "`n3️⃣ Checking public functions" -ForegroundColor Yellow
47+
$publicFunctions = Get-ChildItem -Path "$ModulePath\Public" -Filter "*.ps1" | ForEach-Object { $_.BaseName }
48+
$exportedFunctions = $manifest.ExportedFunctions.Keys
49+
50+
Write-Host " 📁 Functions in Public folder: $($publicFunctions -join ', ')" -ForegroundColor Cyan
51+
Write-Host " 📋 Functions exported in manifest: $($exportedFunctions -join ', ')" -ForegroundColor Cyan
52+
53+
$missingExports = $publicFunctions | Where-Object { $_ -notin $exportedFunctions }
54+
$extraExports = $exportedFunctions | Where-Object { $_ -notin $publicFunctions }
55+
56+
if ($missingExports) {
57+
$warnings += "The following functions are in Public folder but not exported in manifest: $($missingExports -join ', ')"
58+
Write-Host " ⚠️ Not exported: $($missingExports -join ', ')" -ForegroundColor Yellow
59+
}
60+
61+
if ($extraExports) {
62+
$warnings += "The following functions are exported in manifest but not in Public folder: $($extraExports -join ', ')"
63+
Write-Host " ⚠️ Extra exports: $($extraExports -join ', ')" -ForegroundColor Yellow
64+
}
65+
66+
if (-not $missingExports -and -not $extraExports) {
67+
Write-Host " ✅ Function export configuration is correct" -ForegroundColor Green
68+
}
69+
70+
# 4. Check documentation
71+
Write-Host "`n4️⃣ Checking documentation" -ForegroundColor Yellow
72+
$docFiles = @("README.md", "CHANGELOG.md", "LICENSE")
73+
foreach ($doc in $docFiles) {
74+
if (Test-Path $doc) {
75+
Write-Host "$doc exists" -ForegroundColor Green
76+
}
77+
else {
78+
$warnings += "Recommend adding $doc file"
79+
Write-Host " ⚠️ $doc missing" -ForegroundColor Yellow
80+
}
81+
}
82+
83+
# 5. Check version information
84+
Write-Host "`n5️⃣ Checking version management" -ForegroundColor Yellow
85+
try {
86+
$onlineModule = Find-Module -Name $ModuleName -ErrorAction Stop
87+
if ($manifest.Version -gt $onlineModule.Version) {
88+
Write-Host " ✅ Version number correctly incremented ($($onlineModule.Version)$($manifest.Version))" -ForegroundColor Green
89+
}
90+
elseif ($manifest.Version -eq $onlineModule.Version) {
91+
$issues += "Version number not updated, current version $($manifest.Version) is same as online version"
92+
Write-Host " ❌ Version number not updated" -ForegroundColor Red
93+
}
94+
else {
95+
$issues += "Version number rolled back, current version $($manifest.Version) is lower than online version $($onlineModule.Version)"
96+
Write-Host " ❌ Version number rolled back" -ForegroundColor Red
97+
}
98+
}
99+
catch {
100+
Write-Host " 📦 New module, no need to check online version" -ForegroundColor Cyan
101+
}
102+
103+
# 6. Syntax check
104+
Write-Host "`n6️⃣ PowerShell syntax check" -ForegroundColor Yellow
105+
$psFiles = Get-ChildItem -Path $ModulePath -Filter "*.ps1" -Recurse
106+
$syntaxErrors = @()
107+
108+
foreach ($file in $psFiles) {
109+
try {
110+
$null = [System.Management.Automation.PSParser]::Tokenize((Get-Content $file.FullName -Raw), [ref]$null)
111+
Write-Host "$($file.Name) syntax correct" -ForegroundColor Green
112+
}
113+
catch {
114+
$syntaxErrors += "$($file.Name): $_"
115+
Write-Host "$($file.Name) syntax error" -ForegroundColor Red
116+
}
117+
}
118+
119+
if ($syntaxErrors) {
120+
$issues += $syntaxErrors
121+
}
122+
123+
# Summary
124+
Write-Host "`n📋 Check Summary" -ForegroundColor Green
125+
Write-Host "=" * 50
126+
127+
if ($issues.Count -eq 0 -and $warnings.Count -eq 0) {
128+
Write-Host "🎉 Congratulations! Module is ready for publishing!" -ForegroundColor Green
129+
}
130+
else {
131+
if ($issues.Count -gt 0) {
132+
Write-Host "❌ Found $($issues.Count) issues that must be fixed:" -ForegroundColor Red
133+
$issues | ForEach-Object { Write-Host "$_" -ForegroundColor Red }
134+
}
135+
136+
if ($warnings.Count -gt 0) {
137+
Write-Host "⚠️ Found $($warnings.Count) recommendations for improvement:" -ForegroundColor Yellow
138+
$warnings | ForEach-Object { Write-Host "$_" -ForegroundColor Yellow }
139+
}
140+
}
141+
142+
if ($issues.Count -eq 0) {
143+
Write-Host "`n🚀 You can publish the module using:" -ForegroundColor Cyan
144+
Write-Host " .\publish.ps1 -NuGetApiKey 'your-api-key'" -ForegroundColor White
145+
Write-Host " .\publish.ps1 -NuGetApiKey 'your-api-key' -WhatIf # Preview mode" -ForegroundColor White
146+
}

0 commit comments

Comments
 (0)