Metadata-Version: 2.4
Name: releasing
Version: 7.1.0
Summary: Release helpers for projects that publish from a Git-tracked source tree
Keywords: release,packaging,pypi,changelog,markdown,versioning
Author: foundata GmbH, Andreas Haerter
Author-email: Andreas Haerter <ah@foundata.com>
License-Expression: GPL-3.0-or-later
License-File: LICENSES/GPL-3.0-or-later.txt
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: System :: Software Distribution
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: markdown-it-py>=3.0,<5
Requires-Dist: packaging>=23.2
Requires-Dist: typing-extensions>=4.4
Requires-Dist: pyyaml>=6
Maintainer: Andreas Haerter
Maintainer-email: Andreas Haerter <ah@foundata.com>
Requires-Python: >=3.11
Project-URL: Homepage, https://foundata.com/en/projects/releasing/
Project-URL: Documentation, https://foundata.com/en/projects/releasing/#doc
Project-URL: Repository, https://foundata.com/en/projects/releasing/#source
Project-URL: Issues, https://foundata.com/en/projects/releasing/#issues
Project-URL: Changelog, https://foundata.com/en/projects/releasing/#changelog
Description-Content-Type: text/markdown

# releasing (helpers and tooling for software releases)

<!--
SPDX-FileCopyrightText: foundata GmbH <https://foundata.com>
SPDX-License-Identifier: GPL-3.0-or-later
-->

Release helpers for projects that publish from a Git-tracked source tree.

> **Important:** This tooling is built for foundata's own release processes. You
> are welcome to use it but requests to adapt our toolset to different release
> policies or processes are out of scope.

Components and tools:

- **`release`: one command for error-prone steps around a release:** version
  sites, changelogs, artifacts, tags, the push, the upload, the forge's release
  entry, post-publish verification, and the repository Markdown a package index
  needs. Each step is one subcommand; the order of steps stays in each project's
  own procedure.
