Skip to content

Commit 6367e44

Browse files
committed
Merge branch 'dev'
2 parents 59c173a + c34882b commit 6367e44

40 files changed

+1823
-671
lines changed

.github/workflows/build-flatpak.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ jobs:
3030
steps:
3131
- name: Checkout code
3232
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 0
3335

3436
- name: Setup .NET
3537
uses: actions/setup-dotnet@v4
@@ -70,6 +72,8 @@ jobs:
7072
steps:
7173
- name: Checkout code
7274
uses: actions/checkout@v4
75+
with:
76+
fetch-depth: 0
7377

7478
- name: Download build artifacts
7579
uses: actions/download-artifact@v4
@@ -254,11 +258,11 @@ jobs:
254258
255259
- name: Create metainfo file
256260
run: |
257-
# Get version from tag or use default
261+
# Get version from tag or use git hash
258262
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
259263
VERSION=${GITHUB_REF#refs/tags/v}
260264
else
261-
VERSION="1.0.0"
265+
VERSION="0.0.0-dev+$(git rev-parse --short HEAD)"
262266
fi
263267
264268
cat > ${{ env.APP_ID }}.metainfo.xml << EOF
@@ -319,6 +323,8 @@ jobs:
319323
steps:
320324
- name: Checkout code
321325
uses: actions/checkout@v4
326+
with:
327+
fetch-depth: 0
322328

323329
- name: Download Flatpak artifacts
324330
uses: actions/download-artifact@v4
@@ -347,4 +353,4 @@ jobs:
347353
draft: false
348354
prerelease: false
349355
env:
350-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
356+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/build_and_release_all.yml

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,29 +52,22 @@ jobs:
5252
with:
5353
# If manually triggered, use the input branch; otherwise use the tag ref
5454
ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.target_branch || github.ref_name }}
55+
fetch-depth: 0
5556

56-
- name: Setup .NET (8.x)
57-
uses: actions/setup-dotnet@v3
58-
with:
59-
dotnet-version: '8.0.x'
60-
61-
- name: Read Version
62-
id: get_version
57+
- name: Ensure full git history
6358
shell: bash
6459
run: |
6560
set -euo pipefail
66-
67-
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
68-
VERSION="0.0.1"
69-
elif [[ "${{ github.ref_type }}" == "tag" ]]; then
70-
VERSION="${GITHUB_REF#refs/tags/}"
71-
VERSION="${VERSION#release-v}"
61+
if git rev-parse --is-shallow-repository | grep -q true; then
62+
git fetch --prune --unshallow --tags
7263
else
73-
VERSION="0.0.0-dev"
64+
git fetch --prune --tags
7465
fi
75-
76-
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
77-
echo "v$VERSION" > Companion.Desktop/VERSION
66+
67+
- name: Setup .NET (8.x)
68+
uses: actions/setup-dotnet@v3
69+
with:
70+
dotnet-version: '8.0.x'
7871

7972
- name: Restore dependencies
8073
run: dotnet restore Companion.Desktop/Companion.Desktop.csproj
@@ -108,19 +101,6 @@ jobs:
108101
-p:PublishSingleFile=true
109102
fi
110103
111-
- name: Write VERSION into publish output
112-
shell: bash
113-
run: |
114-
set -euo pipefail
115-
case "${{ runner.os }}" in
116-
Windows) PUBLISH_DIR="Companion.Desktop/bin/Release/net8.0/win-${{ matrix.arch }}/publish" ;;
117-
macOS) PUBLISH_DIR="Companion.Desktop/bin/Release/net8.0/osx-${{ matrix.arch }}/publish" ;;
118-
Linux) PUBLISH_DIR="Companion.Desktop/bin/Release/net8.0/linux-${{ matrix.arch }}/publish" ;;
119-
esac
120-
echo "v${{ env.VERSION }}" > "$PUBLISH_DIR/VERSION"
121-
echo "Wrote VERSION to $PUBLISH_DIR/VERSION:"
122-
cat "$PUBLISH_DIR/VERSION"
123-
124104
# ----- macOS: bundle .app + sign + dmg -----
125105
- name: Decode signing certificate
126106
if: matrix.os == 'macos-latest'
@@ -267,6 +247,9 @@ jobs:
267247
hdiutil create -volname "Companion" -srcfolder dmg_build -ov -format UDZO -fs HFS+ -size 500m "${DMG_NAME}"
268248
rm -rf dmg_build
269249
250+
rm -f "Companion-macos-${{ matrix.arch }}.zip"
251+
zip -r "Companion-macos-${{ matrix.arch }}.zip" "${APP_DIR}"
252+
270253
# ----- Linux packaging -----
271254
- name: Linux - zip publish folder
272255
if: matrix.os == 'ubuntu-latest'
@@ -301,6 +284,13 @@ jobs:
301284
name: Companion-macos-${{ matrix.arch }}
302285
path: Companion-macos-${{ matrix.arch }}.dmg
303286
compression-level: 9
287+
- name: Upload macOS App Zip
288+
if: matrix.os == 'macos-latest'
289+
uses: actions/upload-artifact@v4
290+
with:
291+
name: Companion-macos-${{ matrix.arch }}-app
292+
path: Companion-macos-${{ matrix.arch }}.zip
293+
compression-level: 9
304294

