Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@ jobs:
exit 1
fi

- name: Extract changelog section for release
Comment thread
AuraMindNest marked this conversation as resolved.
id: changelog
env:
PLUGIN_VERSION: ${{ steps.versions.outputs.plugin_version }}
WEBLATE_VERSION: ${{ steps.versions.outputs.weblate_version }}
run: |
set -euo pipefail
notes_file="${RUNNER_TEMP}/release-notes.md"
python3 <<'PY'
import os
import re
from pathlib import Path

version = os.environ["PLUGIN_VERSION"]
weblate_version = os.environ["WEBLATE_VERSION"]
changelog = Path("CHANGELOG.md").read_text()
pattern = rf"^## \[{re.escape(version)}\].*?(?=^## |\Z)"
match = re.search(pattern, changelog, re.MULTILINE | re.DOTALL)
if not match:
raise SystemExit(
f"No ## [{version}] section found in CHANGELOG.md"
)
section = match.group(0).rstrip()
notes_file = Path(os.environ["RUNNER_TEMP"]) / "release-notes.md"
notes_file.write_text(
f"{section}\n\n---\n\nBuilt against Weblate {weblate_version}.\n"
)
PY
echo "notes_file=${notes_file}" >> "$GITHUB_OUTPUT"

- name: Configure git for tag push
run: |
git config user.name "github-actions[bot]"
Expand All @@ -77,5 +107,4 @@ jobs:
weblate_version="${{ steps.versions.outputs.weblate_version }}"
gh release create "${tag}" \
--title "${tag} (Weblate ${weblate_version})" \
--generate-notes \
--notes "Built against Weblate ${weblate_version}."
--notes-file "${{ steps.changelog.outputs.notes_file }}"
59 changes: 59 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!--
SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com>

SPDX-License-Identifier: BSL-1.0
-->

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.0.0] - 2026-06-11

### Added

- **QuickBook format** — `QuickBookFormat` convert pipeline for `.qbk` templates; parsing and reconstruction in `boost_weblate.utils.quickbook`; registration via `WEBLATE_FORMATS` in `settings_override.py`.
- **Boost endpoint HTTP API** — routes under `/boost-endpoint/`:
- `GET /boost-endpoint/plugin-ping/` (public health check)
- `GET /boost-endpoint/info/` (authenticated plugin metadata)
- `POST /boost-endpoint/add-or-update/` (authenticated; Celery-backed project/component management)
- **Celery integration** — `boost_add_or_update_task` on Weblate's Celery app; `BoostComponentService` for GitHub submodule clone, scan, and Weblate ORM create/update.
- **Rate limiting** — scoped DRF throttles for protected endpoints (`info`: 60/minute; `add-or-update`: 10/hour); `BOOST_ENDPOINT_THROTTLE_INFO` and `BOOST_ENDPOINT_THROTTLE_ADD_OR_UPDATE` env overrides; HTTP 429 with `Retry-After`.
- **CI pipeline** — umbrella `ci.yml` with lint, test (90% coverage gate), package, dependency audit, Weblate pin sync, and Docker-based plugin smoke/auth/functional jobs.
- **CD pipeline** — staging auto-deploy on `develop` (`cd.yml`); production via `promote-main.yml` (ff-only `develop` → `main`) followed by `main` CD.
- **Weblate version pinning** — `Weblate[all]==…` in `pyproject.toml` synced with Docker `FROM weblate/weblate:…`; enforced by `ci-weblate-pin.yml`; scheduled bumps via `weblate-pin-bump.yml`.
- **Release workflow** — manual `release.yml` tags `main` from `pyproject.toml` version and creates GitHub Releases.

## Deprecation Policy

This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The plugin version in `pyproject.toml` uses `MAJOR.MINOR.PATCH`:

- **MAJOR** — incompatible API or integration changes
- **MINOR** — backward-compatible functionality
- **PATCH** — backward-compatible bug fixes

### Notice period

Breaking removals or behavior changes require at least **one minor release** of deprecation. For example, a feature deprecated in `1.1.0` may be removed in `2.0.0`, not in `1.2.0`.

### How changes are communicated

1. **Changelog** — each deprecation is recorded under `### Deprecated` in the release where it is announced; removal appears under `### Removed` in the major release that drops it.
2. **Runtime warnings** — deprecated Python APIs emit `warnings.warn(..., DeprecationWarning)` where applicable so integrators can detect usage in tests or logs.

### Public integration surface

The following are subject to this policy:

- **HTTP API** — request/response schema and auth requirements for `POST /boost-endpoint/add-or-update/`, `GET /boost-endpoint/info/`, and related Boost endpoint routes documented in `docs/boost-endpoint-api.md`.
- **Format registration** — dotted import paths registered in `WEBLATE_FORMATS` (e.g. `boost_weblate.formats.quickbook.QuickBookFormat`).
- **Settings hook** — documented environment variables read by `settings_override.py` (e.g. `BOOST_ENDPOINT_THROTTLE_INFO`, `BOOST_ENDPOINT_THROTTLE_ADD_OR_UPDATE`).

