summary refs log tree commit diff
path: root/pkgs/development/tools/continuous-integration
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/development/tools/continuous-integration')
-rw-r--r--pkgs/development/tools/continuous-integration/buildkite-agent/default.nix30
-rw-r--r--pkgs/development/tools/continuous-integration/buildkite-agent/generic.nix10
-rw-r--r--pkgs/development/tools/continuous-integration/buildkite-cli/default.nix6
-rw-r--r--pkgs/development/tools/continuous-integration/drone-cli/default.nix15
-rw-r--r--pkgs/development/tools/continuous-integration/drone-runner-docker/default.nix22
-rw-r--r--pkgs/development/tools/continuous-integration/drone-runner-exec/default.nix26
-rw-r--r--pkgs/development/tools/continuous-integration/drone/default.nix19
-rw-r--r--pkgs/development/tools/continuous-integration/fly/default.nix8
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/default.nix274
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/deps.nix1217
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/patches/dir-proj.patch53
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/patches/dont-install-systemd-service.patch15
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/patches/host-context-dirs.patch20
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/patches/ignore-self-update.patch24
-rw-r--r--pkgs/development/tools/continuous-integration/github-runner/patches/use-get-directory-for-diag.patch25
-rw-r--r--pkgs/development/tools/continuous-integration/gitlab-runner/default.nix12
-rw-r--r--pkgs/development/tools/continuous-integration/gocd-agent/default.nix6
-rw-r--r--pkgs/development/tools/continuous-integration/gocd-server/default.nix6
-rw-r--r--pkgs/development/tools/continuous-integration/hci/default.nix23
-rw-r--r--pkgs/development/tools/continuous-integration/hercules-ci-agent/default.nix20
-rw-r--r--pkgs/development/tools/continuous-integration/jenkins/default.nix62
-rwxr-xr-xpkgs/development/tools/continuous-integration/jenkins/update.sh22
-rw-r--r--pkgs/development/tools/continuous-integration/laminar/default.nix65
-rw-r--r--pkgs/development/tools/continuous-integration/laminar/patches/no-network.patch41
24 files changed, 1936 insertions, 85 deletions
diff --git a/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix b/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix
index ceaa704b565..b32eed9a166 100644
--- a/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix
+++ b/pkgs/development/tools/continuous-integration/buildkite-agent/default.nix
@@ -1,26 +1,26 @@
-{ fetchFromGitHub, stdenv, buildGoPackage,
-  makeWrapper, coreutils, git, openssh, bash, gnused, gnugrep }:
-buildGoPackage rec {
+{ fetchFromGitHub, lib, buildGoModule,
+  makeWrapper, coreutils, git, openssh, bash, gnused, gnugrep,
+  nixosTests }:
+buildGoModule rec {
   name = "buildkite-agent-${version}";
-  version = "3.17.0";
-
-  goPackagePath = "github.com/buildkite/agent";
+  version = "3.31.0";
 
   src = fetchFromGitHub {
     owner = "buildkite";
     repo = "agent";
     rev = "v${version}";
-    sha256 = "0a7x919kxnpdn0pnhc5ilx1z6ninx8zgjvsd0jcg4qwh0qqp5ppr";
+    sha256 = "sha256-Rot5A2zSEleTifadHEvAlydchzCdDo/VPZELostDfng=";
   };
+
+  vendorSha256 = "sha256-n3XRxpEKjHf7L7fcGscWTVKBtot9waZbLoS9cG0kHfI=";
+
   postPatch = ''
     substituteInPlace bootstrap/shell/shell.go --replace /bin/bash ${bash}/bin/bash
   '';
 
   nativeBuildInputs = [ makeWrapper ];
 
-  # on Linux, the TMPDIR is /build which is the same prefix as this package
-  # remove once #35068 is merged
-  noAuditTmpdir = stdenv.isLinux;
+  doCheck = false;
 
   postInstall = ''
     # Fix binary name
@@ -28,10 +28,14 @@ buildGoPackage rec {
 
     # These are runtime dependencies
     wrapProgram $out/bin/buildkite-agent \
-      --prefix PATH : '${stdenv.lib.makeBinPath [ openssh git coreutils gnused gnugrep ]}'
+      --prefix PATH : '${lib.makeBinPath [ openssh git coreutils gnused gnugrep ]}'
   '';
 
-  meta = with stdenv.lib; {
+  passthru.tests = {
+    smoke-test = nixosTests.buildkite-agents;
+  };
+
+  meta = with lib; {
     description = "Build runner for buildkite.com";
     longDescription = ''
       The buildkite-agent is a small, reliable, and cross-platform build runner
@@ -43,6 +47,6 @@ buildGoPackage rec {
     homepage = "https://buildkite.com/docs/agent";
     license = licenses.mit;
     maintainers = with maintainers; [ pawelpacana zimbatm rvl ];
-    platforms = platforms.unix;
+    platforms = with platforms; unix ++ darwin;
   };
 }
diff --git a/pkgs/development/tools/continuous-integration/buildkite-agent/generic.nix b/pkgs/development/tools/continuous-integration/buildkite-agent/generic.nix
index 39178201456..3b9de427bde 100644
--- a/pkgs/development/tools/continuous-integration/buildkite-agent/generic.nix
+++ b/pkgs/development/tools/continuous-integration/buildkite-agent/generic.nix
@@ -1,4 +1,4 @@
-{ stdenv, buildGoPackage, makeWrapper, coreutils, git, openssh, bash, gnused, gnugrep
+{ lib, buildGoPackage, makeWrapper, coreutils, git, openssh, bash, gnused, gnugrep
 , src, version, hasBootstrapScript, postPatch ? ""
 , ... }:
 let
@@ -13,7 +13,7 @@ buildGoPackage {
   nativeBuildInputs = [ makeWrapper ];
 
   postInstall = ''
-    ${stdenv.lib.optionalString hasBootstrapScript ''
+    ${lib.optionalString hasBootstrapScript ''
     # Install bootstrap.sh
     mkdir -p $out/libexec/buildkite-agent
     cp $NIX_BUILD_TOP/go/src/${goPackagePath}/templates/bootstrap.sh $out/libexec/buildkite-agent
@@ -25,11 +25,11 @@ buildGoPackage {
 
     # These are runtime dependencies
     wrapProgram $out/bin/buildkite-agent \
-      ${stdenv.lib.optionalString hasBootstrapScript "--set BUILDKITE_BOOTSTRAP_SCRIPT_PATH $out/libexec/buildkite-agent/bootstrap.sh"} \
-      --prefix PATH : '${stdenv.lib.makeBinPath [ openssh git coreutils gnused gnugrep ]}'
+      ${lib.optionalString hasBootstrapScript "--set BUILDKITE_BOOTSTRAP_SCRIPT_PATH $out/libexec/buildkite-agent/bootstrap.sh"} \
+      --prefix PATH : '${lib.makeBinPath [ openssh git coreutils gnused gnugrep ]}'
   '';
 
-  meta = with stdenv.lib; {
+  meta = with lib; {
     description = "Build runner for buildkite.com";
     longDescription = ''
       The buildkite-agent is a small, reliable, and cross-platform build runner
diff --git a/pkgs/development/tools/continuous-integration/buildkite-cli/default.nix b/pkgs/development/tools/continuous-integration/buildkite-cli/default.nix
index aee2a4e2341..73aefdd0cda 100644
--- a/pkgs/development/tools/continuous-integration/buildkite-cli/default.nix
+++ b/pkgs/development/tools/continuous-integration/buildkite-cli/default.nix
@@ -2,16 +2,16 @@
 
 buildGoModule rec {
   pname = "buildkite-cli";
-  version = "1.1.0";
+  version = "1.2.0";
 
   src = fetchFromGitHub {
     owner = "buildkite";
     repo = "cli";
     rev = "v${version}";
-    sha256 = "05hz59qzadkk4ji5icv5sxih31pnn0abnmiwcyfa2mr3l5jaqjnd";
+    sha256 = "sha256-AIa+hEYtPJ4CFvAFSpNJFxY+B3+DJH1Q0hL/3BD/yN0=";
   };
 
-  vendorSha256 = "0jxh3yhh0sdvaykhinxngpipk369hw8z1y3g2z4c1115m5rjp2bb";
+  vendorSha256 = "sha256-4AH9PZWSrBXi9w4Mr7dpXqDkQZGzuELG876YCaFTj2Q=";
 
   doCheck = false;
 
diff --git a/pkgs/development/tools/continuous-integration/drone-cli/default.nix b/pkgs/development/tools/continuous-integration/drone-cli/default.nix
index 3df406eb560..4534298d395 100644
--- a/pkgs/development/tools/continuous-integration/drone-cli/default.nix
+++ b/pkgs/development/tools/continuous-integration/drone-cli/default.nix
@@ -1,12 +1,11 @@
-{ stdenv, fetchFromGitHub, buildGoModule }:
+{ lib, fetchFromGitHub, buildGoModule }:
 
-let version = "1.2.2";
-in buildGoModule rec {
-  inherit version;
+buildGoModule rec {
+  version = "1.3.0";
   pname = "drone-cli";
   revision = "v${version}";
 
-  vendorSha256 = "1ryh94cj37j8x6qwxr5ydyw6cnjppakg1w84sipm11d0vvv98bhi";
+  vendorSha256 = "sha256-I+UBa6gqkPRXNV72iyJcCBLYShZxMtHFHSK77mhDv+U=";
 
   doCheck = false;
 
@@ -18,12 +17,12 @@ in buildGoModule rec {
     owner = "drone";
     repo = "drone-cli";
     rev = revision;
-    sha256 = "082yqm72y8s3v06gkcg947p62sd63y3r2bmdsrfgdrzb5w5a75bl";
+    sha256 = "sha256-j6drDMxvAVfQ1aCFooc9g9HhMRMlFZXGZPiuJZKBbY4=";
   };
 
-  meta = with stdenv.lib; {
+  meta = with lib; {
     maintainers = with maintainers; [ bricewge ];
     license = licenses.asl20;
-    description = "Command line client for the Drone continuous integration server.";
+    description = "Command line client for the Drone continuous integration server";
   };
 }
diff --git a/pkgs/development/tools/continuous-integration/drone-runner-docker/default.nix b/pkgs/development/tools/continuous-integration/drone-runner-docker/default.nix
new file mode 100644
index 00000000000..a2e7b739718
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/drone-runner-docker/default.nix
@@ -0,0 +1,22 @@
+{ lib, fetchFromGitHub, buildGoModule }:
+
+buildGoModule rec {
+  pname = "drone-runner-docker";
+  version = "1.6.3";
+
+  src = fetchFromGitHub {
+    owner = "drone-runners";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "sha256-WI3pr0t6EevIBOQwCAI+CY2O8Q7+W/CLDT/5Y0+tduQ=";
+  };
+
+  vendorSha256 = "15lpdliqz129yq5zgzjvndwdxngxa96g0ska4zkny7ycb3vwq0xm";
+
+  meta = with lib; {
+    maintainers = with maintainers; [ endocrimes ];
+    license = licenses.unfreeRedistributable;
+    homepage = "https://github.com/drone-runners/drone-runner-docker";
+    description = "Drone pipeline runner that executes builds inside Docker containers";
+  };
+}
diff --git a/pkgs/development/tools/continuous-integration/drone-runner-exec/default.nix b/pkgs/development/tools/continuous-integration/drone-runner-exec/default.nix
new file mode 100644
index 00000000000..373c6183725
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/drone-runner-exec/default.nix
@@ -0,0 +1,26 @@
+{ lib
+, buildGoModule
+, fetchFromGitHub
+}:
+
+buildGoModule rec {
+  pname = "drone-runner-exec";
+  version = "unstable-2020-04-19";
+
+  src = fetchFromGitHub {
+    owner = "drone-runners";
+    repo = "drone-runner-exec";
+    rev = "c0a612ef2bdfdc6d261dfbbbb005c887a0c3668d";
+    sha256 = "sha256-0UIJwpC5Y2TQqyZf6C6neICYBZdLQBWAZ8/K1l6KVRs=";
+  };
+
+  vendorSha256 = "sha256-ypYuQKxRhRQGX1HtaWt6F6BD9vBpD8AJwx/4esLrJsw=";
+
+  meta = with lib; {
+    description = "Drone pipeline runner that executes builds directly on the host machine";
+    homepage = "https://github.com/drone-runners/drone-runner-exec";
+    # https://polyformproject.org/licenses/small-business/1.0.0/
+    license = licenses.unfree;
+    maintainers = with maintainers; [ mic92 ];
+  };
+}
diff --git a/pkgs/development/tools/continuous-integration/drone/default.nix b/pkgs/development/tools/continuous-integration/drone/default.nix
index 307dda4f993..46ee41d37df 100644
--- a/pkgs/development/tools/continuous-integration/drone/default.nix
+++ b/pkgs/development/tools/continuous-integration/drone/default.nix
@@ -1,10 +1,11 @@
-{ stdenv, fetchFromGitHub, buildGoModule }:
+{ lib, fetchFromGitHub, buildGoModule
+, enableUnfree ? true }:
 
 buildGoModule rec {
-  name = "drone.io-${version}";
-  version = "1.9.0";
+  pname = "drone.io${lib.optionalString (!enableUnfree) "-oss"}";
+  version = "2.0.3";
 
-  vendorSha256 = "0idf11sr417lxcjryplgb87affr6lgzxazzlyvk0y40hp8zbhwsx";
+  vendorSha256 = "sha256-3qTH/p0l6Ke1F9SUcvK2diqZooOMnlXYO1PHLdJJ8PM=";
 
   doCheck = false;
 
@@ -12,12 +13,16 @@ buildGoModule rec {
     owner = "drone";
     repo = "drone";
     rev = "v${version}";
-    sha256 = "1lsyd245fr1f74rpccvvw41h5g75b79afrb8g589bj13ggjav0xy";
+    sha256 = "sha256-MKV5kor+Wm9cuIFFcjSNyCgVKtY+/B9sgBOXMMRvMPI=";
   };
 
-  meta = with stdenv.lib; {
+  preBuild = ''
+    buildFlagsArray+=( "-tags" "${lib.optionalString (!enableUnfree) "oss nolimit"}" )
+  '';
+
+  meta = with lib; {
     maintainers = with maintainers; [ elohmeier vdemeester ];
-    license = licenses.asl20;
+    license = with licenses; if enableUnfree then unfreeRedistributable else asl20;
     description = "Continuous Integration platform built on container technology";
   };
 }
diff --git a/pkgs/development/tools/continuous-integration/fly/default.nix b/pkgs/development/tools/continuous-integration/fly/default.nix
index 34d30e08c50..22b7752c593 100644
--- a/pkgs/development/tools/continuous-integration/fly/default.nix
+++ b/pkgs/development/tools/continuous-integration/fly/default.nix
@@ -1,17 +1,17 @@
-{ buildGoModule, fetchFromGitHub, stdenv, lib, writeText }:
+{ buildGoModule, fetchFromGitHub, stdenv, lib }:
 
 buildGoModule rec {
   pname = "fly";
-  version = "6.5.0";
+  version = "7.3.2";
 
   src = fetchFromGitHub {
     owner = "concourse";
     repo = "concourse";
     rev = "v${version}";
-    sha256 = "0x8q1l56h24mmq01j3hib2qg0g44z82mxhmmljy8yv5s2iir0sfh";
+    sha256 = "sha256-ID/vqkFzKHLeuojHUxUFYURn+Dxb78XwxfJVV+S130A=";
   };
 
-  vendorSha256 = "1fxbxkg7disndlmb065abnfn7sn79qclkcbizmrq49f064w1ijr4";
+  vendorSha256 = "sha256-30rrRkPIH0sr8koKRLs1Twe6Z55+lr9gkgUDrY+WOTw=";
 
   doCheck = false;
 
diff --git a/pkgs/development/tools/continuous-integration/github-runner/default.nix b/pkgs/development/tools/continuous-integration/github-runner/default.nix
new file mode 100644
index 00000000000..e2d40630905
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/default.nix
@@ -0,0 +1,274 @@
+{ autoPatchelfHook
+, coreutils
+, curl
+, dotnetCorePackages
+, dotnetPackages
+, fetchFromGitHub
+, fetchurl
+, git
+, glibc
+, icu
+, libkrb5
+, lib
+, linkFarm
+, lttng-ust
+, makeWrapper
+, nodejs-12_x
+, openssl
+, stdenv
+, zlib
+}:
+let
+  pname = "github-actions-runner";
+  version = "2.279.0";
+
+  deps = (import ./deps.nix { inherit fetchurl; });
+  nugetPackages = map
+    (x: {
+      name = "${x.name}.nupkg";
+      path = "${x}";
+    })
+    deps;
+  nugetSource = linkFarm "${pname}-${version}-packages" nugetPackages;
+
+  dotnetSdk = dotnetCorePackages.sdk_3_1;
+  runtimeId = "linux-x64";
+
+  disabledTest = [
+    # Self-updating is patched out, hence this test will fail
+    "FullyQualifiedName!=GitHub.Runner.Common.Tests.Listener.RunnerL0.TestRunOnceHandleUpdateMessage"
+  ] ++ map
+    # Online tests
+    (x: "FullyQualifiedName!=GitHub.Runner.Common.Tests.Worker.ActionManagerL0.PrepareActions_${x}")
+    [
+      "CompositeActionWithActionfile_CompositeContainerNested"
+      "CompositeActionWithActionfile_CompositePrestepNested"
+      "CompositeActionWithActionfile_MaxLimit"
+      "CompositeActionWithActionfile_Node"
+      "DownloadActionFromGraph"
+      "DownloadActionFromGraph_Legacy"
+      "NotPullOrBuildImagesMultipleTimes"
+      "NotPullOrBuildImagesMultipleTimes_Legacy"
+      "RepositoryActionWithActionYamlFile_DockerHubImage"
+      "RepositoryActionWithActionYamlFile_DockerHubImage_Legacy"
+      "RepositoryActionWithActionfileAndDockerfile"
+      "RepositoryActionWithActionfileAndDockerfile_Legacy"
+      "RepositoryActionWithActionfile_DockerHubImage"
+      "RepositoryActionWithActionfile_DockerHubImage_Legacy"
+      "RepositoryActionWithActionfile_Dockerfile"
+      "RepositoryActionWithActionfile_Dockerfile_Legacy"
+      "RepositoryActionWithActionfile_DockerfileRelativePath"
+      "RepositoryActionWithActionfile_DockerfileRelativePath_Legacy"
+      "RepositoryActionWithActionfile_Node"
+      "RepositoryActionWithActionfile_Node_Legacy"
+      "RepositoryActionWithDockerfile"
+      "RepositoryActionWithDockerfile_Legacy"
+      "RepositoryActionWithDockerfileInRelativePath"
+      "RepositoryActionWithDockerfileInRelativePath_Legacy"
+      "RepositoryActionWithDockerfilePrepareActions_Repository"
+      "RepositoryActionWithInvalidWrapperActionfile_Node"
+      "RepositoryActionWithInvalidWrapperActionfile_Node_Legacy"
+      "RepositoryActionWithWrapperActionfile_PreSteps"
+      "RepositoryActionWithWrapperActionfile_PreSteps_Legacy"
+    ] ++ map
+    (x: "FullyQualifiedName!=GitHub.Runner.Common.Tests.DotnetsdkDownloadScriptL0.${x}")
+    [
+      "EnsureDotnetsdkBashDownloadScriptUpToDate"
+      "EnsureDotnetsdkPowershellDownloadScriptUpToDate"
+    ];
+  testFilterXml = lib.concatStringsSep "&" disabledTest;
+in
+stdenv.mkDerivation rec {
+  inherit pname version;
+
+  src = fetchFromGitHub {
+    owner = "actions";
+    repo = "runner";
+    rev = "6b75179ec79e2041b3b5b4e9206b73db2d206aac"; # v${version}
+    sha256 = "sha256-d7LAHL8Ff7R++d1HuLxWjtiBZRogySe7xHY/xJAcFms=";
+  };
+
+  nativeBuildInputs = [
+    dotnetSdk
+    dotnetPackages.Nuget
+    makeWrapper
+    autoPatchelfHook
+  ];
+
+  buildInputs = [
+    curl # libcurl.so.4
+    libkrb5 # libgssapi_krb5.so.2
+    lttng-ust # liblttng-ust.so.0
+    stdenv.cc.cc.lib # libstdc++.so.6
+    zlib # libz.so.1
+    icu
+  ];
+
+  patches = [
+    # Don't run Git, no restore on build/test
+    ./patches/dir-proj.patch
+    # Replace some paths that originally point to Nix's read-only store
+    ./patches/host-context-dirs.patch
+    # Use GetDirectory() to obtain "diag" dir
+    ./patches/use-get-directory-for-diag.patch
+    # Don't try to install systemd service
+    ./patches/dont-install-systemd-service.patch
+    # Don't try to self-update runner (cannot be disabled, see https://github.com/actions/runner/issues/485)
+    ./patches/ignore-self-update.patch
+  ];
+
+  postPatch = ''
+    # Relax the version requirement
+    substituteInPlace src/global.json \
+      --replace '3.1.302' '${dotnetSdk.version}'
+
+    # Disable specific tests
+    substituteInPlace src/dir.proj \
+      --replace 'dotnet test Test/Test.csproj' \
+                "dotnet test Test/Test.csproj --filter '${testFilterXml}'"
+
+    # We don't use a Git checkout
+    substituteInPlace src/dir.proj \
+      --replace 'git update-index --assume-unchanged ./Runner.Sdk/BuildConstants.cs' \
+                'echo Patched out.'
+
+    # Fix FHS path
+    substituteInPlace src/Test/L0/Util/IOUtilL0.cs \
+      --replace '/bin/ln' '${coreutils}/bin/ln'
+  '';
+
+  configurePhase = ''
+    runHook preConfigure
+
+    # Set up Nuget dependencies
+    export HOME=$(mktemp -d)
+    export DOTNET_CLI_TELEMETRY_OPTOUT=1
+    export DOTNET_NOLOGO=1
+
+    # Never use nuget.org
+    nuget sources Disable -Name "nuget.org"
+
+    # Restore the dependencies
+    dotnet restore src/ActionsRunner.sln \
+      --runtime "${runtimeId}" \
+      --source "${nugetSource}"
+
+    runHook postConfigure
+  '';
+
+  postConfigure = ''
+    # `crossgen` dependency is called during build
+    patchelf \
+      --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
+      --set-rpath "${lib.makeLibraryPath [ stdenv.cc.cc.lib ]}" \
+      $HOME/.nuget/packages/microsoft.netcore.app.runtime.${runtimeId}/*/tools/crossgen
+  '';
+
+  buildPhase = ''
+    runHook preBuild
+
+    dotnet msbuild \
+      -t:Build \
+      -p:PackageRuntime="${runtimeId}" \
+      -p:BUILDCONFIG="Release" \
+      -p:RunnerVersion="${version}" \
+      -p:GitInfoCommitHash="${src.rev}" \
+      src/dir.proj
+
+    runHook postBuild
+  '';
+
+  doCheck = true;
+
+  checkInputs = [ git ];
+
+  checkPhase = ''
+    runHook preCheck
+
+    mkdir -p _layout/externals
+    ln -s ${nodejs-12_x} _layout/externals/node12
+
+    # BUILDCONFIG needs to be "Debug"
+    dotnet msbuild \
+      -t:test \
+      -p:PackageRuntime="${runtimeId}" \
+      -p:BUILDCONFIG="Debug" \
+      -p:RunnerVersion="${version}" \
+      -p:GitInfoCommitHash="${src.rev}" \
+      src/dir.proj
+
+    runHook postCheck
+  '';
+
+  installPhase = ''
+    runHook preInstall
+
+    # Copy the built binaries to lib/ instead of bin/ as they
+    # have to be wrapped in the fixup phase to work
+    mkdir -p $out/lib
+    cp -r _layout/bin/. $out/lib/
+
+    # Delete debugging files
+    find "$out/lib" -type f -name '*.pdb' -delete
+
+    # Install the helper scripts to bin/ to resemble the upstream package
+    mkdir -p $out/bin
+    install -m755 src/Misc/layoutbin/runsvc.sh        $out/bin/
+    install -m755 src/Misc/layoutbin/RunnerService.js $out/lib/
+    install -m755 src/Misc/layoutroot/run.sh          $out/lib/
+    install -m755 src/Misc/layoutroot/config.sh       $out/lib/
+    install -m755 src/Misc/layoutroot/env.sh          $out/lib/
+
+    # Rewrite reference in helper scripts from bin/ to lib/
+    substituteInPlace $out/lib/run.sh    --replace '"$DIR"/bin' "$out/lib"
+    substituteInPlace $out/lib/config.sh --replace './bin' "$out/lib"
+
+    # Make paths absolute
+    substituteInPlace $out/bin/runsvc.sh \
+      --replace './externals' "$out/externals" \
+      --replace './bin' "$out/lib"
+
+    # The upstream package includes Node 12 and expects it at the path
+    # externals/node12. As opposed to the official releases, we don't
+    # link the Alpine Node flavor.
+    mkdir -p $out/externals
+    ln -s ${nodejs-12_x} $out/externals/node12
+
+    runHook postInstall
+  '';
+
+  # Stripping breaks the binaries
+  dontStrip = true;
+
+  postFixup = ''
+    fix_rpath() {
+      patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out/lib/$1
+    }
+
+    wrap() {
+      makeWrapper $out/lib/$1 $out/bin/$1 \
+        --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath (buildInputs ++ [ openssl ])} \
+        ''${@:2}
+    }
+
+    fix_rpath Runner.Listener
+    fix_rpath Runner.PluginHost
+    fix_rpath Runner.Worker
+
+    wrap Runner.Listener
+    wrap Runner.PluginHost
+    wrap Runner.Worker
+    wrap run.sh
+    wrap env.sh
+
+    wrap config.sh --prefix PATH : ${lib.makeBinPath [ glibc.bin ]}
+  '';
+
+  meta = with lib; {
+    description = "Self-hosted runner for GitHub Actions";
+    homepage = "https://github.com/actions/runner";
+    license = licenses.mit;
+    maintainers = with maintainers; [ veehaitch ];
+    platforms = [ "x86_64-linux" ];
+  };
+}
diff --git a/pkgs/development/tools/continuous-integration/github-runner/deps.nix b/pkgs/development/tools/continuous-integration/github-runner/deps.nix
new file mode 100644
index 00000000000..a556a83aa49
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/deps.nix
@@ -0,0 +1,1217 @@
+{ fetchurl }:
+let
+  fetchNuGet = { name, version, sha256 }: fetchurl {
+    inherit sha256;
+    name = "${name}.${version}";
+    url = "https://www.nuget.org/api/v2/package/${name}/${version}";
+  };
+in
+[
+
+  (fetchNuGet {
+    name = "Castle.Core";
+    version = "4.4.0";
+    sha256 = "0rpcbmyhckvlvp6vbzpj03c1gqz56ixc6f15vgmxmyf1g40c24pf";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.AspNetCore.App.Runtime.linux-x64";
+    version = "3.1.8";
+    sha256 = "140zr3nwkmf6xc52gq4iz6ycyh95fxy0jpgn637pkd9z423z8135";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.AspNet.WebApi.Client";
+    version = "5.2.4";
+    sha256 = "00fkczf69z2rwarcd8kjjdp47517a0ca6lggn72qbilsp03a5scj";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.IdentityModel.Logging";
+    version = "5.2.1";
+    sha256 = "1gpka9jm2gl6f07pcwzwvaxw9xq1a19i9fskn0qs921c5grhlp3g";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.IdentityModel.Tokens";
+    version = "5.2.1";
+    sha256 = "03v6145vr1winq8xxfikydicds4f10qmy1ybyz2gfimnzzx51w00";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.NetCore.App.Runtime.linux-x64";
+    version = "3.1.8";
+    sha256 = "1bv9n9wzsqf9g8h6z10p61xkcx8ad4nnip83qv8yyfvhr4kdmbsa";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.NETCore.Platforms";
+    version = "1.0.1";
+    sha256 = "01al6cfxp68dscl15z7rxfw9zvhm64dncsw09a1vmdkacsa2v6lr";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.NETCore.Platforms";
+    version = "1.1.0";
+    sha256 = "08vh1r12g6ykjygq5d3vq09zylgb84l63k49jc4v8faw9g93iqqm";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.NETCore.Platforms";
+    version = "2.0.0";
+    sha256 = "1fk2fk2639i7nzy58m9dvpdnzql4vb8yl8vr19r2fp8lmj9w2jr0";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.NETCore.Targets";
+    version = "1.1.0";
+    sha256 = "193xwf33fbm0ni3idxzbr5fdq3i2dlfgihsac9jj7whj0gd902nh";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.NET.Test.Sdk";
+    version = "15.0.0";
+    sha256 = "1ca9v53dphsgk22spilfwq1hjzp2sgrrj85v7hd7wfc6gjh31mb5";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.TestPlatform.ObjectModel";
+    version = "15.0.0";
+    sha256 = "0xqssz2y8jzqph6kv1fzy00wzjcnc2whhlf8jsszgpn69ld7f1rb";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.TestPlatform.TestHost";
+    version = "15.0.0";
+    sha256 = "1mi59wxwdqyzmkan0v9qrar96f50xs6k38xzv3l6ky859si2qk4b";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.Win32.Primitives";
+    version = "4.0.1";
+    sha256 = "1n8ap0cmljbqskxpf8fjzn7kh1vvlndsa75k01qig26mbw97k2q7";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.Win32.Primitives";
+    version = "4.3.0";
+    sha256 = "0j0c1wj4ndj21zsgivsc24whiya605603kxrbiw6wkfdync464wq";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.Win32.Registry";
+    version = "4.0.0";
+    sha256 = "1spf4m9pikkc19544p29a47qnhcd885klncahz133hbnyqbkmz9k";
+  })
+
+  (fetchNuGet {
+    name = "Microsoft.Win32.Registry";
+    version = "4.4.0";
+    sha256 = "088j2anh1rnkxdcycw5kgp97ahk7cj741y6kask84880835arsb6";
+  })
+
+  (fetchNuGet {
+    name = "Minimatch";
+    version = "2.0.0";
+    sha256 = "1k84q1bz1qq2nh35nip8vmi65wixsh5y7piln5b4n172xzhfqvx0";
+  })
+
+  (fetchNuGet {
+    name = "Moq";
+    version = "4.11.0";
+    sha256 = "08bnk80scjjqnkdbjam8grcqrw2rvj9z7556hiznac7in3fcp77w";
+  })
+
+  (fetchNuGet {
+    name = "NETStandard.Library";
+    version = "1.6.0";
+    sha256 = "0nmmv4yw7gw04ik8ialj3ak0j6pxa9spih67hnn1h2c38ba8h58k";
+  })
+
+  (fetchNuGet {
+    name = "NETStandard.Library";
+    version = "1.6.1";
+    sha256 = "1z70wvsx2d847a2cjfii7b83pjfs34q05gb037fdjikv5kbagml8";
+  })
+
+  (fetchNuGet {
+    name = "Newtonsoft.Json";
+    version = "10.0.1";
+    sha256 = "15ncqic3p2rzs8q8ppi0irl2miq75kilw4lh8yfgjq96id0ds3hv";
+  })
+
+  (fetchNuGet {
+    name = "Newtonsoft.Json";
+    version = "11.0.2";
+    sha256 = "1784xi44f4k8v1fr696hsccmwpy94bz7kixxqlri98zhcxn406b2";
+  })
+
+  (fetchNuGet {
+    name = "Newtonsoft.Json";
+    version = "9.0.1";
+    sha256 = "0mcy0i7pnfpqm4pcaiyzzji4g0c8i3a5gjz28rrr28110np8304r";
+  })
+
+  (fetchNuGet {
+    name = "Newtonsoft.Json.Bson";
+    version = "1.0.1";
+    sha256 = "1r1hvj5gjl466bya2bfl5aaj8rbwyf5x1msg710wf3k2llbci1xa";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Collections";
+    version = "4.3.0";
+    sha256 = "0bv5qgm6vr47ynxqbnkc7i797fdi8gbjjxii173syrx14nmrkwg0";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Diagnostics.Tools";
+    version = "4.3.0";
+    sha256 = "1wl76vk12zhdh66vmagni66h5xbhgqq7zkdpgw21jhxhvlbcl8pk";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Diagnostics.Tracing";
+    version = "4.3.0";
+    sha256 = "00j6nv2xgmd3bi347k00m7wr542wjlig53rmj28pmw7ddcn97jbn";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Globalization";
+    version = "4.3.0";
+    sha256 = "1daqf33hssad94lamzg01y49xwndy2q97i2lrb7mgn28656qia1x";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Globalization.Calendars";
+    version = "4.3.0";
+    sha256 = "1ghhhk5psqxcg6w88sxkqrc35bxcz27zbqm2y5p5298pv3v7g201";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.IO";
+    version = "4.3.0";
+    sha256 = "0l8xz8zn46w4d10bcn3l4yyn4vhb3lrj2zw8llvz7jk14k4zps5x";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Reflection";
+    version = "4.3.0";
+    sha256 = "02c9h3y35pylc0zfq3wcsvc5nqci95nrkq0mszifc0sjx7xrzkly";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Reflection.Extensions";
+    version = "4.3.0";
+    sha256 = "0zyri97dfc5vyaz9ba65hjj1zbcrzaffhsdlpxc9bh09wy22fq33";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Reflection.Primitives";
+    version = "4.3.0";
+    sha256 = "0x1mm8c6iy8rlxm8w9vqw7gb7s1ljadrn049fmf70cyh42vdfhrf";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Resources.ResourceManager";
+    version = "4.3.0";
+    sha256 = "03kickal0iiby82wa5flar18kyv82s9s6d4xhk5h4bi5kfcyfjzl";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Runtime";
+    version = "4.3.0";
+    sha256 = "1cqh1sv3h5j7ixyb7axxbdkqx6cxy00p4np4j91kpm492rf4s25b";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Runtime.Handles";
+    version = "4.3.0";
+    sha256 = "0bh5bi25nk9w9xi8z23ws45q5yia6k7dg3i4axhfqlnj145l011x";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Runtime.InteropServices";
+    version = "4.3.0";
+    sha256 = "0c3g3g3jmhlhw4klrc86ka9fjbl7i59ds1fadsb2l8nqf8z3kb19";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Text.Encoding";
+    version = "4.3.0";
+    sha256 = "0aqqi1v4wx51h51mk956y783wzags13wa7mgqyclacmsmpv02ps3";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Text.Encoding.Extensions";
+    version = "4.3.0";
+    sha256 = "0lqhgqi0i8194ryqq6v2gqx0fb86db2gqknbm0aq31wb378j7ip8";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Threading.Tasks";
+    version = "4.3.0";
+    sha256 = "03mnvkhskbzxddz4hm113zsch1jyzh2cs450dk3rgfjp8crlw1va";
+  })
+
+  (fetchNuGet {
+    name = "runtime.any.System.Threading.Timer";
+    version = "4.3.0";
+    sha256 = "0aw4phrhwqz9m61r79vyfl5la64bjxj8l34qnrcwb28v49fg2086";
+  })
+
+  (fetchNuGet {
+    name = "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "16rnxzpk5dpbbl1x354yrlsbvwylrq456xzpsha1n9y3glnhyx9d";
+  })
+
+  (fetchNuGet {
+    name = "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "0hkg03sgm2wyq8nqk6dbm9jh5vcq57ry42lkqdmfklrw89lsmr59";
+  })
+
+  (fetchNuGet {
+    name = "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "0c2p354hjx58xhhz7wv6div8xpi90sc6ibdm40qin21bvi7ymcaa";
+  })
+
+  (fetchNuGet {
+    name = "runtime.native.System";
+    version = "4.0.0";
+    sha256 = "1ppk69xk59ggacj9n7g6fyxvzmk1g5p4fkijm0d7xqfkig98qrkf";
+  })
+
+  (fetchNuGet {
+    name = "runtime.native.System";
+    version = "4.3.0";
+    sha256 = "15hgf6zaq9b8br2wi1i3x0zvmk410nlmsmva9p0bbg73v6hml5k4";
+  })
+
+  (fetchNuGet {
+    name = "runtime.native.System.IO.Compression";
+    version = "4.3.0";
+    sha256 = "1vvivbqsk6y4hzcid27pqpm5bsi6sc50hvqwbcx8aap5ifrxfs8d";
+  })
+
+  (fetchNuGet {
+    name = "runtime.native.System.Net.Http";
+    version = "4.3.0";
+    sha256 = "1n6rgz5132lcibbch1qlf0g9jk60r0kqv087hxc0lisy50zpm7kk";
+  })
+
+  (fetchNuGet {
+    name = "runtime.native.System.Security.Cryptography.Apple";
+    version = "4.3.0";
+    sha256 = "1b61p6gw1m02cc1ry996fl49liiwky6181dzr873g9ds92zl326q";
+  })
+
+  (fetchNuGet {
+    name = "runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "18pzfdlwsg2nb1jjjjzyb5qlgy6xjxzmhnfaijq5s2jw3cm3ab97";
+  })
+
+  (fetchNuGet {
+    name = "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "0qyynf9nz5i7pc26cwhgi8j62ps27sqmf78ijcfgzab50z9g8ay3";
+  })
+
+  (fetchNuGet {
+    name = "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "1klrs545awhayryma6l7g2pvnp9xy4z0r1i40r80zb45q3i9nbyf";
+  })
+
+  (fetchNuGet {
+    name = "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple";
+    version = "4.3.0";
+    sha256 = "10yc8jdrwgcl44b4g93f1ds76b176bajd3zqi2faf5rvh1vy9smi";
+  })
+
+  (fetchNuGet {
+    name = "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "0zcxjv5pckplvkg0r6mw3asggm7aqzbdjimhvsasb0cgm59x09l3";
+  })
+
+  (fetchNuGet {
+    name = "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "0vhynn79ih7hw7cwjazn87rm9z9fj0rvxgzlab36jybgcpcgphsn";
+  })
+
+  (fetchNuGet {
+    name = "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "160p68l2c7cqmyqjwxydcvgw7lvl1cr0znkw8fp24d1by9mqc8p3";
+  })
+
+  (fetchNuGet {
+    name = "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "15zrc8fgd8zx28hdghcj5f5i34wf3l6bq5177075m2bc2j34jrqy";
+  })
+
+  (fetchNuGet {
+    name = "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "1p4dgxax6p7rlgj4q73k73rslcnz4wdcv8q2flg1s8ygwcm58ld5";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.Microsoft.Win32.Primitives";
+    version = "4.3.0";
+    sha256 = "0y61k9zbxhdi0glg154v30kkq7f8646nif8lnnxbvkjpakggd5id";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.Console";
+    version = "4.3.0";
+    sha256 = "1pfpkvc6x2if8zbdzg9rnc5fx51yllprl8zkm5npni2k50lisy80";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.Diagnostics.Debug";
+    version = "4.3.0";
+    sha256 = "1lps7fbnw34bnh3lm31gs5c0g0dh7548wfmb8zz62v0zqz71msj5";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.IO.FileSystem";
+    version = "4.3.0";
+    sha256 = "14nbkhvs7sji5r1saj2x8daz82rnf9kx28d3v2qss34qbr32dzix";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.Net.Primitives";
+    version = "4.3.0";
+    sha256 = "0bdnglg59pzx9394sy4ic66kmxhqp8q8bvmykdxcbs5mm0ipwwm4";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.Net.Sockets";
+    version = "4.3.0";
+    sha256 = "03npdxzy8gfv035bv1b9rz7c7hv0rxl5904wjz51if491mw0xy12";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.Private.Uri";
+    version = "4.3.0";
+    sha256 = "1jx02q6kiwlvfksq1q9qr17fj78y5v6mwsszav4qcz9z25d5g6vk";
+  })
+
+  (fetchNuGet {
+    name = "runtime.unix.System.Runtime.Extensions";
+    version = "4.3.0";
+    sha256 = "0pnxxmm8whx38dp6yvwgmh22smknxmqs5n513fc7m4wxvs1bvi4p";
+  })
+
+  (fetchNuGet {
+    name = "Sdk";
+    version = "1.0.0";
+    sha256 = "0425gviagj8xl8mwl4bwn1v98j7407sdk78xgxk37z62vgcgs73w";
+  })
+
+  (fetchNuGet {
+    name = "System.AppContext";
+    version = "4.3.0";
+    sha256 = "1649qvy3dar900z3g817h17nl8jp4ka5vcfmsr05kh0fshn7j3ya";
+  })
+
+  (fetchNuGet {
+    name = "System.Buffers";
+    version = "4.3.0";
+    sha256 = "0fgns20ispwrfqll4q1zc1waqcmylb3zc50ys9x8zlwxh9pmd9jy";
+  })
+
+  (fetchNuGet {
+    name = "System.Collections";
+    version = "4.0.11";
+    sha256 = "1ga40f5lrwldiyw6vy67d0sg7jd7ww6kgwbksm19wrvq9hr0bsm6";
+  })
+
+  (fetchNuGet {
+    name = "System.Collections";
+    version = "4.3.0";
+    sha256 = "19r4y64dqyrq6k4706dnyhhw7fs24kpp3awak7whzss39dakpxk9";
+  })
+
+  (fetchNuGet {
+    name = "System.Collections.Concurrent";
+    version = "4.3.0";
+    sha256 = "0wi10md9aq33jrkh2c24wr2n9hrpyamsdhsxdcnf43b7y86kkii8";
+  })
+
+  (fetchNuGet {
+    name = "System.Collections.Immutable";
+    version = "1.2.0";
+    sha256 = "1jm4pc666yiy7af1mcf7766v710gp0h40p228ghj6bavx7xfa38m";
+  })
+
+  (fetchNuGet {
+    name = "System.Collections.NonGeneric";
+    version = "4.3.0";
+    sha256 = "07q3k0hf3mrcjzwj8fwk6gv3n51cb513w4mgkfxzm3i37sc9kz7k";
+  })
+
+  (fetchNuGet {
+    name = "System.Collections.Specialized";
+    version = "4.3.0";
+    sha256 = "1sdwkma4f6j85m3dpb53v9vcgd0zyc9jb33f8g63byvijcj39n20";
+  })
+
+  (fetchNuGet {
+    name = "System.ComponentModel";
+    version = "4.3.0";
+    sha256 = "0986b10ww3nshy30x9sjyzm0jx339dkjxjj3401r3q0f6fx2wkcb";
+  })
+
+  (fetchNuGet {
+    name = "System.ComponentModel.EventBasedAsync";
+    version = "4.0.11";
+    sha256 = "07r5i7xwban347nsfw28hhjwpr78ywksjyhywvhj1yr0s7sr00wh";
+  })
+
+  (fetchNuGet {
+    name = "System.ComponentModel.Primitives";
+    version = "4.3.0";
+    sha256 = "1svfmcmgs0w0z9xdw2f2ps05rdxmkxxhf0l17xk9l1l8xfahkqr0";
+  })
+
+  (fetchNuGet {
+    name = "System.ComponentModel.TypeConverter";
+    version = "4.1.0";
+    sha256 = "178cva9p1cs043h5n2fry5xkzr3wc9n0hwbxa8m3ymld9m6wcv0y";
+  })
+
+  (fetchNuGet {
+    name = "System.ComponentModel.TypeConverter";
+    version = "4.3.0";
+    sha256 = "17ng0p7v3nbrg3kycz10aqrrlw4lz9hzhws09pfh8gkwicyy481x";
+  })
+
+  (fetchNuGet {
+    name = "System.Console";
+    version = "4.3.0";
+    sha256 = "1flr7a9x920mr5cjsqmsy9wgnv3lvd0h1g521pdr1lkb2qycy7ay";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.Debug";
+    version = "4.0.11";
+    sha256 = "0gmjghrqmlgzxivd2xl50ncbglb7ljzb66rlx8ws6dv8jm0d5siz";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.Debug";
+    version = "4.3.0";
+    sha256 = "00yjlf19wjydyr6cfviaph3vsjzg3d5nvnya26i2fvfg53sknh3y";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.DiagnosticSource";
+    version = "4.3.0";
+    sha256 = "0z6m3pbiy0qw6rn3n209rrzf9x1k4002zh90vwcrsym09ipm2liq";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.Process";
+    version = "4.1.0";
+    sha256 = "061lrcs7xribrmq7kab908lww6kn2xn1w3rdc41q189y0jibl19s";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.TextWriterTraceListener";
+    version = "4.0.0";
+    sha256 = "1xigiwkwyxak0dhm0p8i2zb7a9syly9cdb5s9zkr9rbad4f2fqhs";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.Tools";
+    version = "4.3.0";
+    sha256 = "0in3pic3s2ddyibi8cvgl102zmvp9r9mchh82ns9f0ms4basylw1";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.TraceSource";
+    version = "4.0.0";
+    sha256 = "1mc7r72xznczzf6mz62dm8xhdi14if1h8qgx353xvhz89qyxsa3h";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.TraceSource";
+    version = "4.3.0";
+    sha256 = "1kyw4d7dpjczhw6634nrmg7yyyzq72k75x38y0l0nwhigdlp1766";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.Tracing";
+    version = "4.1.0";
+    sha256 = "1d2r76v1x610x61ahfpigda89gd13qydz6vbwzhpqlyvq8jj6394";
+  })
+
+  (fetchNuGet {
+    name = "System.Diagnostics.Tracing";
+    version = "4.3.0";
+    sha256 = "1m3bx6c2s958qligl67q7grkwfz3w53hpy7nc97mh6f7j5k168c4";
+  })
+
+  (fetchNuGet {
+    name = "System.Dynamic.Runtime";
+    version = "4.3.0";
+    sha256 = "1d951hrvrpndk7insiag80qxjbf2y0y39y8h5hnq9612ws661glk";
+  })
+
+  (fetchNuGet {
+    name = "System.Globalization";
+    version = "4.0.11";
+    sha256 = "070c5jbas2v7smm660zaf1gh0489xanjqymkvafcs4f8cdrs1d5d";
+  })
+
+  (fetchNuGet {
+    name = "System.Globalization";
+    version = "4.3.0";
+    sha256 = "1cp68vv683n6ic2zqh2s1fn4c2sd87g5hpp6l4d4nj4536jz98ki";
+  })
+
+  (fetchNuGet {
+    name = "System.Globalization.Calendars";
+    version = "4.3.0";
+    sha256 = "1xwl230bkakzzkrggy1l1lxmm3xlhk4bq2pkv790j5lm8g887lxq";
+  })
+
+  (fetchNuGet {
+    name = "System.Globalization.Extensions";
+    version = "4.3.0";
+    sha256 = "02a5zfxavhv3jd437bsncbhd2fp1zv4gxzakp1an9l6kdq1mcqls";
+  })
+
+  (fetchNuGet {
+    name = "System.IdentityModel.Tokens.Jwt";
+    version = "5.2.1";
+    sha256 = "08n1z9ngsi26qlhwpjzxafhwl3p279widfci64l2ahxf1gprfqsx";
+  })
+
+  (fetchNuGet {
+    name = "System.IO";
+    version = "4.1.0";
+    sha256 = "1g0yb8p11vfd0kbkyzlfsbsp5z44lwsvyc0h3dpw6vqnbi035ajp";
+  })
+
+  (fetchNuGet {
+    name = "System.IO";
+    version = "4.3.0";
+    sha256 = "05l9qdrzhm4s5dixmx68kxwif4l99ll5gqmh7rqgw554fx0agv5f";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.Compression";
+    version = "4.3.0";
+    sha256 = "084zc82yi6yllgda0zkgl2ys48sypiswbiwrv7irb3r0ai1fp4vz";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.Compression.ZipFile";
+    version = "4.3.0";
+    sha256 = "1yxy5pq4dnsm9hlkg9ysh5f6bf3fahqqb6p8668ndy5c0lk7w2ar";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.FileSystem";
+    version = "4.0.1";
+    sha256 = "0kgfpw6w4djqra3w5crrg8xivbanh1w9dh3qapb28q060wb9flp1";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.FileSystem";
+    version = "4.3.0";
+    sha256 = "0z2dfrbra9i6y16mm9v1v6k47f0fm617vlb7s5iybjjsz6g1ilmw";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.FileSystem.AccessControl";
+    version = "4.4.0";
+    sha256 = "11sna2bv5ai4sivrs7g2gp7g0yjp02s0kasl01j3fa1cvnwwvgkv";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.FileSystem.Primitives";
+    version = "4.0.1";
+    sha256 = "1s0mniajj3lvbyf7vfb5shp4ink5yibsx945k6lvxa96r8la1612";
+  })
+
+  (fetchNuGet {
+    name = "System.IO.FileSystem.Primitives";
+    version = "4.3.0";
+    sha256 = "0j6ndgglcf4brg2lz4wzsh1av1gh8xrzdsn9f0yznskhqn1xzj9c";
+  })
+
+  (fetchNuGet {
+    name = "System.Linq";
+    version = "4.1.0";
+    sha256 = "1ppg83svb39hj4hpp5k7kcryzrf3sfnm08vxd5sm2drrijsla2k5";
+  })
+
+  (fetchNuGet {
+    name = "System.Linq";
+    version = "4.3.0";
+    sha256 = "1w0gmba695rbr80l1k2h4mrwzbzsyfl2z4klmpbsvsg5pm4a56s7";
+  })
+
+  (fetchNuGet {
+    name = "System.Linq.Expressions";
+    version = "4.3.0";
+    sha256 = "0ky2nrcvh70rqq88m9a5yqabsl4fyd17bpr63iy2mbivjs2nyypv";
+  })
+
+  (fetchNuGet {
+    name = "System.Net.Http";
+    version = "4.3.0";
+    sha256 = "1i4gc757xqrzflbk7kc5ksn20kwwfjhw9w7pgdkn19y3cgnl302j";
+  })
+
+  (fetchNuGet {
+    name = "System.Net.NameResolution";
+    version = "4.3.0";
+    sha256 = "15r75pwc0rm3vvwsn8rvm2krf929mjfwliv0mpicjnii24470rkq";
+  })
+
+  (fetchNuGet {
+    name = "System.Net.Primitives";
+    version = "4.3.0";
+    sha256 = "0c87k50rmdgmxx7df2khd9qj7q35j9rzdmm2572cc55dygmdk3ii";
+  })
+
+  (fetchNuGet {
+    name = "System.Net.Sockets";
+    version = "4.3.0";
+    sha256 = "1ssa65k6chcgi6mfmzrznvqaxk8jp0gvl77xhf1hbzakjnpxspla";
+  })
+
+  (fetchNuGet {
+    name = "System.ObjectModel";
+    version = "4.3.0";
+    sha256 = "191p63zy5rpqx7dnrb3h7prvgixmk168fhvvkkvhlazncf8r3nc2";
+  })
+
+  (fetchNuGet {
+    name = "System.Private.DataContractSerialization";
+    version = "4.1.1";
+    sha256 = "1xk9wvgzipssp1393nsg4n16zbr5481k03nkdlj954hzq5jkx89r";
+  })
+
+  (fetchNuGet {
+    name = "System.Private.DataContractSerialization";
+    version = "4.3.0";
+    sha256 = "06fjipqvjp559rrm825x6pll8gimdj9x1n3larigh5hsm584gndw";
+  })
+
+  (fetchNuGet {
+    name = "System.Private.Uri";
+    version = "4.3.0";
+    sha256 = "04r1lkdnsznin0fj4ya1zikxiqr0h6r6a1ww2dsm60gqhdrf0mvx";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection";
+    version = "4.1.0";
+    sha256 = "1js89429pfw79mxvbzp8p3q93il6rdff332hddhzi5wqglc4gml9";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection";
+    version = "4.3.0";
+    sha256 = "0xl55k0mw8cd8ra6dxzh974nxif58s3k1rjv1vbd7gjbjr39j11m";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Emit";
+    version = "4.3.0";
+    sha256 = "11f8y3qfysfcrscjpjym9msk7lsfxkk4fmz9qq95kn3jd0769f74";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Emit.ILGeneration";
+    version = "4.3.0";
+    sha256 = "0w1n67glpv8241vnpz1kl14sy7zlnw414aqwj4hcx5nd86f6994q";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Emit.Lightweight";
+    version = "4.3.0";
+    sha256 = "0ql7lcakycrvzgi9kxz1b3lljd990az1x6c4jsiwcacrvimpib5c";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Extensions";
+    version = "4.0.1";
+    sha256 = "0m7wqwq0zqq9gbpiqvgk3sr92cbrw7cp3xn53xvw7zj6rz6fdirn";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Extensions";
+    version = "4.3.0";
+    sha256 = "02bly8bdc98gs22lqsfx9xicblszr2yan7v2mmw3g7hy6miq5hwq";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Metadata";
+    version = "1.3.0";
+    sha256 = "1y5m6kryhjpqqm2g3h3b6bzig13wkiw954x3b7icqjm6xypm1x3b";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Primitives";
+    version = "4.0.1";
+    sha256 = "1bangaabhsl4k9fg8khn83wm6yial8ik1sza7401621jc6jrym28";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.Primitives";
+    version = "4.3.0";
+    sha256 = "04xqa33bld78yv5r93a8n76shvc8wwcdgr1qvvjh959g3rc31276";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.TypeExtensions";
+    version = "4.1.0";
+    sha256 = "1bjli8a7sc7jlxqgcagl9nh8axzfl11f4ld3rjqsyxc516iijij7";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.TypeExtensions";
+    version = "4.3.0";
+    sha256 = "0y2ssg08d817p0vdag98vn238gyrrynjdj4181hdg780sif3ykp1";
+  })
+
+  (fetchNuGet {
+    name = "System.Reflection.TypeExtensions";
+    version = "4.4.0";
+    sha256 = "0n9r1w4lp2zmadyqkgp4sk9wy90sj4ygq4dh7kzamx26i9biys5h";
+  })
+
+  (fetchNuGet {
+    name = "System.Resources.ResourceManager";
+    version = "4.0.1";
+    sha256 = "0b4i7mncaf8cnai85jv3wnw6hps140cxz8vylv2bik6wyzgvz7bi";
+  })
+
+  (fetchNuGet {
+    name = "System.Resources.ResourceManager";
+    version = "4.3.0";
+    sha256 = "0sjqlzsryb0mg4y4xzf35xi523s4is4hz9q4qgdvlvgivl7qxn49";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime";
+    version = "4.1.0";
+    sha256 = "02hdkgk13rvsd6r9yafbwzss8kr55wnj8d5c7xjnp8gqrwc8sn0m";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime";
+    version = "4.3.0";
+    sha256 = "066ixvgbf2c929kgknshcxqj6539ax7b9m570cp8n179cpfkapz7";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Extensions";
+    version = "4.1.0";
+    sha256 = "0rw4rm4vsm3h3szxp9iijc3ksyviwsv6f63dng3vhqyg4vjdkc2z";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Extensions";
+    version = "4.3.0";
+    sha256 = "1ykp3dnhwvm48nap8q23893hagf665k0kn3cbgsqpwzbijdcgc60";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Handles";
+    version = "4.0.1";
+    sha256 = "1g0zrdi5508v49pfm3iii2hn6nm00bgvfpjq1zxknfjrxxa20r4g";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Handles";
+    version = "4.3.0";
+    sha256 = "0sw2gfj2xr7sw9qjn0j3l9yw07x73lcs97p8xfc9w1x9h5g5m7i8";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.InteropServices";
+    version = "4.1.0";
+    sha256 = "01kxqppx3dr3b6b286xafqilv4s2n0gqvfgzfd4z943ga9i81is1";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.InteropServices";
+    version = "4.3.0";
+    sha256 = "00hywrn4g7hva1b2qri2s6rabzwgxnbpw9zfxmz28z09cpwwgh7j";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.InteropServices.RuntimeInformation";
+    version = "4.0.0";
+    sha256 = "0glmvarf3jz5xh22iy3w9v3wyragcm4hfdr17v90vs7vcrm7fgp6";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.InteropServices.RuntimeInformation";
+    version = "4.3.0";
+    sha256 = "0q18r1sh4vn7bvqgd6dmqlw5v28flbpj349mkdish2vjyvmnb2ii";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Loader";
+    version = "4.0.0";
+    sha256 = "0lpfi3psqcp6zxsjk2qyahal7zaawviimc8lhrlswhip2mx7ykl0";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Loader";
+    version = "4.3.0";
+    sha256 = "07fgipa93g1xxgf7193a6vw677mpzgr0z0cfswbvqqb364cva8dk";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Numerics";
+    version = "4.3.0";
+    sha256 = "19rav39sr5dky7afygh309qamqqmi9kcwvz3i0c5700v0c5cg61z";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Serialization.Json";
+    version = "4.0.2";
+    sha256 = "08ypbzs0sb302ga04ds5b2wxa2gg0q50zpa0nvc87ipjhs0v66dn";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Serialization.Primitives";
+    version = "4.1.1";
+    sha256 = "042rfjixknlr6r10vx2pgf56yming8lkjikamg3g4v29ikk78h7k";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Serialization.Primitives";
+    version = "4.3.0";
+    sha256 = "01vv2p8h4hsz217xxs0rixvb7f2xzbh6wv1gzbfykcbfrza6dvnf";
+  })
+
+  (fetchNuGet {
+    name = "System.Runtime.Serialization.Xml";
+    version = "4.3.0";
+    sha256 = "1b2cxl2h7s8cydbhbmxhvvq071n9ck61g08npg4gyw7nvg37rfni";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.AccessControl";
+    version = "4.4.0";
+    sha256 = "0ixqw47krkazsw0ycm22ivkv7dpg6cjz8z8g0ii44bsx4l8gcx17";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Claims";
+    version = "4.3.0";
+    sha256 = "0jvfn7j22l3mm28qjy3rcw287y9h65ha4m940waaxah07jnbzrhn";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Algorithms";
+    version = "4.2.0";
+    sha256 = "148s9g5dgm33ri7dnh19s4lgnlxbpwvrw2jnzllq2kijj4i4vs85";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Algorithms";
+    version = "4.3.0";
+    sha256 = "03sq183pfl5kp7gkvq77myv7kbpdnq3y0xj7vi4q1kaw54sny0ml";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Cng";
+    version = "4.3.0";
+    sha256 = "1k468aswafdgf56ab6yrn7649kfqx2wm9aslywjam1hdmk5yypmv";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Cng";
+    version = "4.4.0";
+    sha256 = "1grg9id80m358crr5y4q4rhhbrm122yw8jrlcl1ybi7nkmmck40n";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Csp";
+    version = "4.3.0";
+    sha256 = "1x5wcrddf2s3hb8j78cry7yalca4lb5vfnkrysagbn6r9x6xvrx1";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Encoding";
+    version = "4.3.0";
+    sha256 = "1jr6w70igqn07k5zs1ph6xja97hxnb3mqbspdrff6cvssgrixs32";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.OpenSsl";
+    version = "4.3.0";
+    sha256 = "0givpvvj8yc7gv4lhb6s1prq6p2c4147204a0wib89inqzd87gqc";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Pkcs";
+    version = "4.4.0";
+    sha256 = "1bn7d2czpc994qzdph4drv7p1cv4x55j2dhbmr113p0gs4hx33zh";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.Primitives";
+    version = "4.3.0";
+    sha256 = "0pyzncsv48zwly3lw4f2dayqswcfvdwq2nz0dgwmi7fj3pn64wby";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.ProtectedData";
+    version = "4.4.0";
+    sha256 = "1q8ljvqhasyynp94a1d7jknk946m20lkwy2c3wa8zw2pc517fbj6";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Cryptography.X509Certificates";
+    version = "4.3.0";
+    sha256 = "0valjcz5wksbvijylxijjxb1mp38mdhv03r533vnx1q3ikzdav9h";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Principal";
+    version = "4.3.0";
+    sha256 = "12cm2zws06z4lfc4dn31iqv7072zyi4m910d4r6wm8yx85arsfxf";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Principal.Windows";
+    version = "4.3.0";
+    sha256 = "00a0a7c40i3v4cb20s2cmh9csb5jv2l0frvnlzyfxh848xalpdwr";
+  })
+
+  (fetchNuGet {
+    name = "System.Security.Principal.Windows";
+    version = "4.4.0";
+    sha256 = "11rr16fp68apc0arsymgj18w8ajs9a4366wgx9iqwny4glrl20wp";
+  })
+
+  (fetchNuGet {
+    name = "System.ServiceProcess.ServiceController";
+    version = "4.4.0";
+    sha256 = "0hyijvysbcjh20mbbgajg9wh04nkjd6y5lqxgm0a6m28zjcjshl6";
+  })
+
+  (fetchNuGet {
+    name = "System.Text.Encoding";
+    version = "4.0.11";
+    sha256 = "1dyqv0hijg265dwxg6l7aiv74102d6xjiwplh2ar1ly6xfaa4iiw";
+  })
+
+  (fetchNuGet {
+    name = "System.Text.Encoding";
+    version = "4.3.0";
+    sha256 = "1f04lkir4iladpp51sdgmis9dj4y8v08cka0mbmsy0frc9a4gjqr";
+  })
+
+  (fetchNuGet {
+    name = "System.Text.Encoding.CodePages";
+    version = "4.4.0";
+    sha256 = "07bzjnflxjk9vgpljfybrpqmvsr9qr2f20nq5wf11imwa5pbhgfc";
+  })
+
+  (fetchNuGet {
+    name = "System.Text.Encoding.Extensions";
+    version = "4.0.11";
+    sha256 = "08nsfrpiwsg9x5ml4xyl3zyvjfdi4mvbqf93kjdh11j4fwkznizs";
+  })
+
+  (fetchNuGet {
+    name = "System.Text.Encoding.Extensions";
+    version = "4.3.0";
+    sha256 = "11q1y8hh5hrp5a3kw25cb6l00v5l5dvirkz8jr3sq00h1xgcgrxy";
+  })
+
+  (fetchNuGet {
+    name = "System.Text.RegularExpressions";
+    version = "4.3.0";
+    sha256 = "1bgq51k7fwld0njylfn7qc5fmwrk2137gdq7djqdsw347paa9c2l";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading";
+    version = "4.0.11";
+    sha256 = "19x946h926bzvbsgj28csn46gak2crv2skpwsx80hbgazmkgb1ls";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading";
+    version = "4.3.0";
+    sha256 = "0rw9wfamvhayp5zh3j7p1yfmx9b5khbf4q50d8k5rk993rskfd34";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Channels";
+    version = "4.5.0";
+    sha256 = "0n6z3wjia7h2a5vl727p97riydnb6jhhkb1pdcnizza02dwkz0nz";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Tasks";
+    version = "4.0.11";
+    sha256 = "0nr1r41rak82qfa5m0lhk9mp0k93bvfd7bbd9sdzwx9mb36g28p5";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Tasks";
+    version = "4.3.0";
+    sha256 = "134z3v9abw3a6jsw17xl3f6hqjpak5l682k2vz39spj4kmydg6k7";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Tasks.Extensions";
+    version = "4.3.0";
+    sha256 = "1xxcx2xh8jin360yjwm4x4cf5y3a2bwpn2ygkfkwkicz7zk50s2z";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Tasks.Extensions";
+    version = "4.5.1";
+    sha256 = "1ikrplvw4m6pzjbq3bfbpr572n4i9mni577zvmrkaygvx85q3myw";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Thread";
+    version = "4.0.0";
+    sha256 = "1gxxm5fl36pjjpnx1k688dcw8m9l7nmf802nxis6swdaw8k54jzc";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.ThreadPool";
+    version = "4.0.10";
+    sha256 = "0fdr61yjcxh5imvyf93n2m3n5g9pp54bnw2l1d2rdl9z6dd31ypx";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.ThreadPool";
+    version = "4.3.0";
+    sha256 = "027s1f4sbx0y1xqw2irqn6x161lzj8qwvnh2gn78ciiczdv10vf1";
+  })
+
+  (fetchNuGet {
+    name = "System.Threading.Timer";
+    version = "4.3.0";
+    sha256 = "1nx773nsx6z5whv8kaa1wjh037id2f1cxhb69pvgv12hd2b6qs56";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.ReaderWriter";
+    version = "4.0.11";
+    sha256 = "0c6ky1jk5ada9m94wcadih98l6k1fvf6vi7vhn1msjixaha419l5";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.ReaderWriter";
+    version = "4.3.0";
+    sha256 = "0c47yllxifzmh8gq6rq6l36zzvw4kjvlszkqa9wq3fr59n0hl3s1";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.XDocument";
+    version = "4.3.0";
+    sha256 = "08h8fm4l77n0nd4i4fk2386y809bfbwqb7ih9d7564ifcxr5ssxd";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.XmlDocument";
+    version = "4.0.1";
+    sha256 = "0ihsnkvyc76r4dcky7v3ansnbyqjzkbyyia0ir5zvqirzan0bnl1";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.XmlDocument";
+    version = "4.3.0";
+    sha256 = "0bmz1l06dihx52jxjr22dyv5mxv6pj4852lx68grjm7bivhrbfwi";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.XmlSerializer";
+    version = "4.3.0";
+    sha256 = "07pa4sx196vxkgl3csvdmw94nydlsm9ir38xxcs84qjn8cycd912";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.XPath";
+    version = "4.0.1";
+    sha256 = "0fjqgb6y66d72d5n8qq1h213d9nv2vi8mpv8p28j3m9rccmsh04m";
+  })
+
+  (fetchNuGet {
+    name = "System.Xml.XPath.XmlDocument";
+    version = "4.0.1";
+    sha256 = "0l7yljgif41iv5g56l3nxy97hzzgck2a7rhnfnljhx9b0ry41bvc";
+  })
+
+  (fetchNuGet {
+    name = "xunit";
+    version = "2.4.1";
+    sha256 = "0xf3kaywpg15flqaqfgywqyychzk15kz0kz34j21rcv78q9ywq20";
+  })
+
+  (fetchNuGet {
+    name = "xunit.abstractions";
+    version = "2.0.3";
+    sha256 = "00wl8qksgkxld76fgir3ycc5rjqv1sqds6x8yx40927q5py74gfh";
+  })
+
+  (fetchNuGet {
+    name = "xunit.analyzers";
+    version = "0.10.0";
+    sha256 = "15n02q3akyqbvkp8nq75a8rd66d4ax0rx8fhdcn8j78pi235jm7j";
+  })
+
+  (fetchNuGet {
+    name = "xunit.assert";
+    version = "2.4.1";
+    sha256 = "1imynzh80wxq2rp9sc4gxs4x1nriil88f72ilhj5q0m44qqmqpc6";
+  })
+
+  (fetchNuGet {
+    name = "xunit.core";
+    version = "2.4.1";
+    sha256 = "1nnb3j4kzmycaw1g76ii4rfqkvg6l8gqh18falwp8g28h802019a";
+  })
+
+  (fetchNuGet {
+    name = "xunit.extensibility.core";
+    version = "2.4.1";
+    sha256 = "103qsijmnip2pnbhciqyk2jyhdm6snindg5z2s57kqf5pcx9a050";
+  })
+
+  (fetchNuGet {
+    name = "xunit.extensibility.execution";
+    version = "2.4.1";
+    sha256 = "1pbilxh1gp2ywm5idfl0klhl4gb16j86ib4x83p8raql1dv88qia";
+  })
+
+  (fetchNuGet {
+    name = "xunit.runner.visualstudio";
+    version = "2.4.1";
+    sha256 = "0fln5pk18z98gp0zfshy1p9h6r9wc55nyqhap34k89yran646vhn";
+  })
+
+  (fetchNuGet {
+    name = "YamlDotNet.Signed";
+    version = "5.3.0";
+    sha256 = "1gnp5aa2zzg7v61bbn2ra1npy0p07szp5w8vqk44fdj3fcvrdxib";
+  })
+
+]
diff --git a/pkgs/development/tools/continuous-integration/github-runner/patches/dir-proj.patch b/pkgs/development/tools/continuous-integration/github-runner/patches/dir-proj.patch
new file mode 100644
index 00000000000..9a75b12544a
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/patches/dir-proj.patch
@@ -0,0 +1,53 @@
+From 4267ee7fa5169b4fd5ce732118769e559806a390 Mon Sep 17 00:00:00 2001
+From: Vincent Haupert <mail@vincent-haupert.de>
+Date: Sat, 13 Mar 2021 21:52:03 +0100
+Subject: [PATCH] Patch dir.proj
+
+Don't execute Git for GitInfoCommitHash property
+Don't restore for build target
+Don't restore for test target
+---
+ src/dir.proj | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+diff --git a/src/dir.proj b/src/dir.proj
+index 1c91e0c..8b27d3f 100644
+--- a/src/dir.proj
++++ b/src/dir.proj
+@@ -2,9 +2,6 @@
+ <Project ToolsVersion="14.0" DefaultTargets="Build" 
+     xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+     <Target Name="GenerateConstant">
+-        <Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true">
+-            <Output TaskParameter="ConsoleOutput" PropertyName="GitInfoCommitHash" />
+-        </Exec>
+         <Message Text="Building $(Product): $(GitInfoCommitHash) --- $(PackageRuntime)" Importance="high"/>
+ 
+         <ItemGroup>
+@@ -39,14 +36,13 @@
+     </ItemGroup>
+ 
+     <Target Name="Build" DependsOnTargets="GenerateConstant">
+-        <MSBuild Targets="Restore" Projects="@(ProjectFiles)" StopOnFirstFailure="true" />
+         <MSBuild Targets="Publish" Projects="@(ProjectFiles)" BuildInParallel="false" StopOnFirstFailure="true" Properties="Configuration=$(BUILDCONFIG);PackageRuntime=$(PackageRuntime);Version=$(RunnerVersion);RuntimeIdentifier=$(PackageRuntime);PublishDir=$(MSBuildProjectDirectory)/../_layout/bin" />
+         <Exec Command="%22$(DesktopMSBuild)%22 Runner.Service/Windows/RunnerService.csproj /p:Configuration=$(BUILDCONFIG) /p:OutputPath=%22$(MSBuildProjectDirectory)/../_layout/bin%22" ConsoleToMSBuild="true" Condition="'$(PackageRuntime)' == 'win-x64' Or '$(PackageRuntime)' == 'win-x86'" />
+     </Target>
+ 
+     <Target Name="Test" DependsOnTargets="GenerateConstant">
+-        <Exec Command="dotnet build Test/Test.csproj -c $(BUILDCONFIG) /p:PackageRuntime=$(PackageRuntime)" ConsoleToMSBuild="true" />
+-        <Exec Command="dotnet test Test/Test.csproj --no-build --logger:trx" ConsoleToMSBuild="true" />
++        <Exec Command="dotnet build Test/Test.csproj --no-restore -c $(BUILDCONFIG) /p:PackageRuntime=$(PackageRuntime)" ConsoleToMSBuild="true" />
++        <Exec Command="dotnet test Test/Test.csproj --no-restore --no-build --logger:trx" ConsoleToMSBuild="true" />
+     </Target>
+ 
+     <Target Name="Layout" DependsOnTargets="Clean;Build">
+@@ -84,4 +80,4 @@
+         <RemoveDir Directories="Test/bin" />
+         <RemoveDir Directories="Test/obj" />
+     </Target>
+-</Project>
+\ No newline at end of file
++</Project>
+-- 
+2.30.1
+
diff --git a/pkgs/development/tools/continuous-integration/github-runner/patches/dont-install-systemd-service.patch b/pkgs/development/tools/continuous-integration/github-runner/patches/dont-install-systemd-service.patch
new file mode 100644
index 00000000000..6279a4ecb4b
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/patches/dont-install-systemd-service.patch
@@ -0,0 +1,15 @@
+diff --git a/src/Runner.Listener/Configuration/ConfigurationManager.cs b/src/Runner.Listener/Configuration/ConfigurationManager.cs
+index 8d08b06..bdfa3a2 100644
+--- a/src/Runner.Listener/Configuration/ConfigurationManager.cs
++++ b/src/Runner.Listener/Configuration/ConfigurationManager.cs
+@@ -320,10 +320,6 @@ namespace GitHub.Runner.Listener.Configuration
+                 serviceControlManager.ConfigureService(runnerSettings, command);
+             }
+ 
+-#elif OS_LINUX || OS_OSX
+-            // generate service config script for OSX and Linux, GenerateScripts() will no-opt on windows.
+-            var serviceControlManager = HostContext.GetService<ILinuxServiceControlManager>();
+-            serviceControlManager.GenerateScripts(runnerSettings);
+ #endif
+         }
+ 
diff --git a/pkgs/development/tools/continuous-integration/github-runner/patches/host-context-dirs.patch b/pkgs/development/tools/continuous-integration/github-runner/patches/host-context-dirs.patch
new file mode 100644
index 00000000000..662ad9676da
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/patches/host-context-dirs.patch
@@ -0,0 +1,20 @@
+diff --git a/src/Runner.Common/HostContext.cs b/src/Runner.Common/HostContext.cs
+index d4ea48c..2ec8455 100644
+--- a/src/Runner.Common/HostContext.cs
++++ b/src/Runner.Common/HostContext.cs
+@@ -220,12 +220,13 @@ namespace GitHub.Runner.Common
+ 
+                 case WellKnownDirectory.Externals:
+                     path = Path.Combine(
+-                        GetDirectory(WellKnownDirectory.Root),
++                        new DirectoryInfo(GetDirectory(WellKnownDirectory.Bin)).Parent.FullName,
+                         Constants.Path.ExternalsDirectory);
+                     break;
+ 
+                 case WellKnownDirectory.Root:
+-                    path = new DirectoryInfo(GetDirectory(WellKnownDirectory.Bin)).Parent.FullName;
++                    path = Environment.GetEnvironmentVariable("RUNNER_ROOT")
++                                ?? new DirectoryInfo(GetDirectory(WellKnownDirectory.Bin)).Parent.FullName;
+                     break;
+ 
+                 case WellKnownDirectory.Temp:
diff --git a/pkgs/development/tools/continuous-integration/github-runner/patches/ignore-self-update.patch b/pkgs/development/tools/continuous-integration/github-runner/patches/ignore-self-update.patch
new file mode 100644
index 00000000000..b505bbc7503
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/patches/ignore-self-update.patch
@@ -0,0 +1,24 @@
+diff --git a/src/Runner.Listener/Runner.cs b/src/Runner.Listener/Runner.cs
+index 68b0b4e..5da21fe 100644
+--- a/src/Runner.Listener/Runner.cs
++++ b/src/Runner.Listener/Runner.cs
+@@ -391,18 +391,7 @@ namespace GitHub.Runner.Listener
+                             HostContext.WritePerfCounter($"MessageReceived_{message.MessageType}");
+                             if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
+                             {
+-                                if (autoUpdateInProgress == false)
+-                                {
+-                                    autoUpdateInProgress = true;
+-                                    var runnerUpdateMessage = JsonUtility.FromString<AgentRefreshMessage>(message.Body);
+-                                    var selfUpdater = HostContext.GetService<ISelfUpdater>();
+-                                    selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, !runOnce && HostContext.StartupType != StartupType.Service, HostContext.RunnerShutdownToken);
+-                                    Trace.Info("Refresh message received, kick-off selfupdate background process.");
+-                                }
+-                                else
+-                                {
+-                                    Trace.Info("Refresh message received, skip autoupdate since a previous autoupdate is already running.");
+-                                }
++                                Trace.Info("Ignoring received refresh message (would trigger self-update).");
+                             }
+                             else if (string.Equals(message.MessageType, JobRequestMessageTypes.PipelineAgentJobRequest, StringComparison.OrdinalIgnoreCase))
+                             {
diff --git a/pkgs/development/tools/continuous-integration/github-runner/patches/use-get-directory-for-diag.patch b/pkgs/development/tools/continuous-integration/github-runner/patches/use-get-directory-for-diag.patch
new file mode 100644
index 00000000000..ff91bcff158
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/github-runner/patches/use-get-directory-for-diag.patch
@@ -0,0 +1,25 @@
+diff --git a/src/Runner.Common/HostContext.cs b/src/Runner.Common/HostContext.cs
+index d4ea48c..15c1800 100644
+--- a/src/Runner.Common/HostContext.cs
++++ b/src/Runner.Common/HostContext.cs
+@@ -109,7 +109,7 @@ namespace GitHub.Runner.Common
+                 }
+ 
+                 // this should give us _diag folder under runner root directory
+-                string diagLogDirectory = Path.Combine(new DirectoryInfo(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)).Parent.FullName, Constants.Path.DiagDirectory);
++                string diagLogDirectory = GetDirectory(WellKnownDirectory.Diag);
+                 _traceManager = new TraceManager(new HostTraceListener(diagLogDirectory, hostType, logPageSize, logRetentionDays), this.SecretMasker);
+             }
+             else
+@@ -272,7 +272,10 @@ namespace GitHub.Runner.Common
+                     throw new NotSupportedException($"Unexpected well known directory: '{directory}'");
+             }
+ 
+-            _trace.Info($"Well known directory '{directory}': '{path}'");
++            if (_trace != null)
++            {
++                _trace.Info($"Well known directory '{directory}': '{path}'");
++            }
+             return path;
+         }
+ 
diff --git a/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix b/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix
index 890c561cadc..ff5799df4ac 100644
--- a/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix
+++ b/pkgs/development/tools/continuous-integration/gitlab-runner/default.nix
@@ -1,16 +1,16 @@
 { lib, buildGoPackage, fetchFromGitLab, fetchurl }:
 
 let
-  version = "13.3.0";
+  version = "14.1.0";
   # Gitlab runner embeds some docker images these are prebuilt for arm and x86_64
   docker_x86_64 = fetchurl {
-    url = "https://gitlab-runner-downloads.s3.amazonaws.com/v${version}/helper-images/prebuilt-x86_64.tar.xz";
-    sha256 = "0pi33mgcmw1n5myyczg1nx1s8rqx6b4vr7s09jsjd6z81irhc87c";
+    url = "https://gitlab-runner-downloads.s3.amazonaws.com/v${version}/binaries/gitlab-runner-helper/gitlab-runner-helper.x86_64";
+    sha256 = "09p0biig07plf9qiwpsdllh6midi8kzpzk2s71rmms491g4634k2";
   };
 
   docker_arm = fetchurl {
-    url = "https://gitlab-runner-downloads.s3.amazonaws.com/v${version}/helper-images/prebuilt-arm.tar.xz";
-    sha256 = "071bsfnkasdj7lfidfhwcklycan2zpyalqia3rmbwd93m5rwqgrd";
+    url = "https://gitlab-runner-downloads.s3.amazonaws.com/v${version}/binaries/gitlab-runner-helper/gitlab-runner-helper.arm";
+    sha256 = "0z5q5y9lsznwglpg7sd5af51v9640m85v4x4dcj5j37w24bi4wq0";
   };
 in
 buildGoPackage rec {
@@ -30,7 +30,7 @@ buildGoPackage rec {
     owner = "gitlab-org";
     repo = "gitlab-runner";
     rev = "v${version}";
-    sha256 = "0idbj8jmycrh61bvkzjl5xffhvv9jnjqv9q0ivl457sn2jii9bhi";
+    sha256 = "1v2yxs92awwn4m6hq6wc53whfmk6fr4l6j87amcbdzcm4ikzxcvk";
   };
 
   patches = [ ./fix-shell-path.patch ];
diff --git a/pkgs/development/tools/continuous-integration/gocd-agent/default.nix b/pkgs/development/tools/continuous-integration/gocd-agent/default.nix
index 7cefd896f48..3041a031737 100644
--- a/pkgs/development/tools/continuous-integration/gocd-agent/default.nix
+++ b/pkgs/development/tools/continuous-integration/gocd-agent/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, fetchurl, unzip }:
+{ lib, stdenv, fetchurl, unzip }:
 
 stdenv.mkDerivation rec {
   name = "gocd-agent-${version}-${rev}";
@@ -9,7 +9,7 @@ stdenv.mkDerivation rec {
     url = "https://download.go.cd/binaries/${version}-${rev}/generic/go-agent-${version}-${rev}.zip";
     sha256 = "1nirdv82i8x4s1dyb0rmxldh8avappd4g3mbbl6xp7r7s0drcprp";
   };
-  meta = with stdenv.lib; {
+  meta = with lib; {
     description = "A continuous delivery server specializing in advanced workflow modeling and visualization";
     homepage = "http://www.go.cd";
     license = licenses.asl20;
@@ -17,7 +17,7 @@ stdenv.mkDerivation rec {
     maintainers = with maintainers; [ grahamc swarren83 ];
   };
 
-  buildInputs = [ unzip ];
+  nativeBuildInputs = [ unzip ];
 
   buildCommand = "
     unzip $src -d $out
diff --git a/pkgs/development/tools/continuous-integration/gocd-server/default.nix b/pkgs/development/tools/continuous-integration/gocd-server/default.nix
index d23bc9d8d8e..4b3f61cf4b4 100644
--- a/pkgs/development/tools/continuous-integration/gocd-server/default.nix
+++ b/pkgs/development/tools/continuous-integration/gocd-server/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, fetchurl, unzip }:
+{ lib, stdenv, fetchurl, unzip }:
 
 stdenv.mkDerivation rec {
   name = "gocd-server-${version}-${rev}";
@@ -10,7 +10,7 @@ stdenv.mkDerivation rec {
     sha256 = "0c30qzd6awlw0zx91rk6na0mmgykqkgrw9ychx18ivjwma0hr0sc";
   };
 
-  meta = with stdenv.lib; {
+  meta = with lib; {
     description = "A continuous delivery server specializing in advanced workflow modeling and visualization";
     homepage = "http://www.go.cd";
     license = licenses.asl20;
@@ -18,7 +18,7 @@ stdenv.mkDerivation rec {
     maintainers = with maintainers; [ grahamc swarren83 ];
   };
 
-  buildInputs = [ unzip ];
+  nativeBuildInputs = [ unzip ];
 
   buildCommand = "
     unzip $src -d $out
diff --git a/pkgs/development/tools/continuous-integration/hci/default.nix b/pkgs/development/tools/continuous-integration/hci/default.nix
new file mode 100644
index 00000000000..dfca0c4d388
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/hci/default.nix
@@ -0,0 +1,23 @@
+{ haskell, haskellPackages, lib, makeWrapper, runc, stdenv }:
+let
+  inherit (haskell.lib) overrideCabal addBuildDepends;
+  inherit (lib) makeBinPath;
+  bundledBins = lib.optional stdenv.isLinux runc;
+
+  pkg =
+    # justStaticExecutables is needed due to https://github.com/NixOS/nix/issues/2990
+    overrideCabal
+      (addBuildDepends (haskell.lib.justStaticExecutables haskellPackages.hercules-ci-cli) [ makeWrapper ])
+      (o: {
+        postInstall = ''
+          ${o.postInstall or ""}
+          mkdir -p $out/libexec
+          mv $out/bin/hci $out/libexec
+          makeWrapper $out/libexec/hci $out/bin/hci --prefix PATH : ${makeBinPath bundledBins}
+        '';
+      });
+in pkg // {
+    meta = pkg.meta // {
+      position = toString ./default.nix + ":1";
+    };
+  }
diff --git a/pkgs/development/tools/continuous-integration/hercules-ci-agent/default.nix b/pkgs/development/tools/continuous-integration/hercules-ci-agent/default.nix
index c8316f4bb57..bc464c2024e 100644
--- a/pkgs/development/tools/continuous-integration/hercules-ci-agent/default.nix
+++ b/pkgs/development/tools/continuous-integration/hercules-ci-agent/default.nix
@@ -1,7 +1,9 @@
-{ gnutar, gzip, git, haskell, haskellPackages, lib, makeWrapper }:
+{ gnutar, gzip, git, haskell, haskellPackages, lib, makeWrapper, nixos, runc, stdenv }:
 let
   inherit (haskell.lib) overrideCabal addBuildDepends;
   inherit (lib) makeBinPath;
+  bundledBins = [ gnutar gzip git ] ++ lib.optional stdenv.isLinux runc;
+
   pkg =
     # justStaticExecutables is needed due to https://github.com/NixOS/nix/issues/2990
     overrideCabal
@@ -11,11 +13,19 @@ let
           ${o.postInstall or ""}
           mkdir -p $out/libexec
           mv $out/bin/hercules-ci-agent $out/libexec
-          makeWrapper $out/libexec/hercules-ci-agent $out/bin/hercules-ci-agent --prefix PATH : ${makeBinPath [ gnutar gzip git ]}
+          makeWrapper $out/libexec/hercules-ci-agent $out/bin/hercules-ci-agent --prefix PATH : ${makeBinPath bundledBins}
         '';
       });
-in pkg // {
-    meta = pkg.meta // {
+in pkg.overrideAttrs (o: {
+    meta = o.meta // {
       position = toString ./default.nix + ":1";
     };
-  }
+    passthru = o.passthru // {
+      # Does not test the package, but evaluation of the related NixOS module.
+      tests.nixos-minimal-config = nixos {
+        boot.loader.grub.enable = false;
+        fileSystems."/".device = "bogus";
+        services.hercules-ci-agent.enable = true;
+      };
+    };
+  })
diff --git a/pkgs/development/tools/continuous-integration/jenkins/default.nix b/pkgs/development/tools/continuous-integration/jenkins/default.nix
index 8723ca2b443..88156f815ab 100644
--- a/pkgs/development/tools/continuous-integration/jenkins/default.nix
+++ b/pkgs/development/tools/continuous-integration/jenkins/default.nix
@@ -1,24 +1,74 @@
-{ stdenv, fetchurl }:
+{ lib, stdenv, fetchurl, common-updater-scripts, coreutils, git, gnused, makeWrapper, nix
+, nixfmt, openjdk, writeScript, nixosTests, jq, cacert, curl }:
 
 stdenv.mkDerivation rec {
   pname = "jenkins";
-  version = "2.235.5";
+  version = "2.289.2";
 
   src = fetchurl {
     url = "http://mirrors.jenkins.io/war-stable/${version}/jenkins.war";
-    sha256 = "02zpnqhdkhg8p8cddkqklgihjpwcbnybkcw5rspipz6kiyqzg1n7";
+    sha256 = "0413ymfrb00ifxl8ww8nn8y4k07jhgsaxaw2h0qnfh9s6yxifpbf";
   };
 
+  nativeBuildInputs = [ makeWrapper ];
+
   buildCommand = ''
-    mkdir -p "$out/webapps"
+    mkdir -p "$out/bin" "$out/share" "$out/webapps"
+
     cp "$src" "$out/webapps/jenkins.war"
+
+    # Create the `jenkins-cli` command.
+    ${openjdk}/bin/jar -xf "$src" WEB-INF/lib/cli-${version}.jar \
+      && mv WEB-INF/lib/cli-${version}.jar "$out/share/jenkins-cli.jar"
+
+    makeWrapper "${openjdk}/bin/java" "$out/bin/jenkins-cli" \
+      --add-flags "-jar $out/share/jenkins-cli.jar"
   '';
 
-  meta = with stdenv.lib; {
+  passthru = {
+    tests = { inherit (nixosTests) jenkins; };
+
+    updateScript = writeScript "update.sh" ''
+      #!${stdenv.shell}
+      set -o errexit
+      PATH=${
+        lib.makeBinPath [
+          cacert
+          common-updater-scripts
+          coreutils
+          curl
+          git
+          gnused
+          jq
+          nix
+          nixfmt
+        ]
+      }
+
+      core_json="$(curl -s --fail --location https://updates.jenkins.io/stable/update-center.actual.json | jq .core)"
+      oldVersion=$(nix-instantiate --eval -E "with import ./. {}; lib.getVersion jenkins" | tr -d '"')
+
+      version="$(jq -r .version <<<$core_json)"
+      sha256="$(jq -r .sha256 <<<$core_json)"
+      hash="$(nix-hash --type sha256 --to-base32 "$sha256")"
+      url="$(jq -r .url <<<$core_json)"
+
+      if [ ! "$oldVersion" = "$version" ]; then
+        update-source-version jenkins "$version" "$hash" "$url"
+        nixpkgs="$(git rev-parse --show-toplevel)"
+        default_nix="$nixpkgs/pkgs/development/tools/continuous-integration/jenkins/default.nix"
+        nixfmt "$default_nix"
+      else
+        echo "jenkins is already up-to-date"
+      fi
+    '';
+  };
+
+  meta = with lib; {
     description = "An extendable open source continuous integration server";
     homepage = "https://jenkins-ci.org";
     license = licenses.mit;
     platforms = platforms.all;
-    maintainers = with maintainers; [ coconnor fpletz earldouglas ];
+    maintainers = with maintainers; [ coconnor fpletz earldouglas nequissimus ];
   };
 }
diff --git a/pkgs/development/tools/continuous-integration/jenkins/update.sh b/pkgs/development/tools/continuous-integration/jenkins/update.sh
deleted file mode 100755
index 4f2f6527ecc..00000000000
--- a/pkgs/development/tools/continuous-integration/jenkins/update.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env nix-shell
-#!nix-shell -i bash -p curl common-updater-scripts jq
-
-set -eu -o pipefail
-
-core_json="$(curl -s --fail --location https://updates.jenkins.io/stable/update-center.actual.json | jq .core)"
-oldVersion=$(nix-instantiate --eval -E "with import ./. {}; lib.getVersion jenkins" | tr -d '"')
-
-version="$(jq -r .version <<<$core_json)"
-sha256="$(jq -r .sha256 <<<$core_json)"
-hash="$(nix-hash --type sha256 --to-base32 "$sha256")"
-url="$(jq -r .url <<<$core_json)"
-
-if [ ! "${oldVersion}" = "${version}" ]; then
-  update-source-version jenkins "$version" "$hash" "$url"
-  nixpkgs="$(git rev-parse --show-toplevel)"
-  default_nix="$nixpkgs/pkgs/development/tools/continuous-integration/jenkins/default.nix"
-  git add "${default_nix}"
-  git commit -m "jenkins: ${oldVersion} -> ${version}"
-else
-  echo "jenkins is already up-to-date"
-fi
diff --git a/pkgs/development/tools/continuous-integration/laminar/default.nix b/pkgs/development/tools/continuous-integration/laminar/default.nix
new file mode 100644
index 00000000000..8d06ff94a03
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/laminar/default.nix
@@ -0,0 +1,65 @@
+{ stdenv
+, lib
+, fetchurl
+, cmake
+, capnproto
+, sqlite
+, boost
+, zlib
+, rapidjson
+, pandoc
+}:
+let
+  js.vue = fetchurl {
+    url = "https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js";
+    sha256 = "1hm5kci2g6n5ikrvp1kpkkdzimjgylv1xicg2vnkbvd9rb56qa99";
+  };
+  js.vue-router = fetchurl {
+    url =
+      "https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.4.8/vue-router.min.js";
+    sha256 = "0418waib896ywwxkxliip75zp94k3s9wld51afrqrcq70axld0c9";
+  };
+  js.ansi_up = fetchurl {
+    url = "https://raw.githubusercontent.com/drudru/ansi_up/v1.3.0/ansi_up.js";
+    sha256 = "1993dywxqi2ylnxybwk7m0s0bg2bq7kfllpyr0s8ck6chd0p8i6r";
+  };
+  js.Chart = fetchurl {
+    url = "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js";
+    sha256 = "1jh4h12qchsba03dx03mrvs4r8g9qfjn56xm56jqzgqf7r209xq9";
+  };
+in stdenv.mkDerivation rec {
+  pname = "laminar";
+  version = "1.0";
+  src = fetchurl {
+    url = "https://github.com/ohwgiles/laminar/archive/${version}.tar.gz";
+    sha256 = "11m6h3rdmj2rsmsryy7r40gqccj4gg1cnqwy6blscs87gx4s423g";
+  };
+  patches = [ ./patches/no-network.patch ];
+  nativeBuildInputs = [ cmake pandoc ];
+  buildInputs = [ capnproto sqlite boost zlib rapidjson ];
+  preBuild = ''
+    mkdir -p js css
+    cp  ${js.vue}         js/vue.min.js
+    cp  ${js.vue-router}  js/vue-router.min.js
+    cp  ${js.ansi_up}     js/ansi_up.js
+    cp  ${js.Chart}       js/Chart.min.js
+  '';
+
+  postInstall = ''
+    mv $out/usr/share/* $out/share/
+    rmdir $out/usr/share $out/usr
+
+    mkdir -p $out/share/doc/laminar
+    pandoc -s ../UserManual.md -o $out/share/doc/laminar/UserManual.html
+    rm -rf $out/lib # remove upstream systemd units
+    rm -rf $out/etc # remove upstream config file
+  '';
+
+  meta = with lib; {
+    description = "Lightweight and modular continuous integration service";
+    homepage = "https://laminar.ohwg.net";
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+    maintainers = with maintainers; [ kaction maralorn ];
+  };
+}
diff --git a/pkgs/development/tools/continuous-integration/laminar/patches/no-network.patch b/pkgs/development/tools/continuous-integration/laminar/patches/no-network.patch
new file mode 100644
index 00000000000..355baeb837a
--- /dev/null
+++ b/pkgs/development/tools/continuous-integration/laminar/patches/no-network.patch
@@ -0,0 +1,41 @@
+Build system that downloads stuff from network is bad. Build system that
+does so unconditionally is twice as bad.
+
+Required files are downloaded as separate fixed-output derivations and
+put into correct location before build phase starts.
+
+--- laminar-0.8/CMakeLists.txt
++++ laminar-0.8-new/CMakeLists.txt
+@@ -82,15 +82,6 @@
+     COMMAND sh -c '( echo -n "\\#define INDEX_HTML_UNCOMPRESSED_SIZE " && wc -c < "${CMAKE_SOURCE_DIR}/src/resources/index.html" ) > index_html_size.h'
+     DEPENDS src/resources/index.html)
+ 
+-# Download 3rd-party frontend JS libs...
+-file(DOWNLOAD https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js
+-	js/vue.min.js EXPECTED_MD5 fb192338844efe86ec759a40152fcb8e)
+-file(DOWNLOAD https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.4.8/vue-router.min.js
+-	js/vue-router.min.js EXPECTED_MD5 5f51d4dbbf68fd6725956a5a2b865f3b)
+-file(DOWNLOAD https://raw.githubusercontent.com/drudru/ansi_up/v1.3.0/ansi_up.js
+-        js/ansi_up.js EXPECTED_MD5 158566dc1ff8f2804de972f7e841e2f6)
+-file(DOWNLOAD https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js
+-        js/Chart.min.js EXPECTED_MD5 f6c8efa65711e0cbbc99ba72997ecd0e)
+ # ...and compile them
+ generate_compressed_bins(${CMAKE_BINARY_DIR} js/vue-router.min.js js/vue.min.js
+     js/ansi_up.js js/Chart.min.js)
+@@ -141,12 +132,12 @@
+     target_link_libraries(laminar-tests ${GTEST_LIBRARY} capnp-rpc capnp kj-http kj-async kj pthread sqlite3 z)
+ endif()
+ 
+-set(SYSTEMD_UNITDIR /lib/systemd/system CACHE PATH "Path to systemd unit files")
+-set(BASH_COMPLETIONS_DIR /usr/share/bash-completion/completions CACHE PATH "Path to bash completions directory")
+-set(ZSH_COMPLETIONS_DIR /usr/share/zsh/site-functions CACHE PATH "Path to zsh completions directory")
++set(SYSTEMD_UNITDIR lib/systemd/system CACHE PATH "Path to systemd unit files")
++set(BASH_COMPLETIONS_DIR usr/share/bash-completion/completions CACHE PATH "Path to bash completions directory")
++set(ZSH_COMPLETIONS_DIR usr/share/zsh/site-functions CACHE PATH "Path to zsh completions directory")
+ install(TARGETS laminard RUNTIME DESTINATION sbin)
+ install(TARGETS laminarc RUNTIME DESTINATION bin)
+-install(FILES etc/laminar.conf DESTINATION /etc)
++install(FILES etc/laminar.conf DESTINATION etc)
+ install(FILES etc/laminarc-completion.bash DESTINATION ${BASH_COMPLETIONS_DIR} RENAME laminarc)
+ install(FILES etc/laminarc-completion.zsh DESTINATION ${ZSH_COMPLETIONS_DIR} RENAME _laminarc)
+