Skip to content

Commit ced5adf

Browse files
committed
ci: move workflows to repo root .github/workflows, fix all paths
1 parent 1ac3096 commit ced5adf

4 files changed

Lines changed: 342 additions & 443 deletions

File tree

.github/workflows/ci.yml

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
name: CI
2+
3+
# Runs on every push to any branch and on every pull request.
4+
# Builds PowerMeter.exe (Release x64) and both ACSIL DLLs, then runs
5+
# smoke tests to verify the binaries are valid PE images and export
6+
# the expected entry points.
7+
8+
on:
9+
push:
10+
branches: ["**"]
11+
tags-ignore: ["v*"] # releases are handled by release.yml
12+
pull_request:
13+
branches: ["**"]
14+
15+
concurrency:
16+
group: ci-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
# ---------------------------------------------------------------------------
21+
build-overlay:
22+
name: Build PowerMeter.exe
23+
runs-on: windows-latest
24+
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Add MSBuild to PATH
30+
uses: microsoft/setup-msbuild@v2
31+
32+
- name: Build PowerMeter.exe (Release x64)
33+
run: |
34+
msbuild PowerMeter.vcxproj `
35+
/p:Configuration=Release `
36+
/p:Platform=x64 `
37+
/v:minimal `
38+
/nologo
39+
40+
- name: Locate PowerMeter.exe
41+
id: locate-exe
42+
shell: pwsh
43+
run: |
44+
$candidates = @(
45+
"x64\Release\PowerMeter.exe",
46+
"PowerMeter\x64\Release\PowerMeter.exe"
47+
)
48+
$found = $candidates | Where-Object { Test-Path $_ } | Select-Object -First 1
49+
if (-not $found) { Write-Error "PowerMeter.exe not found after build."; exit 1 }
50+
Write-Host "Found: $found"
51+
"exe_path=$found" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
52+
53+
- name: Smoke test - valid AMD64 PE image
54+
shell: pwsh
55+
run: |
56+
$exe = "${{ steps.locate-exe.outputs.exe_path }}"
57+
$bytes = [System.IO.File]::ReadAllBytes($exe)
58+
if ($bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) { Write-Error "Missing MZ header"; exit 1 }
59+
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
60+
$machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
61+
if ($machine -ne 0x8664) { Write-Error ("Not AMD64: 0x{0:X4}" -f $machine); exit 1 }
62+
$size = (Get-Item $exe).Length
63+
if ($size -lt 50KB) { Write-Error "Binary too small: $size bytes"; exit 1 }
64+
Write-Host ("PASS: AMD64 PE, {0:N0} bytes" -f $size)
65+
66+
- name: Upload overlay artifact
67+
uses: actions/upload-artifact@v4
68+
with:
69+
name: PowerMeter-exe
70+
path: ${{ steps.locate-exe.outputs.exe_path }}
71+
retention-days: 7
72+
73+
# ---------------------------------------------------------------------------
74+
build-acsil:
75+
name: Build ACSIL DLLs
76+
runs-on: windows-latest
77+
78+
steps:
79+
- name: Checkout
80+
uses: actions/checkout@v4
81+
82+
- name: Add MSBuild to PATH
83+
uses: microsoft/setup-msbuild@v2
84+
85+
- name: Download Sierra Chart ACS_Source headers
86+
shell: pwsh
87+
run: |
88+
$dest = "${{ github.workspace }}\sc_stub\ACS_Source"
89+
New-Item -ItemType Directory -Force $dest | Out-Null
90+
foreach ($f in @("sierrachart.h","SCStructures.h","SCDateTime.h")) {
91+
Invoke-WebRequest -Uri "https://www.sierrachart.com/ACS_Source/$f" `
92+
-OutFile "$dest\$f" -UseBasicParsing
93+
Write-Host "Downloaded $f"
94+
}
95+
96+
- name: Build PowerMeterFeed DLL (Debug x64)
97+
run: |
98+
msbuild PowerMeterFeed.vcxproj `
99+
/p:Configuration=Debug `
100+
/p:Platform=x64 `
101+
/p:SierraChartRoot="${{ github.workspace }}\sc_stub" `
102+
/v:minimal `
103+
/nologo
104+
working-directory: ACSIL
105+
106+
- name: Build PowerMeterFeedJS DLL (Debug x64)
107+
run: |
108+
msbuild PowerMeterFeedJS.vcxproj `
109+
/p:Configuration=Debug `
110+
/p:Platform=x64 `
111+
/p:SierraChartRoot="${{ github.workspace }}\sc_stub" `
112+
/v:minimal `
113+
/nologo
114+
working-directory: ACSIL
115+
116+
- name: Smoke test - DLLs are valid AMD64 PE images
117+
shell: pwsh
118+
run: |
119+
$dlls = @(
120+
"ACSIL\bin\x64\Debug\PowerMeterFeed_64_d.dll",
121+
"ACSIL\bin\x64\Debug\PowerMeterFeedJS_64_d.dll"
122+
)
123+
foreach ($dll in $dlls) {
124+
if (-not (Test-Path $dll)) { Write-Error "Not found: $dll"; exit 1 }
125+
$bytes = [System.IO.File]::ReadAllBytes($dll)
126+
if ($bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) { Write-Error "Bad MZ: $dll"; exit 1 }
127+
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
128+
$machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
129+
if ($machine -ne 0x8664) { Write-Error ("Not AMD64: $dll (0x{0:X4})" -f $machine); exit 1 }
130+
$size = (Get-Item $dll).Length
131+
if ($size -lt 10KB) { Write-Error "Too small: $size bytes ($dll)"; exit 1 }
132+
Write-Host ("PASS: $(Split-Path $dll -Leaf) ({0:N0} bytes, AMD64)" -f $size)
133+
}
134+
135+
- name: Smoke test - scsf_PowerMeterFeed exported
136+
shell: pwsh
137+
run: |
138+
$dll = "ACSIL\bin\x64\Debug\PowerMeterFeed_64_d.dll"
139+
$exports = dumpbin /exports $dll 2>&1
140+
if ($exports -notmatch "scsf_PowerMeterFeed") {
141+
Write-Error "Export 'scsf_PowerMeterFeed' not found"; Write-Host $exports; exit 1
142+
}
143+
Write-Host "PASS: scsf_PowerMeterFeed exported"
144+
145+
- name: Smoke test - scsf_PowerMeterFeedJS exported
146+
shell: pwsh
147+
run: |
148+
$dll = "ACSIL\bin\x64\Debug\PowerMeterFeedJS_64_d.dll"
149+
$exports = dumpbin /exports $dll 2>&1
150+
if ($exports -notmatch "scsf_PowerMeterFeedJS") {
151+
Write-Error "Export 'scsf_PowerMeterFeedJS' not found"; Write-Host $exports; exit 1
152+
}
153+
Write-Host "PASS: scsf_PowerMeterFeedJS exported"
154+
155+
- name: Upload ACSIL artifacts
156+
uses: actions/upload-artifact@v4
157+
with:
158+
name: ACSIL-debug-dlls
159+
path: ACSIL/bin/x64/Debug/*.dll
160+
retention-days: 7
161+
162+
# ---------------------------------------------------------------------------
163+
ci-passed:
164+
name: CI passed
165+
needs: [build-overlay, build-acsil]
166+
runs-on: ubuntu-latest
167+
if: always()
168+
steps:
169+
- name: Check all jobs succeeded
170+
run: |
171+
if [[ "${{ needs.build-overlay.result }}" != "success" || \
172+
"${{ needs.build-acsil.result }}" != "success" ]]; then
173+
echo "One or more CI jobs failed."
174+
exit 1
175+
fi
176+
echo "All CI jobs passed."

.github/workflows/release.yml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
name: Release
2+
3+
# Triggered when a version tag is pushed:
4+
# git tag v1.2.0 && git push origin v1.2.0
5+
6+
on:
7+
push:
8+
tags:
9+
- "v[0-9]+.[0-9]+.[0-9]+"
10+
- "v[0-9]+.[0-9]+.[0-9]+-*"
11+
12+
permissions:
13+
contents: write
14+
15+
jobs:
16+
release:
17+
name: Build & Publish Release
18+
runs-on: windows-latest
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
with:
24+
fetch-depth: 0
25+
26+
- name: Parse version from tag
27+
id: version
28+
shell: pwsh
29+
run: |
30+
$tag = "${{ github.ref_name }}"
31+
$ver = $tag -replace '^v', ''
32+
Write-Host "Tag: $tag Version: $ver"
33+
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
34+
"version=$ver" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
35+
36+
- name: Add MSBuild to PATH
37+
uses: microsoft/setup-msbuild@v2
38+
39+
- name: Build PowerMeter.exe (Release x64)
40+
run: |
41+
msbuild PowerMeter.vcxproj `
42+
/p:Configuration=Release `
43+
/p:Platform=x64 `
44+
/v:minimal `
45+
/nologo
46+
47+
- name: Create SC stub directories
48+
shell: pwsh
49+
run: |
50+
New-Item -ItemType Directory -Force "${{ github.workspace }}\sc_stub\ACS_Source" | Out-Null
51+
New-Item -ItemType Directory -Force "${{ github.workspace }}\sc_stub\Data" | Out-Null
52+
53+
- name: Download Sierra Chart ACS_Source headers
54+
shell: pwsh
55+
run: |
56+
$dest = "${{ github.workspace }}\sc_stub\ACS_Source"
57+
foreach ($f in @("sierrachart.h","SCStructures.h","SCDateTime.h")) {
58+
Invoke-WebRequest -Uri "https://www.sierrachart.com/ACS_Source/$f" `
59+
-OutFile "$dest\$f" -UseBasicParsing
60+
Write-Host "Downloaded $f"
61+
}
62+
63+
- name: Build PowerMeterFeed_64.dll (Release x64)
64+
run: |
65+
msbuild PowerMeterFeed.vcxproj `
66+
/p:Configuration=Release `
67+
/p:Platform=x64 `
68+
/p:SierraChartRoot="${{ github.workspace }}\sc_stub" `
69+
/v:minimal `
70+
/nologo
71+
working-directory: ACSIL
72+
73+
- name: Build PowerMeterFeedJS_64.dll (Release x64)
74+
run: |
75+
msbuild PowerMeterFeedJS.vcxproj `
76+
/p:Configuration=Release `
77+
/p:Platform=x64 `
78+
/p:SierraChartRoot="${{ github.workspace }}\sc_stub" `
79+
/v:minimal `
80+
/nologo
81+
working-directory: ACSIL
82+
83+
- name: Smoke test - all binaries valid AMD64 PE
84+
shell: pwsh
85+
run: |
86+
$exeCandidates = @("x64\Release\PowerMeter.exe","PowerMeter\x64\Release\PowerMeter.exe")
87+
$exe = $exeCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
88+
if (-not $exe) { Write-Error "PowerMeter.exe not found"; exit 1 }
89+
90+
$binaries = @(
91+
$exe,
92+
"${{ github.workspace }}\sc_stub\Data\PowerMeterFeed_64.dll",
93+
"${{ github.workspace }}\sc_stub\Data\PowerMeterFeedJS_64.dll"
94+
)
95+
foreach ($bin in $binaries) {
96+
if (-not (Test-Path $bin)) { Write-Error "Not found: $bin"; exit 1 }
97+
$bytes = [System.IO.File]::ReadAllBytes($bin)
98+
if ($bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) { Write-Error "Bad MZ: $bin"; exit 1 }
99+
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
100+
$machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
101+
if ($machine -ne 0x8664) { Write-Error ("Not AMD64: $bin" -f $machine); exit 1 }
102+
Write-Host ("PASS: $(Split-Path $bin -Leaf) ({0:N0} bytes)" -f (Get-Item $bin).Length)
103+
}
104+
# Store exe path for packaging step
105+
"exe_path=$exe" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
106+
id: smoketest
107+
108+
- name: Assemble distribution ZIP
109+
id: package
110+
shell: pwsh
111+
run: |
112+
$ver = "${{ steps.version.outputs.version }}"
113+
$stub = "${{ github.workspace }}\sc_stub"
114+
$exe = "${{ steps.smoketest.outputs.exe_path }}"
115+
$distDir = "dist\PowerMeter_v$ver"
116+
$zipPath = "dist\PowerMeter_v$ver.zip"
117+
118+
foreach ($d in @($distDir,"$distDir\ACSIL","$distDir\ACSIL\src","$distDir\docs")) {
119+
New-Item -ItemType Directory -Force $d | Out-Null
120+
}
121+
122+
Copy-Item $exe "$distDir\PowerMeter.exe"
123+
Copy-Item "$stub\Data\PowerMeterFeed_64.dll" "$distDir\ACSIL\"
124+
Copy-Item "$stub\Data\PowerMeterFeedJS_64.dll" "$distDir\ACSIL\"
125+
Copy-Item "PowerMeterFeed.cpp" "$distDir\ACSIL\src\"
126+
Copy-Item "PowerMeterFeedJS.cpp" "$distDir\ACSIL\src\"
127+
Copy-Item "build_acsil.ps1" "$distDir\ACSIL\"
128+
Copy-Item "docs\README.md" "$distDir\README.md"
129+
Copy-Item "docs\ALGORITHM_NOTES.md" "$distDir\docs\"
130+
131+
Compress-Archive -Path "$distDir\*" -DestinationPath $zipPath -Force
132+
Write-Host "Package: $zipPath"
133+
"zip_path=$zipPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
134+
135+
- name: Generate release notes
136+
shell: pwsh
137+
run: |
138+
$tag = "${{ steps.version.outputs.tag }}"
139+
$prevTag = git describe --tags --abbrev=0 "$tag^" 2>$null
140+
if ($prevTag) {
141+
$log = git log "$prevTag..$tag" --pretty=format:"- %s" --no-merges
142+
} else {
143+
$log = git log $tag --pretty=format:"- %s" --no-merges | Select-Object -First 20
144+
}
145+
@"
146+
## What's changed
147+
$($log -join "`n")
148+
149+
## Installation
150+
1. Extract the ZIP.
151+
2. Copy ``ACSIL\PowerMeterFeed_64.dll`` (or ``PowerMeterFeedJS_64.dll``) to ``C:\SierraChart\Data\``.
152+
3. Run ``PowerMeter.exe``.
153+
4. Load the study: **Analysis -> Add Custom Study -> PowerMeter Feed**.
154+
155+
See ``README.md`` inside the ZIP for full instructions.
156+
"@ | Out-File -FilePath release_notes.md -Encoding utf8
157+
158+
- name: Create GitHub Release
159+
uses: softprops/action-gh-release@v2
160+
with:
161+
tag_name: ${{ steps.version.outputs.tag }}
162+
name: PowerMeter ${{ steps.version.outputs.tag }}
163+
body_path: release_notes.md
164+
draft: false
165+
prerelease: ${{ contains(steps.version.outputs.tag, '-') }}
166+
files: ${{ steps.package.outputs.zip_path }}

0 commit comments

Comments
 (0)