Skip to content
Merged
5 changes: 4 additions & 1 deletion .github/instructions/terminal.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ description: "Terminal command patterns for auto-approval in FieldWorks"

# Terminal Commands

Commands with pipes (`|`), `&&`, or `2>&1` require manual approval. Use `scripts/Agent/` wrappers instead.
Commands with pipes (`|`), `&&`, or `2>&1` require manual approval. Use repository wrapper scripts instead.

Placement policy for wrappers:
- Prefer `Build/Agent/` for new build/test/CI orchestration scripts.

**MCP-first:** When the `ps-tools` MCP server is running, prefer MCP tools (`Git-Search`, `Read-FileContent`, `Invoke-AgentTask`, `build`, `test`, agent tools) instead of direct terminal commands. Use wrappers only when MCP is unavailable.

Expand Down
83 changes: 83 additions & 0 deletions .github/workflows/CI-native.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Flex CI Native
on:
push:
branches: ["release/**", "main", "feature/PubSub"]
paths:
- 'Src/**/*.cpp'
- 'Src/**/*.h'
- 'Src/**/*.hpp'
- 'Src/**/*.cc'
- 'Src/**/*.ixx'
- 'Src/**/*.def'
- 'Src/**/*.vcxproj'
- 'Src/**/*.vcxproj.filters'
- 'Src/**/*.mak'
- 'Lib/**/*.cpp'
- 'Lib/**/*.h'
- 'Lib/**/*.hpp'
- 'Lib/**/*.cc'
- 'Lib/**/*.ixx'
- 'Lib/**/*.def'
- 'Build/Src/NativeBuild/**'
- 'Build/scripts/Invoke-CppTest.ps1'
- 'test.ps1'
pull_request:
branches: ["release/**", "main", "feature/PubSub"]
paths:
- 'Src/**/*.cpp'
- 'Src/**/*.h'
- 'Src/**/*.hpp'
- 'Src/**/*.cc'
- 'Src/**/*.ixx'
- 'Src/**/*.def'
- 'Src/**/*.vcxproj'
- 'Src/**/*.vcxproj.filters'
- 'Src/**/*.mak'
- 'Lib/**/*.cpp'
- 'Lib/**/*.h'
- 'Lib/**/*.hpp'
- 'Lib/**/*.cc'
- 'Lib/**/*.ixx'
- 'Lib/**/*.def'
- 'Build/Src/NativeBuild/**'
- 'Build/scripts/Invoke-CppTest.ps1'
- 'test.ps1'
workflow_dispatch:

permissions:
contents: read
checks: write

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
native_build_and_test:
name: Build Debug and run native tests
runs-on: windows-latest
steps:
- name: Checkout Files
uses: actions/checkout@v4
id: checkout

- name: Build and run native tests
id: native_test
shell: powershell
run: |
.\test.ps1 -Configuration Debug -Native
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Summarize native test results
if: ${{ always() }}
shell: powershell
run: |
.\Build\Agent\Summarize-NativeTestResults.ps1 -Configuration Debug

- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && failure() }}
with:
name: native-build-logs
path: |
./*.log
./Output/**/*.log
229 changes: 75 additions & 154 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -1,160 +1,81 @@
name: Flex CI
on:
push:
branches: ["release/**", "main", "feature/PubSub"]
pull_request:
branches: ["release/**", "main", "feature/PubSub"]
workflow_dispatch:
inputs:
run_wix6_installer_build:
description: "Run WiX 6 installer build (opt-in)"
required: false
default: "false"
push:
branches: ["release/**", "main", "feature/PubSub"]
pull_request:
branches: ["release/**", "main", "feature/PubSub"]
workflow_dispatch:

permissions:
contents: read
checks: write

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
debug_build_and_test:
env:
CROWDIN_API_KEY: ${{ secrets.FLEX_CROWDIN_API }}
name: Build Debug and run Tests (x64 only)
runs-on: windows-latest
steps:
- name: Checkout Files
uses: actions/checkout@v4
id: checkout

- name: Download 481 targeting pack
uses: suisei-cn/actions-download-file@818d6b7dc8fe73f2f924b6241f2b1134ca1377d9 # 1.6.0
id: downloadfile # Remember to give an ID if you need the output filename
with:
url: "https://download.microsoft.com/download/8/1/8/81877d8b-a9b2-4153-9ad2-63a6441d11dd/NDP481-DevPack-ENU.exe"
target: public/

- name: Install targeting pack
shell: cmd
working-directory: public
run: NDP481-DevPack-ENU.exe /q

- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
2.1.x
3.1.x
5.0.x

