Skip to content

Commit 385c238

Browse files
feat: Add quickstart guide for setup-test composite action integration
- Introduced quickstart.md for validating setup-test composite action functionality. - Included prerequisites, integration steps, validation checklist, and test scenarios. - Documented expected outcomes and debug commands for ease of use. --- feat: Document research findings for local GitHub composite action - Created research.md consolidating decisions on composite action structure, error handling, and integration patterns. - Outlined rationale for using a single action with mode parameter for BeforeAll and AfterAll scripts. - Provided implementation guidance and technical decisions summary. --- feat: Define tasks for implementing local GitHub composite action - Established tasks.md outlining execution flow, task dependencies, and phases for implementation. - Specified tasks for setup, testing, core implementation, integration, and polish. - Included validation checklist to ensure all requirements are met before execution.
1 parent 205fb8b commit 385c238

File tree

9 files changed

+2690
-0
lines changed

9 files changed

+2690
-0
lines changed

.github/copilot-instructions.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Process-PSModule Development Guidelines
2+
3+
Auto-generated from all feature plans. Last updated: 2025-10-01
4+
5+
## Active Technologies
6+
- PowerShell 7.4+ (GitHub Actions composite actions) + PSModule/GitHub-Script@v1, PSModule/Install-PSModuleHelpers@v1 (001-building-on-this)
7+
8+
## Project Structure
9+
```
10+
src/
11+
tests/
12+
```
13+
14+
## Commands
15+
# Add commands for PowerShell 7.4+ (GitHub Actions composite actions)
16+
17+
## Code Style
18+
PowerShell 7.4+ (GitHub Actions composite actions): Follow standard conventions
19+
20+
## Recent Changes
21+
- 001-building-on-this: Added PowerShell 7.4+ (GitHub Actions composite actions) + PSModule/GitHub-Script@v1, PSModule/Install-PSModuleHelpers@v1
22+
23+
<!-- MANUAL ADDITIONS START -->
24+
<!-- MANUAL ADDITIONS END -->
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
# Contract: Setup-Test Composite Action
2+
3+
**File**: `.github/actions/setup-test/action.yml`
4+
**Type**: GitHub Actions Composite Action
5+
**Purpose**: Execute BeforeAll.ps1 or AfterAll.ps1 test setup/teardown scripts based on mode parameter
6+
7+
## Action Definition Contract
8+
9+
This is the contract specification for the composite action. The actual implementation will be in `.github/actions/setup-test/action.yml`.
10+
11+
```yaml
12+
name: 'Setup-Test'
13+
description: 'Execute BeforeAll or AfterAll test setup/teardown scripts based on mode parameter'
14+
author: 'PSModule'
15+
16+
inputs:
17+
mode:
18+
description: 'Execution mode: "before" (BeforeAll.ps1) or "after" (AfterAll.ps1)'
19+
required: true
20+
21+
Debug:
22+
description: 'Enable debug output'
23+
required: false
24+
default: 'false'
25+
26+
Verbose:
27+
description: 'Enable verbose output'
28+
required: false
29+
default: 'false'
30+
31+
Prerelease:
32+
description: 'Use prerelease version of GitHub module'
33+
required: false
34+
default: 'false'
35+
36+
Version:
37+
description: 'Exact version of GitHub module to install'
38+
required: false
39+
default: ''
40+
41+
WorkingDirectory:
42+
description: 'Working directory where script will run from'
43+
required: false
44+
default: '.'
45+
46+
runs:
47+
using: 'composite'
48+
steps:
49+
- name: Install-PSModuleHelpers
50+
uses: PSModule/Install-PSModuleHelpers@v1
51+
52+
- name: Execute Setup/Teardown Script
53+
uses: PSModule/GitHub-Script@v1
54+
with:
55+
Name: 'Setup-Test-${{ inputs.mode }}'
56+
ShowInfo: false
57+
ShowOutput: true
58+
Debug: ${{ inputs.Debug }}
59+
Verbose: ${{ inputs.Verbose }}
60+
Prerelease: ${{ inputs.Prerelease }}
61+
Version: ${{ inputs.Version }}
62+
WorkingDirectory: ${{ inputs.WorkingDirectory }}
63+
Script: |
64+
# PowerShell script implementation
65+
# See script-implementation.md for detailed script logic
66+
```
67+
68+
## Inputs Contract
69+
70+
### Required Inputs
71+
72+
| Input | Type | Validation | Example |
73+
|-------|------|------------|---------|
74+
| mode | string | Must be "before" or "after" | "before" |
75+
76+
### Optional Inputs
77+
78+
| Input | Type | Default | Description |
79+
|-------|------|---------|-------------|
80+
| Debug | boolean | false | Enable debug output |
81+
| Verbose | boolean | false | Enable verbose output |
82+
| Prerelease | boolean | false | Use prerelease GitHub module |
83+
| Version | string | '' | Exact GitHub module version |
84+
| WorkingDirectory | string | '.' | Script working directory |
85+
86+
## Environment Variables Contract
87+
88+
The action expects these environment variables to be set by the caller (passed as secrets):
89+
90+
| Variable | Purpose | Required |
91+
|----------|---------|----------|
92+
| TEST_APP_ENT_CLIENT_ID | Enterprise GitHub App client ID | Optional |
93+
| TEST_APP_ENT_PRIVATE_KEY | Enterprise GitHub App private key | Optional |
94+
| TEST_APP_ORG_CLIENT_ID | Organization GitHub App client ID | Optional |
95+
| TEST_APP_ORG_PRIVATE_KEY | Organization GitHub App private key | Optional |
96+
| TEST_USER_ORG_FG_PAT | Fine-grained PAT with org access | Optional |
97+
| TEST_USER_USER_FG_PAT | Fine-grained PAT with user access | Optional |
98+
| TEST_USER_PAT | Classic PAT | Optional |
99+
| GITHUB_TOKEN | GitHub Actions token | Optional |
100+
101+
**Note**: All environment variables are optional. Scripts may require specific variables based on their test requirements.
102+
103+
## Outputs Contract
104+
105+
**No outputs**: This action communicates results via exit codes and console output.
106+
107+
- **Success**: Exit code 0 (action step shows green checkmark)
108+
- **Failure**: Exit code non-zero (action step shows red X) - only for mode="before" with script errors
109+
110+
## Behavior Contract
111+
112+
### Mode: "before"
113+
114+
**Purpose**: Execute BeforeAll.ps1 setup script before tests
115+
116+
**Execution Flow**:
117+
1. Check if tests directory exists
118+
- Not found → Exit 0 with message "No tests directory found - exiting successfully"
119+
2. Check if tests/BeforeAll.ps1 exists
120+
- Not found → Exit 0 with message "No BeforeAll.ps1 script found - exiting successfully"
121+
3. Execute tests/BeforeAll.ps1
122+
- Change to tests directory
123+
- Run script with environment variables
124+
- On success → Exit 0 with message "BeforeAll script completed successfully: [path]"
125+
- On failure → Exit non-zero with error "BeforeAll script failed: [path] - [error]"
126+
- Always restore previous directory (via finally block)
127+
128+
**Error Handling**: Script failures cause job failure (errors propagated)
129+
130+
### Mode: "after"
131+
132+
**Purpose**: Execute AfterAll.ps1 teardown script after tests
133+
134+
**Execution Flow**:
135+
1. Check if tests directory exists
136+
- Not found → Exit 0 with message "No tests directory found - exiting successfully"
137+
2. Check if tests/AfterAll.ps1 exists
138+
- Not found → Exit 0 with message "No AfterAll.ps1 script found - exiting successfully"
139+
3. Execute tests/AfterAll.ps1
140+
- Change to tests directory
141+
- Run script with environment variables
142+
- On success → Exit 0 with message "AfterAll script completed successfully: [path]"
143+
- On failure → Exit 0 with warning "AfterAll script failed: [path] - [error]"
144+
- Always restore previous directory (via finally block)
145+
146+
**Error Handling**: Script failures logged as warnings but don't cause job failure (exit 0)
147+
148+
## Output Format Contract
149+
150+
All output wrapped in LogGroup with title based on mode:
151+
152+
**Mode "before"**: `LogGroup "Running BeforeAll Setup Scripts" { ... }`
153+
154+
**Mode "after"**: `LogGroup "Running AfterAll Teardown Scripts" { ... }`
155+
156+
### Standard Output Messages
157+
158+
| Scenario | Output Message | Level |
159+
|----------|---------------|-------|
160+
| No tests directory | "No tests directory found - exiting successfully" | Info |
161+
| Tests directory found | "Tests found at [$testsPath]" | Info |
162+
| Script not found (before) | "No BeforeAll.ps1 script found - exiting successfully" | Info |
163+
| Script not found (after) | "No AfterAll.ps1 script found - exiting successfully" | Info |
164+
| Script execution start | "Running [BeforeAll\|AfterAll] setup/teardown script: $scriptPath" | Info |
165+
| Script success | "[BeforeAll\|AfterAll] script completed successfully: $scriptPath" | Info |
166+
| Script failure (before) | "BeforeAll script failed: $scriptPath - $_" | Error |
167+
| Script failure (after) | "AfterAll script failed: $scriptPath - $_" | Warning |
168+
169+
## Caller Integration Contract
170+
171+
### Example: BeforeAll-ModuleLocal Job
172+
173+
```yaml
174+
BeforeAll-ModuleLocal:
175+
name: BeforeAll-ModuleLocal
176+
runs-on: ubuntu-latest
177+
steps:
178+
- name: Checkout Code
179+
uses: actions/checkout@v5
180+
181+
- name: Run BeforeAll Setup
182+
uses: ./.github/actions/setup-test
183+
env:
184+
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
185+
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
186+
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
187+
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
188+
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
189+
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
190+
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
191+
GITHUB_TOKEN: ${{ github.token }}
192+
with:
193+
mode: before
194+
Debug: ${{ inputs.Debug }}
195+
Verbose: ${{ inputs.Verbose }}
196+
Prerelease: ${{ inputs.Prerelease }}
197+
Version: ${{ inputs.Version }}
198+
WorkingDirectory: ${{ inputs.WorkingDirectory }}
199+
```
200+
201+
### Example: AfterAll-ModuleLocal Job
202+
203+
```yaml
204+
AfterAll-ModuleLocal:
205+
name: AfterAll-ModuleLocal
206+
runs-on: ubuntu-latest
207+
needs:
208+
- Test-ModuleLocal
209+
if: always()
210+
steps:
211+
- name: Checkout Code
212+
uses: actions/checkout@v5
213+
214+
- name: Run AfterAll Teardown
215+
if: always()
216+
uses: ./.github/actions/setup-test
217+
env:
218+
TEST_APP_ENT_CLIENT_ID: ${{ secrets.TEST_APP_ENT_CLIENT_ID }}
219+
TEST_APP_ENT_PRIVATE_KEY: ${{ secrets.TEST_APP_ENT_PRIVATE_KEY }}
220+
TEST_APP_ORG_CLIENT_ID: ${{ secrets.TEST_APP_ORG_CLIENT_ID }}
221+
TEST_APP_ORG_PRIVATE_KEY: ${{ secrets.TEST_APP_ORG_PRIVATE_KEY }}
222+
TEST_USER_ORG_FG_PAT: ${{ secrets.TEST_USER_ORG_FG_PAT }}
223+
TEST_USER_USER_FG_PAT: ${{ secrets.TEST_USER_USER_FG_PAT }}
224+
TEST_USER_PAT: ${{ secrets.TEST_USER_PAT }}
225+
GITHUB_TOKEN: ${{ github.token }}
226+
with:
227+
mode: after
228+
Debug: ${{ inputs.Debug }}
229+
Verbose: ${{ inputs.Verbose }}
230+
Prerelease: ${{ inputs.Prerelease }}
231+
Version: ${{ inputs.Version }}
232+
WorkingDirectory: ${{ inputs.WorkingDirectory }}
233+
```
234+
235+
**Required Caller Setup**:
236+
1. Repository must be checked out (actions/checkout@v5)
237+
2. All required secrets must be passed as environment variables
238+
3. AfterAll-ModuleLocal job must have `if: always()` to ensure cleanup runs
239+
4. AfterAll-ModuleLocal step should also have `if: always()` for resilience
240+
241+
## Validation Contract
242+
243+
### Pre-Execution Validation
244+
245+
1. **mode parameter**: Action script will validate mode is "before" or "after"
246+
- Invalid mode → Error with message about valid values
247+
2. **Repository checkout**: Caller responsibility to run actions/checkout@v5
248+
3. **Working directory**: GitHub-Script handles WorkingDirectory validation
249+
250+
### Runtime Validation
251+
252+
1. **tests directory**: Action validates existence via Resolve-Path
253+
2. **Script file**: Action validates existence via Test-Path
254+
3. **Script execution**: Action wraps in try/catch for error handling
255+
256+
### Post-Execution Validation
257+
258+
1. **Working directory restore**: Guaranteed via try/finally block
259+
2. **Exit code**: 0 for success, non-zero for failure (mode="before" only)
260+
3. **Output completeness**: All status messages logged to console
261+
262+
## Dependencies Contract
263+
264+
### Action Dependencies
265+
266+
1. **PSModule/Install-PSModuleHelpers@v1**
267+
- Must run before GitHub-Script step
268+
- Provides PSModule helper functions
269+
- No inputs required
270+
271+
2. **PSModule/GitHub-Script@v1**
272+
- Executes PowerShell script
273+
- Provides LogGroup helper
274+
- Receives all action inputs and environment variables
275+
276+
### Script Dependencies
277+
278+
Scripts (BeforeAll.ps1, AfterAll.ps1) can assume:
279+
1. PowerShell 7.4+ environment
280+
2. All environment variables are set
281+
3. Execution directory is tests/
282+
4. PSModule helpers are available
283+
5. ubuntu-latest runner environment
284+
285+
## Error Handling Contract
286+
287+
### Mode "before" Error Handling
288+
289+
| Error Scenario | Handling | Exit Code | Job Status |
290+
|----------------|----------|-----------|------------|
291+
| Invalid mode | Error message + exit | Non-zero | Failed |
292+
| No tests directory | Info message + exit | 0 | Success |
293+
| No BeforeAll.ps1 | Info message + exit | 0 | Success |
294+
| Script execution error | Error message + throw | Non-zero | Failed |
295+
| Script execution success | Info message + exit | 0 | Success |
296+
297+
### Mode "after" Error Handling
298+
299+
| Error Scenario | Handling | Exit Code | Job Status |
300+
|----------------|----------|-----------|------------|
301+
| Invalid mode | Error message + exit | Non-zero | Failed |
302+
| No tests directory | Info message + exit | 0 | Success |
303+
| No AfterAll.ps1 | Info message + exit | 0 | Success |
304+
| Script execution error | Warning message + exit | 0 | Success |
305+
| Script execution success | Info message + exit | 0 | Success |
306+
307+
### Error Messages Contract
308+
309+
**Invalid Mode**:
310+
```
311+
Invalid mode '$mode'. Mode must be 'before' or 'after'.
312+
```
313+
314+
**Script Execution Error (before)**:
315+
```
316+
BeforeAll script failed: [absolute-path] - [error-message]
317+
```
318+
319+
**Script Execution Error (after)**:
320+
```
321+
WARNING: AfterAll script failed: [absolute-path] - [error-message]
322+
```
323+
324+
## Performance Contract
325+
326+
| Metric | Target | Notes |
327+
|--------|--------|-------|
328+
| Action invocation overhead | <2 seconds | Install-PSModuleHelpers + GitHub-Script startup |
329+
| Script discovery time | <100ms | Single Resolve-Path + Test-Path |
330+
| Total execution time | Script runtime + overhead | Depends on script complexity |
331+
332+
## Security Contract
333+
334+
1. **Secrets**: Passed as environment variables, not logged
335+
2. **Script execution**: Runs in isolated job context on ubuntu-latest
336+
3. **Working directory**: Restored via finally block (no directory escape)
337+
4. **Output sanitization**: Caller responsibility to avoid logging secrets in scripts
338+
339+
---
340+
**Contract Complete**: Ready for test implementation and integration.

0 commit comments

Comments
 (0)