diff --git a/.github/workflows/flake-lock-fix.yml b/.github/workflows/flake-lock-fix.yml new file mode 100644 index 000000000..6ec90be35 --- /dev/null +++ b/.github/workflows/flake-lock-fix.yml @@ -0,0 +1,46 @@ +name: Fix flake hashes + +on: + push: + branches: [dev] + paths: ['pnpm-lock.yaml'] + +jobs: + fix: + name: Fix flake hashes + runs-on: ubuntu-latest + permissions: + id-token: write + contents: write + steps: + - name: Checkout dev + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: dev + persist-credentials: true + + - name: Install Determinate Nix + uses: DeterminateSystems/determinate-nix-action@bafaa638b9d5ec0e7e3ac1a7fc80453ef1fd265f # v3.20.0 + + - id: check + run: nix flake check -L + continue-on-error: true + + - name: Fix hash mismatches + if: steps.check.outcome == 'failure' + run: determinate-nixd fix hashes --auto-apply + + - name: Commit and push if changed + if: steps.check.outcome == 'failure' + shell: bash + run: | + set -euo pipefail + if git diff --quiet; then + echo "No changes after fix hashes; nothing to commit." + exit 0 + fi + git config user.name "sable-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add --update --ignore-removal . + git commit -m "chore(nix): auto-fix nix hashes" + git push origin HEAD:dev --force-with-lease diff --git a/.gitignore b/.gitignore index 7ec719709..76af75542 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,12 @@ build.sh # the following line was added with nvim by Shea because its annoying to clear every so often .vscode/bookmarks.json + +# Nix things +## nix build output +result +## direnv config + local state +.envrc +.direnv +## auto-generated pre-commit config +.pre-commit-config.yaml diff --git a/.vscode/settings.json b/.vscode/settings.json index f2ceb43b5..60018f71d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,5 +12,7 @@ }, "[json]": { "editor.defaultFormatter": "oxc.oxc-vscode" - } + }, + "nixEnvSelector.nixFile": "${workspaceFolder}/flake.nix", + "nixEnvSelector.useFlakes": true } diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..536adabd7 --- /dev/null +++ b/flake.lock @@ -0,0 +1,142 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1777988971, + "narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1776796298, + "narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "3cfd774b0a530725a077e17354fbdb87ea1c4aad", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1777954456, + "narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1777168982, + "narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs", + "treefmt-nix": "treefmt-nix" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1775636079, + "narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..822e02de3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: AGPL-3.0 +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + git-hooks.url = "github:cachix/git-hooks.nix"; + git-hooks.inputs.nixpkgs.follows = "nixpkgs"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = + inputs@{ flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + inputs.git-hooks.flakeModule + inputs.treefmt-nix.flakeModule + ]; + + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + + perSystem = + { + config, + pkgs, + lib, + ... + }: + let + self = inputs.self; + + packageJson = builtins.fromJSON (builtins.readFile ./package.json); + + nodejs = pkgs.nodejs_24; + pnpm = pkgs.pnpm_10; + pnpmConfigHook = pkgs.pnpmConfigHook.override { inherit pnpm; }; + + pnpmNativeBuildInputs = [ + nodejs + pnpm + pnpmConfigHook + ]; + + mkPnpmDeps = + { + src, + version, + pnpmInstallFlags, + }: + pkgs.fetchPnpmDeps { + inherit + pnpm + src + version + pnpmInstallFlags + ; + pname = "sable"; + fetcherVersion = 3; + hash = "sha256-9QIBOF1d7Z086IsOAHpOayKA3uNY0e5imYQixHKFXxw="; + }; + + mkPnpmCheck = + name: script: + pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "sable-${name}"; + inherit (packageJson) version; + src = lib.cleanSource ./.; + + pnpmInstallFlags = [ "--ignore-scripts" ]; + + pnpmDeps = mkPnpmDeps { + inherit (finalAttrs) src version pnpmInstallFlags; + }; + + nativeBuildInputs = pnpmNativeBuildInputs; + + buildPhase = '' + runHook preBuild + pnpm run ${script} + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + touch $out + runHook postInstall + ''; + + doCheck = false; + }); + in + { + treefmt = { + projectRootFile = "flake.nix"; + programs = { + nixfmt.enable = true; + oxfmt.enable = true; + }; + settings.global.excludes = [ + "dist" + "node_modules" + "pnpm-lock.yaml" + "pnpm-workspace.yaml" + "package.json" + "LICENSE" + "CHANGELOG.md" + "./changeset" + ]; + }; + pre-commit.settings.hooks = { + treefmt = { + enable = true; + package = config.treefmt.build.wrapper; + }; + }; + + packages.sable = pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "sable"; + inherit (packageJson) version; + src = lib.cleanSource ./.; + + # ignoring knope for building + pnpmInstallFlags = [ "--ignore-scripts" ]; + + pnpmDeps = mkPnpmDeps { + inherit (finalAttrs) src version pnpmInstallFlags; + }; + + nativeBuildInputs = pnpmNativeBuildInputs; + + env.VITE_BUILD_HASH = self.shortRev or self.dirtyShortRev or ""; + env.VITE_IS_RELEASE_TAG = "false"; + + buildPhase = '' + runHook preBuild + pnpm run build + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + cp -r dist $out + runHook postInstall + ''; + }); + + packages.default = config.packages.sable; + + checks = { + build = config.packages.sable; + lint = mkPnpmCheck "lint" "lint"; + fmt = mkPnpmCheck "fmt" "fmt:check"; + test = mkPnpmCheck "test" "test:run"; + typecheck = mkPnpmCheck "typecheck" "typecheck"; + knip = mkPnpmCheck "knip" "knip"; + }; + + devShells.default = pkgs.mkShell { + packages = [ + nodejs + pnpm + pkgs.corepack + pkgs.vitejs + pkgs.oxlint + pkgs.oxfmt + pkgs.knope + pkgs.typescript + pkgs.typescript-language-server + pkgs.nil + pkgs.nixd + ]; + shellHook = config.pre-commit.installationScript; + }; + }; + }; +} diff --git a/oxfmt.config.ts b/oxfmt.config.ts index 593c2425c..c193a0268 100644 --- a/oxfmt.config.ts +++ b/oxfmt.config.ts @@ -1,6 +1,6 @@ -import { defineConfig } from 'oxfmt'; +import type { OxfmtConfig } from 'oxfmt'; -export default defineConfig({ +export default { printWidth: 100, tabWidth: 2, singleQuote: true, @@ -15,4 +15,4 @@ export default defineConfig({ 'CHANGELOG.md', './changeset', ], -}); +} satisfies OxfmtConfig;