### Non-guarantees

Internal modules under `boost_weblate.utils.*` and undocumented environment variables may change in minor releases unless explicitly listed above.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ Each deploy SSHes to `/opt/cppa-weblate-plugin`, pulls the branch, rebuilds with
1. **Promote** — run **Actions → Promote develop to main** ([`promote-main.yml`](.github/workflows/promote-main.yml)): fast-forward `main` to `develop` and push with repository secret **`PROMOTE_PAT`** (required so CI and deploy workflows run; `GITHUB_TOKEN` pushes do not trigger them).
2. **Deploy** — when CI on `main` succeeds, `cd.yml` deploys using **production** environment secrets (`SSH_HOST`, `SSH_USER`, `SSH_PRIVATE_KEY`, `WEBLATE_PORT`, `WEBLATE_URL_PREFIX`; optional `SSH_PORT`).

**Release** tagging ([`release.yml`](.github/workflows/release.yml)) is independent of deploy — run manually when you want a GitHub Release on `main`.
**Release** tagging ([`release.yml`](.github/workflows/release.yml)) is independent of deploy — run manually when you want a GitHub Release on `main`. Release notes are taken from the matching `## [version]` section in [`CHANGELOG.md`](CHANGELOG.md) for the version in `pyproject.toml`.

Full deployment and promotion procedure: [docs/deployment-runbook.md](docs/deployment-runbook.md) (staging, production, `PROMOTE_PAT`, rollback, release tagging).

Expand All @@ -341,6 +341,8 @@ Each script builds `docker/docker-compose.ci.yml`, waits for health, runs its py

| Topic | File | Description |
|-------|------|-------------|
| Changelog | [`CHANGELOG.md`](CHANGELOG.md) | Version history (Keep a Changelog) |
| API stability | [`CHANGELOG.md#deprecation-policy`](CHANGELOG.md#deprecation-policy) | SemVer, deprecation notice period, public API surface |
| All env vars | [`.env.example`](.env.example) | Annotated template — copy to `.env` on the deploy server |
| Deployment & promotion | [`docs/deployment-runbook.md`](docs/deployment-runbook.md) | Staging/production CD, `PROMOTE_PAT`, environments, health checks, rollback, release tagging |
| Boost endpoint throttles | [`src/boost_weblate/settings_override.py`](src/boost_weblate/settings_override.py) | `BOOST_ENDPOINT_THROTTLE_INFO`, `BOOST_ENDPOINT_THROTTLE_ADD_OR_UPDATE`; merged into `REST_FRAMEWORK` |
Expand Down
9 changes: 6 additions & 3 deletions docs/deployment-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,22 +385,25 @@ The workflow does not check deploy status or server health.
- Plugin version: `[project].version` (e.g. `1.0.0`)
- Weblate pin: `Weblate[all]==…` (e.g. `2026.5`)
2. Fails if tag `v<plugin-version>` already exists on `origin` (prevents duplicate releases)
3. Creates annotated tag `v<plugin-version>` on current `main` HEAD and pushes it
4. Creates a GitHub Release with auto-generated notes, title `v<version> (Weblate <pin>)`, and body noting Weblate compatibility
3. Extracts the matching `## [<plugin-version>]` section from [`CHANGELOG.md`](../CHANGELOG.md) (fails if missing, before any tag is pushed)
4. Creates annotated tag `v<plugin-version>` on current `main` HEAD and pushes it
5. Creates a GitHub Release with title `v<version> (Weblate <pin>)` and the extracted changelog as release notes, plus a trailing Weblate compatibility line

Use the release title and body to verify which Weblate version the tagged tree was built against.

### Prerequisites

- `version` in `pyproject.toml` on `main` must be the release you intend (bump on `develop` and promote, or commit on `main`, before running)
- [`CHANGELOG.md`](../CHANGELOG.md) on `main` must include a `## [<version>]` section for that version
- Tag `v<version>` must not already exist

### Failure modes

| Failure | Likely cause |
|---------|----------------|
| Tag already exists | Re-ran without bumping `version` in `pyproject.toml` |
| Wrong release contents | `main` HEAD did not include the expected `pyproject.toml` |
| No changelog section | `CHANGELOG.md` on `main` has no `## [<version>]` heading for the intended release |
| Wrong release contents | `main` HEAD did not include the expected `pyproject.toml` or `CHANGELOG.md` |
| `gh release create` failed | Permissions or network; check whether the tag was pushed and finish the release manually on GitHub |

### Important
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ module-name = "boost_weblate"
module-root = "src"
source-include = [
".env.example",
"CHANGELOG.md",
"docker/**",
"docs/**",
"LICENSES/**",
Expand Down
Loading