From c50f6d7c46149db07568ab2bff78487985385027 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 3 Aug 2026 04:09:26 +0200 Subject: [PATCH] docs(specs): add v1 functional specification Defines the initial public API for the PowerShellGallery module: - API metadata discovery - Package search and metadata retrieval - Listing management (hide/show) for package owners Includes naming conventions, parameter design, error handling, testing strategy, and migration notes from current stubs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- docs/specs/v1.md | 270 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 docs/specs/v1.md diff --git a/docs/specs/v1.md b/docs/specs/v1.md new file mode 100644 index 0000000..b33467f --- /dev/null +++ b/docs/specs/v1.md @@ -0,0 +1,270 @@ +# PowerShellGallery v1 Specification + +## Overview + +`PowerShellGallery` is a PowerShell module for interacting with the [PowerShell Gallery](https://www.powershellgallery.com). Version 1 focuses on two publisher-oriented workflows: + +1. **Discovery** — read package and API metadata from the public OData v2 endpoint. +2. **Listing management** — list and unlist package versions you own, using gallery API credentials. + +This spec defines the public API, expected behavior, error handling, and testing strategy for the v1 release. + +## Supported PowerShell version + +Latest PowerShell Long-Term Support (LTS) release, per the PSModule module standard. Windows PowerShell 5.1 is not a v1 target. + +## Out of scope for v1 + +- Installing, updating, or saving packages (covered by `PowerShellGet`). +- Publishing packages to the gallery. +- User or organization management. +- Admin-level gallery operations. +- Cross-gallery support (e.g., private NuGet feeds). + +## Naming convention + +Public nouns are prefixed with the module term of art: `PowerShellGallery`. + +Existing stub names `Hide-PowerShellGalleryItem` and `Show-PowerShellGalleryItem` are renamed to use the more precise noun `Package`, with backward-compatible aliases retained for the v1 major release. + +## Public API + +### `Get-PowerShellGalleryAPI` + +Get metadata from the PowerShell Gallery v2 API root. + +#### Synopsis + +```text +Get-PowerShellGalleryAPI [[-Uri] ] [] +``` + +#### Parameters + +| Name | Type | Mandatory | Default | Description | +| ---- | ---- | --------- | ------- | ----------- | +| `Uri` | `string` | No | `https://www.powershellgallery.com/api/v2/` | Base URI of the gallery OData endpoint. | + +#### Behavior + +- Performs an HTTP `GET` against the provided URI with `application/json` content negotiation. +- Returns the raw service response (commonly an OData service document / JSON). +- Throws a terminating error if the endpoint is unreachable or returns a non-success status code. + +#### Example + +```powershell +Get-PowerShellGalleryAPI +``` + +--- + +### `Find-PowerShellGalleryPackage` + +Search for packages on the PowerShell Gallery. + +#### Synopsis + +```text +Find-PowerShellGalleryPackage [[-Name] ] [-Tag ] [-IncludePrerelease] [-First ] + [-Skip ] [-OrderBy ] [] +``` + +#### Parameters + +| Name | Type | Mandatory | Default | Description | +| ---- | ---- | --------- | ------- | ----------- | +| `Name` | `string` | No | `*` | Package ID or search term. Supports wildcards. | +| `Tag` | `string[]` | No | none | Filter to packages that declare all specified tags. | +| `IncludePrerelease` | `switch` | No | false | Include prerelease versions in results. | +| `First` | `uint` | No | `50` | Maximum number of results to return. Capped at `1000`. | +| `Skip` | `uint` | No | `0` | Number of results to skip for pagination. | +| `OrderBy` | `string` | No | `DownloadCount desc` | OData `$orderby` expression. | + +#### Behavior + +- Queries `https://www.powershellgallery.com/api/v2/Packages()`. +- Supports pipeline input for `Name`. +- Returns one object per package version by default. +- Use `Get-PowerShellGalleryPackage` when you need a single package/version. + +#### Example + +```powershell +Find-PowerShellGalleryPackage -Name 'Pester' -First 5 +'Az.*' | Find-PowerShellGalleryPackage -First 10 +``` + +--- + +### `Get-PowerShellGalleryPackage` + +Get detailed metadata for a specific package and optionally a specific version. + +#### Synopsis + +```text +Get-PowerShellGalleryPackage [-Name] [[-Version] ] [-IncludePrerelease] + [] +``` + +#### Parameters + +| Name | Type | Mandatory | Default | Description | +| ---- | ---- | --------- | ------- | ----------- | +| `Name` | `string` | Yes | — | Exact package ID. | +| `Version` | `string` | No | latest stable | Specific version to retrieve. Accepts NuGet version strings including prerelease labels. | +| `IncludePrerelease` | `switch` | No | false | When `Version` is omitted, return the latest prerelease instead of the latest stable. | + +#### Behavior + +- If `Version` is provided, queries `Packages(Id='{Name}',Version='{Version}')`. +- If `Version` is omitted, queries the package feed filtered by ID, ordered by published date, and returns the newest item. +- Throws a terminating error if the package or version does not exist. + +#### Example + +```powershell +Get-PowerShellGalleryPackage -Name 'Pester' +Get-PowerShellGalleryPackage -Name 'Pester' -Version '5.5.0' +``` + +--- + +### `Hide-PowerShellGalleryPackage` + +Unlist a package version on the PowerShell Gallery. + +#### Synopsis + +```text +Hide-PowerShellGalleryPackage [-Name] [-Version] [-APIKey] + [-WhatIf] [-Confirm] [] +``` + +#### Aliases + +- `Unlist-PowerShellGalleryPackage` + +#### Parameters + +| Name | Type | Mandatory | Default | Description | +| ---- | ---- | --------- | ------- | ----------- | +| `Name` | `string` | Yes | — | Exact package ID. | +| `Version` | `string` | Yes | — | Exact version to unlist. | +| `APIKey` | `string` | Yes | — | PowerShell Gallery API key for the package owner. | + +#### Behavior + +- Requires ownership of the package. +- Uses the gallery listing endpoint to mark the version as unlisted. +- Supports `-WhatIf` and `-Confirm` via `SupportsShouldProcess`. +- Writes a non-terminating warning if the operation is not yet implemented or the gallery endpoint is unavailable. + +#### Example + +```powershell +Hide-PowerShellGalleryPackage -Name 'MyModule' -Version '1.0.0' -APIKey $env:PSGalleryAPIKey +``` + +--- + +### `Show-PowerShellGalleryPackage` + +List a package version on the PowerShell Gallery. + +#### Synopsis + +```text +Show-PowerShellGalleryPackage [-Name] [-Version] [-APIKey] + [-WhatIf] [-Confirm] [] +``` + +#### Aliases + +- `List-PowerShellGalleryPackage` + +#### Parameters + +| Name | Type | Mandatory | Default | Description | +| ---- | ---- | --------- | ------- | ----------- | +| `Name` | `string` | Yes | — | Exact package ID. | +| `Version` | `string` | Yes | — | Exact version to list. | +| `APIKey` | `string` | Yes | — | PowerShell Gallery API key for the package owner. | + +#### Behavior + +- Requires ownership of the package. +- Uses the gallery listing endpoint to mark the version as listed. +- Supports `-WhatIf` and `-Confirm` via `SupportsShouldProcess`. + +#### Example + +```powershell +Show-PowerShellGalleryPackage -Name 'MyModule' -Version '1.0.0' -APIKey $env:PSGalleryAPIKey +``` + +## Private helpers + +Private functions are grouped under `src/functions/private/Gallery/`. + +| Function | Responsibility | +| -------- | -------------- | +| `Invoke-PowerShellGalleryAPI` | Shared REST wrapper: handles URI building, headers, content negotiation, timeout, and error translation. | +| `Get-PowerShellGalleryResource` | Generic OData resource GET (to be merged into or replaced by `Invoke-PowerShellGalleryAPI`). | +| `Update-PowerShellGalleryResourceListing` | Shared POST to the gallery listing endpoint used by `Hide`/`Show`. | + +## Return types + +Commands return plain objects deserialized from OData JSON by default. A future release may introduce typed output classes; v1 does not. + +## Error handling + +- Use `ErrorAction` semantics consistently. +- Wrap `Invoke-RestMethod` failures in descriptive error records where the gallery response adds useful context. +- Authentication or authorization failures from listing endpoints produce clear, actionable messages. +- Discovery commands must not throw on empty result sets; they return nothing. + +## Authentication + +- Read commands require no authentication. +- Listing-management commands require a PowerShell Gallery API key with ownership of the target package. +- The API key is passed via the `APIKey` parameter. Do not persist keys in the module; callers supply them per command. + +## Logging and progress + +- Emit `Verbose` output for URIs, pagination, and auth-skipping details. +- Emit `Warning` when a listing command cannot complete because the gallery endpoint is unavailable. +- Do not emit progress bars for simple HTTP calls. + +## Testing + +Follow the [PSModule Test Specification](https://psmodule.github.io/docs/Modules/Test-Specification/): + +- No mocks; use real inputs and the public gallery endpoint. +- Test each public command with `Describe`/`Context`/`It` hierarchy. +- Discovery tests use well-known packages (e.g., `Pester`, `PowerShellGet`) to ensure stable results. +- Listing-management tests validate parameter binding and `-WhatIf` behavior; they do not mutate real packages. +- Code coverage target remains 50% as configured in `.github/PSModule.yml` for v1. + +## Documentation + +- Each public function has full comment-based help with synopsis, description, examples, and parameter help. +- A `.md` overview file is added alongside public functions. +- README is updated to describe v1 capabilities. + +## Migration from current stubs + +| Current file | v1 disposition | +| ------------ | -------------- | +| `Get-PSGalleryAPI.ps1` | Rename to `Get-PowerShellGalleryAPI.ps1`; keep URI default. | +| `Hide-PowerShellGalleryItem.ps1` | Rename to `Hide-PowerShellGalleryPackage.ps1`; add `Unlist-PowerShellGalleryPackage` alias. | +| `Show-PowerShellGalleryItem.ps1` | Rename to `Show-PowerShellGalleryPackage.ps1`; add `List-PowerShellGalleryPackage` alias. | +| `Get-PSGalleryResource.ps1` | Refactor into `Invoke-PowerShellGalleryAPI` or retain as private helper. | +| `Update-PSGalleryResourceListing.ps1` | Retain as private helper; fix auth and parameter handling. | + +## Open questions + +1. Does the gallery expose a stable, API-key-only listing endpoint, or do we need a full web-login + anti-forgery token flow? +2. Should `Find-PowerShellGalleryPackage` collapse multiple versions of the same package ID by default? +3. Should v1 include `Save-PowerShellGalleryPackage` (download `.nupkg`) or leave that to `PowerShellGet`?