-
Notifications
You must be signed in to change notification settings - Fork 1
Set up GitHub Actions CI with Nix #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set up GitHub Actions CI with Nix #15
Conversation
Create comprehensive implementation plan for setting up CI with GitHub Actions using the same Nix environment as development. Plan includes separate jobs for backend, frontend, and Nix checks with proper caching strategy.
WalkthroughAdds a new GitHub Actions CI workflow (.github/workflows/ci.yml) that orchestrates Nix checks, a Haskell backend job, and a TypeScript/Svelte frontend job sharing an OpenAPI artifact. Updates Changes
Sequence DiagramsequenceDiagram
participant GH as GitHub Actions
participant NC as nix-checks
participant BE as backend (Haskell)
participant ART as Artifact Storage
participant FE as frontend (TS/Svelte)
GH->>NC: start nix-checks (parallel)
GH->>BE: start backend (parallel)
NC->>NC: validate flake\ncheck formatting
BE->>BE: restore Stack cache\nlint, build, test\ngenerate OpenAPI spec
BE->>ART: upload OpenAPI spec
rect rgba(120,180,240,0.08)
Note over FE: waits for backend artifact
end
BE-->>FE: backend done (needs)
FE->>ART: download OpenAPI spec
FE->>FE: setup Nix/Cachix\nrestore pnpm cache\ninstall deps\ngenerate TS client\nformat/lint/typecheck/test/build
NC-->>GH: pass
BE-->>GH: pass
FE-->>GH: pass
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Implement comprehensive CI pipeline with three parallel jobs: - Nix checks: flake check and nixfmt - Backend: fourmolu, hlint, stack build/test - Frontend: prettier, eslint, svelte-check, vitest, build Uses same Nix environment as development via cachix/install-nix-action. Includes caching for Stack artifacts and pnpm store for faster builds.
Change workflow triggers to run on: - Push to master branch only - All pull requests This prevents duplicate CI runs on feature branches.
- Generate .cabal file before running fourmolu (needed for language extensions) - Use prettier --check instead of pnpm format --check for proper validation
Fourmolu needs the .cabal file to recognize language extensions like OverloadedRecordDot. Generate it using 'stack build --dry-run' before running checks in both nix-checks and backend jobs. Changes: - Use stack instead of hpack (stack includes hpack built-in) - Generate .cabal in nix-checks job before 'nix flake check' - Add stack caching to nix-checks job for faster builds
Fourmolu needs the .cabal file to read language extensions like OverloadedRecordDot. Committing the .cabal file ensures it's always available for pre-commit hooks and CI checks.
Instead of relying on .cabal file (which is gitignored), configure fourmolu.yaml with ghc-opt flags for all language extensions from package.yaml. This allows fourmolu to recognize OverloadedRecordDot and other extensions without needing the .cabal file. Changes: - Add ghc-opt section to fourmolu.yaml with all default-extensions - Revert .gitignore to keep *.cabal gitignored - Remove unnecessary cabal generation steps from CI workflow
Based on fourmolu documentation, fourmolu requires the .cabal file to detect language extensions like OverloadedRecordDot. The ghc-opt configuration in fourmolu.yaml doesn't work for language extensions. Solution: - Enable hpack pre-commit hook to generate .cabal from package.yaml - Configure fourmolu to run after hpack using after = ["hpack"] - Add hpack to devenv packages - Remove incorrect ghc-opt configuration from fourmolu.yaml References: - https://fourmolu.github.io/config/ - https://flake.parts/options/git-hooks-nix
The fourmolu formatting check is already run in the nix-checks job via 'nix flake check', which executes all git-hooks.nix pre-commit hooks including fourmolu. Running it separately in the backend job is redundant and was causing CI failures.
Removed working-directory overrides that were causing pnpm install to run in the root directory instead of frontend/. The job already has defaults.run.working-directory set to frontend, so the overrides were unnecessary and causing pnpm to fail.
The 'nix develop' command enters the nix shell at the root directory where flake.nix is located, not in the frontend/ subdirectory. This caused prettier to check root files including .devenv/ which contains invalid JSON. Solution: Explicitly cd into frontend directory before running each command.
Use 'nix develop ..' to reference the parent flake while keeping the working directory in frontend/. This allows pnpm and prettier to run in the correct directory without needing cd commands.
Remove working-directory default and explicitly cd into frontend for each command. The nix develop command executes from the repo root, so we need to cd into frontend to ensure pnpm and prettier run in the correct directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
.github/workflows/ci.yml (3)
31-32: Consider checking all Nix files for formatting consistency.Currently, only
flake.nixis checked for formatting. If there are other.nixfiles in the repository, they should also be checked for consistent formatting.Apply this diff to check all Nix files:
- - name: Check Nix formatting - run: nix develop --impure --command nixfmt --check flake.nix + - name: Check Nix formatting + run: nix develop --impure --command bash -c 'find . -name "*.nix" -exec nixfmt --check {} +'
63-73: Consider batching commands for better performance.Multiple separate
nix develop --impure --commandinvocations add overhead. Consider batching related commands in a single shell session.Example refactor:
- - name: Lint Haskell code - run: nix develop --impure --command bash -c 'find src app test -name "*.hs" -exec hlint {} +' - - - name: Build Haskell project - run: nix develop --impure --command stack build --fast - - - name: Run Haskell tests - run: nix develop --impure --command stack test --fast - - - name: Generate OpenAPI spec - run: nix develop --impure --command stack exec generate-openapi + - name: Build and test Haskell project + run: | + nix develop --impure --command bash -c ' + find src app test -name "*.hs" -exec hlint {} + && + stack build --fast && + stack test --fast && + stack exec generate-openapi + '
119-138: Consider using working-directory or batching commands.The repeated
cd frontend &&pattern in every step adds verbosity. Consider using theworking-directorykey or batching related commands.Option 1: Use working-directory (cleaner but separate steps):
- name: Install dependencies + working-directory: frontend - run: nix develop --impure --command bash -c 'cd frontend && pnpm install' + run: nix develop --impure --command pnpm installOption 2: Batch related commands (faster but less granular error reporting):
- - name: Install dependencies - run: nix develop --impure --command bash -c 'cd frontend && pnpm install' - - - name: Generate TypeScript client - run: nix develop --impure --command bash -c 'cd frontend && pnpm generate-client' - - - name: Check TypeScript formatting - run: nix develop --impure --command bash -c 'cd frontend && prettier --check .' - - - name: Lint TypeScript code - run: nix develop --impure --command bash -c 'cd frontend && pnpm lint' - - - name: Type check - run: nix develop --impure --command bash -c 'cd frontend && pnpm check' - - - name: Run tests - run: nix develop --impure --command bash -c 'cd frontend && pnpm test:run' - - - name: Build frontend - run: nix develop --impure --command bash -c 'cd frontend && pnpm build' + - name: Build and test frontend + run: | + nix develop --impure --command bash -c ' + cd frontend && + pnpm install && + pnpm generate-client && + prettier --check . && + pnpm lint && + pnpm check && + pnpm test:run && + pnpm build + '
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.github/workflows/ci.yml(1 hunks)flake.nix(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-26T04:01:46.339Z
Learnt from: CR
Repo: 0xgleb/quanty PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-26T04:01:46.339Z
Learning: Applies to **/*.hs : Do not enable language extensions that are already enabled project-wide (GHC2024/package.yaml); only add module-specific pragmas when necessary
Applied to files:
flake.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Backend (Haskell)
- GitHub Check: Nix Checks
🔇 Additional comments (6)
flake.nix (2)
54-54: LGTM!Adding hpack to the development shell packages is consistent with enabling it as a git hook, making it available for both automated and manual use.
27-31: git-hooks.nix supports theafterfield — configuration is correct. Theafterfield is a documented feature that allows referencing other hooks by id, and the configuration correctly usesafter = [ "hpack" ]to ensure fourmolu runs after hpack generates the .cabal file..github/workflows/ci.yml (4)
81-91: LGTM! Correct job dependency and artifact sharing.The frontend job correctly depends on the backend job and downloads the OpenAPI spec artifact for client generation. This ensures the TypeScript client is generated from the latest backend specification.
106-117: Good caching strategy for pnpm store.The workflow correctly retrieves the pnpm store path from within the Nix environment and caches it based on the lockfile hash. This should provide good cache hit rates and speed up dependency installation.
72-79: Both workflow assumptions are correct and properly implemented.The verification confirms:
- The
generate-openapiexecutable is properly defined inpackage.yamlwith the executable configured inapp/GenerateOpenApi.hs- The executable writes
openapi.jsonto the repository root (line 12 ofapp/GenerateOpenApi.hs), matching the workflow's artifact path expectation- The frontend job's dependency on this artifact is justified and will work correctly
63-64: No issues found—directory structure exists and supports hlint.Verification confirms that
src,app, andtestdirectories all exist in the repository and contain Haskell source files. The hlint command on line 64 of.github/workflows/ci.ymlwill execute correctly against the project's actual structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
frontend/src/lib/components/calculator/OptionParametersForm.svelte (1)
222-230: Consider type-safe error handling.The current pattern relies on
isErrorto gate error display, but TypeScript doesn't narrow theerrortype based on theisErrorflag. The error could still beundefinedeven whenisErroristrue.For better type safety and alignment with the coding guidelines, consider refactoring to use Effect's error handling (
Effect.catchAll/catchTag) with explicitly typed error variants. This would eliminate the need for separateisErroranderrorfields and provide compile-time guarantees about error handling.As per coding guidelines.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/src/lib/components/calculator/OptionParametersForm.svelte(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx,svelte}
📄 CodeRabbit inference engine (AGENTS.md)
frontend/**/*.{ts,tsx,svelte}: Use Effect for all async operations and error handling; prefer Effect.gen over Promise/async-await
Model errors explicitly with tagged unions and handle errors via Effect.catchAll/catchTag; do not silently swallow errors
Validate external data with @effect/schema (Schema.decode) and use refinements for business rules; no any or unknown without validation
All external API calls must include a timeout using Effect.timeout
Use Layers for dependency injection in TypeScript services
Do not use try/catch in new TypeScript code; use Effect.try and Effect error-handling instead
Files:
frontend/src/lib/components/calculator/OptionParametersForm.svelte
frontend/src/**/*.svelte
📄 CodeRabbit inference engine (AGENTS.md)
Use Svelte 5 runes for reactivity ($state, $derived, $effect) and execute Effect programs with Effect.runPromise in components
Files:
frontend/src/lib/components/calculator/OptionParametersForm.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Nix Checks
- GitHub Check: Backend (Haskell)
🔇 Additional comments (1)
frontend/src/lib/components/calculator/OptionParametersForm.svelte (1)
18-24: <!-- [scratchpad_start]
[task review_file_1/1 review_verification_2/2]
Verify getErrorMessage handles undefined[observations]
- Found blackScholes.ts at frontend/src/lib/services/blackScholes.ts
- getErrorMessage signature shows it ALREADY accepts undefined in parameter:
error: BlackScholesError | Error | null | undefined- Function returns object with title and message fields
- Need to see full implementation to verify it handles all cases
[analysis]
- Good news: getErrorMessage signature already includes undefined in its parameter type
- This means the change from Error | null to Error | undefined in CalculateMutation is safe
- The function is designed to handle undefined values
[pending]
Get full implementation of getErrorMessage to verify it handles undefined without errors[actions]
Display full getErrorMessage implementation from blackScholes.ts
Create comprehensive implementation plan for setting up CI with GitHub Actions using the same Nix environment as development. Plan includes separate jobs for backend, frontend, and Nix checks with proper caching strategy.
Summary by CodeRabbit
Chores
Bug Fixes