Thank you for your interest in contributing to send-teams-notification!
- PowerShell 7+
- Pester 5.x (testing framework)
- Git
For external contributors (fork first):
# Fork the repo on GitHub, then:
git clone https://github.com/YOUR-USERNAME/send-teams-notification.git
cd send-teams-notification
git remote add upstream https://github.com/marcus-hooper/send-teams-notification.gitFor maintainers (direct access):
git clone https://github.com/marcus-hooper/send-teams-notification.git
cd send-teams-notificationVerify setup:
Invoke-Pester ./tests -Output DetailedBefore pushing, run the same checks as CI:
# Lint check (must pass)
Invoke-ScriptAnalyzer -Path ./scripts -Recurse -Settings PSGallery
# Formatting check (must pass)
Get-ChildItem -Path ./scripts -Include '*.ps1','*.psm1' -Recurse | ForEach-Object {
$original = Get-Content -Path $_.FullName -Raw
$formatted = Invoke-Formatter -ScriptDefinition $original
if ($original -ne $formatted) { Write-Warning "Needs formatting: $($_.Name)" }
}
# Unit tests (must pass)
Invoke-Pester ./tests -Output DetailedTip: To auto-fix formatting issues, use
Invoke-Formatterto rewrite the file:$content = Get-Content -Path ./scripts/Send-TeamsNotification.psm1 -Raw Invoke-Formatter -ScriptDefinition $content | Set-Content -Path ./scripts/Send-TeamsNotification.psm1
$config = New-PesterConfiguration
$config.Run.Path = './tests'
$config.Output.Verbosity = 'Detailed'
$config.CodeCoverage.Enabled = $true
$config.CodeCoverage.Path = @('./scripts/send-teams.ps1', './scripts/Send-TeamsNotification.psm1')
Invoke-Pester -Configuration $config# All-in-one CI check (lint, format, test)
$pass = $true
Invoke-ScriptAnalyzer -Path ./scripts -Recurse -Settings PSGallery | ForEach-Object { $pass = $false; $_ }
Get-ChildItem -Path ./scripts -Include '*.ps1','*.psm1' -Recurse | ForEach-Object {
$orig = Get-Content $_.FullName -Raw; $fmt = Invoke-Formatter -ScriptDefinition $orig
if ($orig -ne $fmt) { Write-Warning "Needs formatting: $($_.Name)"; $pass = $false }
}
if ($pass) { Invoke-Pester ./tests -Output Detailed }Use Conventional Commits format:
<type>: <description>
[optional body]
[optional footer]
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
refactor |
Code change that neither fixes a bug nor adds a feature |
test |
Adding or updating tests |
ci |
CI/workflow changes |
deps |
Dependency updates |
security |
Security improvements |
chore |
Maintenance tasks |
perf |
Performance improvement |
feat: add support for custom card actions
fix: handle empty commit_messages array gracefully
docs: update webhook configuration instructions
test: add tests for Build-FactsArray edge cases
ci: update actions/checkout to latest version
chore: clean up unused test fixtures
perf: optimize JSON serialization in payload builder
For breaking changes, use ! after the type or add a BREAKING CHANGE: footer:
feat!: change webhook payload format
Card body structure changed to support new Teams requirements.
Or with a footer:
feat: change webhook payload format
BREAKING CHANGE: Card body structure changed to support new Teams requirements.
-
Create a branch from
main:git checkout -b <type>/short-description
Use branch prefixes that match your commit type:
Branch Prefix Use For feature/New features fix/Bug fixes docs/Documentation changes refactor/Code refactoring ci/CI/workflow changes -
Run CI locally (see above)
-
Add tests for new functionality
-
Ensure CHANGELOG.md has an
[Unreleased]section (CI validates this exists)
All PRs must pass these checks before merge:
| Check | Description | Threshold |
|---|---|---|
| CHANGELOG | [Unreleased] section must exist |
Required |
| Lint | PSScriptAnalyzer with PSGallery settings | No errors |
| Formatting | Invoke-Formatter consistency check | No differences |
| Tests | Pester unit tests | All pass |
| Coverage | Collected and uploaded to Codecov | 80%+ target (not enforced) |
| Integration | action.yml validation, module import | All pass |
| Cross-platform | Module tests on ubuntu, windows, macos | All pass |
Security Checks (run automatically):
| Check | Workflow | Purpose |
|---|---|---|
| CodeQL | codeql.yml | Static security testing |
| OSSF Scorecard | scorecard.yml | Supply chain security |
| Dependency Review | On PR | Flags vulnerable dependencies |
Use the PR template. Include:
- Summary of changes
- Related issue (if any)
- Type of change (bug fix, feature, etc.)
- Testing performed
- All PRs require review before merge
- Address review feedback promptly
- Resolve all conversations before merge
- Squash merge to
main
# Use ErrorAction Stop for critical operations
Invoke-RestMethod -Uri $url -Method Post -Body $body -ErrorAction Stop
# Use try/catch for error handling
try {
# ... operation
} catch {
throw "Operation failed: $_"
}
# Add SupportsShouldProcess for state-changing functions
function Send-Something {
[CmdletBinding(SupportsShouldProcess)]
param(...)
}- UTF-8 encoding without BOM for all files
- Emoji characters must be constructed from Unicode code points to avoid YAML encoding issues:
# Correct $emoji = [char]::ConvertFromUtf32(0x2705) # Avoid (causes YAML issues) $emoji = "✅"
- Export functions via
Export-ModuleMemberin the module file - Add Pester tests for all new exported functions
When adding new functions to Send-TeamsNotification.psm1:
- Add the function implementation
- Add it to
Export-ModuleMember -Function - Add corresponding tests in
Send-TeamsNotification.Tests.ps1
| Job | Runner | Description |
|---|---|---|
| validate-changelog | ubuntu-latest | Validates CHANGELOG.md format and [Unreleased] section |
| lint-and-format | ubuntu-latest | PSScriptAnalyzer and Invoke-Formatter checks |
| test | ubuntu-latest | Pester tests with JaCoCo coverage |
| integration-test | ubuntu-latest | action.yml validation, module import, validation tests |
| cross-platform-test | ubuntu, windows, macos | Module import and function tests on all platforms |
| ci-status | ubuntu-latest | Aggregated status check for all jobs |
# Run all tests
Invoke-Pester ./tests -Output Detailed
# Run tests with coverage
$config = New-PesterConfiguration
$config.Run.Path = './tests'
$config.Output.Verbosity = 'Detailed'
$config.CodeCoverage.Enabled = $true
$config.CodeCoverage.Path = @('./scripts/send-teams.ps1', './scripts/Send-TeamsNotification.psm1')
Invoke-Pester -Configuration $config| Change Type | Test Requirement |
|---|---|
| New function | Add unit tests covering happy path and error cases |
| Bug fix | Add regression test that fails without the fix |
| Refactor | Ensure existing tests still pass |
Tests are located in tests/Send-TeamsNotification.Tests.ps1. See existing tests for patterns on mocking Invoke-RestMethod.
Use the bug report template. Include:
- PowerShell version (
$PSVersionTable.PSVersion) - Steps to reproduce
- Expected vs actual behavior
- Relevant error messages
Use the feature request template. Include:
- Problem statement
- Proposed solution
- Alternatives considered
Releases are managed by maintainers:
- All CI checks pass on
main - CHANGELOG.md updated with version and date
- Tag created:
git tag -a v1.0.0 -m "Release v1.0.0" - Tag pushed:
git push origin v1.0.0 - GitHub Actions creates release and updates major version tag (
v1)
- Questions: Open a Discussion
- Bugs: Open an Issue
- Features: Open an Issue
- Security: See SECURITY.md for responsible disclosure
By contributing, you agree that your contributions will be licensed under the MIT License.