- **`tools/`: small helpers for maintainers:** reviewing unpushed commit
  messages, and keeping the Markdown configuration of many repositories in
  step. They run from a clone; see [Repository tools](#repository-tools).

<!-- rumdl-disable MD033 -->
<!-- HTML for consistent rendering across limited platform parsers -->
<div align="center" id="project-readme-header">
<br>
<br>

**⭐ Found this useful? Support open-source and star this project:**

[![GitHub repository](https://img.shields.io/github/stars/foundata/releasing.svg)](https://github.com/foundata/releasing)

<br>
</div>
<!-- rumdl-enable MD033 -->


## Table of contents<a id="toc"></a>

- [Installation](#installation)
- [Commands](#commands)
  - [`release`](#release)
- [Output](#output)
- [Repository tools](#repository-tools)
- [Releasing this package](#releasing-this-package)
- [Development](#development)
- [Licensing, copyright](#licensing-copyright)
- [Author information](#author-information)


## Installation<a id="installation"></a>

[![PyPI package version](https://img.shields.io/pypi/v/releasing.svg?logo=pypi)](https://pypi.org/project/releasing)

Add it to a development dependency group of the project that releases:

```toml
[dependency-groups]
dev = ["releasing"]
```

Run it without installing anything into the project:

```sh
uvx --from git+https://github.com/foundata/releasing release --help
```

Python 3.11 to 3.14 are supported. The minimum is 3.11 rather than the 3.12
baseline of the foundata Python guide because the package is a development
dependency of projects that target Debian 12, which ships Python 3.11.


## Commands<a id="commands"></a>

### `release`<a id="release"></a>

Project-aware subcommands read the release declaration, one table in
`pyproject.toml`, `releasing.toml` or `.releasing.toml`. Markdown preparation
and explicit-version artifact operations also work independently; see
[The release declaration](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/config.md).

- `release config check`: validate the declaration and every file it names,
  and print the effective values.
- `release version check` and `release version bump`: every declared
  version site, the lockfile, lockstep pins and the tag agree, or move them all
  to a new version. See [Version sites](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/version.md).
- `release changelog check`, `show` and `release`: Keep a Changelog
  sections, dates and links are consistent, one section is printed for a
  release description, or the unreleased entries become a dated section. See
  [Changelog sections](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/changelog.md).
- `release build`: export a committed revision, prepare the index Markdown
  inside that export, build, check and record a manifest. Ansible builds also
  require passing sanity sessions on that commit. See
  [Building from an exported revision](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/build.md).
- `release tag create`, `check` and `delete`: a guarded annotated tag, and a
  deletion that stays legal only while no release exists. See
  [Release tags](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/tag.md).
- `release status`: report which steps of a release are done, pending or
  broken. See [Where a release stands](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/status.md).
- `release push`: publish the release branch and its tag together, after
  re-checking both. See [Publishing the branch and the tag](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/push.md).
- `release publish`: upload exactly the files a manifest names, refusing any
  other file beside them. See [Uploading what was validated](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/publish.md).
- `release forge release-create`: create the forge's release entry from the
  changelog and the manifest. See
  [The forge's release entry](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/forge-release.md).
- `release verify`: check that the index serves the validated files and the
  forge reports the tag as latest. For PyPI, also check that an isolated install
  reports the version. For a project that publishes no artifact, check the
  remote release tag and the forge's latest release. See
  [Verifying a published release](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/verify.md).
- `release artifacts check`, `manifest` and `verify`: distributions carry
  the right version, a description without relative links and no litter; their
  digests are recorded and later compared. See [Artifacts](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/artifacts.md).
- `release markdown prepare`: rewrite repository-relative link and image
  destinations to absolute URLs without reformatting the document. See
  [Preparing Markdown for package indexes](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/markdown.md).
- `release markdown requirements check`, `assign`, `list` and `unlabeled`:
  validate stable requirement identifiers, assign new ones, export an inventory
  or review unlabeled items. See
  [Maintaining requirement identifiers](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/requirements.md).
- `release quay description-set`: publish the README of a tag as the
  description of Quay repositories, free of the raw HTML that Quay shows as
  text or drops, and read it back. See
  [The Quay repository description](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/quay.md).

The end-to-end order is in
[Releasing a Python package](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/python-packages.md),
[Releasing an Ansible collection](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/ansible-collections.md) and
[Releasing a source repository](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/source-repositories.md).


## Output<a id="output"></a>

Every command sends its result to stdout and its progress to stderr, so
output can be redirected without knowing which command is in hand.

Stdout carries what the command produced: the tag it created, the files it
built, the changelog section, the manifest JSON or the report. Checks can
produce results too: `config check` prints the effective configuration,
`version check` prints the version, and `artifacts check` prints a summary per
artifact. Checks without result data leave stdout empty. Every check
communicates success or failure through its exit status.

Stderr carries what happened on the way: what is being done, every command
that changed something, and every request to a forge or an index.

```console
$ release tag create 2.2.0 --manifest ../dist-2.2.0/artifacts.json
» Found artifacts built from 41db3420c2d6 in the manifest
» Verified the working tree is clean
» Exporting 41db3420c2d6 into a temporary directory
$ git -C /home/example/project archive --format=tar 41db3420c2d6...
» Checking version sites, lockfile, pins and changelog in the export
» GET https://api.github.com/repos/foundata/releasing/releases/tags/v2.2.0 → 404
$ git -C /home/example/project tag -a v2.2.0 41db3420c2d6 -m 'version 2.2.0'
v2.2.0
```

`--quiet` (`-q`), accepted before or after the command, keeps stdout and drops
the progress on stderr. It never suppresses an error. Redirecting stderr with
`2>/dev/null` discards errors as well as progress. Use `2>&1 | tee release.log`
to keep both streams together.

Every command that changes something accepts `--dry-run`: it reports what it
would do, marks the commands it would run, and changes nothing. A command that
only reads does not offer the flag.

Every command exits with `0` on success, `1` when a check or operation fails
and `2` on invalid usage.


## Repository tools<a id="repository-tools"></a>

This repository also carries small helpers for recurring work before a release
and for maintaining several projects at once. They live in
[`tools/`](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/tools/) and are not part of the installed package; run them from a
clone of this repository.

- [`git-review-unpushed.sh`](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/tools/git-review-unpushed.sh): visit the
  commits the current branch has not pushed yet, oldest first, and edit their
  messages before they are published. Works in any Git repository and never
  pushes. See its [README](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/tools/git-review-unpushed-README.md).
- [`markdown-config-drift.sh`](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/tools/markdown-config-drift.sh): compare every
  repository's `.rumdl.toml` with the one the foundata Markdown guide shows,
  name the stale copies, and with `-w` rewrite them. See
  [Setup and checks](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/DEVELOPMENT.md#setup-and-checks).


## Releasing this package<a id="releasing-this-package"></a>

`releasing` releases itself with its own commands. The procedure is in the
[development guide](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/DEVELOPMENT.md#releases); the recipe it follows is
[Releasing a Python package](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/docs/python-packages.md). The declaration is
the `[tool.releasing]` table in `pyproject.toml`.


## Development<a id="development"></a>

See the [development guide](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/DEVELOPMENT.md) for the checks, the test layout
and the corpus maintenance.


## Licensing, copyright<a id="licensing-copyright"></a>

<!--REUSE-IgnoreStart-->
<!-- should match SPDX-PackageSupplier -->
Copyright (c) 2026, foundata GmbH <https://foundata.com>

This project is licensed under the GNU General Public License v3.0 or later
(SPDX-License-Identifier: `GPL-3.0-or-later`), see
[`LICENSES/GPL-3.0-or-later.txt`](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/LICENSES/GPL-3.0-or-later.txt) for the full
text.

The [`REUSE.toml`](https://github.com/foundata/releasing/blob/refs/tags/v7.1.0/REUSE.toml) file provides detailed licensing and copyright
information in a human- and machine-readable format. This includes parts that
may be subject to different licensing or usage terms, such as third-party
components. The repository conforms to the
[REUSE specification](https://reuse.software/spec/). You can use
[`reuse spdx`](https://reuse.readthedocs.io/en/latest/readme.html#cli) to
create an
[SPDX software bill of materials (SBOM)](https://en.wikipedia.org/wiki/Software_Package_Data_Exchange).
<!--REUSE-IgnoreEnd-->

[![REUSE status](https://api.reuse.software/badge/github.com/foundata/releasing)](https://api.reuse.software/info/github.com/foundata/releasing)


### Trademarks<a id="trademarks"></a>

Third-party trademarks used in this repository:

- Ansible® is a trademark of Red Hat, LLC, registered in the United States and
  other countries.
- Debian® is a trademark of Software in the Public Interest, Inc., registered in
  Germany and the United States.
- Linux® is a trademark of Linus Torvalds, registered in Germany, the European
  Union and the United States.
- Windows® is a trademark of Microsoft Corporation, registered in Germany, the
  European Union and the United States.

Their use here is purely descriptive and does not imply any affiliation with or
endorsement by the trademark holders.

Own and licensed trademarks used in this repository:

- foundata® is a trademark of [IPAM GmbH](https://ipam-services.com/),
  registered in Germany and the European Union, licensed to
  [foundata GmbH](https://foundata.com/).


## Author information<a id="author-information"></a>

This [project](https://foundata.com/en/projects/) was created and is maintained
by [foundata](https://foundata.com/).
