Skip to content

fix: explicitly release GitConfigParser to prevent destructor error on Python 3.14#181

Open
matthiasbalke wants to merge 1 commit intohassio-addons:mainfrom
matthiasbalke:fix/config-writer-not-released
Open

fix: explicitly release GitConfigParser to prevent destructor error on Python 3.14#181
matthiasbalke wants to merge 1 commit intohassio-addons:mainfrom
matthiasbalke:fix/config-writer-not-released

Conversation

@matthiasbalke
Copy link
Copy Markdown

@matthiasbalke matthiasbalke commented Mar 28, 2026

Problem

In repositoryupdater/github.py, config_writer() is called on the cloned repo but the returned GitConfigParser object is never explicitly released via config.release().

When cleanup() later runs shutil.rmtree() on the temp directory, the GitConfigParser object may still be alive in memory. Python 3.14's garbage collector then invokes __del__ on it, which attempts to write to the already-deleted path, causing a FileNotFoundError and failing the workflow.

Traceback observed:

Exception ignored in: <gitdb.util.LazyMixin object at 0x...>
Traceback (most recent call last):
  File ".../gitpython/git/config.py", line ..., in __del__
    self.write()
  File ".../gitpython/git/config.py", line ..., in write
    ...
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/.../config'

Fix

Call config.release() before returning from clone(). This explicitly flushes and closes the GitConfigParser, preventing its destructor from running after the temp directory is removed.

config.set_value("commit", "gpgsign", "false")
config.release()  # <-- added

return repo

This follows the pattern recommended in the GitPython docs and is consistent with using config_writer() as a context manager.

Summary by CodeRabbit

  • Bug Fixes
    • Finalize git configuration after writing settings during cloning to prevent incomplete config state.

@matthiasbalke matthiasbalke requested a review from frenck as a code owner March 28, 2026 23:14
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

Walkthrough

Finalizes the git config writer after setting values and strengthens repository cleanup by closing the git repo handle, removing its reference, forcing garbage collection, and then deleting the working directory. Also updates the Docker build to install the package from a specific Git revision.

Changes