305295
- name: Upload Windows Artifact
306296
if: matrix.os == 'windows-latest'
@@ -314,7 +304,7 @@ jobs:
314304
uses: actions/upload-artifact@v4
315305
with:
316306
name: Companion-linux-${{ matrix.arch }}
317-
path: Companion-linux-${{ matrix.arch }}.zip
307+
path: ./Companion.Desktop/bin/Release/net8.0/linux-${{ matrix.arch }}/publish/**
318308
compression-level: 0
319309

320310
release:
@@ -353,11 +343,17 @@ jobs:
353343
fi
354344
done
355345
356-
# Copy Linux zips (they are inside artifact folders)
357-
find ./artifacts -type f -name "Companion-linux-*.zip" -exec cp {} ./release_files/ \;
346+
# Re-zip Linux folders to a single file per arch
347+
for arch in x64 arm64; do
348+
if [ -d "./artifacts/Companion-linux-${arch}" ]; then
349+
(cd "./artifacts/Companion-linux-${arch}" && zip -r "../../release_files/Companion-linux-${arch}.zip" .)
350+
fi
351+
done
358352
359353
# Copy macOS DMGs (also inside artifact folders)
360354
find ./artifacts -type f -name "Companion-macos-*.dmg" -exec cp {} ./release_files/ \;
355+
# Copy macOS app zips
356+
find ./artifacts -type f -name "Companion-macos-*.zip" -exec cp {} ./release_files/ \;
361357
362358
ls -la ./release_files
363359
@@ -385,10 +381,11 @@ jobs:
385381
### Downloads
386382
* **Windows**: `Companion-windows-x64.zip` / `Companion-windows-arm64.zip`
387383
* **macOS**: `Companion-macos-x64.dmg` / `Companion-macos-arm64.dmg`
384+
* **macOS (App ZIP)**: `Companion-macos-x64.zip` / `Companion-macos-arm64.zip`
388385
* **Linux**: `Companion-linux-x64.zip` / `Companion-linux-arm64.zip`
389386
390387
### Install
391388
* **Windows**: unzip and run `Companion.Desktop.exe`.
392-
* **macOS**: open `.dmg` and drag **Companion.app** to Applications.
389+
* **macOS**: open `.dmg` and drag **Companion.app** to Applications. (ZIP contains the `.app` bundle.)
393390
* **Linux**: unzip and run `./Companion.Desktop` (chmod +x if needed).
394391
files: ./release_files/*

.github/workflows/gen-test-coverage-report.yml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ concurrency:
44
group: coverage-${{ github.workflow }}-${{ github.ref }}
55
cancel-in-progress: true
66

7-
# Runs on master branch commits,
8-
# every commit in a pull request, any published release.
97
on:
108
workflow_dispatch:
119
push:
@@ -17,7 +15,6 @@ on:
1715

1816
jobs:
1917
coverage:
20-
# Minimal permissions; bump only if you actually need more
2118
permissions:
2219
contents: read
2320
pull-requests: write
@@ -36,20 +33,18 @@ jobs:
3633
with:
3734
dotnet-version: '8.0.x'
3835

39-
# If you rely on workloads (e.g., MAUI/Avalonia workloads), keep this.
40-
# It can be slow; remove if not needed.
36+
# Keep only if you truly need workloads (often you don't for unit tests)
4137
- name: Restore workloads
4238
run: dotnet workload restore
4339

44-
# ---- Project path updates (OpenIPC_Config -> Companion.Desktop) ----
4540
- name: Restore dependencies
4641
run: dotnet restore Companion.Desktop/Companion.Desktop.csproj
4742

4843
- name: Build project
4944
run: dotnet build Companion.Desktop/Companion.Desktop.csproj --configuration Release --no-restore
5045

5146
- name: Run tests with coverage
52-
run: dotnet test Companion.Tests/Companion.Tests.csproj --configuration Release --verbosity normal --logger "trx" --collect:"XPlat Code Coverage"
47+
run: dotnet test Companion.Tests/Companion.Tests.csproj --configuration Release --no-build --verbosity normal --logger "trx" --collect:"XPlat Code Coverage"
5348

5449
- name: Combine Coverage Reports
5550
uses: danielpalme/ReportGenerator-GitHub-Action@5.2.4
@@ -83,8 +78,8 @@ jobs:
8378
thresholds: "10 30"
8479

8580
- name: Add Coverage PR Comment
86-
uses: marocchino/sticky-pull-request-comment@v2
8781
if: github.event_name == 'pull_request'
82+
uses: marocchino/sticky-pull-request-comment@v2
8883
with:
8984
recreate: true
9085
path: code-coverage-results.md
@@ -98,12 +93,11 @@ jobs:
9893
retention-days: 3
9994

10095
- name: Publish Test Results
101-
uses: EnricoMi/publish-unit-test-result-action@v2.16.1
10296
if: always()
97+
uses: EnricoMi/publish-unit-test-result-action@v2.16.1
10398
with:
10499
trx_files: "${{ github.workspace }}/**/*.trx"
105100

