Metadata-Version: 2.4
Name: release-scope
Version: 0.1.0
Summary: Collect what sits between production and the default branch across GitLab services: tags, MRs, Jira keys, failed jobs
Keywords: release,gitlab,jira,deployments,merge-requests,ci,cli,python
Author: Artur Shiriev
Author-email: Artur Shiriev <me@shiriev.ru>
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: Build Tools
Requires-Dist: typer>=0.13
Requires-Dist: pydantic>=2 ; python_full_version < '3.12'
Requires-Dist: pydantic>=2.0.2 ; python_full_version == '3.12.*'
Requires-Dist: pydantic>=2.8.2 ; python_full_version == '3.13.*'
Requires-Dist: pydantic>=2.12 ; python_full_version >= '3.14'
Requires-Dist: pydantic-settings>=2
Requires-Dist: modern-di-typer>=3,<4
Requires-Dist: httpx2>=2
Requires-Dist: httpware[pydantic]>=0.15.0
Requires-Python: >=3.11, <4
Project-URL: Homepage, https://modern-python.org
Project-URL: Repository, https://github.com/modern-python/release-scope
Project-URL: Issues, https://github.com/modern-python/release-scope/issues
Project-URL: Changelog, https://github.com/modern-python/release-scope/releases
Description-Content-Type: text/markdown

[![PyPI version](https://img.shields.io/pypi/v/release-scope.svg)](https://pypi.org/project/release-scope/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/release-scope.svg)](https://pypi.org/project/release-scope/)
[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/modern-python/release-scope/actions/workflows/ci.yml)
[![CI](https://github.com/modern-python/release-scope/actions/workflows/ci.yml/badge.svg)](https://github.com/modern-python/release-scope/actions/workflows/ci.yml)
[![License](https://img.shields.io/github/license/modern-python/release-scope.svg)](https://github.com/modern-python/release-scope/blob/main/LICENSE)

`release-scope` collects what sits between production and the default branch across GitLab services: tags, MRs,
Jira keys, failed jobs.

For every service it reads the latest successful production deployment, walks the default branch down to that
commit, and writes one JSON report: a row per merge request or direct commit, newest first, with the tags that
point into it, the environments running it, the Jira keys its MR mentions, and the failed jobs of its main-branch
and tag pipelines.

## Quickstart

```sh
export RELEASE_SCOPE_GITLAB__ENDPOINT=https://gitlab.example.com
export RELEASE_SCOPE_GITLAB__TOKEN=glpat-...          # read_api scope
export RELEASE_SCOPE_ENVIRONMENTS='["prod", "preview"]'
export RELEASE_SCOPE_PRODUCTION_ENVIRONMENT=prod

uvx release-scope collect --group team/backend --output report.json --cache cache.json
```

`--group` and `--project` are repeatable and can be mixed. The command exits `1` when any service failed to
collect; the report is still written and names the error on that service.

## Configuration

Every setting is an environment variable; nothing about a GitLab or Jira instance is built in.

| Variable | Default | Meaning |
|---|---|---|
| `RELEASE_SCOPE_GITLAB__ENDPOINT` | `https://gitlab.com` | GitLab base URL |
| `RELEASE_SCOPE_GITLAB__TOKEN` or `GITLAB_TOKEN` | required | Token with `read_api` |
| `RELEASE_SCOPE_ENVIRONMENTS` | `["production"]` | Environments shown per service, as a JSON list |
| `RELEASE_SCOPE_PRODUCTION_ENVIRONMENT` | `production` | Environment whose deployed commit starts the range |
| `RELEASE_SCOPE_JIRA_ENDPOINT` | unset | When set, Jira keys link to `<endpoint>/browse/<KEY>` |
| `RELEASE_SCOPE_JIRA_PROJECT_KEYS` | `[]` | Keep only keys of these Jira projects; empty keeps all |
| `RELEASE_SCOPE_MAX_COMMITS` | `1000` | Stop walking a service's range after this many commits |
| `RELEASE_SCOPE_REQUEST_TIMEOUT` | `10` | Per-request timeout in seconds |

## Report

The report is versioned by `schema_version`; the models live in
[`release_scope/_report.py`](https://github.com/modern-python/release-scope/blob/main/release_scope/_report.py).
One row, trimmed:

```json
{
  "kind": "merge_request",
  "tags": [{"name": "1.2.0", "url": "...", "pipeline": {"id": 201, "status": "success", "failed_jobs": []}}],
  "merge_requests": [{"iid": 12, "title": "SHOP-12 new endpoint", "url": "..."}],
  "commits": [{"sha": "c3...", "title": "Merge branch 'feature/SHOP-12'"}],
  "jira_keys": [{"key": "SHOP-12", "url": "https://jira.example.com/browse/SHOP-12"}],
  "environments": ["preview"],
  "main_pipeline": {"id": 103, "status": "failed", "failed_jobs": [{"kind": "job", "name": "lint", "allow_failure": false}]}
}
```

## Cache

`--cache` names a JSON file that is read if present and rewritten atomically after the run. It holds only facts
that do not change once settled: which merge requests a commit belongs to, and the failed jobs of a finished
pipeline keyed by its `updated_at`, so a retried job invalidates the entry. Entries the run did not use are
dropped. A missing, corrupt, or older-schema cache is ignored with a warning; the cache only saves requests and
never changes the report.
