Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Build

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
rid: win-x64
- os: ubuntu-latest
rid: linux-x64
- os: macos-latest
rid: osx-arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x

- run: dotnet build Stampeded.slnx -c Release
- run: dotnet test Stampeded.slnx -c Release --no-build

# Framework-dependent on purpose: the app needs an installed .NET SDK at runtime
# anyway (Roslyn's MSBuild workspace, dotnet build/test), so bundling a runtime
# would only grow the artifact. RID-specific so an apphost exists to launch.
- run: dotnet publish src/Stampeded/Stampeded.csproj -c Release -r ${{ matrix.rid }} --no-self-contained -o publish/${{ matrix.rid }}

- name: Zip (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: Compress-Archive -Path publish/win-x64/* -DestinationPath Stampeded-win-x64.zip

# Info-ZIP keeps the execute bit; Compress-Archive and upload-artifact drop it.
- name: Zip (Linux)
if: runner.os == 'Linux'
shell: bash
run: cd publish/linux-x64 && zip -r -q ../../Stampeded-linux-x64.zip .

# Unsigned and unnotarized: first launch needs `xattr -dr com.apple.quarantine Stampeded.app`.
- name: dmg (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
mkdir dmg
cp -R publish/osx-arm64/Stampeded.app dmg/
ln -s /Applications dmg/Applications
hdiutil create -volname Stampeded -srcfolder dmg -ov -format UDZO Stampeded-macos-arm64.dmg

- uses: actions/upload-artifact@v7
with:
name: Stampeded-${{ matrix.rid }}
path: |
Stampeded-*.zip
Stampeded-*.dmg
if-no-files-found: error
26 changes: 26 additions & 0 deletions src/Stampeded/Assets/macos/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>Stampeded</string>
<key>CFBundleDisplayName</key>
<string>Stampeded</string>
<key>CFBundleIdentifier</key>
<string>net.icsharpcode.stampeded</string>
<key>CFBundleVersion</key>
<string>0.1.0</string>
<key>CFBundleShortVersionString</key>
<string>0.1.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleExecutable</key>
<string>Stampeded</string>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
18 changes: 18 additions & 0 deletions src/Stampeded/Stampeded.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,22 @@
<AvaloniaResource Include="Assets/**/*.svg" />
<EmbeddedResource Include="Editor/ILAsm-Mode.xshd" />
</ItemGroup>
<!-- macOS runs an application out of a .app directory, not a loose folder of files. The
bundle is assembled here, on the publish target, so a plain
`dotnet publish -r osx-arm64` reproduces what CI ships, with nothing that exists only in
the workflow. The file list is taken before the bundle directory is created, so the
bundle never copies itself. No CFBundleIconFile: there is no .icns yet. -->
<Target Name="BuildMacAppBundle" AfterTargets="Publish" Condition="$(RuntimeIdentifier.StartsWith('osx-'))">
<PropertyGroup>
<_MacBundleContents>$(PublishDir)$(AssemblyName).app/Contents</_MacBundleContents>
</PropertyGroup>
<ItemGroup>
<_MacPublishFiles Include="$(PublishDir)**/*" Exclude="$(PublishDir)$(AssemblyName).app/**" />
</ItemGroup>
<RemoveDir Directories="$(PublishDir)$(AssemblyName).app" />
<Copy SourceFiles="@(_MacPublishFiles)" DestinationFiles="@(_MacPublishFiles->'$(_MacBundleContents)/MacOS/%(RecursiveDir)%(Filename)%(Extension)')" />
<Copy SourceFiles="$(MSBuildProjectDirectory)/Assets/macos/Info.plist" DestinationFolder="$(_MacBundleContents)" />
<Exec Command="chmod +x &quot;$(_MacBundleContents)/MacOS/$(AssemblyName)&quot;" Condition="!$([MSBuild]::IsOSPlatform('Windows'))" />
<Message Importance="high" Text="macOS bundle written to $(PublishDir)$(AssemblyName).app" />
</Target>
</Project>
8 changes: 1 addition & 7 deletions tests/Stampeded.Core.Tests/BuildArtifactCleanupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,7 @@ public void SetUp()
[TearDown]
public void TearDown()
{
try
{
Directory.Delete(root, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(root);
}

static void WriteFile(string directory, string name)
Expand Down
2 changes: 1 addition & 1 deletion tests/Stampeded.Core.Tests/DecompilationServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Third line.</summary>
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}
}
8 changes: 4 additions & 4 deletions tests/Stampeded.Core.Tests/DraftEditTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void RewritesADraftInPlace()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand All @@ -54,7 +54,7 @@ public void SurvivesReopeningTheReview()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand All @@ -74,7 +74,7 @@ public void IgnoresADraftThatIsNotThere()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand All @@ -99,7 +99,7 @@ public void AReplyKeepsTheThreadItAnswersAcrossSessions()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}
}
4 changes: 2 additions & 2 deletions tests/Stampeded.Core.Tests/EnclosingMemberTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class TypeInferenceTests
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand Down Expand Up @@ -98,7 +98,7 @@ public void Dispose() { }
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand Down
8 changes: 1 addition & 7 deletions tests/Stampeded.Core.Tests/GeneratedSourcesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ public void RemoveTemporaryDirectories()
{
foreach (var dir in temporaryDirectories)
{
try
{
Directory.Delete(dir, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(dir);
}
temporaryDirectories.Clear();
}
Expand Down
8 changes: 1 addition & 7 deletions tests/Stampeded.Core.Tests/GitBlobReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,7 @@ public void RemoveTemporaryDirectories()
{
foreach (var dir in temporaryDirectories)
{
try
{
Directory.Delete(dir, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(dir);
}
temporaryDirectories.Clear();
}
Expand Down
8 changes: 1 addition & 7 deletions tests/Stampeded.Core.Tests/GitInterdiffTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,7 @@ public void RemoveTemporaryDirectories()
{
foreach (var dir in temporaryDirectories)
{
try
{
Directory.Delete(dir, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(dir);
}
temporaryDirectories.Clear();
}
Expand Down
21 changes: 11 additions & 10 deletions tests/Stampeded.Core.Tests/GitMergeStateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,7 @@ public void RemoveTemporaryDirectories()
{
foreach (var dir in temporaryDirectories)
{
try
{
Directory.Delete(dir, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(dir);
}
temporaryDirectories.Clear();
}
Expand Down Expand Up @@ -160,10 +154,11 @@ public async Task RemovesTheWorktreeThatHoldsTheBranch()
await Git("branch", "already-in");
string worktree = NewDirectory();
await Git("worktree", "add", "--quiet", worktree, "already-in");
string worktreeAsGitReportsIt = await AsGitReports(worktree);

var deletion = await new GitService(repo).DeleteBranchAsync("already-in");

Assert.That(deletion.RemovedWorktree, Is.EqualTo(worktree));
Assert.That(deletion.RemovedWorktree, Is.EqualTo(worktreeAsGitReportsIt));
Assert.That(Directory.Exists(worktree), Is.False);
Assert.That(await Git("branch", "--format=%(refname:short)"), Does.Not.Contain("already-in"));
}
Expand Down Expand Up @@ -205,13 +200,14 @@ public async Task RemovesAWorktreeWithSubmodulesThatGitRefusesToTouch()
await Git("branch", "already-in");
string worktree = NewDirectory();
await Git("worktree", "add", "--quiet", worktree, "already-in");
string worktreeAsGitReportsIt = await AsGitReports(worktree);

var deletion = await new GitService(repo).DeleteBranchAsync("already-in");

Assert.That(deletion.RemovedWorktree, Is.EqualTo(worktree));
Assert.That(deletion.RemovedWorktree, Is.EqualTo(worktreeAsGitReportsIt));
Assert.That(Directory.Exists(worktree), Is.False);
Assert.That(await Git("branch", "--format=%(refname:short)"), Does.Not.Contain("already-in"));
Assert.That(await Git("worktree", "list", "--porcelain"), Does.Not.Contain(worktree),
Assert.That(await Git("worktree", "list", "--porcelain"), Does.Not.Contain(worktreeAsGitReportsIt),
"the administrative entry has to go with the directory");
}

Expand Down Expand Up @@ -273,4 +269,9 @@ async Task Commit(string fileName, string content)
}

Task<string> Git(params string[] args) => ExternalTool.RunAsync("git", args, repo);

/// <summary>The path in the form git prints it - forward slashes on Windows, symlinks
/// resolved on macOS - which is the form the service passes on unchanged.</summary>
static async Task<string> AsGitReports(string dir)
=> (await ExternalTool.RunAsync("git", ["rev-parse", "--show-toplevel"], dir)).Trim();
}
8 changes: 1 addition & 7 deletions tests/Stampeded.Core.Tests/GitPushTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@ public void RemoveTemporaryDirectories()
{
foreach (var dir in temporaryDirectories)
{
try
{
Directory.Delete(dir, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(dir);
}
temporaryDirectories.Clear();
}
Expand Down
18 changes: 9 additions & 9 deletions tests/Stampeded.Core.Tests/GitRebaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@ public void RemoveTemporaryDirectories()
{
foreach (var dir in temporaryDirectories)
{
try
{
Directory.Delete(dir, recursive: true);
}
catch (IOException)
{
}
TempDirectory.Delete(dir);
}
temporaryDirectories.Clear();
}
Expand All @@ -67,6 +61,7 @@ public async Task RebasesABranchThatIsCheckedOutInAWorktree()
{
string worktree = NewDirectory();
await Git(repo, "worktree", "add", "--quiet", worktree, "topic");
string worktreeAsGitReportsIt = await AsGitReports(worktree);

var git = new GitService(repo);
var result = await git.RebaseBranchAsync("topic", "main");
Expand All @@ -75,14 +70,14 @@ public async Task RebasesABranchThatIsCheckedOutInAWorktree()
"topic should now sit on top of main");
// The checkout that holds the branch has to move with it, or its index and working
// tree describe a commit the branch no longer points at.
Assert.That(result.Checkout, Is.EqualTo(worktree));
Assert.That(result.Checkout, Is.EqualTo(worktreeAsGitReportsIt));
Assert.That((await Git(worktree, "rev-parse", "HEAD")).Trim(), Is.EqualTo(await RevParse("topic")));
Assert.That((await Git(worktree, "status", "--porcelain")).Trim(), Is.Empty);
Assert.That(File.Exists(Path.Combine(worktree, "main.txt")), Is.True,
"the rebased checkout should have main's file");

// The recovery the UI offers has to work here, and git branch -f would be refused.
Assert.That(result.RecoveryCommand("topic"), Is.EqualTo($"git -C {worktree} reset --hard {result.Before[..9]}"));
Assert.That(result.RecoveryCommand("topic"), Is.EqualTo($"git -C {worktreeAsGitReportsIt} reset --hard {result.Before[..9]}"));
await Git(worktree, "reset", "--hard", result.Before);
Assert.That(await RevParse("topic"), Is.EqualTo(result.Before));
}
Expand Down Expand Up @@ -176,6 +171,11 @@ async Task Commit(string fileName, string content)

Task<string> Git(string dir, params string[] args) => ExternalTool.RunAsync("git", args, dir);

/// <summary>The path in the form git prints it - forward slashes on Windows, symlinks
/// resolved on macOS - which is the form the service passes on unchanged.</summary>
static async Task<string> AsGitReports(string dir)
=> (await ExternalTool.RunAsync("git", ["rev-parse", "--show-toplevel"], dir)).Trim();

async Task<string> RevParse(string reference) => (await Git(repo, "rev-parse", reference)).Trim();

async Task<string> MergeBase(string a, string b) => (await Git(repo, "merge-base", a, b)).Trim();
Expand Down
6 changes: 3 additions & 3 deletions tests/Stampeded.Core.Tests/ReReviewTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public void StoreCapturesSupersededStateOnHeadMove()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand Down Expand Up @@ -73,7 +73,7 @@ public void ThePreviousHeadOutlivesTheOpenThatDiscoveredTheMove()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}

Expand Down Expand Up @@ -101,7 +101,7 @@ public void StateWrittenBeforeTheBaselineExistedStillLoads()
}
finally
{
Directory.Delete(dir, recursive: true);
TempDirectory.Delete(dir);
}
}
}
Loading