Skip to content

Commit 2b126f5

Browse files
feat: Complete implementation plan for unified CI and release workflow
- Analyzed existing workflow.yml and CI.yml to understand differences - Designed conditional execution logic for intelligent CI/Release mode switching - Created comprehensive data model for workflow state transitions - Documented workflow API contract maintaining backward compatibility - Created migration guide (quickstart.md) for consuming repositories - Updated copilot instructions with recent changes Constitutional compliance: - Workflow-First Design: Enhances existing reusable workflow - TDD: Test scenarios documented before implementation - Platform Independence: No platform-specific changes - Quality Gates: Existing gates preserved - Semantic Versioning: Breaking change requires v5.0.0 Breaking Change: CI.yml deprecated; unified workflow.yml handles both CI and release
1 parent 5a91cf0 commit 2b126f5

File tree

6 files changed

+1832
-4
lines changed

6 files changed

+1832
-4
lines changed

.github/copilot-instructions.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
11
# Process-PSModule Development Guidelines
22

3-
Auto-generated from all feature plans. Last updated: 2025-10-01
3+
Auto-generated from all feature plans. Last updated: 2025-10-02
44

55
## Active Technologies
66

7-
- PowerShell 7.4+ (GitHub Actions composite actions) + PSModule/GitHub-Script@v1, PSModule/Install-PSModuleHelpers@v1 (001-building-on-this)
7+
- PowerShell 7.4+ (GitHub Actions composite actions) + PSModule/GitHub-Script@v1, PSModule/Install-PSModuleHelpers@v1, PSModule/Publish-PSModule@v2 (001-merge-ci-release-workflows)
88

99
## Project Structure
1010

1111
```plaintext
12-
src/
12+
.github/workflows/
13+
specs/
1314
tests/
1415
```
1516

1617
## Commands
1718

18-
Add commands for PowerShell 7.4+ (GitHub Actions composite actions)
19+
Workflow development for PowerShell 7.4+ (GitHub Actions composite actions)
1920

2021
## Code Style
2122

2223
PowerShell 7.4+ (GitHub Actions composite actions): Follow standard conventions
24+
GitHub Actions YAML: Follow conditional execution patterns
2325

2426
## Recent Changes
2527

28+
- 001-merge-ci-release-workflows: Unified workflow.yml handles CI and release with conditional execution; CI.yml deprecated (v5.0.0 breaking change)
2629
- 001-building-on-this: Added PowerShell 7.4+ (GitHub Actions composite actions) + PSModule/GitHub-Script@v1, PSModule/Install-PSModuleHelpers@v1
2730

