codeberg-cli 0.5.5

CLI Tool for codeberg similar to gh and glab
Documentation
{ inputs, ... }:
{
  perSystem =
    {
      self',
      pkgs,
      lib,
      ...
    }:
    let
      craneLib = (inputs.crane.mkLib pkgs).overrideToolchain (_: self'.packages.buildToolchain);
      craneLibFull = (inputs.crane.mkLib pkgs).overrideToolchain (_: self'.packages.devToolchain);
      src = craneLib.cleanCargoSource inputs.self;
      commonArgs = rec {
        inherit src;
        strictDeps = true;

        nativeBuildInputs = [ pkgs.pkg-config ];

        buildInputs = [
          pkgs.openssl
        ];

        env = {
          # this approach should be favored over LD_LIBRARY_PATH as it is more precise
          RUSTFLAGS = "-C link-args=-Wl,-rpath,${lib.makeLibraryPath buildInputs}";
        };
      };
    in
    {
      packages = {
        default = self'.packages.berg;

        # Build *just* the cargo dependencies, so we can reuse
        # all of that work (e.g. via cachix) when running in CI
        berg-deps = craneLib.buildDepsOnly commonArgs;

        # Build the actual crate itself, reusing the dependency
        # artifacts from above.
        berg = craneLib.buildPackage (
          commonArgs
          // {
            cargoArtifacts = self'.packages.berg-deps;

            nativeBuildInputs = commonArgs.nativeBuildInputs ++ [
              pkgs.installShellFiles # includes installShellCompletion
            ];

            # allow for auto completion
            postInstall = lib.optionalString (pkgs.stdenv.buildPlatform.canExecute pkgs.stdenv.hostPlatform) ''
              installShellCompletion --cmd berg \
                --bash <($out/bin/berg completion bash) \
                --fish <($out/bin/berg completion fish) \
                --zsh <($out/bin/berg completion zsh)
            '';

            meta = {
              description = "CLI Tool for Codeberg similar to gh and glab";
              homepage = "https://codeberg.org/Aviac/codeberg-cli";
              license = [ lib.licenses.agpl3Plus ];
              maintainers = [ lib.maintainers.robwalt ];
              mainProgram = "berg";
            };
          }
        );
      };

      checks = {
        # Build the crate as part of `nix flake check` for convenience
        berg = self'.packages.berg;

        # Run clippy (and deny all warnings) on the crate source,
        # again, reusing the dependency artifacts from above.
        #
        # Note that this is done as a separate derivation so that
        # we can block the CI if there are issues here, but not
        # prevent downstream consumers from building our crate by itself.
        berg-clippy = craneLibFull.cargoClippy (
          commonArgs
          // {
            cargoArtifacts = self'.packages.berg-deps;
            cargoClippyExtraArgs = "--all-targets -- --deny warnings";
          }
        );

        berg-doc = craneLibFull.cargoDoc (
          commonArgs
          // {
            cargoArtifacts = self'.packages.berg-deps;
            # This can be commented out or tweaked as necessary, e.g. set to
            # `--deny rustdoc::broken-intra-doc-links` to only enforce that lint
            env.RUSTDOCFLAGS = "--deny warnings";
          }
        );

        # Check formatting
        berg-fmt = craneLibFull.cargoFmt {
          inherit src;
        };

        berg-toml-fmt =
          let
            taploConfigToml = pkgs.writeTextFile {
              name = "config.toml";
              text = ''
                [formatting]
                align_entries = true # Align entries vertically. Entries that have table headers, comments, or blank lines between them are not aligned.

                reorder_keys = true # Alphabetically reorder keys that are not separated by blank lines.
                reorder_arrays = true # Alphabetically reorder array values that are not separated by blank lines.
                reorder_inline_tables = true # Alphabetically reorder inline tables.
              '';
            };
          in
          craneLibFull.taploFmt {
            src = pkgs.lib.sources.sourceFilesBySuffices src [ ".toml" ];
            # taplo arguments can be further customized below as needed
            taploExtraArgs = "--config ${taploConfigToml}";
          };

        # Audit dependencies
        berg-audit = craneLibFull.cargoAudit {
          inherit (inputs) advisory-db;
          inherit src;
        };

        # Audit licenses
        berg-deny =
          let
            cargoDenyConfig = pkgs.writeTextFile {
              name = "cargo-deny.toml";
              text = ''
                # .cargo-deny.toml

                [licenses]
                # Require high confidence in license detection
                confidence-threshold = 0.8
                # Explicitly list allowed SPDX licenses
                allow = [
                    "AGPL-3.0-or-later",
                    "MIT",
                    "Apache-2.0",
                    "BSD-3-Clause",
                    "MPL-2.0",
                    "Unicode-3.0",
                    "CDLA-Permissive-2.0",
                    "ISC"
                ]

                [bans]
                # Warn about multiple versions of the same crate
                multiple-versions = "warn"
                skip = []

                [sources]
                # Forbid unknown git sources (optional for security)
                allow-git = []
                allow-registry = ["https://github.com/rust-lang/crates.io-index"]
              '';
            };
          in
          craneLibFull.cargoDeny {
            inherit src;
            cargoDenyChecks = "-c ${cargoDenyConfig} bans licenses sources";
          };

        # Run tests with cargo-nextest
        # Consider setting `doCheck = false` on `berg` if you do not want
        # the tests to run twice
        berg-nextest = craneLibFull.cargoNextest (
          commonArgs
          // {
            cargoArtifacts = self'.packages.berg-deps;
            partitions = 1;
            partitionType = "count";
            cargoNextestPartitionsExtraArgs = "--no-tests=pass";
          }
        );

      };
    };
}