git.delta.rocks / jrsonnet / refs/commits / e468723051e7

difftreelog

ci post results as a comment

lysuzqzyYaroslav Bolyukin2026-05-07parent: #b842704.patch.diff
in: master

2 files changed

modifiedflake.nixdiffbeforeafterboth
--- a/flake.nix
+++ b/flake.nix
@@ -39,12 +39,104 @@
         mkForce
         optionals
         optionalAttrs
+        concatMapStringsSep
         ;
+      rel = system: inputs.self.legacyPackages.${system}.release;
+      releaseSections = [
+        {
+          name = "Linux (glibc)";
+          artifacts = [
+            {
+              label = "jrsonnet-x86_64-linux-glibc";
+              drv = (rel "x86_64-linux").jrsonnet-linux-glibc;
+            }
+            {
+              label = "jrsonnet-experimental-x86_64-linux-glibc";
+              drv = (rel "x86_64-linux").jrsonnet-experimental-linux-glibc;
+            }
+            {
+              label = "jrsonnet-aarch64-linux-glibc";
+              drv = (rel "aarch64-linux").jrsonnet-linux-glibc;
+            }
+            {
+              label = "jrsonnet-experimental-aarch64-linux-glibc";
+              drv = (rel "aarch64-linux").jrsonnet-experimental-linux-glibc;
+            }
+            {
+              label = "jrsonnet-i686-linux-glibc";
+              drv = (rel "i686-linux").jrsonnet-linux-glibc;
+            }
+            {
+              label = "jrsonnet-experimental-i686-linux-glibc";
+              drv = (rel "i686-linux").jrsonnet-experimental-linux-glibc;
+            }
+            {
+              label = "jrsonnet-armv7l-linux-glibc";
+              drv = (rel "armv7l-linux").jrsonnet-linux-glibc;
+            }
+            {
+              label = "jrsonnet-experimental-armv7l-linux-glibc";
+              drv = (rel "armv7l-linux").jrsonnet-experimental-linux-glibc;
+            }
+          ];
+        }
+        {
+          name = "Linux (musl)";
+          artifacts = [
+            {
+              label = "jrsonnet-x86_64-linux-musl";
+              drv = (rel "x86_64-linux").jrsonnet-linux-musl;
+            }
+            {
+              label = "jrsonnet-experimental-x86_64-linux-musl";
+              drv = (rel "x86_64-linux").jrsonnet-experimental-linux-musl;
+            }
+            {
+              label = "jrsonnet-aarch64-linux-musl";
+              drv = (rel "aarch64-linux").jrsonnet-linux-musl;
+            }
+            {
+              label = "jrsonnet-experimental-aarch64-linux-musl";
+              drv = (rel "aarch64-linux").jrsonnet-experimental-linux-musl;
+            }
+          ];
+        }
+        {
+          name = "macOS";
+          artifacts = [
+            {
+              label = "jrsonnet-aarch64-darwin";
+              drv = (rel "aarch64-linux").jrsonnet-darwin;
+            }
+            {
+              label = "jrsonnet-experimental-aarch64-darwin";
+              drv = (rel "aarch64-linux").jrsonnet-experimental-darwin;
+            }
+          ];
+        }
+        {
+          name = "Windows";
+          artifacts = [
+            {
+              label = "jrsonnet-x86_64-windows";
+              drv = (rel "x86_64-linux").jrsonnet-windows;
+              windows = true;
+            }
+            {
+              label = "jrsonnet-experimental-x86_64-windows";
+              drv = (rel "x86_64-linux").jrsonnet-experimental-windows;
+              windows = true;
+            }
+          ];
+        }
+      ];
+      releaseArtifacts = builtins.concatMap (s: s.artifacts) releaseSections;
     in
     inputs.flake-parts.lib.mkFlake { inherit inputs; } {
       imports = [
         inputs.shelly.flakeModule
         inputs.hercules-ci-effects.flakeModule
+        ./nix/post-comment.nix
       ];
       systems = [
         "x86_64-linux"
@@ -310,80 +402,10 @@
               ]);
           };
         };
