Metadata-Version: 2.4
Name: github-issue-eraser
Version: 0.0.2
Summary: List and delete closed GitHub issues after backing up issue images.
Author: Kaizten Analytics
License-Expression: LicenseRef-Proprietary
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# GitHub Issue Eraser

`github-issue-eraser` lists and deletes closed GitHub issues by using the authenticated GitHub CLI account. Before deleting a closed issue that contains images, it looks for the local clone under your home directory by default and backs those images up into the clone's `images/` directory.

Deletion is guarded: without `--delete`, the erase workflow is a dry run.

## Behavior

- The script accepts only named options; it does not use positional arguments.
- Only closed issues are listed or deleted.
- Pull requests are naturally excluded by `gh issue list`.
- Organization mode discovers non-archived repositories with issues enabled.
- Repository mode checks `ORGANIZATION/REPOSITORY`.
- Image URLs are extracted from the issue body and comments.
- Markdown images, HTML `<img src="...">` tags, direct image URLs, and common
  GitHub issue attachment URLs are detected.
- In delete mode, and in dry-run mode with `--image-download`, images are saved
  under:

```text
LOCAL_REPOSITORY/
  images/
    issue-123-01-image.png
```

- In default dry-run mode, images are saved under:

```text
/tmp/github-issue-eraser/
  ORGANIZATION/
    REPOSITORY/
      images/
        issue-123-01-image.png
```

- When a previously saved exact image is already present, the script reuses it
  instead of saving another copy. The `images/` directory contains only the
  downloaded image files.

If an issue contains images and the local clone cannot be found, the script skips deletion for that issue. If an image download fails, the script also skips deletion for that issue. Issues without images do not require a local clone.

At the end of a dry run or delete run, the script prints a summary with the organization name, number of repositories checked, number of matching local repositories found, and one table row for each inspected closed issue. The table reports the closed issue number, number of images found, number of images saved, and whether all images were downloaded. Issues are deleted only when this image download status is `true`.

## Requirements

- Python 3.10 or newer
- GitHub CLI (`gh`)
- An authenticated GitHub CLI session:

```bash
gh auth login
```

## Building

### Testing

Run the unit tests from the project root:

```bash
python3 -m unittest discover -s tests -v
```

### Package artifact

Build and validate the package artifacts:

```bash
./build-package.sh
```

This creates the wheel and source distribution under `dist/` and checks the package metadata with Twine.

### Publish artifact

Publish the generated artifacts to PyPI:

```bash
./publish-pypi.sh
```

The publish script checks that Twine is available, creates a local `.venv` for Twine when needed, verifies that `dist/` contains generated artifacts, and then uploads them. If PyPI returns HTTP 400 because the package version was already published, the script reports that clearly; increment the version in `pyproject.toml`, rebuild, and publish again.

### Install artifact

The software can be installed as follows (using a virtual environment):
```sh
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install github-issue-eraser
```

## Usage

After installing the package, use the `github-issue-eraser` command. From a source checkout, you can also run `./github-issue-eraser.py`.

### Help

```bash
github-issue-eraser -h
usage: github-issue-eraser [-h] --organization ORGANIZATION [--repository REPOSITORY] [--repos-root REPOS_ROOT] [--limit LIMIT] [--list] [--delete] [--image-download]

List and delete closed GitHub issues after backing up issue images.

options:
  -h, --help            show this help message and exit
  --organization, --org ORGANIZATION
                        GitHub organization or owner.
  --repository REPOSITORY
                        Repository name inside the organization.
  --repos-root REPOS_ROOT
                        Local repository search root. Default: ~
  --limit LIMIT         Maximum items to fetch per gh list call. Default: 1000
  --list                List closed issues without preparing deletion.
  --delete              Actually delete closed issues. Without this flag, deletion mode is a dry run.
  --image-download      In dry-run mode, download issue images into each local repository instead of /tmp.
```

### Use cases

List closed issues in every issue-enabled, non-archived repository owned by an organization:

```bash
github-issue-eraser --organization ORGANIZATION --list
```

List closed issues in one repository:

```bash
github-issue-eraser --organization ORGANIZATION --repository REPOSITORY --list
```

Preview deletion work without deleting anything:

```bash
github-issue-eraser --organization ORGANIZATION
github-issue-eraser --organization ORGANIZATION --repository REPOSITORY
```

By default, dry-run image downloads are saved under `/tmp/github-issue-eraser`
so local repositories are not modified. To execute a dry run while saving images
into each matching local repository's `images/` directory, use
`--image-download`:

```bash
github-issue-eraser --organization ORGANIZATION --repository REPOSITORY --image-download
```

Delete closed issues after image backup checks:

```bash
github-issue-eraser --organization ORGANIZATION --delete
github-issue-eraser --organization ORGANIZATION --repository REPOSITORY --delete
```

Use `--repos-root` when local clones are not under your home directory:

```bash
github-issue-eraser --organization ORGANIZATION --repository REPOSITORY --repos-root ~/work --delete
```

Use `--limit` to change how many repositories and issues are fetched per GitHub
CLI list call:

```bash
github-issue-eraser --organization ORGANIZATION --limit 2000 --list
```

## Examples

Dry-run output includes the repositories checked, closed issues found, local
repository path, image URLs to download, and the action that would be taken:

```bash
github-issue-eraser --organization kaizten --repository tools
```

After reviewing the dry run, run with `--delete` to actually remove closed
issues:

```bash
github-issue-eraser --organization kaizten --repository tools --delete
```
