diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 1789576a8..ab103d6df 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -77,9 +77,18 @@ jobs: needs: [setup] env: GHOSTTY_VERSION: ${{ needs.setup.outputs.version }} + ZIG_LOCAL_CACHE_DIR: /zig/local-cache + ZIG_GLOBAL_CACHE_DIR: /zig/global-cache steps: - uses: actions/checkout@v4 + - name: Setup Cache + uses: namespacelabs/nscloud-cache-action@v1.2.0 + with: + path: | + /nix + /zig + - uses: cachix/install-nix-action@v30 with: nix_path: nixpkgs=channel:nixos-unstable @@ -91,8 +100,8 @@ jobs: - name: Create Tarball run: | - git archive --format=tgz --prefix="ghostty-${GHOSTTY_VERSION}/" -o "ghostty-${GHOSTTY_VERSION}.tar.gz" HEAD - git archive --format=tgz --prefix=ghostty-source/ -o ghostty-source.tar.gz HEAD + nix develop -c zig build distcheck + cp zig-out/dist/ghostty-${GHOSTTY_VERSION}.tar.gz . - name: Sign Tarball run: | @@ -108,8 +117,6 @@ jobs: path: |- ghostty-${{ env.GHOSTTY_VERSION }}.tar.gz ghostty-${{ env.GHOSTTY_VERSION }}.tar.gz.minisig - ghostty-source.tar.gz - ghostty-source.tar.gz.minisig build-macos: needs: [setup] diff --git a/.github/workflows/release-tip.yml b/.github/workflows/release-tip.yml index a031f3ad1..d23787743 100644 --- a/.github/workflows/release-tip.yml +++ b/.github/workflows/release-tip.yml @@ -101,8 +101,17 @@ jobs: ) }} runs-on: namespace-profile-ghostty-md + env: + ZIG_LOCAL_CACHE_DIR: /zig/local-cache + ZIG_GLOBAL_CACHE_DIR: /zig/global-cache steps: - uses: actions/checkout@v4 + - name: Setup Cache + uses: namespacelabs/nscloud-cache-action@v1.2.0 + with: + path: | + /nix + /zig - uses: cachix/install-nix-action@v30 with: nix_path: nixpkgs=channel:nixos-unstable @@ -111,12 +120,17 @@ jobs: name: ghostty authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - name: Create Tarball - run: git archive --format=tgz --prefix=ghostty-source/ -o ghostty-source.tar.gz HEAD + run: | + rm -rf zig-out/dist + nix develop -c zig build distcheck + cp zig-out/dist/*.tar.gz ghostty-source.tar.gz + - name: Sign Tarball run: | echo -n "${{ secrets.MINISIGN_KEY }}" > minisign.key echo -n "${{ secrets.MINISIGN_PASSWORD }}" > minisign.password nix develop -c minisign -S -m ghostty-source.tar.gz -s minisign.key < minisign.password + - name: Update Release uses: softprops/action-gh-release@v2 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 037c7bb15..f0bcf4fff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,7 @@ jobs: runs-on: namespace-profile-ghostty-sm needs: - build-bench + - build-dist - build-flatpak - build-linux - build-linux-libghostty @@ -209,6 +210,35 @@ jobs: - name: Test NixOS package build run: nix build .#ghostty + build-dist: + runs-on: namespace-profile-ghostty-md + needs: test + env: + ZIG_LOCAL_CACHE_DIR: /zig/local-cache + ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Cache + uses: namespacelabs/nscloud-cache-action@v1.2.0 + with: + path: | + /nix + /zig + + # Install Nix and use that to run our tests so our environment matches exactly. + - uses: cachix/install-nix-action@v30 + with: + nix_path: nixpkgs=channel:nixos-unstable + - uses: cachix/cachix-action@v15 + with: + name: ghostty + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: Build and Check Source Tarball + run: nix develop -c zig build distcheck + build-macos: runs-on: namespace-profile-ghostty-macos needs: test diff --git a/build.zig b/build.zig index 280f15de9..0751bab51 100644 --- a/build.zig +++ b/build.zig @@ -15,25 +15,31 @@ pub fn build(b: *std.Build) !void { // Ghostty dependencies used by many artifacts. const deps = try buildpkg.SharedDeps.init(b, &config); - const exe = try buildpkg.GhosttyExe.init(b, &config, &deps); if (config.emit_helpgen) deps.help_strings.install(); + // Ghostty executable, the actual runnable Ghostty program. + const exe = try buildpkg.GhosttyExe.init(b, &config, &deps); + // Ghostty docs - if (config.emit_docs) { - const docs = try buildpkg.GhosttyDocs.init(b, &deps); - docs.install(); - } + const docs = try buildpkg.GhosttyDocs.init(b, &deps); + if (config.emit_docs) docs.install(); // Ghostty webdata - if (config.emit_webdata) { - const webdata = try buildpkg.GhosttyWebdata.init(b, &deps); - webdata.install(); - } + const webdata = try buildpkg.GhosttyWebdata.init(b, &deps); + if (config.emit_webdata) webdata.install(); // Ghostty bench tools - if (config.emit_bench) { - const bench = try buildpkg.GhosttyBench.init(b, &deps); - bench.install(); + const bench = try buildpkg.GhosttyBench.init(b, &deps); + if (config.emit_bench) bench.install(); + + // Ghostty dist tarball + const dist = try buildpkg.GhosttyDist.init(b, &config); + { + const step = b.step("dist", "Build the dist tarball"); + step.dependOn(dist.install_step); + const check_step = b.step("distcheck", "Install and validate the dist tarball"); + check_step.dependOn(dist.check_step); + check_step.dependOn(dist.install_step); } // If we're not building libghostty, then install the exe and resources. diff --git a/src/build/GhosttyDist.zig b/src/build/GhosttyDist.zig new file mode 100644 index 000000000..3218482a3 --- /dev/null +++ b/src/build/GhosttyDist.zig @@ -0,0 +1,87 @@ +const GhosttyDist = @This(); + +const std = @import("std"); +const Config = @import("Config.zig"); +const SharedDeps = @import("SharedDeps.zig"); + +/// The final source tarball. +archive: std.Build.LazyPath, + +/// The step to install the tarball. +install_step: *std.Build.Step, + +/// The step to depend on +archive_step: *std.Build.Step, + +/// The step to depend on for checking the dist +check_step: *std.Build.Step, + +pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist { + // git archive to create the final tarball. "git archive" is the + // easiest way I can find to create a tarball that ignores stuff + // from gitignore and also supports adding files as well as removing + // dist-only files (the "export-ignore" git attribute). + const git_archive = b.addSystemCommand(&.{ + "git", + "archive", + "--format=tgz", + + // This is important. Standard source tarballs extract into + // a directory named `project-version`. This is expected by + // standard tooling such as debhelper and rpmbuild. + b.fmt("--prefix=ghostty-{}/", .{cfg.version}), + + "-o", + }); + const output = git_archive.addOutputFileArg(b.fmt( + "ghostty-{}.tar.gz", + .{cfg.version}, + )); + git_archive.addArg("HEAD"); + + // The install step to put the dist into the build directory. + const install = b.addInstallFile( + output, + b.fmt("dist/ghostty-{}.tar.gz", .{cfg.version}), + ); + + // The check step to ensure the archive works. + const check = b.addSystemCommand(&.{ "tar", "xvzf" }); + check.addFileArg(output); + check.addArg("-C"); + + // This is the root Ghostty source dir of the extracted source tarball. + // i.e. this is way `build.zig` is. + const extract_dir = check + .addOutputDirectoryArg("ghostty") + .path(b, b.fmt("ghostty-{}", .{cfg.version})); + + // Check that tests pass within the extracted directory. This isn't + // a fully hermetic test because we're sharing the Zig cache. In + // the future we could add an option to use a totally new cache but + // in the interest of speed we don't do that for now and hope other + // CI catches any issues. + const check_test = step: { + const step = b.addSystemCommand(&.{ "zig", "build", "test" }); + step.setCwd(extract_dir); + + // Must be set so that Zig knows that this command doesn't + // have side effects and is being run for its exit code check. + // Zig will cache depending on its extract dir. + step.expectExitCode(0); + + // Capture stderr so it doesn't spew into the parent build. + // On the flip side, if the test fails we won't know why so + // that sucks but we should have already ran tests at this point. + _ = step.captureStdErr(); + + break :step step; + }; + + return .{ + .archive = output, + .install_step = &install.step, + .archive_step = &git_archive.step, + .check_step = &check_test.step, + }; +} diff --git a/src/build/main.zig b/src/build/main.zig index b5ff75b59..3154d395f 100644 --- a/src/build/main.zig +++ b/src/build/main.zig @@ -8,6 +8,7 @@ pub const GitVersion = @import("GitVersion.zig"); // Artifacts pub const GhosttyBench = @import("GhosttyBench.zig"); +pub const GhosttyDist = @import("GhosttyDist.zig"); pub const GhosttyDocs = @import("GhosttyDocs.zig"); pub const GhosttyExe = @import("GhosttyExe.zig"); pub const GhosttyFrameData = @import("GhosttyFrameData.zig");