-      hercules-ci.github-releases.files =
-        let
-          rel = system: inputs.self.legacyPackages.${system}.release;
-          bin = drv: "${drv}/bin/jrsonnet";
-          exe = drv: "${drv}/bin/jrsonnet.exe";
-        in
-        [
-          {
-            label = "jrsonnet-x86_64-linux-musl";
-            path = bin (rel "x86_64-linux").jrsonnet-linux-musl;
-          }
-          {
-            label = "jrsonnet-experimental-x86_64-linux-musl";
-            path = bin (rel "x86_64-linux").jrsonnet-experimental-linux-musl;
-          }
-          {
-            label = "jrsonnet-aarch64-darwin";
-            path = bin (rel "aarch64-linux").jrsonnet-darwin;
-          }
-          {
-            label = "jrsonnet-experimental-aarch64-darwin";
-            path = bin (rel "aarch64-linux").jrsonnet-experimental-darwin;
-          }
-          {
-            label = "jrsonnet-x86_64-windows.exe";
-            path = exe (rel "x86_64-linux").jrsonnet-windows;
-          }
-          {
-            label = "jrsonnet-experimental-x86_64-windows.exe";
-            path = exe (rel "x86_64-linux").jrsonnet-experimental-windows;
-          }
-
-          {
-            label = "jrsonnet-aarch64-linux-musl";
-            path = bin (rel "aarch64-linux").jrsonnet-linux-musl;
-          }
-          {
-            label = "jrsonnet-experimental-aarch64-linux-musl";
-            path = bin (rel "aarch64-linux").jrsonnet-experimental-linux-musl;
-          }
-
-          {
-            label = "jrsonnet-x86_64-linux-glibc";
-            path = bin (rel "x86_64-linux").jrsonnet-linux-glibc;
-          }
-          {
-            label = "jrsonnet-experimental-x86_64-linux-glibc";
-            path = bin (rel "x86_64-linux").jrsonnet-experimental-linux-glibc;
-          }
-          {
-            label = "jrsonnet-aarch64-linux-glibc";
-            path = bin (rel "aarch64-linux").jrsonnet-linux-glibc;
-          }
-          {
-            label = "jrsonnet-experimental-aarch64-linux-glibc";
-            path = bin (rel "aarch64-linux").jrsonnet-experimental-linux-glibc;
-          }
-          {
-            label = "jrsonnet-i686-linux-glibc";
-            path = bin (rel "i686-linux").jrsonnet-linux-glibc;
-          }
-          {
-            label = "jrsonnet-experimental-i686-linux-glibc";
-            path = bin (rel "i686-linux").jrsonnet-experimental-linux-glibc;
-          }
-          {
-            label = "jrsonnet-armv7l-linux-glibc";
-            path = bin (rel "armv7l-linux").jrsonnet-linux-glibc;
-          }
-          {
-            label = "jrsonnet-experimental-armv7l-linux-glibc";
-            path = bin (rel "armv7l-linux").jrsonnet-experimental-linux-glibc;
-          }
-        ];
+      hercules-ci.github-releases.files = map (a: {
+        label = a.label + (if a.windows or false then ".exe" else "");
+        path = "${a.drv}/bin/jrsonnet${if a.windows or false then ".exe" else ""}";
+      }) releaseArtifacts;
       hercules-ci.cargo-publish = {
         enable = true;
         secretName = "crates-io";
@@ -398,6 +420,30 @@
           dayOfWeek = [ "Sat" ];
         };
       };
