Skip to content

feat: convert the git tool to a typescript installer - #7436

Merged
viceice merged 9 commits into
mainfrom
feat/last-v1-tool-to-v2
Sep 23, 2026
Merged

viceice merged 9 commits into
mainfrom
feat/last-v1-tool-to-v2

Conversation

@viceice

@viceice viceice commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Converts git, the last v1 shell tool, into a TypeScript install service, so every tool install-tool accepts is backed by a service.

This is a prerequisite for #6166 / #7435: without a service, git cannot appear in the generated tool list, which is also why git-lfs currently carries a parent that consumers can't resolve.

The service

src/cli/tools/git/index.ts replaces src/usr/local/containerbase/tools/git.sh:

  • GitPrepareService fetches the git-core ppa key with HttpService and writes etc/apt/keyrings/git.asc plus etc/apt/sources.list.d/git.list, with the codename from getDistro() and the architecture from EnvService. Paths go through envSvc.rootDir, the same convention AptService uses, so it is testable.
  • GitInstallService installs through AptService, then verifies the installed version is at least 2.33.0 — the minimum Renovate needs — and fails with the same message as the old script. link is a documented no-op because apt installs system wide, postInstall keeps the safe.directory flutter workaround, test runs git --version, and uninstall removes the package again through a new AptService.remove().

Root

git can only be installed as root, and that is now enforced in the cli rather than deep inside apt: BaseInstallService gains a needsRoot flag, and InstallToolService returns the new NotRoot code from both install() and uninstall() with a clear message. The check runs before validate(), so a permissions problem is no longer reported as "tool version not supported".

