# Maintaining

## Semver

This project tries to follow the [semver policy](https://semver.org/) - although not followed 100% in the past.

Usually an entry of {{% badge style="breaking" %}}Breaking{{% /badge %}} on the [What's new](introduction/releasenotes) page causes a new major release number.

All other entries on the [What's new](introduction/releasenotes) page will increase the minor release number.

Releases resulting in a new major or minor number are called main release.

Releases containing bugfixes only, are only increasing the patch release number. Those releases don't result in announcements on the [What's new](introduction/releasenotes) page.

Entries on the [What's new](introduction/releasenotes) page are checked and enforced during the `version-release` GitHub Action.

## Managing Issues

Issues are categorized and managed by assigning [labels](#labels) to it.

Once working on an issue, assign it to a fitting maintainer.

When done, close the ticket. Once an issue is closed, it needs to be assigned to next release milestone.

A once released ticket is not allowed to be reopened and rereleased in a different milestone. This would cause the changelog to be changed even for the milestone the issue was previously released in. Instead write a new ticket.

## Managing Pull Requests

If a PR is merged and closed it needs an accompanied issue assigned to. If there is no issue for a PR, the maintainer needs to create one.

You can assign multiple PRs to one issue as long as they belong together.

Usually set the same labels and milestone for the PR as for the accompanied issue.

## Labels

### Kind

An issue that results in changesets must have exactly one of the following labels. This needs to be assigned latest before release.

| Label                                                    | Description                                | Changelog section |
|----------------------------------------------------------|--------------------------------------------|-------------------|
| {{% badge color="#5498d8" %}}documentation{{% /badge %}} | Improvements or additions to documentation | -                 |
| {{% badge color="#99d856" %}}discussion{{% /badge %}}    | This issue was converted to a discussion   | -                 |
| {{% badge color="#d8d104" %}}task{{% /badge %}}          | Maintenance work                           | Maintenance       |
| {{% badge color="#d8ae04" %}}feature{{% /badge %}}       | New feature or request                     | Features          |
| {{% badge color="#d88704" %}}bug{{% /badge %}}           | Something isn't working                    | Fixes             |

### Impact

If the issue would cause a new main release due to [semver semantics](#semver) it needs one of the according labels and the matching badge on the [What's new](introduction/releasenotes) page.

| Label                                               | Description                                             |
|-----------------------------------------------------|---------------------------------------------------------|
| {{% badge color="#d73a4a" %}}change{{% /badge %}}   | Introduces changes with existing installations          |
| {{% badge color="#d73a4a" %}}breaking{{% /badge %}} | Introduces breaking changes with existing installations |

### Declination

If an issue does not result in changesets but is closed anyways, it must have exactly one of the following labels.

| Label                                                 | Description                               |
|-------------------------------------------------------|-------------------------------------------
| {{% badge color="#9fa2a5" %}}duplicate{{% /badge %}}  | This issue or pull request already exists |
| {{% badge color="#9fa2a5" %}}invalid{{% /badge %}}    | This doesn't seem right                   |
| {{% badge color="#9fa2a5" %}}support{{% /badge %}}    | Request for achieving a special goal      |
| {{% badge color="#9fa2a5" %}}unresolved{{% /badge %}} | No progress on this issue                 |
| {{% badge color="#9fa2a5" %}}update{{% /badge %}}     | A change in behavior after updat          |
| {{% badge color="#9fa2a5" %}}wontchange{{% /badge %}} | This will not be worked on                |

### Halt

You can assign one further label out of the following list to signal readers that development on an open issue is currently halted for different reasons.

| Label                                                    | Description                                             |
|----------------------------------------------------------|---------------------------------------------------------|
| {{% badge color="#998f6b" %}}blocked{{% /badge %}}       | Depends on other issue to be fixed first                |
| {{% badge color="#998f6b" %}}idea{{% /badge %}}          | A valuable idea that's currently not worked on          |
| {{% badge color="#998f6b" %}}undecided{{% /badge %}}     | No decision was made yet                               |
| {{% badge color="#6426ff" %}}helpwanted{{% /badge %}}    | Great idea, send in a PR                                |
| {{% badge color="#6426ff" %}}needsfeedback{{% /badge %}} | Further information is needed                           |

### 3rd-Party

If the issue is not caused by a programming error in the themes own code, you can label the causing program or library.

| Label                                               | Description                                                 |
|-----------------------------------------------------|-------------------------------------------------------------|
| {{% badge color="#e550a7" %}}asciidoc{{% /badge %}} | This is a topic related to processing of AsciiDoc           |
| {{% badge color="#e550a7" %}}browser{{% /badge %}}  | This is a topic related to the browser but not the theme    |
| {{% badge color="#e550a7" %}}device{{% /badge %}}   | This is a topic related to a certain device                 |
| {{% badge color="#e550a7" %}}hugo{{% /badge %}}     | This is a topic related to Hugo itself but not the theme    |
| {{% badge color="#e550a7" %}}mermaid{{% /badge %}}  | This is a topic related to Mermaid itself but not the theme |

## SBOM

Every third-party resource the project uses is declared in `docs/data/relearn/thirdparty.toml`. That file is the single source of truth behind the [credits](more/credits) page, the [SBOM](configuration/publishing/sbom) at `sbom.cdx.json`, and several checks in the test suite.

**When you vendor an update, change its `version` in the same commit that changes the files.** A version is knowable at the moment of vendoring and at no other time. Some of these bundles carry no version string at all, and the ones that do disagree about where to put it. Nothing can check it, which is why every component carries a digest of its files as well: a component that changed on disk without changing its `version` still shows up in the diff of `sbom.cdx.json`.

A font is the exception that can be asked. It declares its own version inside the file, where subsetting and conversion both leave it, so `npm run fontversion` in the infra repository reads it back out of what you vendored rather than out of the page you downloaded from.

The test suite fails when the declaration and the vendored tree disagree, in either direction: a directory holding files that no component claims, or a component claiming paths that no longer exist. Add a new dependency to the declaration or the build stays red.

**`npm test` also fails when the committed `sbom.cdx.json` is not what the declaration currently renders**, so regenerating is a step of the change rather than an afterthought.

````bash
cd ../hugo-theme-relearn-infra
npm ci
npm run sbom:update
````

The release workflow regenerates the file too, after it has stamped the new version - the document's own version and timestamp come from `layouts/partials/version.txt` and `CHANGELOG.md`, which hold the values of the release being made only from that point on. Until then those two fields keep naming the previous release, while the components track whatever is vendored.

## Making Releases

A release is based on a milestone named like the release itself - just the version number, eg: `1.2.3`. It's in the maintainers responsibility to check [semver semantics](#semver) of the milestone's name prior to release and change it if necessary.

Making releases is automated by the `version-release` GitHub workflow. It requires the version number of the milestone that should be released. The release will be created from the `main` branch of the repository.

Treat released milestones as immutable. Don't rerelease an already released milestone. An already released milestone may already been consumed by your users.

### Automation Steps

During execution of the workflow a few things are checked. If a check fails the action fails, resulting in no new release. You can correct the errors afterwards and rerun the action.

The following checks will be enforced

- the [test suite](development/testing) passes against both the minimum supported and the latest Hugo release, which includes the [dependency declaration](#sbom) matching the vendored tree and `sbom.cdx.json` matching the declaration
- the milestone exists
- there is at least one closed issue assigned to the milestone
- all assigned issues for this milestone are closed
- if it's a main release, there must be an accompanying releasenotes file present in the repo at `introduction/releasenotes/<major>/<minor>.en.md`

After a successful run of the action

- the changelog at `introduction/changelog/<major>/<minor>/<patch>.<lang>.md` is created for english and piratish, including missing generic upper level files
- the `CHANGELOG.md` is updated
- the releasenotes at `introduction/releasenotes/<major>/<minor>.en.md` are updated, including release version and release date
- missing generic upper level files for english and piratish are created
- the version number for the `<meta generator>` is updated
- the [SBOM](#sbom) at `sbom.cdx.json` is regenerated
- the updated files are committed
- the milestone is closed
- the repository is tagged with the version number (eg. `1.2.3`), the main version number (eg. `1.2.x`) and the major version number (eg. `1.x`)
- a new entry in the [GitHub release list](https://github.com/McShelby/hugo-theme-relearn/releases) with the according changelog will be created
- `sbom.cdx.json` is attached to that release, so it can be downloaded by version
- a signed build provenance attestation is issued for the `sbom.cdx.json` at that tag, unless the signing service is unavailable - a release is never held up for it
- the [official documentation](https://mcshelby.github.io/hugo-theme-relearn/) is built and deployed
- the [test suite](development/testing)'s baselines of the documentation's file set are regenerated and pushed to the infra repository, so the next scheduled test run passes, and the infra repository is tagged with the release's version; this needs the `INFRA_DEPLOY_KEY` secret holding the private half of a deploy key with write access to the infra repository
- the version number for the `<meta generator>` is updated to a temporary and committed (this helps to determine if users are running directly on the main branch or are using releases)
- a new milestone for the next patch release is created (this can later be renamed to a main release if necessary)

### Rehearsing on a Branch

The workflow only performs an actual release when it runs on `main`. Started on any other branch it runs the parts that are safe to repeat - the [test suite](development/testing) and the documentation build - and skips every step that changes something outside the run. The milestone input is ignored there, and only required on `main`.

In both cases the built site is uploaded as a workflow artifact named `<workflow>-<run number>-<run id>` and kept for 30 days, so you can download the result of a run and inspect it before releasing for real. It is found at the bottom of the run's summary page in the [Actions tab](https://github.com/McShelby/hugo-theme-relearn/actions/workflows/version-release.yaml).