+      hercules-ci.post-comment = {
+        enable = true;
+        caches = [ "jrsonnet.cachix.org" ];
+        script =
+          let
+            benchmarks = inputs.self.legacyPackages.x86_64-linux.benchmarks.default;
+            renderSection = s: ''
+              echo
+              echo "### ${s.name}"
+              echo
+              ${concatMapStringsSep "\n" (a: ''echo "- [${a.label}]($(nixTar ${a.drv}))"'') s.artifacts}
+            '';
+          in
+          ''
+            {
+              echo "## Benchmark results"
+              echo
+              echo "[View rendered]($(nixRender ${benchmarks}))"
+              echo
+              echo "## Downloads"
+              ${concatMapStringsSep "\n" renderSection releaseSections}
+            } > $out
+          '';
+      };
       herculesCI =
         { lib, config, ... }:
         {
addednix/post-comment.nixdiffbeforeafterboth
after · nix/post-comment.nix
1{2  config,3  lib,4  withSystem,5  ...6}:7let8  inherit (lib)9    mkOption10    mkIf11    types12    concatStringsSep13    ;14  cfg = config.hercules-ci.post-comment;15in16{17  options.hercules-ci.post-comment = {18    enable = mkOption {19      type = types.bool;20      default = false;21      description = ''22        Whether to post a GitHub commit comment for every commit Hercules CI runs on.23      '';24    };25    script = mkOption {26      type = types.lines;27      description = ''28        Bash snippet that writes the comment body to `$out`. Runs as part of the effect29        (after secrets are loaded), so the helpers below are in scope:3031        - `nixTar <store-path>` — prints a signed deltarocks URL that streams the path32          as a tar.zst, realised through the configured caches.33        - `nixRender <store-path>` — prints a signed deltarocks URL that renders the34          path's AsciiDoc content as HTML.35      '';36      example = lib.literalExpression ''37        '''38          {39            echo "Render: $(nixRender ''${benchmarks})"40            echo "Tar:    $(nixTar ''${binary})"41          } > $out42        '''43      '';44    };45    system = mkOption {46      type = types.str;47      default = "x86_64-linux";48      description = ''49        System on which the effect runs.50      '';51    };52    baseUrl = mkOption {53      type = types.str;54      default = "https://delta.rocks";55      description = ''56        Base URL of the deltarocks signing service.57      '';58    };59    caches = mkOption {60      type = types.listOf types.str;61      default = [ ];62      example = [ "jrsonnet.cachix.org" ];63      description = ''64        Cache hosts the signing service should use as substituters when realising the65        signed store path.66      '';67    };68    signSecret = mkOption {69      type = types.str;70      default = "deltarocks-nix-sign";71      description = ''72        Name of the Hercules CI agent secret that holds the deltarocks signing key.73        Its `data` must have a field named `ogSecret`.74      '';75    };76  };7778  config = mkIf cfg.enable {79    herculesCI =80      { config, ... }:81      {82        onPush.default.outputs.effects.post-comment = withSystem cfg.system (83          { pkgs, hci-effects, ... }:84          hci-effects.mkEffect {85            name = "post-comment";86            inputs = [ pkgs.openssl ];87            secretsMap = {88              token = {89                type = "GitToken";90              };91              ogSecret = cfg.signSecret;92            };93            owner = config.repo.owner;94            repoName = config.repo.name;95            rev = config.repo.rev;96            baseUrl = cfg.baseUrl;97            caches = concatStringsSep " " cfg.caches;98            effectScript = ''99              set -euo pipefail100101              token=$(readSecretString token .token)102              ogSecret=$(readSecretString ogSecret .ogSecret)103              read -ra cacheArr <<<"$caches"104              if [[ ''${#cacheArr[@]} -eq 0 ]]; then105                echo "hercules-ci.post-comment: at least one cache host is required" >&2106                exit 1107              fi108              sortedCaches=$(printf '%s\n' "''${cacheArr[@]}" | LC_ALL=C sort | paste -sd,)109110              _hmacHex() {111                printf '%s' "$1" \112                  | openssl dgst -sha256 -hmac "$ogSecret" -hex \113                  | sed 's/^.*= //'114              }115116              _uri() {117                jq -nj --arg s "$1" '$s|@uri'118              }119120              _signedUrl() {121                local endpoint=$1 drv=$2122                local sig123                sig=$(_hmacHex "''${endpoint}:''${sortedCaches}:''${drv}")124                local query=""125                for c in "''${cacheArr[@]}"; do126                  query+="cache=$(_uri "$c")&"127                done128                query+="drv=$(_uri "$drv")&sig=''${sig}"129                printf '%s/%s?%s' "$baseUrl" "$endpoint" "$query"130              }131132              nixTar() { _signedUrl nixTar "$1"; }133              nixRender() { _signedUrl nixRender "$1"; }134135              out=$(mktemp)136              ${cfg.script}137138              jq -n --rawfile content "$out" '{body: $content}' \139                | curl -fsSL -X POST \140                    -H "Authorization: Bearer $token" \141                    -H "Accept: application/vnd.github+json" \142                    -H "X-GitHub-Api-Version: 2022-11-28" \143                    --data-binary @- \144                    "https://api.github.com/repos/$owner/$repoName/commits/$rev/comments"145            '';146          }147        );148      };149  };150}