106-
# Cleanup: use find (rm -rf with ** globs is unreliable in bash)
107101
- name: Cleanup Disk Space
108102
if: always()
109103
shell: bash
@@ -113,8 +107,6 @@ jobs:
113107
find "${{ github.workspace }}" -type f -name "*.cobertura.xml" -delete || true
114108
rm -f "${{ github.workspace }}/Cobertura.xml" "${{ github.workspace }}/code-coverage-results.md" || true
115109
116-
# Optional: pruning artifacts requires extra perms and can be flaky.
117-
# Keeping it, but scoping it to non-PR events avoids unnecessary API calls.
118110
- name: Prune Old Artifacts
119111
if: always() && github.event_name != 'pull_request'
120112
uses: c-hive/gha-remove-artifacts@v1

Companion.Desktop/Companion.Desktop.csproj

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,23 @@
1111
<RootNamespace>Companion.Desktop</RootNamespace>
1212
<AssemblyName>Companion.Desktop</AssemblyName>
1313
<UseAppHost>true</UseAppHost>
14-
<MacCatalystIcon>Assets/Icons/OpenIPC.icns</MacCatalystIcon>
14+
<MacCatalystIcon>..\Companion\Assets\Icons\OpenIPC.icns</MacCatalystIcon>
1515
</PropertyGroup>
1616

17+
<Target Name="WriteVersionFile" AfterTargets="Build">
18+
<ItemGroup>
19+
<_VersionFileLines Include="v$(InformationalVersion)" />
20+
</ItemGroup>
21+
<WriteLinesToFile File="$(OutputPath)VERSION" Lines="@(_VersionFileLines)" Overwrite="true" />
22+
</Target>
23+
24+
<Target Name="WriteVersionFileForPublish" AfterTargets="Publish">
25+
<ItemGroup>
26+
<_VersionFileLines Include="v$(InformationalVersion)" />
27+
</ItemGroup>
28+
<WriteLinesToFile File="$(PublishDir)VERSION" Lines="@(_VersionFileLines)" Overwrite="true" />
29+
</Target>
30+
1731
<PropertyGroup>
1832
<ApplicationManifest>app.manifest</ApplicationManifest>
1933
</PropertyGroup>

