Skip to content

Commit 4bdf3bb

Browse files
authored
Merge pull request #51 from rulasg/Improvement-from-projecthelper
Improvement that comes from ProjectHelper work
2 parents 918b728 + 509b1ac commit 4bdf3bb

18 files changed

Lines changed: 900 additions & 588 deletions

.github/copilot-instructions.md

Lines changed: 129 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,153 @@
1-
# Copilot Instructions for IncludeHelper
1+
# ProjectHelper Copilot Instructions
22

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.
45

5-
## Architecture Overview
6+
## Architecture & Core Patterns
67

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"
1414

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
1621

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
2326
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}
3429
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+
```
3833

39-
## Logging and Debugging
34+
## Development Workflows
4035

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+
```
4542

46-
## Test Conventions
43+
Uses **TestingHelper** module from PSGallery (installed automatically).
4744

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+
```
4951

50-
**Test Structure:**
52+
### Debugging
53+
Enable module debug output:
5154
```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+
```
5658

57-
# Act - Execute the function being tested
58-
Add-IncludeToWorkspace -Name "getHashCode.ps1" -FolderName "Include" -DestinationModulePath "TestModule"
59+
## Code Patterns & Conventions
5960

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
6371
```
6472

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
6877

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.
7085

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+
```
7291

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+
```
74131

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+
```
76139

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)
78144

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
80151

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`.

.github/workflows/deploy_module_on_release.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ jobs:
1919
run: |
2020
echo $EVENT_CONTEXT
2121
22+
- name: Run test.ps1
23+
shell: pwsh
24+
run: |
25+
$result = ./test.ps1 -ShowTestErrors
26+
27+
Write-Output $result
28+
29+
import-module ./tools/Test_Helper/
30+
31+
$passed = Test-Result -Result $result
32+
33+
if($passed)
34+
{ "All test passed" | Write-Verbose -verbose ; exit 0 }
35+
else
36+
{ "Not all tests passed" | Write-Verbose -verbose ; exit 1 }
37+
2238
- name: deploy_ps1
2339
shell: pwsh
2440
env:
@@ -27,8 +43,16 @@ jobs:
2743
RELEASE_TAG: ${{ github.event.release.tag_name }}
2844
RELEASE_NAME: ${{ github.event.release.name }}
2945
run: |
30-
$env:EVENT_REF = $env:REF
3146
47+
# Import required modules for deployment
48+
import-module ./tools/Test_Helper/
49+
50+
Get-RequiredModule -Verbose | Import-RequiredModule -AllowPrerelease
51+
52+
# GET TAG NAME
53+
54+
## Ref definition. Branch or Tag
55+
$env:EVENT_REF = $env:REF
3256
If ([string]::IsNullOrEmpty($env:EVENT_REF)) {
3357
# Release published trigger
3458
$tag = $env:RELEASE_TAG
@@ -41,8 +65,8 @@ jobs:
4165
4266
If([string]::IsNullorwhitespace($tag)) {
4367
# Tag name is empty, exit
44-
write-error "Tag name is empty"
45-
exit 1
68+
throw "Tag name is empty"
4669
}
4770
71+
# DEPLOYMENT
4872
./deploy.ps1 -VersionTag $tag -NugetApiKey $env:NUGETAPIKEY

.github/workflows/test_with_TestingHelper.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ jobs:
3333
shell: pwsh
3434
run: |
3535
$result = ./test.ps1 -ShowTestErrors
36-
$result
3736
38-
# Allow Not Implemented and Skipped tests to pass
39-
$passed = $result.Tests -eq $result.Pass + $result.NotImplemented + $result.Skipped
40-
# $passed = $result.Tests -eq $result.Pass
37+
Write-Output $result
38+
39+
import-module ./tools/Test_Helper/
40+
41+
$passed = Test-Result -Result $result
4142
4243
if($passed)
4344
{ "All test passed" | Write-Verbose -verbose ; exit 0 }

0 commit comments

Comments
 (0)