The v1 and v2 runtime support (V1ToolInstallService, V2ToolInstallService, bin/v1-install-tool.sh, bin/v2-install-tool.sh and the remaining tools/v2/*.sh) is deliberately left in place for compatibility with downstream images; only the git script itself is removed.

Verification

  • pnpm eslint, pnpm lint:types, pnpm lint:markdown and prettier pass.

  • pnpm test:vitest: 569 tests, 100% statements / branches / functions / lines. src/cli/tools/git/index.spec.ts covers prepare (asserting both written files), install, the too-old-version rejection, link, post-install, test and uninstall; install-tool.service.spec.ts covers both NotRoot paths.

  • pnpm test:docker --network host --allow-host-network -t test-x86_64 latest: the testc stage, which is the one that exercises this change, installs git and prints git version 2.55.0, then installs git-lfs on top, and the stage completes.

    That run then failed later in the unrelated teste stage at install-tool apm 0.30.0, because apm's bundled GitPython cannot find a git executable there. That is a local-only artifact: BASE_IMAGE defaults to the containerbase stage built from ghcr.io/containerbase/ubuntu:24.04, which ships no git package (verified with dpkg -l git), while CI points BASE_IMAGE at the real base image, which installs git. Nothing in that stage calls install-tool git.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Git setup now configures the Ubuntu Git Core package source and installs Git through the tool manager.
    • Git version checks accept vendor-suffixed versions, provided the version is at least 2.33.0.
  • Bug Fixes
    • Uninstall requests for tools that cannot be removed now return a clear unsupported-operation result.
    • Install and uninstall requests requiring root access now report a specific error when run without sufficient privileges.
  • Changed Behavior
    • Git installed through the tool manager can no longer be uninstalled through it.

Replaces the last v1 shell tool with a `GitInstallService` and a
`GitPrepareService`. The prepare step adds the `git-core` ppa keyring and
source list, the install step runs apt through `AptService` and verifies the
installed version is at least 2.33.0, and uninstall removes the package again
via a new `AptService.remove`.

git still requires root, which is enforced by a `needsRoot` flag on the install
service: the cli now reports `NotRoot` with a clear message instead of failing
somewhere inside apt.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: faba4973-38eb-4a85-9a8b-c764cb64d656

📥 Commits

Reviewing files that changed from the base of the PR and between 4aaea1b and 9732ac6.

📒 Files selected for processing (5)
  • src/cli/install-tool/base-install.service.ts
  • src/cli/install-tool/install-tool.service.spec.ts
  • src/cli/install-tool/install-tool.service.ts
  • src/cli/tools/git/index.spec.ts
  • src/cli/tools/git/index.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The CLI now checks root requirements during installation and uninstallation, and checks whether a tool supports uninstallation. Git preparation and installation use registered CLI services. Git version parsing accepts vendor-suffixed output, and the former Git installation shell script was removed.

Changes

Git CLI installation and root checks

Layer / File(s) Summary
Tool install and uninstall policies
src/cli/install-tool/base-install.service.ts, src/cli/install-tool/install-tool.service.ts, src/cli/utils/codes.ts, src/cli/install-tool/install-tool.service.spec.ts
BaseInstallService defaults canUninstall to true. Installation returns NotRoot when root is required and unavailable. Uninstallation returns NotSupported when the tool cannot be uninstalled; otherwise, it checks the root requirement. Tests cover these results and fatal messages.
Git PPA preparation
src/cli/tools/git/index.ts, src/cli/prepare-tool/index.ts, src/cli/tools/git/index.spec.ts
GitPrepareService writes a deb822 PPA source entry with the detected suite and architecture. The prepare container registers the service, and tests check the source contents.
Git installation and version checks
src/cli/tools/git/index.ts, src/cli/install-tool/index.ts, src/cli/tools/git/index.spec.ts, src/usr/local/containerbase/tools/git.sh
The install container registers GitInstallService, which cannot be uninstalled. It coerces the full Git version output and checks the 2.33.0 minimum. Tests cover installation, version parsing, Git configuration, and the test command. The former Git installation shell script was removed.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Merge Risk: ⚪ Minimal · up to 9732a

Git installation and preparation use the registered CLI services, and no merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: converting the Git tool to a TypeScript installer.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

Comment thread src/cli/tools/git/index.ts
viceice and others added 8 commits September 23, 2026 08:59
`etc/apt/sources.list.d` ships with the image, so the prepare step can just
write the source list. The unit test creates the directory with `ensurePaths`,
mirroring the image layout.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
Binds the root only tool into the existing container and mocks the bun service
through its prototype, like the surrounding tests already do, so no second
container is needed to keep the tool lookups unambiguous.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
Writes `etc/apt/sources.list.d/git.sources` in the deb822 format instead of the
one line `git.list`, matching how apt sources are written nowadays.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
Uses the `codeBlock` tag from common-tags, like the other generated config
files in this repo, instead of joining an array of lines. The dedented output
has no trailing newline, which matches how the conan profile and the maven
settings are written.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
Keeps the expected file contents indented with the surrounding test code
instead of flush to column zero.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
Distributions may append a suffix like `2.55.0-1ubuntu1` to the version git
prints, which `dpkg --compare-versions` handled but semver cannot parse.
Coerces the output before comparing it with the minimum version, and fails with
a clear message when no version can be found at all.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
The installed version is already printed by the test step, which runs
`git --version`.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
The apt package is shared by every recorded git version, so uninstalling one of
them would remove the system git while another version is still current and
git-lfs still depends on it.

Adds a `canUninstall` flag to the install services, which git sets to false, so
`uninstall-tool git` reports `NotSupported` like it did before the conversion.
Drops the now unused `AptService.remove` again.

Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
@gitar-bot

gitar-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 closed / 1 findings

🟡 Medium risk · Adds root-only system-wide Git installation and PPA configuration through the installer.

Converts the last v1 shell tool (git) into a TypeScript install service, unifying all tools behind a service layer. The change adds root permission enforcement at the CLI level, implements Git source preparation via apt, version verification against 2.33.0 minimum, and support for uninstalling the system package. No issues found.

✅ 1 closed
✅ Edge Case: Uninstalling any recorded git version removes the system git package

📄 src/cli/tools/git/index.ts:62-64 📄 src/cli/tools/git/index.ts:91-93 📄 src/cli/install-tool/install-tool.service.ts:255-269
install() ignores the requested version, so install-tool git 2.55.0 followed by install-tool git 2.56.0 leaves two versions recorded in VersionService, and both point at the one apt package. If you then run uninstall-tool git 2.55.0 on the older, non-current version, InstallToolService.uninstall only checks for children of that exact version. So git-lfs, which is attached to the current 2.56.0, doesn't block it. GitInstallService.uninstall then runs apt-get remove git anyway. The system git is gone, but 2.56.0 is still recorded as installed and current, and git-lfs keeps a parent that no longer exists. The fix is to run apt-get remove only when the version being removed is the last recorded git version, for example by injecting VersionService and checking findInstalled('git').

Review coverage

📋 Rules No rules evaluated

🧪 Functional validation Not enabled · Set up

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 2 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

@viceice
viceice added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit 3ccff09 Sep 23, 2026
59 checks passed
@viceice
viceice deleted the feat/last-v1-tool-to-v2 branch September 23, 2026 08:58
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