Companion.Tests/Companion.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PackageReference Include="Avalonia.Desktop" Version="0.10.13"/>
1414
<PackageReference Include="Avalonia.Svg.Skia" Version="11.2.0.2"/>
1515
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.2.0.12" />
16-
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
16+
<PackageReference Include="coverlet.collector" Version="6.0.4"/>
1717
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.2" />
1818
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0"/>
1919
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>

Companion.Tests/Services/UpdateCheckerTests.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,36 @@ public async Task CheckForUpdateAsync_ShouldReturnUpdateAvailable_WhenNewVersion
5151
Assert.That(result.DownloadUrl, Is.EqualTo("https://example.com/download"));
5252
Assert.That(result.NewVersion, Is.EqualTo("release-v1.2.0"));
5353
}
54-
}
54+
55+
[Test]
56+
public async Task CheckForUpdateAsync_HandlesBuildMetadataInCurrentVersion()
57+
{
58+
// Arrange
59+
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
60+
mockHttpMessageHandler
61+
.Protected()
62+
.Setup<Task<HttpResponseMessage>>(
63+
"SendAsync",
64+
ItExpr.IsAny<HttpRequestMessage>(),
65+
ItExpr.IsAny<CancellationToken>())
66+
.ReturnsAsync(new HttpResponseMessage
67+
{
68+
StatusCode = HttpStatusCode.OK,
69+
Content = new StringContent(MockUpdateJson)
70+
});
71+
72+
var mockHttpClient = new HttpClient(mockHttpMessageHandler.Object);
73+
74+
var mockConfiguration = new Mock<IConfiguration>();
75+
mockConfiguration.Setup(c => c["UpdateChecker:LatestJsonUrl"]).Returns("https://mock-url/latest.json");
76+
77+
var updateChecker = new UpdateChecker(mockHttpClient, mockConfiguration.Object);
78+
79+
// Act
80+
var result = await updateChecker.CheckForUpdateAsync("v0.0.1+githash");
81+
82+
// Assert
83+
Assert.That(result.HasUpdate, Is.True);
84+
Assert.That(result.NewVersion, Is.EqualTo("release-v1.2.0"));
85+
}
86+
}

Companion.Tests/Services/VersionHelperTests.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Moq;
22
using Companion.Services;
3+
using System.Reflection;
34

45
namespace OpenIPC.Companion.Tests.Services;
56

@@ -27,10 +28,10 @@ public void GetAppVersion_ReturnsVersionFromFile_InDevelopmentEnvironment()
2728
{
2829
// Arrange
2930
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
30-
var expectedVersion = "1.0.0-test";
31+
var expectedVersion = "v1.0.0-test";
3132

3233
_mockFileSystem.Setup(fs => fs.Exists(It.IsAny<string>())).Returns(true);
33-
_mockFileSystem.Setup(fs => fs.ReadAllText(It.IsAny<string>())).Returns(expectedVersion);
34+
_mockFileSystem.Setup(fs => fs.ReadAllText(It.IsAny<string>())).Returns("1.0.0-test");
3435

3536
// Act
3637
var version = VersionHelper.GetAppVersion();
@@ -53,4 +54,27 @@ public void GetAppVersion_ReturnsUnknownVersion_OnException()
5354
// Assert
5455
Assert.That(version, Is.EqualTo("Unknown Version"));
5556
}
56-
}
57+
58+
[Test]
59+
public void GetAppVersion_ReturnsAssemblyVersion_WhenFileMissing()
60+
{
61+
// Arrange
62+
_mockFileSystem.Setup(fs => fs.Exists(It.IsAny<string>())).Returns(false);
63+
var targetAssembly = typeof(VersionHelper).Assembly;
64+
var informationalVersion = targetAssembly
65+
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
66+
.InformationalVersion;
67+
var assemblyVersion = targetAssembly.GetName().Version?.ToString();
68+
69+
// Act
70+
var version = VersionHelper.GetAppVersion();
71+
72+
// Assert
73+
var expected = !string.IsNullOrWhiteSpace(informationalVersion)
74+
? $"v{informationalVersion}"
75+
: $"v{assemblyVersion}";
76+
77+
Assert.That(expected, Is.Not.Null.And.Not.Empty);
78+
Assert.That(version, Is.EqualTo(expected));
79+
}
80+
}

0 commit comments

Comments
 (0)