Skip to content

feat: add automatic nix garbage collection and fix macOS shell tests - #1514

Merged
shunkakinoki merged 2 commits into
mainfrom
feat/nix-gc-and-macos-test-fixes
Apr 19, 2026
Merged

feat: add automatic nix garbage collection and fix macOS shell tests#1514
shunkakinoki merged 2 commits into
mainfrom
feat/nix-gc-and-macos-test-fixes

Conversation

@shunkakinoki

Copy link
Copy Markdown
Owner

Summary

  • Add weekly nix garbage collection (delete generations >30 days) via nix-darwin launchd daemon and home-manager systemd timer
  • Add make clean-all for nuclear GC, change make clean to retain 30 days + run nix store optimise
  • Fix 6 failing shell tests on macOS: replace readlink -f (GNU-only) with portable resolve_cmd_dir helper, fix stat -c (GNU) with macOS-compatible wrapper, fix PATH isolation leaking pbcopy via /usr/bin

Test plan

  • make shell-test - 326 examples, 0 failures
  • make shell-lint - exit 0

@mesa-dot-dev

mesa-dot-dev Bot commented Apr 19, 2026

Copy link
Copy Markdown

You do not have enough credits to review this pull request. Please purchase more credits to continue.

@coderabbitai

coderabbitai Bot commented Apr 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@shunkakinoki has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 54 minutes and 28 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 54 minutes and 28 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f9e1a723-ec0a-4b79-8825-c5eac9c5947c

📥 Commits

Reviewing files that changed from the base of the PR and between 94ef9db and e2a5405.

📒 Files selected for processing (1)
  • config/mempalace/default.nix
📝 Walkthrough

Walkthrough

The changes introduce automated Nix garbage collection scheduling with weekly frequency and 30-day retention policies across both home-manager and nix-darwin configurations. A new launchd daemon manages garbage collection on macOS, and the test suite is refactored with portable command resolution utilities.

Changes

Cohort / File(s) Summary
Nix Garbage Collection Configuration
Makefile, home-manager/nix/nix.nix, nix-darwin/services/default.nix, nix-darwin/services/nix-gc/default.nix
Introduced garbage collection scheduling with --delete-older-than 30d across Makefile and Nix home-manager config. Created new launchd daemon module that runs weekly GC on Sunday at 03:00 for nix-darwin systems when not in runner mode.
Test Helper Infrastructure
spec/test_helpers.sh
Added resolve_cmd_dir() and portable_stat_perms() helper functions. Updated nix_script_preprocess() to replace @find@ and @stat@ placeholders with runtime-resolved command paths.
Clipboard and Notification Tests
spec/clipboard_copy_spec.sh, spec/clipboard_paste_spec.sh, spec/notify_local_spec.sh
Refactored setup() blocks to use new resolve_cmd_dir() helper instead of inline dirname/readlink -f for bash/cat directory resolution, simplifying command path handling across backend tests.
Secure Dotenv Test Harness
spec/secure_dotenv_spec.sh
Added STAT_WRAPPER script in setup() to provide portable cross-platform file permission queries. Updated placeholder substitution to inject wrapper path instead of system stat binary, with assertions now calling the wrapper.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 Weekly garbage dances free,
Thirty days of memory,
Nix grows lean with launchd's care,
Tests now portable everywhere! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add automatic nix garbage collection and fix macOS shell tests' directly and comprehensively summarizes both main changes: adding automatic GC and fixing macOS shell tests.
Description check ✅ Passed The description provides relevant details about the changeset, including specific changes to Nix GC configuration, Makefile targets, shell test fixes, and test results demonstrating successful validation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/nix-gc-and-macos-test-fixes

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mesa-dot-dev

mesa-dot-dev Bot commented Apr 19, 2026

Copy link
Copy Markdown

Mesa Description

TL;DR

Added weekly automatic Nix garbage collection on macOS and Linux, introduced make clean-all for full GC, and fixed 6 macOS shell test failures by improving command portability.