- name: Add NETFX tools to PATH
shell: powershell
run: |
'C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools' | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2
- name: Build Debug and run tests
id: build_and_test
shell: powershell
run: |
$ErrorActionPreference = 'Stop'
./build.ps1 -Configuration Debug -Platform x64 -MsBuildArgs @('/m', '/p:action=test', '/p:desktopNotAvailable=true') -LogFile Build/build.log

- name: Scan Debug Build Output
shell: powershell
working-directory: Build
run: |
$results = Select-String -Path "build.log" -Pattern "^\s*[1-9][0-9]* Error\(s\)"
if ($results) {
foreach ($result in $results) {
Write-Host "Found errors in build.log $($result.LineNumber): $($result.Line)" -ForegroundColor red
}
exit 1
} else {
Write-Host "No errors found" -ForegroundColor green
exit 0
}

- name: Capture Test Results
shell: powershell
working-directory: Build
run: .\NUnitReport /a ^| tee-object -FilePath test-results.log

- name: Report Test Results
uses: sillsdev/fw-nunitreport-action@v2.0.0
with:
log-path: Build/test-results.log
token: ${{ secrets.GITHUB_TOKEN }}

# Upload build and test artifacts
- uses: actions/upload-artifact@v4
with:
name: build-logs
path: Build/*.log

# Upload generated manifests for inspection (registration-free COM)
- uses: actions/upload-artifact@v4
with:
name: regfree-manifests
path: |
Output/Debug/FieldWorks.exe.manifest
if-no-files-found: warn

# Smoke test: Verify registration-free COM activation (no registry writes)
- name: Smoke test - Reg-free COM activation
shell: powershell
run: |
Write-Host "Testing registration-free COM activation..." -ForegroundColor Cyan
$exitCode = & "Output\Debug\ComManifestTestHost.exe"
if ($LASTEXITCODE -ne 0) {
Write-Host "❌ COM activation test failed with exit code $LASTEXITCODE" -ForegroundColor Red
exit $LASTEXITCODE
} else {
Write-Host "✅ COM activation test passed" -ForegroundColor Green
}

wix6_installer_build:
if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_wix6_installer_build == 'true'
name: Build WiX 6 installer (opt-in)
runs-on: windows-latest
steps:
- name: Checkout Files
uses: actions/checkout@v4

- name: Download 481 targeting pack
uses: suisei-cn/actions-download-file@818d6b7dc8fe73f2f924b6241f2b1134ca1377d9 # 1.6.0
id: downloadfile
with:
url: "https://download.microsoft.com/download/8/1/8/81877d8b-a9b2-4153-9ad2-63a6441d11dd/NDP481-DevPack-ENU.exe"
target: public/

- name: Install targeting pack
shell: cmd
working-directory: public
run: NDP481-DevPack-ENU.exe /q

- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
2.1.x
3.1.x
5.0.x

- name: Add NETFX tools to PATH
shell: powershell
run: |
'C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools' | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2

- name: Build WiX 6 installer
shell: powershell
run: |
$ErrorActionPreference = 'Stop'
./build.ps1 -BuildInstaller -InstallerToolset Wix6 -Configuration Debug -Platform x64 -LogFile Build/wix6-installer.log

- uses: actions/upload-artifact@v4
with:
name: wix6-installer-logs
path: Build/wix6-installer.log
debug_build_and_test:
name: Build Debug and run managed tests
runs-on: windows-latest
steps:
- name: Checkout Files
uses: actions/checkout@v4
id: checkout

- name: Build managed (with tests)
id: managed_build
shell: powershell
run: |
.\build.ps1 -Configuration Debug -Platform x64 -BuildTests
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Run managed tests
id: managed_test
shell: powershell
run: |
.\test.ps1 -Configuration Debug -NoBuild -TestFilter 'TestCategory!=LongRunning&TestCategory!=ByHand&TestCategory!=SmokeTest&TestCategory!=DesktopRequired'
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

- name: Upload TRX test results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: trx-results
path: |
**/*.trx
if-no-files-found: warn

- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && failure() }}
with:
name: build-logs
path: |
./*.log
./Output/**/*.log

publish_test_results:
name: Publish Test Results
if: ${{ !cancelled() }}
needs: debug_build_and_test
runs-on: ubuntu-latest
permissions:
contents: read
issues: read
checks: write
pull-requests: write
steps:
- name: Download TRX artifacts
uses: actions/download-artifact@v4
with:
name: trx-results
path: test-results

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@27d65e188ec43221b20d26de30f4892fad91df2f
with:
files: 'test-results/**/*.trx'
check_name: NUnit Tests
comment_mode: always
job_summary: true
fail_on: test failures
Loading
Loading