Cohort / File(s) Summary
Git Configuration Finalization
repositoryupdater/github.py
Added a config.release() call after writing user.email, user.name, and disabling commit.gpgsign to explicitly finalize the git config writer.
Repository Cleanup and GC
repositoryupdater/repository.py
Cleanup now captures the working directory, closes the git_repo handle, deletes the git_repo reference, calls gc.collect(), then removes the working directory recursively.
Docker build: package source change
action/Dockerfile
Replaced PyPI installation of repository-updater==2.0.1 with installing from a specific Git revision (git+https://github.com/.../repository-updater.git@fix/config-writer-not-released).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibble configs, then set them free,
Close the door, sweep out debris.
GC hums softly, burrow neat and bright,
Hop on—new builds take flight! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: explicitly releasing GitConfigParser to prevent destructor errors on Python 3.14, which directly matches the core fix in repositoryupdater/github.py.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@matthiasbalke
Copy link
Copy Markdown
Author

matthiasbalke commented Mar 28, 2026

This happens in my own addon repository: https://github.com/matthiasbalke/ha-addons-edge/tree/ef66f5317bf660f8f45f2a4436af6b511f869abf

I validated the patch using my own addon repository. The error is gone now.

Before

Run hassio-addons/repository-updater@88408cfe4468560e649cb9c227431a696c9298ea
/usr/bin/docker run --name ed0a35601af56f3d461d857a30d9d31b74fe_2140b0 --label 45ed0a --workdir /github/workspace --rm -e "INPUT_APP" -e "INPUT_REPOSITORY" -e "INPUT_TOKEN" -e "INPUT_ADDON" -e "INPUT_FORCE" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e "ACTIONS_RESULTS_URL" -e "ACTIONS_ORCHESTRATION_ID" -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp":"/github/runner_temp" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/ha-addons-edge/ha-addons-edge":"/github/workspace" 45ed0a:35601af56f3d461d857a30d9d31b74fe
Home Assistant Community Apps Repository Updater, version 2.0.1
Home Assistant Community Apps Repository Updater
---------------------------------------------------
Authenticated with GitHub as Matthias Balke
Locating app repository "matthiasbalke/ha-addons-edge"...Found!
Cloning app repository...Cloned!
Locating repository app list...Loaded!
Repository channel: edge
Only updating app "todo" this run!
Start loading repository apps:
--------------------------------------------------
Loading app collabora-code
Loading app information from: https://github.com/matthiasbalke/addon-collabora-code
Current version: 0a18530 (0a18530)
--------------------------------------------------
Done loading all repository apps
Re-generating app repository README.md file...Done
Committing changes...Skipped, no changes.
Cleanup...Done
Exception during destruction of GitConfigParser
Traceback (most recent call last):
  File "/usr/local/lib/python3.14/site-packages/git/config.py", line 423, in release
    self.write()
    ~~~~~~~~~~^^
  File "/usr/local/lib/python3.14/site-packages/git/config.py", line 114, in assure_data_present
    return func(self, *args, **kwargs)
  File "/usr/local/lib/python3.14/site-packages/git/config.py", line 755, in write
    with open(fp, "wb") as fp_open:
         ~~~~^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/repoupdatereyxunvaz/.git/config'

After

Run matthiasbalke/repository-updater@7bc8c6f8e4e8f404f3c9bc2e016e94080fc614ac
/usr/bin/docker run --name f483cc7962c21a44a849830f822f06646cb_d27e82 --label 997f48 --workdir /github/workspace --rm -e "INPUT_APP" -e "INPUT_REPOSITORY" -e "INPUT_TOKEN" -e "INPUT_ADDON" -e "INPUT_FORCE" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUT
Home Assistant Community Apps Repository Updater, version 2.0.1
Home Assistant Community Apps Repository Updater
---------------------------------------------------
Authenticated with GitHub as Matthias Balke
Locating app repository "matthiasbalke/ha-addons-edge"...Found!
Cloning app repository...Cloned!
Locating repository app list...Loaded!
Repository channel: edge
Only updating app "todo" this run!
Start loading repository apps:
--------------------------------------------------
Loading app collabora-code
Loading app information from: https://github.com/matthiasbalke/addon-collabora-code
Current version: 0a18530 (0a18530)
--------------------------------------------------
Loading app todo
Loading app information from: https://github.com/matthiasbalke/addon-todo
Current version: bc96e92 (bc96e92)
Latest version: bc96e92 (bc96e92)
This app is up to date.
--------------------------------------------------
Done loading all repository apps
Re-generating app repository README.md file...Done
Committing changes...Skipped, no changes.
Cleanup...Done

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
repositoryupdater/repository.py (1)

215-219: Cleanup sequence is correct, but App objects may retain references to git_repo.

The cleanup logic properly captures the working directory, closes the repo handle, deletes the reference, and forces garbage collection before removing the directory. This addresses the GitConfigParser destructor issue.

Based on the PR comments noting this fix "was not sufficient," App objects created in load_repository() receive a reference to self.git_repo (stored as self.repository). These references may prevent the Repo object from being garbage collected even after del self.git_repo.

Consider clearing App references before cleanup:

♻️ Clear App references before cleanup
     def cleanup(self):
         """Cleanup after you leave."""
         click.echo("Cleanup...", nl=False)
         working_dir = self.git_repo.working_dir
+        self.apps.clear()
         self.git_repo.close()
         del self.git_repo
         gc.collect()
         shutil.rmtree(working_dir, True)
         click.echo(crayons.green("Done"))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@repositoryupdater/repository.py` around lines 215 - 219, Before closing and
deleting self.git_repo, clear any lingering references from App instances that
were assigned the repo in load_repository(): iterate over the App objects (those
created in load_repository or stored on self, e.g. self.apps or wherever they
are kept) and set each_app.repository = None (or delete the attribute) so they
no longer reference self.git_repo; only after wiping those App.repository
references proceed with self.git_repo.close(), del self.git_repo, gc.collect(),
and shutil.rmtree(working_dir, True).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@repositoryupdater/repository.py`:
- Around line 215-219: Before closing and deleting self.git_repo, clear any
lingering references from App instances that were assigned the repo in
load_repository(): iterate over the App objects (those created in
load_repository or stored on self, e.g. self.apps or wherever they are kept) and
set each_app.repository = None (or delete the attribute) so they no longer
reference self.git_repo; only after wiping those App.repository references
proceed with self.git_repo.close(), del self.git_repo, gc.collect(), and
shutil.rmtree(working_dir, True).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef8a93c3-1bc0-4f6b-882f-e3856d757f6d

📥 Commits

Reviewing files that changed from the base of the PR and between 1777013 and abe11cf.

📒 Files selected for processing (1)
  • repositoryupdater/repository.py

@matthiasbalke matthiasbalke force-pushed the fix/config-writer-not-released branch from bab675c to 1777013 Compare March 29, 2026 00: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