What changed?

  • Makefile: Modified clean to retain 30 days of Nix generations and optimize the store; added clean-all for comprehensive Nix cleanup.
  • home-manager/nix/nix.nix: Enabled weekly automatic Nix garbage collection, deleting generations older than 30 days.
  • nix-darwin/services/default.nix: Integrated the new nix-gc service module into nix-darwin services.
  • nix-darwin/services/nix-gc/default.nix: Created a new Nix Darwin service com.shunkakinoki.nix-gc for weekly automated Nix garbage collection (nix-collect-garbage --delete-older-than 30d) every Sunday at 3:00 AM, conditional on isRunner flag.
  • spec/clipboard_copy_spec.sh: Refactored system command management for tests by creating symlinks in MOCK_BIN and setting an isolated PATH, and introduced resolve_cmd_dir helper.
  • spec/clipboard_paste_spec.sh: Replaced repetitive inline bash directory resolution with the new resolve_cmd_dir function in setup functions.
  • spec/notify_local_spec.sh: Refactored to replace duplicated inline logic for resolving command directories with resolve_cmd_dir.
  • spec/secure_dotenv_spec.sh: Incorporated a portable-stat.sh wrapper for consistent cross-platform stat command syntax in file permission tests.
  • spec/test_helpers.sh: Introduced portable helpers resolve_cmd_dir and portable_stat_perms; updated nix_script_preprocess to dynamically resolve @find@ and @stat@ paths using command -v.

Description generated by Mesa. Update settings

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces automated Nix garbage collection and store optimization across the environment, including updates to the Makefile, Home Manager, and nix-darwin configurations. It also improves the portability of shell scripts and test helpers, specifically addressing differences between GNU and BSD utilities like readlink and stat. Feedback focuses on ensuring consistent use of sudo for store optimization, utilizing idiomatic nix-darwin modules for garbage collection, and improving the robustness of the Python-based path resolution helper.

Comment thread Makefile
@echo "🧹 Cleaning up old generations and garbage collecting..."
@$(SUDO) nix-collect-garbage -d
@$(SUDO) nix-collect-garbage --delete-older-than 30d
@nix store optimise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The nix store optimise command should be run with $(SUDO) to ensure it has the necessary permissions to hardlink files across the entire Nix store. Since the preceding nix-collect-garbage command uses $(SUDO), it is consistent to use it here as well for a full system cleanup.

	@$(SUDO) nix store optimise

Comment thread Makefile
clean-all: ## Delete ALL old Nix generations and garbage collect (nuclear).
@echo "🧹 Removing all old generations..."
@$(SUDO) nix-collect-garbage -d
@nix store optimise

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the clean target, nix store optimise in clean-all should use $(SUDO) to effectively optimize the entire store.

	@$(SUDO) nix store optimise

Comment on lines +7 to +21
launchd.daemons."com.shunkakinoki.nix-gc" = {
script = ''
/nix/var/nix/profiles/default/bin/nix-collect-garbage --delete-older-than 30d
'';
serviceConfig = {
RunAtLoad = false;
StartCalendarInterval = [
{
Weekday = 0;
Hour = 3;
Minute = 0;
}
];
};
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of manually defining a launchd daemon, it is more idiomatic to use the built-in nix.gc module provided by nix-darwin. This simplifies the configuration, uses the configured Nix package automatically, and follows established patterns for managing garbage collection on macOS.

  nix.gc = {
    automatic = true;
    interval = {
      Weekday = 0;
      Hour = 3;
      Minute = 0;
    };
    options = "--delete-older-than 30d";
  };

Comment thread spec/test_helpers.sh
if readlink -f "$cmd_path" >/dev/null 2>&1; then
dirname "$(readlink -f "$cmd_path")"
else
dirname "$(python3 -c "import os; print(os.path.realpath('$cmd_path'))")"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using $cmd_path directly inside the Python command string can lead to syntax errors or unexpected behavior if the path contains single quotes. It is safer to pass the path as an argument to the Python script and access it via sys.argv.

Suggested change
dirname "$(python3 -c "import os; print(os.path.realpath('$cmd_path'))")"
dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$cmd_path")"

@shunkakinoki
shunkakinoki merged commit d5c4a1a into main Apr 19, 2026
27 checks passed
@shunkakinoki
shunkakinoki deleted the feat/nix-gc-and-macos-test-fixes branch April 19, 2026 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant