default.nix

  1{
  2  pkgs ? import (import ./.npins).nixpkgs { },
  3  version ? builtins.null,
  4  debug ? false,
  5}:
  6let
  7  # releaseTargets is a list of platforms (in the nix double format) to platforms
  8  # in the `go tool dist list` format (that GOOS and GOOARCH expect). this is
  9  # used to generate a list of release targets, and to include/exclude tests
 10  # when building cross-platform and native binaries.
 11  releaseTargets = {
 12    aarch64-embedded = "linux/arm64";
 13    aarch64-multiplatform = "linux/arm64";
 14    aarch64-windows = "windows/arm64";
 15    riscv64 = "linux/riscv64";
 16    riscv64-embedded = "linux/riscv64";
 17    x86_64-linux = "linux/amd64";
 18    x86_64-windows = "windows/amd64";
 19    x86_64-darwin = "darwin/amd64";
 20    aarch64-darwin = "darwin/arm64";
 21  };
 22
 23  inherit (pkgs) lib;
 24
 25  buildTarget =
 26    {
 27      platform ? pkgs.stdenv.hostPlatform.system,
 28      version ? builtins.null,
 29      release ? false,
 30    }:
 31    let
 32      parts = lib.strings.splitString "/" releaseTargets."${platform}";
 33      suffix = lib.strings.concatStringsSep "-" parts;
 34      goos = builtins.elemAt parts 0;
 35      goarch = builtins.elemAt parts 1;
 36
 37      isNative = platform == pkgs.stdenv.hostPlatform.system;
 38    in
 39    # git-bug does not currently have any direct or transitive C dependencies.
 40    # as such, we do not need to use pkgsCross, which would introduce
 41    # additional overhead, but does properly handle setting up different
 42    # linkers and would be required if cgo is introduced.
 43    pkgs.buildGoModule {
 44      name = if isNative then "git-bug" else "git-bug-${suffix}";
 45
 46      src = lib.sources.cleanSourceWith {
 47        filter =
 48          name: type:
 49          let
 50            baseName = baseNameOf (toString name);
 51          in
 52          !(
 53            (
 54              type == "directory"
 55              && lib.any (n: n == baseName) [
 56                # keep-sorted start
 57                ".direnv"
 58                ".git"
 59                ".githooks.d"
 60                ".github"
 61                ".npins"
 62                "nix"
 63                "webui/node_modules"
 64                "webui/public"
 65                "webui/src"
 66                "webui/types"
 67                # keep-sorted end
 68              ]
 69            )
 70            || (lib.any (n: n == baseName) [
 71              # keep-sorted start
 72              ".codespellrc"
 73              ".editorconfig"
 74              ".envrc"
 75              ".envrc.local"
 76              ".git-blame-ignore-revs"
 77              ".gitignore"
 78              ".gitmessage"
 79              ".mailmap"
 80              ".pinact.yaml"
 81              "Makefile"
 82              "Maskfile.md"
 83              "cliff.toml"
 84              "default.nix"
 85              "git-bug" # the binary built when using the go compiler directly
 86              "shell-hook.bash"
 87              "shell.nix"
 88              # keep-sorted end
 89            ])
 90            # swap, backup, and temporary files
 91            || lib.strings.hasSuffix "~" baseName
 92            || lib.strings.match "^\\.sw[a-z]$" baseName != null
 93            || lib.strings.match "^\\..*\\.sw[a-z]$" baseName != null
 94            # nix-build result symlinks
 95            || (type == "symlink" && lib.strings.hasPrefix "result" baseName)
 96            # misc stuff (sockets and such that don't belong in the store)
 97            || (type == "unknown")
 98          );
 99        src = ./.;
100      };
101
102      vendorHash = "sha256-F5E7Xu6t3f4rDaA8izqzR6ha8EHSdiQSHdj/LlVBAj0=";
103
104      excludedPackages = [
105        # keep-sorted start
106        "doc"
107        "misc"
108        "tests"
109        # keep-sorted end
110      ];
111
112      ldflags =
113        lib.optionals (!debug || release) [
114          # keep-sorted start
115          "-s" # omit the symbol table
116          "-w" # omit DWARF debug info
117          # keep-sorted end
118        ]
119        ++ lib.optionals (version != builtins.null) [ "-X main.version=${version}" ];
120
121      # normally, pack the web ui for builds, but for debug builds, fetch it
122      # from the filesystem (this is what this build tag controls)
123      tags = lib.optionals (debug && !release) [ "debug" ];
124
125      flags = lib.optionals (debug && !release) [
126        # enable debugger-friendly compiler options for non-release builds
127        "-gcflags=all='-N -l'"
128      ];
129
130      env = {
131        CGO_ENABLED = 0; # disable cgo to enable static builds
132      };
133
134      preBuild = lib.strings.concatLines (
135        lib.optionals (!debug) [
136          # TODO: embed //webui
137        ]
138        ++ [
139          # keep-sorted start
140          "export GOARCH=${goarch}"
141          "export GOOS=${goos}"
142          # keep-sorted end
143        ]
144      );
145
146      postInstall =
147        let
148          extension = lib.optionalString (goos == "windows") ".exe";
149        in
150        lib.optionalString release ''
151          if test -d $out/bin/${goos}_${goarch}; then
152            mv \
153              $out/bin/${goos}_${goarch}/git-bug* \
154              $out/bin/git-bug-${suffix}${extension}
155            rmdir $out/bin/${goos}_${goarch}
156          fi
157
158          # the host-native binary when built on linux or macos
159          if test -x $out/bin/git-bug; then
160            mv $out/bin/git-bug $out/bin/git-bug-${suffix}
161          fi
162        '';
163
164      nativeCheckInputs = with pkgs; [ gitMinimal ];
165
166      doCheck = isNative && !debug;
167
168      # skip tests that require the network
169      checkFlags =
170        let
171          e2eTests = [
172            "TestValidateUsername/existing_organisation"
173            "TestValidateUsername/existing_organisation_with_bad_case"
174            "TestValidateUsername/existing_username"
175            "TestValidateUsername/existing_username_with_bad_case"
176            "TestValidateUsername/non_existing_username"
177            "TestValidateProject/public_project"
178          ];
179        in
180        [ "-skip=^${lib.concatStringsSep "$|^" e2eTests}$" ];
181
182      meta = {
183        description = "Distributed bug tracker embedded in Git";
184        homepage = "https://github.com/git-bug/git-bug";
185        license = lib.licenses.gpl3Plus;
186      };
187    };
188in
189{
190  # build target for the current system
191  default = buildTarget { inherit version; };
192
193  # this drv builds release binaries for every platform. the output directory
194  # contains all of the binaries uniquely named with their platform, suitable
195  # for uploading as release artifacts.
196  release = pkgs.symlinkJoin {
197    name = "git-bug-release-binaries";
198    paths = map (
199      platform:
200      buildTarget {
201        inherit platform version;
202        release = true;
203      }
204    ) (builtins.attrNames releaseTargets);
205  };
206}