|
1 | | -# Copilot Instructions for IncludeHelper |
| 1 | +# ProjectHelper Copilot Instructions |
2 | 2 |
|
3 | | -IncludeHelper is a PowerShell module that provides shared utility functions and a framework for distributing reusable code components ("includes") across other modules. |
| 3 | +## Project Overview |
| 4 | +**ProjectHelper** is a PowerShell module for GitHub Projects interaction via GraphQL API. It provides CLI-like functions to manage GitHub projects, items, users, and collaborators from PowerShell. |
4 | 5 |
|
5 | | -## Architecture Overview |
| 6 | +## Architecture & Core Patterns |
6 | 7 |
|
7 | | -**Module Structure:** |
8 | | -- `config/`: Configuration utilities and module initialization |
9 | | -- `helper/`: Core module helpers (module path resolution, folder management) |
10 | | -- `include/`: Shared utility functions (logging, API calls, database, config management) |
11 | | -- `private/`: Internal functions not exported |
12 | | -- `public/`: Exported functions (the public API) |
13 | | -- `Test/`: Mirrored structure with unit tests and mocks |
| 8 | +### Module Structure |
| 9 | +- **Loading Order** (`ProjectHelper.psm1`): `config` → `helper` → `include` → `private` → `public` |
| 10 | +- **Public Functions**: Exported via `Export-ModuleMember -Function <name>` in each file |
| 11 | +- **Private Functions**: In `/private` folder, not exported; used internally by public functions |
| 12 | +- **Include Files** (`/include`): Shared utilities loaded early; example: `callAPI.ps1` (GraphQL/REST), `MyWrite.ps1` (logging) |
| 13 | +- **Driver Functions** (`/public/driver`): Low-level integration with GitHub APIs; marked with comment "integration function not intended for direct user use" |
14 | 14 |
|
15 | | -**Loading Order** (in `IncludeHelper.psm1`): `config` → `helper` → `include` → `private` → `public` |
| 15 | +### Key Files & Responsibilities |
| 16 | +- `include/callAPI.ps1`: Handles `Invoke-GraphQL` and `Invoke-RestAPI` calls to GitHub |
| 17 | +- `helper/invokeCommand.helper.ps1`: Provides `Invoke-MyCommand` for alias-based command dispatch (enables test mocking) |
| 18 | +- `include/config.ps1`: Configuration storage in `~/.helpers/ProjectHelper/config/` |
| 19 | +- `public/graphql/*.{query,mutant,tag}`: GraphQL template files (fragments and queries) |
| 20 | +- `Test/Test.psd1`: Parallel test module with identical structure to main module |
16 | 21 |
|
17 | | -## PowerShell Function Conventions |
18 | | - |
19 | | -### All Functions |
20 | | -- Must include `[CmdletBinding()]` attribute |
21 | | -- Must include `param()` block (even if empty) |
22 | | -- Use proper script documentation with `<# .SYNOPSIS #>` blocks |
| 22 | +### Invocation Pattern (Critical for Testing) |
| 23 | +```powershell |
| 24 | +# Production: Direct API calls |
| 25 | +Invoke-GraphQL -Query $query -Variables $variables |
23 | 26 |
|
24 | | -### Public Functions (`public/` folder) |
25 | | -- Add `Export-ModuleMember -Function 'FunctionName'` on the closing `}` line |
26 | | -- Example: |
27 | | - ```powershell |
28 | | - function Add-IncludeToWorkspace { |
29 | | - [CmdletBinding()] |
30 | | - param([Parameter(Mandatory)][string]$Name) |
31 | | - # Logic |
32 | | - } Export-ModuleMember -Function 'Add-IncludeToWorkspace' |
33 | | - ``` |
| 27 | +# High-level: Uses Invoke-MyCommand alias dispatch (mockable) |
| 28 | +Invoke-MyCommand -Command "findProject" -Parameters @{owner=$Owner; pattern=$Pattern} |
34 | 29 |
|
35 | | -### Helper Functions (`helper/` folder) |
36 | | -- Available module-wide; follow naming convention: verbs that clearly indicate utility purpose |
37 | | -- Key helpers: `Find-ModuleRootPath`, `Get-ModuleFolder`, `Get-Ps1FullPath` |
| 30 | +# Set custom implementation for testing/mocking: |
| 31 | +Set-MyInvokeCommandAlias -Alias $alias -Command $Command |
| 32 | +``` |
38 | 33 |
|
39 | | -## Logging and Debugging |
| 34 | +## Development Workflows |
40 | 35 |
|
41 | | -- Use `MyWrite.ps1` functions: `Write-MyError`, `Write-MyWarning`, `Write-MyVerbose`, `Write-MyDebug`, `Write-MyHost` |
42 | | -- Control verbosity via environment variables: `$env:ModuleHelper_VERBOSE="all"` or specific function names |
43 | | -- Control debugging via `$env:ModuleHelper_DEBUG="all"` or specific sections |
44 | | -- Test verbosity/debug state with `Test-MyVerbose` and `Test-MyDebug` |
| 36 | +### Running Tests |
| 37 | +```powershell |
| 38 | +./test.ps1 # Run all tests |
| 39 | +./test.ps1 -ShowTestErrors # Show error details |
| 40 | +./test.ps1 -TestName "Test_*" # Run specific test |
| 41 | +``` |
45 | 42 |
|
46 | | -## Test Conventions |
| 43 | +Uses **TestingHelper** module from PSGallery (installed automatically). |
47 | 44 |
|
48 | | -Tests use `TestingHelper` module and follow pattern: `function Test_FunctionName_Scenario` |
| 45 | +### Building & Deploying |
| 46 | +```powershell |
| 47 | +./build.ps1 # Build module |
| 48 | +./deploy.ps1 -VersionTag "v1.0.0" # Deploy to PSGallery |
| 49 | +./sync.ps1 # Sync with TestingHelper templates |
| 50 | +``` |
49 | 51 |
|
50 | | -**Test Structure:** |
| 52 | +### Debugging |
| 53 | +Enable module debug output: |
51 | 54 | ```powershell |
52 | | -function Test_AddIncludeToWorkspace { |
53 | | - # Arrange - Setup test data and mocks |
54 | | - Import-Module -Name TestingHelper |
55 | | - New-ModuleV3 -Name TestModule |
| 55 | +Enable-ProjectHelperDebug |
| 56 | +Disable-ProjectHelperDebug |
| 57 | +``` |
56 | 58 |
|
57 | | - # Act - Execute the function being tested |
58 | | - Add-IncludeToWorkspace -Name "getHashCode.ps1" -FolderName "Include" -DestinationModulePath "TestModule" |
| 59 | +## Code Patterns & Conventions |
59 | 60 |
|
60 | | - # Assert - Verify results |
61 | | - Assert-ItemExist -path (Join-Path $folderPath "getHashCode.ps1") |
62 | | -} |
| 61 | +### GraphQL Integration |
| 62 | +1. Store GraphQL in template files: `/public/graphql/queryName.query` or `.mutant` |
| 63 | +2. Retrieve via: `Get-GraphQLString "queryName.query"` |
| 64 | +3. Execute: `Invoke-GraphQL -Query $query -Variables $variables` |
| 65 | + |
| 66 | +Example: |
| 67 | +```powershell |
| 68 | +$query = Get-GraphQLString "findProject.query" |
| 69 | +$variables = @{ login = $Owner; pattern = $Pattern } |
| 70 | +$response = Invoke-GraphQL -Query $query -Variables $variables |
63 | 71 | ``` |
64 | 72 |
|
65 | | -- Use `Assert-NotImplemented` for unfinished tests |
66 | | -- Test files in `Test/public/` mirror functions in `public/` |
67 | | -- Run tests with `./test.ps1` (uses `TestingHelper` module) |
| 73 | +### Public vs. Private Functions |
| 74 | +- **Public** (`/public`): User-facing, high-level; transform data, handle caching |
| 75 | +- **Private** (`/private`): Lower-level helpers; return raw GitHub data |
| 76 | +- **Driver** (`/public/driver`): Thin wrappers around API calls; minimal logic |
68 | 77 |
|
69 | | -## Core Patterns |
| 78 | +### Command Aliases with Parameter Templates |
| 79 | +Use `Set-MyInvokeCommandAlias` for dynamic command dispatch: |
| 80 | +```powershell |
| 81 | +Set-MyInvokeCommandAlias -Alias "findProject" -Command "Invoke-FindProject -Owner {owner} -Pattern {pattern}" |
| 82 | +Invoke-MyCommand -Command "findProject" -Parameters @{owner="foo"; pattern="bar"} |
| 83 | +``` |
| 84 | +This enables mocking in tests without changing implementation. |
70 | 85 |
|
71 | | -**Module Discovery:** Use `Find-ModuleRootPath` to locate module root by searching up from current path for `*.psd1` files (skips Test.psd1). |
| 86 | +### Pipeline & Object Transformation |
| 87 | +Functions support pipeline input for bulk operations: |
| 88 | +```powershell |
| 89 | +"user1", "user2" | Add-ProjectUser -Owner $owner -ProjectNumber 123 -Role "WRITER" |
| 90 | +``` |
72 | 91 |
|
73 | | -**Folder Management:** `Get-ModuleFolder` maps logical names (`Include`, `Public`, `TestPrivate`, etc.) to filesystem paths. Valid names defined in `helper/module.helper.ps1` `$VALID_FOLDER_NAMES`. |
| 92 | +### Error Handling |
| 93 | +- GraphQL errors: Check `$response.errors` before processing |
| 94 | +- Include meaningful context in error messages |
| 95 | +- Use `Write-MyError`, `Write-MyVerbose`, `Write-MyDebug` for consistent logging |
| 96 | + |
| 97 | +## Testing Patterns |
| 98 | + |
| 99 | +### Test File Location |
| 100 | +Test files must mirror the module structure: |
| 101 | +- **Source**: `public/code.ps1` → **Test**: `Test/public/code.test.ps1` |
| 102 | +- **Source**: `public/driver/invoke-getnode.ps1` → **Test**: `Test/public/driver/invoke-getnode.test.ps1` |
| 103 | +- **Source**: `private/dates.ps1` → **Test**: `Test/private/dates.test.ps1` |
| 104 | + |
| 105 | +The folder structure in `Test/` must exactly match the structure in the main module. |
| 106 | + |
| 107 | +### Test Function Naming |
| 108 | +- **Format**: `Test_<FunctionName>_<Scenario>` |
| 109 | +- **Examples**: |
| 110 | + - `Test_FindProject_SUCCESS` (success case) |
| 111 | + - `Test_AddProjectUser_SUCCESS_SingleUser` (specific variant) |
| 112 | + - `Test_GetProjectIssue_NotFound` (error case) |
| 113 | +- **Conventions**: |
| 114 | + - Use PascalCase matching the actual function name (e.g., `Get-SomeInfo` → `Test_GetSomeInfo_<tip>`) |
| 115 | + - `<tip>` should be a descriptive word indicating the test goal (SUCCESS, NotFound, InvalidInput, etc.) |
| 116 | + - Use assertions: `Assert-IsTrue`, `Assert-Contains`, `Assert-AreEqual`, `Assert-Count`, `Assert-IsNull` |
| 117 | + |
| 118 | +### Mock System |
| 119 | +Located in `Test/include/`: |
| 120 | +- `invokeCommand.mock.ps1`: Mocks `Invoke-MyCommand` calls via JSON files in `Test/private/mocks/` |
| 121 | +- `callPrivateContext.ps1`: Execute private functions in module context |
| 122 | + |
| 123 | +### Mock Data Structure |
| 124 | +```powershell |
| 125 | +# Test/private/mocks/mockCommands.json defines: |
| 126 | +{ |
| 127 | + "Command": "Invoke-GetUser -Handle rulasg", |
| 128 | + "FileName": "invoke-GetUser-rulasg.json" |
| 129 | +} |
| 130 | +``` |
74 | 131 |
|
75 | | -**Configuration:** JSON-based, stored in `~/.helpers/{ModuleName}/config/`. Use `Get-Configuration`, `Save-Configuration`, `Test-Configuration` from `include/config.ps1`. |
| 132 | +### Common Test Setup |
| 133 | +```powershell |
| 134 | +Reset-InvokeCommandMock |
| 135 | +Mock_DatabaseRoot |
| 136 | +MockCall_GetProject $project -SkipItems |
| 137 | +MockCallJson -Command "command" -File "response.json" |
| 138 | +``` |
76 | 139 |
|
77 | | -**Command Aliasing:** Use `Set-MyInvokeCommandAlias` and `Invoke-MyCommand` for mockable external commands (database calls, API invocations). |
| 140 | +## Key Dependencies |
| 141 | +- **GitHub API**: GraphQL (primary), REST (legacy) |
| 142 | +- **TestingHelper**: Test framework from PSGallery |
| 143 | +- **InvokeHelper**: Command dispatch/mocking library (external) |
78 | 144 |
|
79 | | -## Development Commands |
| 145 | +## Important Gotchas |
| 146 | +1. **Module Loading**: Functions depend on proper load order; new files in `/private` or `/public` auto-loaded |
| 147 | +2. **Aliases**: Use `Set-MyInvokeCommandAlias` before calling `Invoke-MyCommand` for consistency |
| 148 | +3. **GraphQL Templates**: Fragment files (`.tag`) must match schema; test with actual GitHub API responses |
| 149 | +4. **Configuration**: Stored per-module; reset with `Reset-ProjectHelperEnvironment` |
| 150 | +5. **PSScriptAnalyzer**: PR checks fail on warnings; review `.github/workflows/powershell.yml` rules |
80 | 151 |
|
81 | | -- `./test.ps1` - Run all unit tests |
82 | | -- `./sync.ps1` - Sync includes to workspace/module |
83 | | -- `./deploy.ps1` - Deploy module |
84 | | -- `./release.ps1` - Release module version |
| 152 | +## PR Branch & Active Work |
| 153 | +Currently on `projectv2ContributionUpdate` - Implementing project access management with new user collaboration features. Recent changes focus on `Invoke-UpdateProjectV2Collaborators` and `Add-ProjectUser` functions with proper string splitting via `-split` with `[System.StringSplitOptions]::RemoveEmptyEntries`. |
0 commit comments