2831
<!-- MANUAL ADDITIONS START -->
Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
# Workflow API Contract: Unified CI and Release Workflow
2+
3+
**Feature**: 001-merge-ci-release-workflows
4+
**Date**: 2025-10-02
5+
**Workflow File**: `.github/workflows/workflow.yml`
6+
7+
## Contract Overview
8+
9+
The unified workflow maintains the same API surface as the existing workflow.yml to ensure backward compatibility with consuming repositories.
10+
11+
## Workflow Trigger
12+
13+
```yaml
14+
on:
15+
workflow_call:
16+
# Unchanged from v4.x
17+
```
18+
19+
**Contract**: Workflow is callable from consuming repository workflows using `uses:` syntax.
20+
21+
**Example Consumer Usage**:
22+
```yaml
23+
name: Process-PSModule
24+
25+
on:
26+
pull_request:
27+
branches: [main]
28+
types: [closed, opened, reopened, synchronize, labeled]
29+
push:
30+
branches: [main]
31+
workflow_dispatch:
32+
33+
jobs:
34+
Process-PSModule:
35+
uses: PSModule/Process-PSModule/.github/workflows/workflow.yml@v5
36+
secrets:
37+
APIKEY: ${{ secrets.APIKEY }}
38+
```
39+
40+
## Inputs
41+
42+
All inputs remain unchanged from workflow.yml v4.x:
43+
44+
### Input: Name
45+
- **Type**: `string`
46+
- **Description**: The name of the module to process. Scripts default to the repository name if nothing is specified.
47+
- **Required**: `false`
48+
- **Default**: Repository name (auto-detected)
49+
50+
### Input: SettingsPath
51+
- **Type**: `string`
52+
- **Description**: The path to the settings file. Settings in the settings file take precedence over the action inputs.
53+
- **Required**: `false`
54+
- **Default**: `.github/PSModule.yml`
55+
56+
### Input: Debug
57+
- **Type**: `boolean`
58+
- **Description**: Enable debug output.
59+
- **Required**: `false`
60+
- **Default**: `false`
61+
62+
### Input: Verbose
63+
- **Type**: `boolean`
64+
- **Description**: Enable verbose output.
65+
- **Required**: `false`
66+
- **Default**: `false`
67+
68+
### Input: Version
69+
- **Type**: `string`
70+
- **Description**: Specifies the version of the GitHub module to be installed. The value must be an exact version.
71+
- **Required**: `false`
72+
- **Default**: `''` (latest stable)
73+
74+
### Input: Prerelease
75+
- **Type**: `boolean`
76+
- **Description**: Whether to use a prerelease version of the 'GitHub' module.
77+
- **Required**: `false`
78+
- **Default**: `false`
79+
80+
### Input: WorkingDirectory
81+
- **Type**: `string`
82+
- **Description**: The path to the root of the repo.
83+
- **Required**: `false`
84+
- **Default**: `'.'` (repository root)
85+
86+
## Secrets
87+
88+
All secrets remain unchanged from workflow.yml v4.x:
89+
90+
### Secret: APIKey
91+
- **Description**: The API key for the PowerShell Gallery.
92+
- **Required**: `true` (for Publish-Module job execution)
93+
- **Used By**: Publish-Module job
94+
- **Note**: Required even in CI-only mode (job is skipped but secret must be defined)
95+
96+
### Secret: TEST_APP_ENT_CLIENT_ID
97+
- **Description**: The client ID of an Enterprise GitHub App for running tests.
98+
- **Required**: `false`
99+
- **Used By**: Test-ModuleLocal job (if Enterprise App tests are enabled)
100+
101+
### Secret: TEST_APP_ENT_PRIVATE_KEY
102+
- **Description**: The private key of an Enterprise GitHub App for running tests.
103+
- **Required**: `false`
104+
- **Used By**: Test-ModuleLocal job (if Enterprise App tests are enabled)
105+
106+
### Secret: TEST_APP_ORG_CLIENT_ID
107+
- **Description**: The client ID of an Organization GitHub App for running tests.
108+
- **Required**: `false`
109+
- **Used By**: Test-ModuleLocal job (if Organization App tests are enabled)
110+
111+
### Secret: TEST_APP_ORG_PRIVATE_KEY
112+
- **Description**: The private key of an Organization GitHub App for running tests.
113+
- **Required**: `false`
114+
- **Used By**: Test-ModuleLocal job (if Organization App tests are enabled)
115+
116+
### Secret: TEST_USER_ORG_FG_PAT
117+
- **Description**: The fine-grained personal access token with org access for running tests.
118+
- **Required**: `false`
119+
- **Used By**: Test-ModuleLocal job (if org-level tests are enabled)
120+
121+
### Secret: TEST_USER_USER_FG_PAT
122+
- **Description**: The fine-grained personal access token with user account access for running tests.
123+
- **Required**: `false`
124+
- **Used By**: Test-ModuleLocal job (if user-level tests are enabled)
125+
126+
### Secret: TEST_USER_PAT
127+
- **Description**: The classic personal access token for running tests.
128+
- **Required**: `false`
129+
- **Used By**: Test-ModuleLocal job (if PAT-based tests are enabled)
130+
131+
## Outputs
132+
133+
The workflow does not define explicit outputs. Results are communicated through:
134+
135+
1. **Workflow Artifacts**:
136+
- `module`: Built module artifact (from Build-Module job)
137+
- `site`: Documentation site artifact (from Build-Site job)
138+
- `test-results`: Test result files (from test jobs)
139+
- `code-coverage`: Code coverage reports (from Get-CodeCoverage job)
140+
141+
2. **GitHub Releases**: Created by Publish-Module job (release mode only)
142+
143+
3. **GitHub Pages**: Deployed by Publish-Site job (release mode only)
144+
145+
4. **Workflow Status**: Success/failure status reported to PR and commit status checks
146+
147+
## Permissions
148+
149+
The workflow requires the following permissions:
150+
151+
```yaml
152+
permissions:
153+
contents: write # to checkout the repo and create releases on the repo
154+
pull-requests: write # to write comments to PRs
155+
statuses: write # to update the status of the workflow from linter
156+
pages: write # to deploy to Pages
157+
id-token: write # to verify the deployment originates from an appropriate source
158+
```
159+
160+
**Note**: These permissions are required for full functionality (CI + Release mode). In CI-only mode, `pages` and `id-token` permissions are unused but do not cause issues.
161+
162+
## Job Execution Contract
163+
164+
### Always Executed Jobs
165+
166+
The following jobs execute in all modes (CI-only and CI + Release):
167+
168+
1. **Get-Settings**: Load and parse module settings
169+
2. **Build-Module**: Compile module from source
170+
3. **Build-Docs**: Generate module documentation
171+
4. **Build-Site**: Build documentation site
172+
5. **Test-SourceCode**: Matrix test source code (multiple OS)
173+
6. **Lint-SourceCode**: Matrix lint source code (multiple OS)
174+
7. **Test-Module**: Test built module integrity
175+
8. **BeforeAll-ModuleLocal**: Setup external test resources (if tests/BeforeAll.ps1 exists)
176+
9. **Test-ModuleLocal**: Matrix test module functionality (ubuntu, windows, macos)
177+
10. **AfterAll-ModuleLocal**: Teardown external test resources (if tests/AfterAll.ps1 exists)
178+
11. **Get-TestResults**: Aggregate and validate test results
179+
12. **Get-CodeCoverage**: Analyze code coverage
180+
181+
### Conditionally Executed Jobs
182+
183+
The following jobs execute only in CI + Release mode:
184+
185+
13. **Publish-Module**: Publish module to PowerShell Gallery
186+
- **Condition**: Tests pass AND (merged PR OR push to default branch)
187+
188+
14. **Publish-Site**: Deploy documentation to GitHub Pages
189+
- **Condition**: Tests pass AND Build-Site succeeds AND (merged PR OR push to default branch)
190+
191+
## Conditional Execution Logic
192+
193+
### Publish-Module Condition
194+
195+
```yaml
196+
if: |
197+
needs.Get-Settings.result == 'success' &&
198+
needs.Get-TestResults.result == 'success' &&
199+
needs.Get-CodeCoverage.result == 'success' &&
200+
!cancelled() &&
201+
(
202+
(github.event_name == 'pull_request' && github.event.pull_request.merged == true) ||
203+
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
204+
)
205+
```
206+
207+
**Publishes When**:
208+
- All tests pass (Get-TestResults, Get-CodeCoverage success)
209+
- Workflow not cancelled
210+
- **Either**:
211+
- Pull request merged to default branch, **OR**
212+
- Direct push to default branch
213+
214+
**Skips When**:
215+
- Tests fail
216+
- Workflow cancelled
217+
- Unmerged pull request
218+
- Manual trigger (`workflow_dispatch`)
219+
- Scheduled run (`schedule`)
220+
- Push to non-default branch
221+
222+
### Publish-Site Condition
223+
224+
```yaml
225+
if: |
226+
needs.Get-Settings.result == 'success' &&
227+
needs.Get-TestResults.result == 'success' &&
228+
needs.Get-CodeCoverage.result == 'success' &&
229+
needs.Build-Site.result == 'success' &&
230+
!cancelled() &&
231+
(
232+
(github.event_name == 'pull_request' && github.event.pull_request.merged == true) ||
233+
(github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch))
234+
)
235+
```
236+
237+
**Publishes When**: Same as Publish-Module, plus Build-Site must succeed
238+
239+
## Behavioral Contract by Trigger Type
240+
241+
### Trigger: Pull Request (Opened/Synchronized/Reopened)
242+
243+
**Event**: `github.event_name == 'pull_request'` AND `github.event.pull_request.merged == false`
244+
245+
**Behavior**:
246+
- ✅ Execute all CI jobs (build, test, lint)
247+
- ❌ Skip Publish-Module
248+
- ❌ Skip Publish-Site
249+
- ✅ Report test results as PR status checks
250+
- ✅ Comment on PR with test/coverage results
251+
252+
**Exit**: Workflow completes after test results
253+
254+
### Trigger: Pull Request (Merged)
255+
256+
**Event**: `github.event_name == 'pull_request'` AND `github.event.pull_request.merged == true`
257+
258+
**Behavior**:
259+
- ✅ Execute all CI jobs (build, test, lint)
260+
- ✅ Execute Publish-Module (if tests pass)
261+
- ✅ Execute Publish-Site (if tests pass and Build-Site succeeds)
262+
- ✅ Create GitHub release
263+
- ✅ Deploy documentation to GitHub Pages
264+
265+
**Exit**: Workflow completes after successful publish
266+
267+
### Trigger: Push to Default Branch
268+
269+
**Event**: `github.event_name == 'push'` AND `github.ref == 'refs/heads/main'`
270+
271+
**Behavior**: Same as merged pull request
272+
- ✅ Execute all CI jobs
273+
- ✅ Execute Publish-Module (if tests pass)
274+
- ✅ Execute Publish-Site (if tests pass)
275+
276+
**Note**: Direct pushes bypass PR validation; use with caution
277+
278+
### Trigger: Push to Non-Default Branch
279+
280+
**Event**: `github.event_name == 'push'` AND `github.ref != 'refs/heads/main'`
281+
282+
**Behavior**:
283+
- ✅ Execute all CI jobs
284+
- ❌ Skip Publish-Module
285+
- ❌ Skip Publish-Site
286+
287+
**Use Case**: Feature branch validation without PR
288+
289+
### Trigger: Manual (workflow_dispatch)
290+
291+
**Event**: `github.event_name == 'workflow_dispatch'`
292+
293+
**Behavior**:
294+
- ✅ Execute all CI jobs
295+
- ❌ Skip Publish-Module
296+
- ❌ Skip Publish-Site
297+
298+
**Use Case**: On-demand validation without publishing
299+
300+
### Trigger: Scheduled (schedule)
301+
302+
**Event**: `github.event_name == 'schedule'`
303+
304+
**Behavior**:
305+
- ✅ Execute all CI jobs
306+
- ❌ Skip Publish-Module
307+
- ❌ Skip Publish-Site
308+
309+
**Use Case**: Nightly regression testing
310+
311+
## Breaking Changes from v4.x
312+
313+
### For Consuming Repositories Using workflow.yml
314+
315+
**Impact**: ✅ **None** - Existing behavior preserved
316+
317+
**Changes Required**: None (optional: review trigger conditions in consuming repo workflow)
318+
319+
### For Consuming Repositories Using CI.yml
320+
321+
**Impact**: ⚠️ **Deprecation Warning** - CI.yml marked deprecated
322+
323+
**Changes Required**: Migrate to workflow.yml during v5.x lifecycle
324+
325+
**Migration Path**:
326+
1. Update consuming repository workflow to call workflow.yml instead of CI.yml
327+
2. Test both PR and merge workflows
328+
3. Remove CI.yml reference from consuming repository
329+
330+
### For Process-PSModule Framework
331+
332+
**Impact**: 🌟 **Breaking Change** - Major version bump (v5.0.0)
333+
334+
**Changes**:
335+
- CI.yml deprecated (removed in v6.0.0)
336+
- Unified workflow.yml handles all scenarios
337+
- New conditional execution logic
338+
339+
## Validation Test Cases
340+
341+
Consuming repositories should validate these scenarios after migration:
342+
343+
1. ✅ **PR Opened**: CI runs, no publish
344+
2. ✅ **PR Synchronized**: CI runs, no publish
345+
3. ✅ **PR Merged**: CI runs, publish succeeds
346+
4. ✅ **Direct Push to Main**: CI runs, publish succeeds
347+
5. ✅ **Push to Feature Branch**: CI runs (if configured), no publish
348+
6. ✅ **Manual Trigger**: CI runs, no publish
349+
7. ✅ **Test Failure**: Workflow fails, no publish
350+
8. ✅ **Coverage Below Threshold**: Workflow fails, no publish
351+
352+
## Support and Compatibility
353+
354+
| Process-PSModule Version | Unified Workflow | CI.yml Support | API Breaking Changes |
355+
|-------------------------|------------------|----------------|---------------------|
356+
| v4.x (current) | ❌ No | ✅ Yes | N/A |
357+
| v5.0 (this feature) | ✅ Yes | ⚠️ Deprecated | No (for workflow.yml users) |
358+
| v6.0 (future) | ✅ Yes | ❌ Removed | Yes (CI.yml removed) |
359+
360+
## Conclusion
361+
362+
The unified workflow maintains API compatibility with workflow.yml v4.x while adding intelligent conditional execution. Consuming repositories using workflow.yml continue working without changes. Consumers using CI.yml should migrate during the v5.x support period.

0 commit comments

Comments
 (0)