From 093aa61d7271e9102160b180f0b46b8ff257b610 Mon Sep 17 00:00:00 2001 From: ghostbuster91 Date: Wed, 24 Jun 2026 18:47:32 +0200 Subject: [PATCH] Migrate nix packaging to scala-cli-nix (JVM, buildCoursierApp) Replace the per-platform native-binary fetcher in flake.nix with a scala-cli-nix buildCoursierApp derivation that wraps the published org.virtuslab::cellar-cli JARs directly from Maven Central. - flake.nix: add scala-cli-nix input, replace platform table + native derivations with a single callPackage ./derivation.nix - derivation.nix: new file, buildCoursierApp with scala.lock.json - scala.lock.json: generated by scn lock-coords, pins 28 transitive JARs - ci.yml: promote nix job from flake show to nix build - release.yml: replace per-platform SRI hash sed with scn lock-coords regeneration + simplified version-only sed on flake.nix - RELEASING.md: document the new scala.lock.json step and retry behaviour Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 39 +++++------ RELEASING.md | 5 +- derivation.nix | 8 +++ flake.lock | 23 ++++++- flake.nix | 100 ++++------------------------ scala.lock.json | 121 ++++++++++++++++++++++++++++++++++ 7 files changed, 190 insertions(+), 108 deletions(-) create mode 100644 derivation.nix create mode 100644 scala.lock.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04d95e7..339a0eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,4 +48,4 @@ jobs: with: nix_path: nixpkgs=channel:nixos-unstable - - run: nix flake show + - run: nix build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 877f558..0eb6ebf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -159,34 +159,35 @@ jobs: working-directory: artifacts run: cosign sign-blob --yes checksums.txt --bundle checksums.txt.bundle - - name: Update flake.nix + - uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641 # v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - name: Regenerate scala.lock.json run: | VERSION="${{ inputs.version }}" + # Maven Central propagation can take a few minutes after publish. + for i in $(seq 1 10); do + nix run github:scala-nix/scala-cli-nix -- lock-coords \ + --dep "org.virtuslab::cellar-cli:${VERSION}" \ + --main-class cellar.cli.CellarApp && break + echo "Attempt $i failed, retrying in 30s..." + sleep 30 + done - # Convert hex sha256 to Nix SRI format (sha256-) - sri_hash() { - echo -n "$1" | xxd -r -p | base64 | tr -d '\n' | sed 's/^/sha256-/' - } - - LINUX_X86=$(sri_hash "$(grep "linux-x86_64.tar.gz" artifacts/checksums.txt | awk '{print $1}')") - LINUX_ARM=$(sri_hash "$(grep "linux-aarch64.tar.gz" artifacts/checksums.txt | awk '{print $1}')") - MACOS_ARM=$(sri_hash "$(grep "macos-arm64.tar.gz" artifacts/checksums.txt | awk '{print $1}')") - MACOS_X86=$(sri_hash "$(grep "macos-x86_64.tar.gz" artifacts/checksums.txt | awk '{print $1}')") - - sed -i "0,/version = \".*\";/s|version = \".*\";|version = \"${VERSION}\";|" flake.nix - sed -i "/linux-x86_64/{n;s|hash = \".*\";|hash = \"${LINUX_X86}\";|}" flake.nix - sed -i "/linux-aarch64/{n;s|hash = \".*\";|hash = \"${LINUX_ARM}\";|}" flake.nix - sed -i "/macos-x86_64/{n;s|hash = \".*\";|hash = \"${MACOS_X86}\";|}" flake.nix - sed -i "/macos-arm64/{n;s|hash = \".*\";|hash = \"${MACOS_ARM}\";|}" flake.nix + - name: Update flake.nix + run: | + VERSION="${{ inputs.version }}" + sed -i "s/version = \".*\";/version = \"${VERSION}\";/" flake.nix - name: Commit, tag, and push run: | VERSION="${{ inputs.version }}" git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add flake.nix - git diff --cached --quiet && echo "No flake changes" && exit 0 - git commit -m "Update flake.nix to ${VERSION}" + git add flake.nix scala.lock.json + git diff --cached --quiet && echo "No changes to commit" && exit 0 + git commit -m "Release ${VERSION}" git push origin main git tag "v${VERSION}" git push origin "v${VERSION}" diff --git a/RELEASING.md b/RELEASING.md index 18e01ae..b56dc79 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -19,12 +19,15 @@ This document describes how to cut a release, what artifacts are produced, and h - Publishes the `lib` and `cli` modules to Maven Central as `org.virtuslab:cellar-lib_3:` and `org.virtuslab:cellar-cli_3:`. - Generates a SHA256 checksum file. - Signs the checksum file using cosign keyless (OIDC). - - Updates `flake.nix` with the new version and SRI hashes, commits to `main`. + - Regenerates `scala.lock.json` from the freshly published Maven coordinates using `scn lock-coords` ([scala-cli-nix](https://github.com/scala-nix/scala-cli-nix)). + - Updates `version` in `flake.nix`, commits `flake.nix` and `scala.lock.json` to `main`. - Creates and pushes a `v` git tag. - Publishes a GitHub Release with all artifacts attached. The Maven publish waits for the native-binary and JAR builds to succeed before uploading — a Sonatype release is immutable, so we must not publish a version whose corresponding GitHub Release assets (referenced by the coursier app descriptor) failed to build. If Sonatype then rejects the upload (e.g. duplicate version, namespace mismatch, signature failure), no GitHub Release is created and no tag is pushed. +The `scala.lock.json` regeneration step retries up to 10 times with 30-second intervals to account for Maven Central propagation delay after publish. + No container images are built or published by this release flow. ## Supported platforms diff --git a/derivation.nix b/derivation.nix new file mode 100644 index 0000000..068ed00 --- /dev/null +++ b/derivation.nix @@ -0,0 +1,8 @@ +{ scala-cli-nix, version }: + +scala-cli-nix.buildCoursierApp { + pname = "cellar"; + inherit version; + lockFile = ./scala.lock.json; + mainClass = "cellar.cli.CellarApp"; +} diff --git a/flake.lock b/flake.lock index efc4226..10cb02a 100644 --- a/flake.lock +++ b/flake.lock @@ -18,7 +18,28 @@ }, "root": { "inputs": { - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "scala-cli-nix": "scala-cli-nix" + } + }, + "scala-cli-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1782242239, + "narHash": "sha256-kqPVxdAUFFFDktEcCjd+9mK1cphEKMr6PER4Z6hHVJ4=", + "owner": "scala-nix", + "repo": "scala-cli-nix", + "rev": "ee6c4edc6f1bb418df5eeafe87786410a6a400a9", + "type": "github" + }, + "original": { + "owner": "scala-nix", + "repo": "scala-cli-nix", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index da04085..9b3741d 100644 --- a/flake.nix +++ b/flake.nix @@ -1,102 +1,30 @@ { description = "Look up the public API of any JVM dependency from the terminal"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + scala-cli-nix = { + url = "github:scala-nix/scala-cli-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; - outputs = { self, nixpkgs }: + outputs = { self, nixpkgs, scala-cli-nix }: let version = "0.1.0-M9"; - - # Per-platform release artifact metadata - platforms = { - x86_64-linux = { - archive = "cellar-${version}-linux-x86_64.tar.gz"; - hash = "sha256-40JX4uEavG0VO2yMaeJFLm8rt8EQYLhs3F9dygglvxY="; - }; - aarch64-linux = { - archive = "cellar-${version}-linux-aarch64.tar.gz"; - hash = "sha256-2XxcxjpnnOsPkg9lcMBZMc/PCbovujseL9NTIkScXiY="; - }; - x86_64-darwin = { - archive = "cellar-${version}-macos-x86_64.tar.gz"; - hash = "sha256-aGv5hOQOhRycrfjp7zAO3lgveS6T0AqaKDxi74pkmE0="; - }; - aarch64-darwin = { - archive = "cellar-${version}-macos-arm64.tar.gz"; - hash = "sha256-Q23mpapwujuBtfyk/d8oFjmw8796BZP/zxg85tgpXvw="; - }; - }; - - eachSystem = nixpkgs.lib.genAttrs (builtins.attrNames platforms); + systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + eachSystem = nixpkgs.lib.genAttrs systems; in { packages = eachSystem (system: let - pkgs = nixpkgs.legacyPackages.${system}; - meta = platforms.${system}; - src = pkgs.fetchurl { - url = "https://github.com/VirtusLab/cellar/releases/download/v${version}/${meta.archive}"; - hash = meta.hash; + pkgs = import nixpkgs { + inherit system; + overlays = [ scala-cli-nix.overlays.default ]; }; in { - default = pkgs.stdenv.mkDerivation { - pname = "cellar"; - inherit version src; - - sourceRoot = "."; - - nativeBuildInputs = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ - pkgs.autoPatchelfHook - pkgs.glibc - pkgs.zlib - ]; - - unpackPhase = '' - tar xzf $src - ''; - - installPhase = '' - mkdir -p $out/bin - cp cellar $out/bin/cellar - chmod +x $out/bin/cellar - ''; - - meta = with pkgs.lib; { - description = "Look up the public API of any JVM dependency from the terminal"; - homepage = "https://github.com/VirtusLab/cellar"; - license = licenses.mpl20; - platforms = [ system ]; - mainProgram = "cellar"; - }; - }; - - # Install a locally-built binary into the nix profile. - # Usage: ./mill cli.nativeImage && nix profile install --impure .#dev - dev = let - binary = builtins.path { - path = builtins.toPath "${builtins.getEnv "PWD"}/out/cli/nativeImage.dest/native-executable"; - name = "cellar-native-executable"; - }; - in pkgs.stdenv.mkDerivation { - pname = "cellar"; - version = "dev"; - dontUnpack = true; - - installPhase = '' - mkdir -p $out/bin - cp ${binary} $out/bin/cellar - chmod +x $out/bin/cellar - ''; - - meta = with pkgs.lib; { - description = "Look up the public API of any JVM dependency from the terminal (dev build)"; - homepage = "https://github.com/VirtusLab/cellar"; - license = licenses.mpl20; - platforms = [ system ]; - mainProgram = "cellar"; - }; - }; + default = pkgs.callPackage ./derivation.nix { inherit version; }; } ); diff --git a/scala.lock.json b/scala.lock.json new file mode 100644 index 0000000..e14b882 --- /dev/null +++ b/scala.lock.json @@ -0,0 +1,121 @@ +{ + "dependencies": [ + { + "sha256": "OA529lAByYzWLHso5/iZtgkhhRmgKHkqSEviB371KnI=", + "url": "https://repo1.maven.org/maven2/ch/epfl/scala/tasty-query_3/1.7.0/tasty-query_3-1.7.0.jar" + }, + { + "sha256": "K8oTN3Jp8zpXW/adfoSvW5EkMVZgYq2EWbvtye1TnTo=", + "url": "https://repo1.maven.org/maven2/co/fs2/fs2-core_3/3.11.0/fs2-core_3-3.11.0.jar" + }, + { + "sha256": "iI6009BvNxzxSxwddOiA92nzdK4+M4KZV57WLYQIefk=", + "url": "https://repo1.maven.org/maven2/co/fs2/fs2-io_3/3.11.0/fs2-io_3-3.11.0.jar" + }, + { + "sha256": "Cdz2y1DslaqBj+7G7YhRJjHB7cQOjLpA/h924SuXYgw=", + "url": "https://repo1.maven.org/maven2/com/comcast/ip4s-core_3/3.6.0/ip4s-core_3-3.6.0.jar" + }, + { + "sha256": "MujJhkU2nQVICqSFSHwQ0zFH6FeHYKhbUgTbGLo/U10=", + "url": "https://repo1.maven.org/maven2/com/github/pureconfig/pureconfig-core_3/0.17.10/pureconfig-core_3-0.17.10.jar" + }, + { + "sha256": "moeOOawIhNMK/w692tjlk1Tv92AOgz4v5SNzlm9YEmM=", + "url": "https://repo1.maven.org/maven2/com/monovore/decline-effect_3/2.4.1/decline-effect_3-2.4.1.jar" + }, + { + "sha256": "FD3U1rV2G0CVVHHF948zcWS0u21Rlfm1fw4Ruu3TE00=", + "url": "https://repo1.maven.org/maven2/com/monovore/decline_3/2.4.1/decline_3-2.4.1.jar" + }, + { + "sha256": "SksK/7IqlXJAnTpr3pnOPyBFxVHK3Byn/glpCJLFJsM=", + "url": "https://repo1.maven.org/maven2/com/typesafe/config/1.4.5/config-1.4.5.jar" + }, + { + "sha256": "dZL+SceJtVQpSDGFrCKsbaQ2gKOcU7gYxQvKD7fdang=", + "url": "https://repo1.maven.org/maven2/io/get-coursier/interface/1.0.28/interface-1.0.28.jar" + }, + { + "sha256": "daw2bo7LaR4Gp+hQQe7Q9nkZpkblJi+gkBIlaYwQQ3U=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/modules/scala-asm/9.9.0-scala-1/scala-asm-9.9.0-scala-1.jar" + }, + { + "sha256": "p9n/OHsFlubmL+YJVEg+Mcu1h1ih7FcWerwsCYKM2gE=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/scala-library/3.8.1/scala-library-3.8.1.jar" + }, + { + "sha256": "4SeOyxKgqhbnZEBURQJ5wlRux7dr27aIisgumm75rHE=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/scala3-compiler_3/3.8.1/scala3-compiler_3-3.8.1.jar" + }, + { + "sha256": "ixyn2NtnhQqam1uDr6DlLPDQ1BuBGMY3oT0z8RHsga8=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/scala3-interfaces/3.8.1/scala3-interfaces-3.8.1.jar" + }, + { + "sha256": "XpruRQyaFYDYYQl0RI6ewVJZJUt3rkUVBhnB4u2PATc=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.8.1/scala3-library_3-3.8.1.jar" + }, + { + "sha256": "kHC+2OchuPiAJBNKyuWGs0v98gkq8jk016NZn/CF09U=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/scala3-tasty-inspector_3/3.8.1/scala3-tasty-inspector_3-3.8.1.jar" + }, + { + "sha256": "OpQLU5cbO5CLt/EgL/pAnQ5cZ8++wD8xqlmS3hK0QL0=", + "url": "https://repo1.maven.org/maven2/org/scala-lang/tasty-core_3/3.8.1/tasty-core_3-3.8.1.jar" + }, + { + "sha256": "K6zFdh4DkgoijlydILM9nFHUOq8vUuj4OezmMJZuuIA=", + "url": "https://repo1.maven.org/maven2/org/scala-sbt/compiler-interface/1.10.7/compiler-interface-1.10.7.jar" + }, + { + "sha256": "HWuR76QrcPwGTK7W1iliN04Tsnc3+IWofITGZ7ML5iU=", + "url": "https://repo1.maven.org/maven2/org/scala-sbt/util-interface/1.10.7/util-interface-1.10.7.jar" + }, + { + "sha256": "mR7vOKAZiT7WXXfY2O8WuF/615ntJ9XwzLVHM3/JbG0=", + "url": "https://repo1.maven.org/maven2/org/scodec/scodec-bits_3/1.1.38/scodec-bits_3-1.1.38.jar" + }, + { + "sha256": "0+9XXj5JeWeNwBvx3M5RAhSTtNEft/G+itmCh3wWocA=", + "url": "https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar" + }, + { + "sha256": "yFP3SjGdfbZH3LsfHATEt0yaQRZDoYZGXUa2PbA3M8Y=", + "url": "https://repo1.maven.org/maven2/org/typelevel/cats-core_3/2.11.0/cats-core_3-2.11.0.jar" + }, + { + "sha256": "NapvXrU5w/opPF6A0GUBEtrDWG6pXZJ/JI7bhImLPdI=", + "url": "https://repo1.maven.org/maven2/org/typelevel/cats-effect-kernel_3/3.5.7/cats-effect-kernel_3-3.5.7.jar" + }, + { + "sha256": "xkh/mJURMEmxpuzANedKBbcQ4CWMANFPLZiUq4pdam4=", + "url": "https://repo1.maven.org/maven2/org/typelevel/cats-effect-std_3/3.5.7/cats-effect-std_3-3.5.7.jar" + }, + { + "sha256": "nU7cB0rXaOjImdXVoyJ2Xu0xgOsGy8JKCsjWdD8ZTnA=", + "url": "https://repo1.maven.org/maven2/org/typelevel/cats-effect_3/3.5.7/cats-effect_3-3.5.7.jar" + }, + { + "sha256": "If5JZ1NaJ1jYAIdpxxsdbJtulDb083YxGV200DSoHiA=", + "url": "https://repo1.maven.org/maven2/org/typelevel/cats-kernel_3/2.11.0/cats-kernel_3-2.11.0.jar" + }, + { + "sha256": "LLFM1L2XsfcwPH3Fs7j/b6o/vITOLwkWKI0hm42cFA0=", + "url": "https://repo1.maven.org/maven2/org/typelevel/literally_3/1.1.0/literally_3-1.1.0.jar" + }, + { + "sha256": "uhx6r5q6Mhe5GUKRH/RQ46QVINvfUKttLqxRPH/zOH8=", + "url": "https://repo1.maven.org/maven2/org/virtuslab/cellar-cli_3/0.1.0-M9/cellar-cli_3-0.1.0-M9.jar" + }, + { + "sha256": "+JKcnxZZU7YDKB/TX3nSaisOB/KzhCmst9sXVtIJjU0=", + "url": "https://repo1.maven.org/maven2/org/virtuslab/cellar-lib_3/0.1.0-M9/cellar-lib_3-0.1.0-M9.jar" + } + ], + "javaOptions": [ + ], + "kind": "coursier-app", + "mainClass": "cellar.cli.CellarApp", + "version": 9 +}