DEVX-68: feat: add pre-built Docker runner images and tested image build/push tools
Post-merge / detect-type (push) Successful in 32s
Post-merge / configure-repo (push) Successful in 40s
Post-merge / sync-wiki (push) Successful in 42s
Post-merge / release (push) Successful in 53s
Post-merge / vikunja (push) Successful in 1m1s
Post-merge / validate-commit-msg (push) Successful in 1m8s
Post-merge / badges (push) Successful in 1m19s
Post-merge / publish (push) Failing after 38s
Build Images / detect-type (push) Successful in 33s
Build Images / build-and-push (push) Failing after 2m54s
Build Images / cleanup (push) Has been skipped

This commit was merged in pull request #108.
This commit is contained in:
2026-06-27 01:34:05 +00:00
parent d4ddbd7e7a
commit c0238e75df
14 changed files with 2034 additions and 389 deletions
+55
View File
@@ -249,3 +249,58 @@ devx-clean:
@find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
@find . -type f -name "*.pyc" -delete 2>/dev/null || true
@rm -rf .coverage htmlcov/ dist/ build/ *.egg-info/ .molecule/ 2>/dev/null || true
# ── Pre-built image setup ─────────────────────────────────────────────────────
#
# When running inside a pre-built Docker runner image (ci-base, ci-quality,
# ci-full), all deps are already installed in /opt/venv. This target links
# the venv and installs the project itself (no-deps, fast).
# Falls back to devx-setup-ci if /opt/venv is not present (local dev).
devx-setup-image:
@if [ -d /opt/venv ]; then \
ln -sf /opt/venv $(DEVX_VENV); \
. $(DEVX_BIN)/activate && pip install -e . --no-deps 2>/dev/null; \
echo "[devx-setup-image] Linked /opt/venv and installed project (no-deps)."; \
else \
echo "[devx-setup-image] /opt/venv not found — falling back to devx-setup-ci"; \
$(MAKE) devx-setup-ci; \
fi
# ── Docker image build / push / cleanup ───────────────────────────────────────
#
# Variables:
# DEVX_GITEA_REGISTRY — registry URL (default: git.oblachno.oblachno.fyi)
# DEVX_IMAGE_MANIFEST — path to JSON manifest (default: docker/images.json)
# DEVX_IMAGE_OWNER — package owner for cleanup (default: oblachno-oss)
DEVX_GITEA_REGISTRY ?= git.oblachno.oblachno.fyi
DEVX_IMAGE_MANIFEST ?= docker/images.json
DEVX_IMAGE_OWNER ?= oblachno-oss
# Build all images from manifest (no push)
devx-build-images:
@$(DEVX_PYTHON) -m devx.tools.build_image --manifest $(DEVX_IMAGE_MANIFEST) --pull
# Build and push all images to the Gitea registry
devx-push-images:
@$(DEVX_PYTHON) -m devx.tools.build_image \
--manifest $(DEVX_IMAGE_MANIFEST) \
--registry $(DEVX_GITEA_REGISTRY) \
--push --pull
# Dry-run: show what would be built/pushed
devx-build-images-dry-run:
@$(DEVX_PYTHON) -m devx.tools.build_image \
--manifest $(DEVX_IMAGE_MANIFEST) \
--registry $(DEVX_GITEA_REGISTRY) \
--push --dry-run
# Clean up old image versions (keep last 2 + latest)
devx-clean-images:
@$(DEVX_PYTHON) -m devx.tools.clean_images \
--owner $(DEVX_IMAGE_OWNER) \
--name oblachno-oss/runner-images/ci-base \
--name oblachno-oss/runner-images/ci-quality \
--name oblachno-oss/runner-images/ci-full \
--keep 2
+334
View File
@@ -0,0 +1,334 @@
#!/usr/bin/env python3
"""Build and push Docker images to a Gitea container registry.
Replaces raw ``docker build`` / ``docker push`` shell commands with a
tested Python tool. Supports:
- Building from any Dockerfile with a configurable context directory
- Tagging with multiple tags (e.g. ``latest`` + version)
- Optional push to a Gitea registry (with login)
- Dry-run mode (prints commands without executing)
Usage::
# Build a single image
python3 -m devx.tools.build_image \\
--dockerfile docker/ci-base/Dockerfile \\
--tag ci-base:latest \\
--tag ci-base:0.19.3
# Build and push to registry
python3 -m devx.tools.build_image \\
--dockerfile docker/ci-base/Dockerfile \\
--tag ci-base:latest \\
--tag ci-base:0.19.3 \\
--registry git.oblachno.oblachno.fyi \\
--push
# Build multiple images (from a manifest file)
python3 -m devx.tools.build_image --manifest docker/images.json --push
The manifest file is a JSON list of dicts, each with:
- ``name``: image name (e.g. ``ci-base``)
- ``dockerfile``: path to Dockerfile (relative to repo root)
- ``context``: build context directory (optional, defaults to repo root)
- ``tags``: list of tags (optional, defaults to ``["latest"]``)
Registry authentication uses ``REPO_TOKEN`` (or ``GITEA_REGISTRY_TOKEN``)
and ``REGISTRY_USERNAME`` (or ``GITEA_REGISTRY_USERNAME``) environment
variables, matching the existing CI workflow patterns.
"""
from __future__ import annotations
import json
import os
import subprocess # nosec B404
from dataclasses import dataclass, field
from pathlib import Path
import click
from devx.i18n import _
@dataclass
class ImageSpec:
"""Specification for a single Docker image to build."""
name: str
dockerfile: str
context: str = "."
tags: list[str] = field(default_factory=lambda: ["latest"])
@classmethod
def from_dict(cls, data: dict[str, object]) -> ImageSpec:
"""Create an ImageSpec from a dict (e.g. from a JSON manifest)."""
name = str(data.get("name", ""))
if not name:
raise ValueError(_("Image manifest entry missing 'name'"))
dockerfile = str(data.get("dockerfile", ""))
if not dockerfile:
raise ValueError(_("Image manifest entry missing 'dockerfile'"))
context = str(data.get("context", "."))
tags_raw = data.get("tags", ["latest"])
if not isinstance(tags_raw, list):
raise ValueError(_("Image 'tags' must be a list"))
tags = [str(t) for t in tags_raw] if tags_raw else ["latest"]
return cls(name=name, dockerfile=dockerfile, context=context, tags=tags)
def load_manifest(path: str | Path) -> list[ImageSpec]:
"""Load a JSON manifest file describing images to build.
The file must contain a JSON list of dicts with at least ``name`` and
``dockerfile`` keys. ``context`` and ``tags`` are optional.
Returns a list of :class:`ImageSpec` instances.
"""
p = Path(path)
if not p.is_file():
raise click.ClickException(_("Manifest file not found: {path}", path=p))
with p.open() as f: # noqa: PTH123
data = json.load(f)
if not isinstance(data, list):
raise click.ClickException(_("Manifest must be a JSON list"))
return [ImageSpec.from_dict(entry) for entry in data]
def build_full_tag(registry: str | None, name: str, tag: str) -> str:
"""Build a full image tag, optionally prefixed with a registry.
>>> build_full_tag(None, "ci-base", "latest")
'ci-base:latest'
>>> build_full_tag("git.example.com", "ci-base", "0.1.0")
'git.example.com/ci-base:0.1.0'
"""
if registry:
return f"{registry}/{name}:{tag}"
return f"{name}:{tag}"
def registry_login(
registry: str,
username: str,
token: str,
*,
dry_run: bool = False,
) -> bool:
"""Log in to a Docker registry.
Returns True on success, False on failure.
In dry-run mode, prints the command without executing.
"""
cmd = ["docker", "login", registry, "-u", username, "--password-stdin"]
if dry_run:
click.echo(f"[dry-run] {' '.join(cmd)}")
return True
result = subprocess.run( # nosec B603
cmd,
input=token,
text=True,
capture_output=True,
check=False,
)
if result.returncode != 0:
click.echo(
_("Registry login failed: {error}", error=result.stderr.strip()),
err=True,
)
return False
click.echo(f"Logged in to {registry}")
return True
def build_image(
spec: ImageSpec,
registry: str | None = None,
*,
dry_run: bool = False,
pull: bool = False,
) -> bool:
"""Build a Docker image from a Dockerfile.
Tags the image with all specified tags, optionally prefixed with the
registry. Returns True on success, False on failure.
"""
if not Path(spec.dockerfile).is_file():
click.echo(
_("Dockerfile not found: {path}", path=spec.dockerfile),
err=True,
)
return False
full_tags = [build_full_tag(registry, spec.name, t) for t in spec.tags]
cmd = ["docker", "build"]
if pull:
cmd.append("--pull")
for ft in full_tags:
cmd.extend(["-t", ft])
cmd.extend(["-f", spec.dockerfile, spec.context])
if dry_run:
click.echo(f"[dry-run] {' '.join(cmd)}")
return True
click.echo(f"Building {spec.name} ({len(full_tags)} tag(s))...")
result = subprocess.run( # nosec B603
cmd,
check=False,
)
if result.returncode != 0:
click.echo(_("Build failed for {name}", name=spec.name), err=True)
return False
click.echo(f"Built {spec.name}")
return True
def push_image(
spec: ImageSpec,
registry: str,
*,
dry_run: bool = False,
) -> bool:
"""Push all tags of a Docker image to the registry.
Returns True if all pushes succeed, False if any fail.
"""
full_tags = [build_full_tag(registry, spec.name, t) for t in spec.tags]
all_ok = True
for ft in full_tags:
cmd = ["docker", "push", ft]
if dry_run:
click.echo(f"[dry-run] {' '.join(cmd)}")
continue
click.echo(f"Pushing {ft}...")
result = subprocess.run( # nosec B603
cmd,
capture_output=True,
text=True,
check=False,
)
if result.returncode != 0:
click.echo(
_("Push failed for {tag}: {error}", tag=ft, error=result.stderr.strip()),
err=True,
)
all_ok = False
else:
click.echo(f"Pushed {ft}")
return all_ok
def _get_registry_creds() -> tuple[str, str]:
"""Get registry credentials from environment variables.
Supports both REPO_TOKEN/GITEA_REGISTRY_TOKEN and
REGISTRY_USERNAME/GITEA_REGISTRY_USERNAME patterns.
"""
token = os.environ.get("REPO_TOKEN") or os.environ.get("GITEA_REGISTRY_TOKEN", "")
username = os.environ.get("REGISTRY_USERNAME") or os.environ.get("GITEA_REGISTRY_USERNAME", "")
return username, token
@click.command()
@click.option(
"--dockerfile",
"dockerfile",
default=None,
help="Path to Dockerfile (for single-image build).",
)
@click.option(
"--context",
"context",
default=".",
help="Build context directory (for single-image build).",
)
@click.option(
"--name",
"name",
default=None,
help="Image name (for single-image build).",
)
@click.option(
"--tag",
"tags",
multiple=True,
help="Tag(s) for the image. Can be repeated. Defaults to 'latest'.",
)
@click.option(
"--manifest",
"manifest",
default=None,
help="Path to JSON manifest file listing images to build.",
)
@click.option(
"--registry",
"registry",
default=None,
help="Registry URL (e.g. git.example.com). If set with --push, images are tagged and pushed there.",
)
@click.option(
"--push",
is_flag=True,
default=False,
help="Push images to the registry after building.",
)
@click.option(
"--dry-run",
is_flag=True,
default=False,
help="Print commands without executing.",
)
@click.option(
"--pull",
is_flag=True,
default=False,
help="Pass --pull to docker build (always fetch latest base image).",
)
def main(
dockerfile: str | None,
context: str,
name: str | None,
tags: tuple[str, ...],
manifest: str | None,
registry: str | None,
push: bool,
dry_run: bool,
pull: bool,
) -> None:
"""Build and optionally push Docker images to a Gitea registry."""
if manifest:
specs = load_manifest(manifest)
elif dockerfile and name:
tag_list = list(tags) if tags else ["latest"]
specs = [ImageSpec(name=name, dockerfile=dockerfile, context=context, tags=tag_list)]
else:
raise click.ClickException(_("Provide --manifest or both --dockerfile and --name"))
if push:
if not registry:
raise click.ClickException(_("--push requires --registry"))
username, token = _get_registry_creds()
if not token or not username:
raise click.ClickException(
_("Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars")
)
if not registry_login(registry, username, token, dry_run=dry_run):
raise click.ClickException(_("Registry login failed"))
failed: list[str] = []
for spec in specs:
if not build_image(spec, registry, dry_run=dry_run, pull=pull):
failed.append(spec.name)
continue
if push and not push_image(spec, registry, dry_run=dry_run): # type: ignore[arg-type]
failed.append(spec.name)
if failed:
raise click.ClickException(_("Failed images: {names}", names=", ".join(failed)))
click.echo(f"\nDone. {len(specs)} image(s) processed.")
if __name__ == "__main__": # pragma: no cover
main() # pragma: no cover
+221
View File
@@ -0,0 +1,221 @@
#!/usr/bin/env python3
"""Clean up old Docker images from a Gitea container registry.
Queries the Gitea API for all versions of a package (container type) and
deletes all but the most recent N versions. The ``latest`` tag is always
preserved if present.
Usage::
# Clean up ci-base images, keep last 2 versions
python3 -m devx.tools.clean_images \\
--owner oblachno-oss \\
--name ci-base \\
--keep 2
# Clean up multiple images
python3 -m devx.tools.clean_images \\
--owner oblachno-oss \\
--name ci-base \\
--name ci-quality \\
--name ci-full \\
--keep 2
# Dry run (list what would be deleted)
python3 -m devx.tools.clean_images \\
--owner oblachno-oss \\
--name ci-base \\
--keep 2 \\
--dry-run
Authentication uses ``REPO_TOKEN`` environment variable.
"""
from __future__ import annotations
import os
from typing import Any
import click
import requests
from devx.config import GITEA_API_URL
from devx.i18n import _
def list_package_versions(
api_url: str,
owner: str,
name: str,
token: str,
*,
timeout: int = 30,
) -> list[dict[str, Any]]:
"""List all versions of a container package from the Gitea API.
Returns a list of version dicts, each containing at least ``version``
and ``created_at`` fields.
"""
url = f"{api_url}/packages/{owner}?type=container&name={name}"
headers = {"Authorization": f"token {token}"}
all_versions: list[dict[str, Any]] = []
page = 1
while True:
resp = requests.get(
f"{url}&page={page}&limit=50",
headers=headers,
timeout=timeout,
)
resp.raise_for_status()
data = resp.json()
if not data:
break
all_versions.extend(data)
if len(data) < 50:
break
page += 1
return all_versions
def delete_package_version(
api_url: str,
owner: str,
name: str,
version: str,
token: str,
*,
timeout: int = 30,
) -> bool:
"""Delete a specific version of a container package.
Returns True on success, False on failure.
"""
url = f"{api_url}/packages/{owner}/{name}/{version}"
headers = {"Authorization": f"token {token}"}
resp = requests.delete(url, headers=headers, timeout=timeout)
return resp.status_code in (204, 200)
def sort_versions_by_date(
versions: list[dict[str, Any]],
) -> list[dict[str, Any]]:
"""Sort package versions by creation date, newest first.
Falls back to version string comparison if created_at is missing.
"""
def _sort_key(v: dict[str, Any]) -> str:
return str(v.get("created_at", v.get("version", "")))
return sorted(versions, key=_sort_key, reverse=True)
def select_for_deletion(
versions: list[dict[str, Any]],
keep: int,
) -> list[dict[str, Any]]:
"""Select versions to delete, keeping the most recent ``keep`` versions.
Versions named ``latest`` are always preserved.
"""
sorted_versions = sort_versions_by_date(versions)
to_delete = sorted_versions[keep:]
# Always preserve 'latest' tag
to_delete = [v for v in to_delete if v.get("version") != "latest"]
return to_delete
@click.command()
@click.option(
"--owner",
required=True,
help="Package owner (user or org).",
)
@click.option(
"--name",
"names",
multiple=True,
required=True,
help="Package name(s). Can be repeated.",
)
@click.option(
"--keep",
default=2,
type=int,
show_default=True,
help="Number of recent versions to keep (excluding 'latest').",
)
@click.option(
"--dry-run",
is_flag=True,
default=False,
help="List versions that would be deleted without actually deleting.",
)
@click.option(
"--api-url",
default=None,
help="Gitea API URL (defaults to DEVX_GITEA_API_URL or built-in default).",
)
def main(
owner: str,
names: tuple[str, ...],
keep: int,
dry_run: bool,
api_url: str | None,
) -> None:
"""Clean up old Docker image versions from a Gitea registry."""
token = os.environ.get("REPO_TOKEN", "")
if not token:
raise click.ClickException(_("REPO_TOKEN environment variable required"))
base_url = api_url or GITEA_API_URL
total_deleted = 0
total_kept = 0
for name in names:
click.echo(f"\n{'=' * 60}")
click.echo(f"Package: {owner}/{name}")
click.echo(f"{'=' * 60}")
try:
versions = list_package_versions(base_url, owner, name, token)
except requests.RequestException as exc:
click.echo(
_("Failed to list versions for {name}: {error}", name=name, error=exc),
err=True,
)
continue
if not versions:
click.echo(_("No versions found."))
continue
click.echo(f"Found {len(versions)} version(s):")
for v in sort_versions_by_date(versions):
click.echo(f" {v.get('version', '?')} (created: {v.get('created_at', '?')})")
to_delete = select_for_deletion(versions, keep)
kept_count = len(versions) - len(to_delete)
click.echo(f"\nKeeping {kept_count}, would delete {len(to_delete)}")
if dry_run:
for v in to_delete:
click.echo(f" [dry-run] Would delete: {v.get('version', '?')}")
total_kept += kept_count
continue
deleted_count = 0
for v in to_delete:
version = str(v.get("version", ""))
if delete_package_version(base_url, owner, name, version, token):
click.echo(f" Deleted: {version}")
deleted_count += 1
else:
click.echo(f" FAILED to delete: {version}", err=True)
total_deleted += deleted_count
total_kept += kept_count
click.echo(f"\nDone. Deleted {total_deleted}, kept {total_kept}.")
if __name__ == "__main__": # pragma: no cover
main() # pragma: no cover
+517 -381
View File
@@ -343,6 +343,14 @@
"ru": " Updated: {title}",
"zh": " Updated: {title}"
},
"--push requires --registry": {
"bg": "--push requires --registry",
"de": "--push requires --registry",
"en": "--push requires --registry",
"pl": "--push requires --registry",
"ru": "--push requires --registry",
"zh": "--push requires --registry"
},
"--skip-build: skipping package build and PyPI publish.": {
"bg": "--skip-build: skipping package build and PyPI publish.",
"de": "--skip-build: skipping package build and PyPI publish.",
@@ -367,6 +375,14 @@
"ru": "API poll warning: {exc}",
"zh": "API poll warning: {exc}"
},
"Additional directory to scan (default: scripts, tests). Can be repeated.": {
"bg": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"de": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"en": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"pl": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"ru": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"zh": "Additional directory to scan (default: scripts, tests). Can be repeated."
},
"All molecule tests passed.": {
"bg": "All molecule tests passed.",
"de": "All molecule tests passed.",
@@ -383,6 +399,22 @@
"ru": "Another molecule runner failed. Stopping this runner early.",
"zh": "Another molecule runner failed. Stopping this runner early."
},
"Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description": {
"bg": "Клон '{branch}' не съдържа ID на задача.\n Очакван формат: {prefix}-N-кратко-описание",
"de": "Branch '{branch}' enthält keine Task-ID.\n Erwartetes Format: {prefix}-N-kurz-beschreibung",
"en": "Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description",
"pl": "Gałąź '{branch}' nie zawiera ID zadania.\n Oczekiwany format: {prefix}-N-krótki-opis",
"ru": "Ветка '{branch}' не содержит ID задачи.\n Ожидаемый формат: {prefix}-N-краткое-описание",
"zh": "分支 '{branch}' 不包含任务 ID。\n 预期格式: {prefix}-N-简短描述"
},
"Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description\n Example: {prefix}-42-add-feature\n Fix: rename the branch or create a Vikunja task first:\n python -m devx.tools.create_task --title \"Task title\"": {
"bg": "Клон '{branch}' не съдържа ID на задача.\n Очакван формат: {prefix}-N-кратко-описание\n Пример: {prefix}-42-add-feature\n Решение: преименувайте клона или създайте Vikunja задача:\n python -m devx.tools.create_task --title \"Заглавие на задача\"",
"de": "Branch '{branch}' enthält keine Task-ID.\n Erwartetes Format: {prefix}-N-kurz-beschreibung\n Beispiel: {prefix}-42-add-feature\n Fix: Branch umbenennen oder Vikunja-Task erstellen:\n python -m devx.tools.create_task --title \"Task-Titel\"",
"en": "Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description\n Example: {prefix}-42-add-feature\n Fix: rename the branch or create a Vikunja task first:\n python -m devx.tools.create_task --title \"Task title\"",
"pl": "Gałąź '{branch}' nie zawiera ID zadania.\n Oczekiwany format: {prefix}-N-krótki-opis\n Przykład: {prefix}-42-add-feature\n Naprawa: zmień nazwę gałęzi lub utwórz zadanie Vikunja:\n python -m devx.tools.create_task --title \"Tytuł zadania\"",
"ru": "Ветка '{branch}' не содержит ID задачи.\n Ожидаемый формат: {prefix}-N-краткое-описание\n Пример: {prefix}-42-add-feature\n Исправление: переименуйте ветку или создайте задачу Vikunja:\n python -m devx.tools.create_task --title \"Заголовок задачи\"",
"zh": "分支 '{branch}' 不包含任务 ID。\n 预期格式: {prefix}-N-简短描述\n 示例: {prefix}-42-add-feature\n 修复: 重命名分支或先创建 Vikunja 任务:\n python -m devx.tools.create_task --title \"任务标题\""
},
"Branch is behind master. Rebase manually:\n git fetch origin master && git rebase origin/master && git push --force-with-lease\nThen re-add the ready-to-merge label.": {
"bg": "Branch is behind master. Rebase manually:\n git fetch origin master && git rebase origin/master && git push --force-with-lease\nThen re-add the ready-to-merge label.",
"de": "Branch is behind master. Rebase manually:\n git fetch origin master && git rebase origin/master && git push --force-with-lease\nThen re-add the ready-to-merge label.",
@@ -391,6 +423,38 @@
"ru": "Branch is behind master. Rebase manually:\n git fetch origin master && git rebase origin/master && git push --force-with-lease\nThen re-add the ready-to-merge label.",
"zh": "Branch is behind master. Rebase manually:\n git fetch origin master && git rebase origin/master && git push --force-with-lease\nThen re-add the ready-to-merge label."
},
"Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master": {
"bg": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"de": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"en": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"pl": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"ru": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"zh": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master"
},
"Branch name (e.g., DEVX-256-fix-foo)": {
"bg": "Branch name (e.g., DEVX-256-fix-foo)",
"de": "Branch name (e.g., DEVX-256-fix-foo)",
"en": "Branch name (e.g., DEVX-256-fix-foo)",
"pl": "Branch name (e.g., DEVX-256-fix-foo)",
"ru": "Branch name (e.g., DEVX-256-fix-foo)",
"zh": "Branch name (e.g., DEVX-256-fix-foo)"
},
"Branch name must contain a task ID.": {
"bg": "Branch name must contain a task ID.",
"de": "Branch name must contain a task ID.",
"en": "Branch name must contain a task ID.",
"pl": "Branch name must contain a task ID.",
"ru": "Branch name must contain a task ID.",
"zh": "Branch name must contain a task ID."
},
"Build failed for {name}": {
"bg": "Build failed for {name}",
"de": "Build failed for {name}",
"en": "Build failed for {name}",
"pl": "Build failed for {name}",
"ru": "Build failed for {name}",
"zh": "Build failed for {name}"
},
"Bumping version: {current} -> v{new_version}": {
"bg": "Bumping version: {current} -> v{new_version}",
"de": "Bumping version: {current} -> v{new_version}",
@@ -399,6 +463,14 @@
"ru": "Bumping version: {current} -> v{new_version}",
"zh": "Bumping version: {current} -> v{new_version}"
},
"Check that changed files have corresponding tests": {
"bg": "Check that changed files have corresponding tests",
"de": "Check that changed files have corresponding tests",
"en": "Check that changed files have corresponding tests",
"pl": "Check that changed files have corresponding tests",
"ru": "Check that changed files have corresponding tests",
"zh": "Check that changed files have corresponding tests"
},
"Checking CLI command documentation...": {
"bg": "Checking CLI command documentation...",
"de": "Checking CLI command documentation...",
@@ -423,6 +495,14 @@
"ru": "Comparing {base}..{head} ({count} files changed)",
"zh": "Comparing {base}..{head} ({count} files changed)"
},
"Configuration OK: [tool.devx] present, devx versions consistent.": {
"bg": "Конфигурацията е OK: [tool.devx] присъства, версиите на devx са консистентни.",
"de": "Konfiguration OK: [tool.devx] vorhanden, devx-Versionen konsistent.",
"en": "Configuration OK: [tool.devx] present, devx versions consistent.",
"pl": "Konfiguracja OK: [tool.devx] obecne, wersje devx spójne.",
"ru": "Конфигурация OK: [tool.devx] присутствует, версии devx согласованы.",
"zh": "配置正常: [tool.devx] 已存在, devx 版本一致。"
},
"Configuring branch protection for {branch}...": {
"bg": "Конфигуриране на защита на клона {branch}...",
"de": "Konfiguriere Branch-Schutz für {branch}...",
@@ -439,13 +519,13 @@
"ru": "Настройка параметров репозитория...",
"zh": "正在配置仓库设置..."
},
"Configuration OK: [tool.devx] present, devx versions consistent.": {
"bg": "Конфигурацията е OK: [tool.devx] присъства, версиите на devx са консистентни.",
"de": "Konfiguration OK: [tool.devx] vorhanden, devx-Versionen konsistent.",
"en": "Configuration OK: [tool.devx] present, devx versions consistent.",
"pl": "Konfiguracja OK: [tool.devx] obecne, wersje devx spójne.",
"ru": "Конфигурация OK: [tool.devx] присутствует, версии devx согласованы.",
"zh": "配置正常: [tool.devx] 已存在, devx 版本一致。"
"Could not detect current branch: {error}": {
"bg": "Не може да се определи текущия клон: {error}",
"de": "Aktueller Branch konnte nicht erkannt werden: {error}",
"en": "Could not detect current branch: {error}",
"pl": "Nie można wykryć bieżącej gałęzi: {error}",
"ru": "Не удалось определить текущую ветку: {error}",
"zh": "无法检测当前分支: {error}"
},
"Could not extract conventional commit message from PR commits.": {
"bg": "Could not extract conventional commit message from PR commits.",
@@ -455,6 +535,22 @@
"ru": "Could not extract conventional commit message from PR commits.",
"zh": "Could not extract conventional commit message from PR commits."
},
"Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).": {
"bg": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"de": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"en": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"pl": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"ru": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"zh": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found)."
},
"Could not find Vikunja task {task_id} in project {project_id}.": {
"bg": "Не е намерена Vikunja задача {task_id} в проект {project_id}.",
"de": "Vikunja-Task {task_id} in Projekt {project_id} nicht gefunden.",
"en": "Could not find Vikunja task {task_id} in project {project_id}.",
"pl": "Nie znaleziono zadania Vikunja {task_id} w projekcie {project_id}.",
"ru": "Не найдена задача Vikunja {task_id} в проекте {project_id}.",
"zh": "在项目 {project_id} 中找不到 Vikunja 任务 {task_id}。"
},
"Could not find Vikunja task {task_id} in project {project_id}. Every PR must have a corresponding Vikunja task.": {
"bg": "Could not find Vikunja task {task_id} in project {project_id}. Every PR must have a corresponding Vikunja task.",
"de": "Could not find Vikunja task {task_id} in project {project_id}. Every PR must have a corresponding Vikunja task.",
@@ -479,6 +575,22 @@
"ru": "Could not parse test execution time from output.",
"zh": "Could not parse test execution time from output."
},
"Created PR #{index}: {title}\n {url}": {
"bg": "Създаден PR #{index}: {title}\n {url}",
"de": "PR erstellt #{index}: {title}\n {url}",
"en": "Created PR #{index}: {title}\n {url}",
"pl": "Utworzono PR #{index}: {title}\n {url}",
"ru": "Создан PR #{index}: {title}\n {url}",
"zh": "已创建 PR #{index}: {title}\n {url}"
},
"Created Vikunja task: {identifier} (id={task_id})": {
"bg": "Създадена Vikunja задача: {identifier} (id={task_id})",
"de": "Vikunja-Task erstellt: {identifier} (id={task_id})",
"en": "Created Vikunja task: {identifier} (id={task_id})",
"pl": "Utworzono zadanie Vikunja: {identifier} (id={task_id})",
"ru": "Создана задача Vikunja: {identifier} (id={task_id})",
"zh": "已创建 Vikunja 任务: {identifier} (id={task_id})"
},
"Created issue #{issue_id}: {title}": {
"bg": "Created issue #{issue_id}: {title}",
"de": "Created issue #{issue_id}: {title}",
@@ -495,13 +607,13 @@
"ru": "Created release commit.",
"zh": "Created release commit."
},
"devx version mismatch across extras: {detail}": {
"bg": "несъответствие на версията на devx между extras: {detail}",
"de": "devx-Versionskonflikt zwischen Extras: {detail}",
"en": "devx version mismatch across extras: {detail}",
"pl": "niezgodność wersji devx między extras: {detail}",
"ru": "несоответствие версии devx между extras: {detail}",
"zh": "devx 版本在 extras 之间不一致: {detail}"
"Dependencies must have documentation comments.": {
"bg": "Dependencies must have documentation comments.",
"de": "Dependencies must have documentation comments.",
"en": "Dependencies must have documentation comments.",
"pl": "Dependencies must have documentation comments.",
"ru": "Dependencies must have documentation comments.",
"zh": "Dependencies must have documentation comments."
},
"Docker daemon already running": {
"bg": "Докер демонът вече работи",
@@ -527,6 +639,14 @@
"ru": "Docker-демон запущен",
"zh": "Docker 守护进程已启动"
},
"Dockerfile not found: {path}": {
"bg": "Dockerfile not found: {path}",
"de": "Dockerfile not found: {path}",
"en": "Dockerfile not found: {path}",
"pl": "Dockerfile not found: {path}",
"ru": "Dockerfile not found: {path}",
"zh": "Dockerfile not found: {path}"
},
"Dry-run mode: on branch '{branch}' (not master). Some checks may behave differently.": {
"bg": "Dry-run mode: on branch '{branch}' (not master). Some checks may behave differently.",
"de": "Dry-run mode: on branch '{branch}' (not master). Some checks may behave differently.",
@@ -575,6 +695,14 @@
"ru": "ERROR: mapping.json not found at {path}",
"zh": "ERROR: mapping.json not found at {path}"
},
"FAILED: {count} undocumented dependency/ies": {
"bg": "FAILED: {count} undocumented dependency/ies",
"de": "FAILED: {count} undocumented dependency/ies",
"en": "FAILED: {count} undocumented dependency/ies",
"pl": "FAILED: {count} undocumented dependency/ies",
"ru": "FAILED: {count} undocumented dependency/ies",
"zh": "FAILED: {count} undocumented dependency/ies"
},
"FAILED: {pair} exited with code {code}": {
"bg": "FAILED: {pair} exited with code {code}",
"de": "FAILED: {pair} exited with code {code}",
@@ -583,6 +711,14 @@
"ru": "FAILED: {pair} exited with code {code}",
"zh": "FAILED: {pair} exited with code {code}"
},
"Failed images: {names}": {
"bg": "Failed images: {names}",
"de": "Failed images: {names}",
"en": "Failed images: {names}",
"pl": "Failed images: {names}",
"ru": "Failed images: {names}",
"zh": "Failed images: {names}"
},
"Failed to create issue via tea: {error}": {
"bg": "Failed to create issue via tea: {error}",
"de": "Failed to create issue via tea: {error}",
@@ -591,6 +727,14 @@
"ru": "Failed to create issue via tea: {error}",
"zh": "Failed to create issue via tea: {error}"
},
"Failed to list versions for {name}: {error}": {
"bg": "Failed to list versions for {name}: {error}",
"de": "Failed to list versions for {name}: {error}",
"en": "Failed to list versions for {name}: {error}",
"pl": "Failed to list versions for {name}: {error}",
"ru": "Failed to list versions for {name}: {error}",
"zh": "Failed to list versions for {name}: {error}"
},
"Found {count} existing wiki pages.": {
"bg": "Found {count} existing wiki pages.",
"de": "Found {count} existing wiki pages.",
@@ -599,6 +743,22 @@
"ru": "Found {count} existing wiki pages.",
"zh": "Found {count} existing wiki pages."
},
"Found {count} mutable global(s) — use factory functions or pytest fixtures.": {
"bg": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"de": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"en": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"pl": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"ru": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"zh": "Found {count} mutable global(s) — use factory functions or pytest fixtures."
},
"Found {count} stale documentation reference(s)": {
"bg": "Found {count} stale documentation reference(s)",
"de": "Found {count} stale documentation reference(s)",
"en": "Found {count} stale documentation reference(s)",
"pl": "Found {count} stale documentation reference(s)",
"ru": "Found {count} stale documentation reference(s)",
"zh": "Found {count} stale documentation reference(s)"
},
"GITEA_URL/REPO_TOKEN/RUN_ID not set; running without cross-runner cancellation.": {
"bg": "GITEA_URL/REPO_TOKEN/RUN_ID not set; running without cross-runner cancellation.",
"de": "GITEA_URL/REPO_TOKEN/RUN_ID not set; running without cross-runner cancellation.",
@@ -687,6 +847,30 @@
"ru": "Хост Docker недоступен, запускается локальный dockerd...",
"zh": "主机 Docker 不可用,正在启动本地 dockerd..."
},
"Image 'tags' must be a list": {
"bg": "Image 'tags' must be a list",
"de": "Image 'tags' must be a list",
"en": "Image 'tags' must be a list",
"pl": "Image 'tags' must be a list",
"ru": "Image 'tags' must be a list",
"zh": "Image 'tags' must be a list"
},
"Image manifest entry missing 'dockerfile'": {
"bg": "Image manifest entry missing 'dockerfile'",
"de": "Image manifest entry missing 'dockerfile'",
"en": "Image manifest entry missing 'dockerfile'",
"pl": "Image manifest entry missing 'dockerfile'",
"ru": "Image manifest entry missing 'dockerfile'",
"zh": "Image manifest entry missing 'dockerfile'"
},
"Image manifest entry missing 'name'": {
"bg": "Image manifest entry missing 'name'",
"de": "Image manifest entry missing 'name'",
"en": "Image manifest entry missing 'name'",
"pl": "Image manifest entry missing 'name'",
"ru": "Image manifest entry missing 'name'",
"zh": "Image manifest entry missing 'name'"
},
"Infrastructure commit (no DEVX-N task ID), skipping Vikunja update: {msg}": {
"bg": "Инфраструктурен commit (без идентификатор на задача DEVX-N), пропускаме обновяването на Vikunja: {msg}",
"de": "Infrastruktur-Commit (keine DEVX-N Task-ID), Vikunja-Update wird übersprungen: {msg}",
@@ -735,6 +919,22 @@
"ru": "Lint passed.",
"zh": "Lint passed."
},
"Manifest file not found: {path}": {
"bg": "Manifest file not found: {path}",
"de": "Manifest file not found: {path}",
"en": "Manifest file not found: {path}",
"pl": "Manifest file not found: {path}",
"ru": "Manifest file not found: {path}",
"zh": "Manifest file not found: {path}"
},
"Manifest must be a JSON list": {
"bg": "Manifest must be a JSON list",
"de": "Manifest must be a JSON list",
"en": "Manifest must be a JSON list",
"pl": "Manifest must be a JSON list",
"ru": "Manifest must be a JSON list",
"zh": "Manifest must be a JSON list"
},
"Mapped file {file} is empty. Update the content or remove from mapping.json.": {
"bg": "Mapped file {file} is empty. Update the content or remove from mapping.json.",
"de": "Mapped file {file} is empty. Update the content or remove from mapping.json.",
@@ -775,6 +975,14 @@
"ru": "Директория molecule не найдена: {path}",
"zh": "未找到 molecule 目录: {path}"
},
"Next steps:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-short-description\n 3. Implement changes, commit with conventional commit format\n 4. git push -u origin HEAD\n 5. make create-pr (creates PR with title: {identifier}: {title})": {
"bg": "Следващи стъпки:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-кратко-описание\n 3. Имплементирайте промените, commit с conventional commit формат\n 4. git push -u origin HEAD\n 5. make create-pr (създава PR с заглавие: {identifier}: {title})",
"de": "Nächste Schritte:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-kurz-beschreibung\n 3. Änderungen implementieren, mit Conventional-Commit-Format committen\n 4. git push -u origin HEAD\n 5. make create-pr (erstellt PR mit Titel: {identifier}: {title})",
"en": "Next steps:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-short-description\n 3. Implement changes, commit with conventional commit format\n 4. git push -u origin HEAD\n 5. make create-pr (creates PR with title: {identifier}: {title})",
"pl": "Następne kroki:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-krótki-opis\n 3. Wprowadź zmiany, commituj w formacie conventional commit\n 4. git push -u origin HEAD\n 5. make create-pr (tworzy PR z tytułem: {identifier}: {title})",
"ru": "Следующие шаги:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-краткое-описание\n 3. Реализуйте изменения, коммитьте в conventional commit формате\n 4. git push -u origin HEAD\n 5. make create-pr (создаёт PR с заголовком: {identifier}: {title})",
"zh": "后续步骤:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-简短描述\n 3. 实现更改,使用 conventional commit 格式提交\n 4. git push -u origin HEAD\n 5. make create-pr (创建 PR,标题: {identifier}: {title})"
},
"Nice! Gitea release {tag} created.": {
"bg": "Отлично! Gitea release {tag} е създаден.",
"de": "Prima! Gitea-Release {tag} erstellt.",
@@ -847,6 +1055,14 @@
"ru": "No task ID ({prefix}-N) found in commit message: {msg}. Every non-infrastructure commit must have a task ID.",
"zh": "No task ID ({prefix}-N) found in commit message: {msg}. Every non-infrastructure commit must have a task ID."
},
"No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.": {
"bg": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"de": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"en": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"pl": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"ru": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"zh": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description."
},
"No unreleased changes found. Nothing to release.": {
"bg": "No unreleased changes found. Nothing to release.",
"de": "No unreleased changes found. Nothing to release.",
@@ -863,6 +1079,14 @@
"ru": "No user-facing changes since {tag} — only workflow/infrastructure files changed. Skipping release.",
"zh": "No user-facing changes since {tag} — only workflow/infrastructure files changed. Skipping release."
},
"No versions found.": {
"bg": "No versions found.",
"de": "No versions found.",
"en": "No versions found.",
"pl": "No versions found.",
"ru": "No versions found.",
"zh": "No versions found."
},
"Note: Self-approval not allowed. Posting COMMENT instead.": {
"bg": "Note: Self-approval not allowed. Posting COMMENT instead.",
"de": "Note: Self-approval not allowed. Posting COMMENT instead.",
@@ -871,6 +1095,14 @@
"ru": "Note: Self-approval not allowed. Posting COMMENT instead.",
"zh": "Note: Self-approval not allowed. Posting COMMENT instead."
},
"Only check staged files (for pre-commit)": {
"bg": "Only check staged files (for pre-commit)",
"de": "Only check staged files (for pre-commit)",
"en": "Only check staged files (for pre-commit)",
"pl": "Only check staged files (for pre-commit)",
"ru": "Only check staged files (for pre-commit)",
"zh": "Only check staged files (for pre-commit)"
},
"Oops! Commit message must follow conventional commit format.\n Expected: <type>: <description>\n Got: {subject}\n Allowed types: feat, fix, chore, docs, style, refactor,\n perf, test, ci, build, revert, BREAKING CHANGE": {
"bg": "Опа! Съобщението за commit трябва да следва конвенционален формат.\n Очаква се: <type>: <description>\n Получено: {subject}\n Разрешени типове: feat, fix, chore, docs, style, refactor,\n perf, test, ci, build, revert, BREAKING CHANGE",
"de": "Ups! Commit-Nachricht muss dem konventionellen Commit-Format folgen.\n Erwartet: <type>: <description>\n Erhalten: {subject}\n Erlaubte Typen: feat, fix, chore, docs, style, refactor,\n perf, test, ci, build, revert, BREAKING CHANGE",
@@ -959,6 +1191,22 @@
"ru": "PASSED: {pair}",
"zh": "PASSED: {pair}"
},
"PR already exists: #{index} — {url}": {
"bg": "PR вече съществува: #{index} — {url}",
"de": "PR existiert bereits: #{index} — {url}",
"en": "PR already exists: #{index} — {url}",
"pl": "PR już istnieje: #{index} — {url}",
"ru": "PR уже существует: #{index} — {url}",
"zh": "PR 已存在: #{index} — {url}"
},
"PR number (to fetch title from Gitea)": {
"bg": "PR number (to fetch title from Gitea)",
"de": "PR number (to fetch title from Gitea)",
"en": "PR number (to fetch title from Gitea)",
"pl": "PR number (to fetch title from Gitea)",
"ru": "PR number (to fetch title from Gitea)",
"zh": "PR number (to fetch title from Gitea)"
},
"PR number must be an integer, got: {pr_number}": {
"bg": "PR number must be an integer, got: {pr_number}",
"de": "PR number must be an integer, got: {pr_number}",
@@ -967,6 +1215,14 @@
"ru": "PR number must be an integer, got: {pr_number}",
"zh": "PR number must be an integer, got: {pr_number}"
},
"PR title (auto-fetched if --pr-number given)": {
"bg": "PR title (auto-fetched if --pr-number given)",
"de": "PR title (auto-fetched if --pr-number given)",
"en": "PR title (auto-fetched if --pr-number given)",
"pl": "PR title (auto-fetched if --pr-number given)",
"ru": "PR title (auto-fetched if --pr-number given)",
"zh": "PR title (auto-fetched if --pr-number given)"
},
"PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {pr_title}": {
"bg": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {pr_title}",
"de": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {pr_title}",
@@ -975,6 +1231,30 @@
"ru": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {pr_title}",
"zh": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {pr_title}"
},
"PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}": {
"bg": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"de": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"en": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"pl": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"ru": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"zh": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}"
},
"PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}": {
"bg": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"de": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"en": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"pl": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"ru": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"zh": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}"
},
"PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}": {
"bg": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"de": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"en": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"pl": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"ru": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"zh": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}"
},
"PYPI_TOKEN not set and no registry URL configured — skipping PyPI publish. No worries, we'll just create the Gitea release.": {
"bg": "PYPI_TOKEN не е зададен и няма конфигуриран URL на registry — пропускаме публикуването в PyPI. Без притеснения, просто ще създадем Gitea release.",
"de": "PYPI_TOKEN nicht gesetzt und keine Registry-URL konfiguriert — PyPI-Veröffentlichung wird übersprungen. Keine Sorge, wir erstellen einfach das Gitea-Release.",
@@ -991,6 +1271,14 @@
"ru": "Извлечён owner={owner}, repo={repo} из DEVX_REPO_NAME",
"zh": "从 DEVX_REPO_NAME 解析 owner={owner}, repo={repo}"
},
"Path to pyproject.toml (default: pyproject.toml in CWD).": {
"bg": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"de": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"en": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"pl": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"ru": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"zh": "Path to pyproject.toml (default: pyproject.toml in CWD)."
},
"Per-test speed check FAILED: {count} test(s) exceed {limit}s limit.": {
"bg": "Per-test speed check FAILED: {count} test(s) exceed {limit}s limit.",
"de": "Per-test speed check FAILED: {count} test(s) exceed {limit}s limit.",
@@ -999,6 +1287,38 @@
"ru": "Per-test speed check FAILED: {count} test(s) exceed {limit}s limit.",
"zh": "Per-test speed check FAILED: {count} test(s) exceed {limit}s limit."
},
"Pre-merge validation failed.": {
"bg": "Pre-merge validation failed.",
"de": "Pre-merge validation failed.",
"en": "Pre-merge validation failed.",
"pl": "Pre-merge validation failed.",
"ru": "Pre-merge validation failed.",
"zh": "Pre-merge validation failed."
},
"Pre-push check passed: task {task_id} exists.": {
"bg": "Pre-push проверката премина: задача {task_id} съществува.",
"de": "Pre-push-Prüfung bestanden: Task {task_id} existiert.",
"en": "Pre-push check passed: task {task_id} exists.",
"pl": "Sprawdzanie pre-push zakończone: zadanie {task_id} istnieje.",
"ru": "Pre-push проверка пройдена: задача {task_id} существует.",
"zh": "Pre-push 检查通过: 任务 {task_id} 存在。"
},
"Print warnings but always exit 0": {
"bg": "Print warnings but always exit 0",
"de": "Print warnings but always exit 0",
"en": "Print warnings but always exit 0",
"pl": "Print warnings but always exit 0",
"ru": "Print warnings but always exit 0",
"zh": "Print warnings but always exit 0"
},
"Provide --manifest or both --dockerfile and --name": {
"bg": "Provide --manifest or both --dockerfile and --name",
"de": "Provide --manifest or both --dockerfile and --name",
"en": "Provide --manifest or both --dockerfile and --name",
"pl": "Provide --manifest or both --dockerfile and --name",
"ru": "Provide --manifest or both --dockerfile and --name",
"zh": "Provide --manifest or both --dockerfile and --name"
},
"Provide a commit message file or use --git.": {
"bg": "Provide a commit message file or use --git.",
"de": "Provide a commit message file or use --git.",
@@ -1031,6 +1351,14 @@
"ru": "Publishing release {tag}...",
"zh": "Publishing release {tag}..."
},
"Push failed for {tag}: {error}": {
"bg": "Push failed for {tag}: {error}",
"de": "Push failed for {tag}: {error}",
"en": "Push failed for {tag}: {error}",
"pl": "Push failed for {tag}: {error}",
"ru": "Push failed for {tag}: {error}",
"zh": "Push failed for {tag}: {error}"
},
"Pushed release commit to master.": {
"bg": "Pushed release commit to master.",
"de": "Pushed release commit to master.",
@@ -1047,6 +1375,54 @@
"ru": "Публикация в PyPI не удалась (некритично — продолжаем создание Gitea release):\n{error}",
"zh": "PyPI 发布失败(非致命 — 继续创建 Gitea release):\n{error}"
},
"REPO argument is required (or set GITHUB_REPOSITORY env var).": {
"bg": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"de": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"en": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"pl": "Argument REPO jest wymagany (lub ustaw zmienną GITHUB_REPOSITORY).",
"ru": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"zh": "REPO argument is required (or set GITHUB_REPOSITORY env var)."
},
"REPO_TOKEN environment variable required": {
"bg": "REPO_TOKEN environment variable required",
"de": "REPO_TOKEN environment variable required",
"en": "REPO_TOKEN environment variable required",
"pl": "REPO_TOKEN environment variable required",
"ru": "REPO_TOKEN environment variable required",
"zh": "REPO_TOKEN environment variable required"
},
"REPO_TOKEN is not set. Required to create a PR.": {
"bg": "REPO_TOKEN не е зададен. Необходим за създаване на PR.",
"de": "REPO_TOKEN nicht gesetzt. Erforderlich zum Erstellen eines PR.",
"en": "REPO_TOKEN is not set. Required to create a PR.",
"pl": "REPO_TOKEN nie jest ustawiony. Wymagany do utworzenia PR.",
"ru": "REPO_TOKEN не установлен. Требуется для создания PR.",
"zh": "REPO_TOKEN 未设置。创建 PR 所需。"
},
"Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars": {
"bg": "Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars",
"de": "Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars",
"en": "Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars",
"pl": "Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars",
"ru": "Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars",
"zh": "Registry credentials required: set REPO_TOKEN and REGISTRY_USERNAME env vars"
},
"Registry login failed": {
"bg": "Registry login failed",
"de": "Registry login failed",
"en": "Registry login failed",
"pl": "Registry login failed",
"ru": "Registry login failed",
"zh": "Registry login failed"
},
"Registry login failed: {error}": {
"bg": "Registry login failed: {error}",
"de": "Registry login failed: {error}",
"en": "Registry login failed: {error}",
"pl": "Registry login failed: {error}",
"ru": "Registry login failed: {error}",
"zh": "Registry login failed: {error}"
},
"Release creation failed: {error}": {
"bg": "Release creation failed: {error}",
"de": "Release creation failed: {error}",
@@ -1079,6 +1455,30 @@
"ru": "Конфигурация репозитория завершена.",
"zh": "仓库配置完成。"
},
"Repository in owner/name format": {
"bg": "Repository in owner/name format",
"de": "Repository in owner/name format",
"en": "Repository in owner/name format",
"pl": "Repository in owner/name format",
"ru": "Repository in owner/name format",
"zh": "Repository in owner/name format"
},
"Repository name not set. Use DEVX_REPO_NAME or GITHUB_REPOSITORY env var.": {
"bg": "Името на хранилището не е зададено. Използвайте DEVX_REPO_NAME или GITHUB_REPOSITORY env var.",
"de": "Repository-Name nicht gesetzt. Verwende DEVX_REPO_NAME oder GITHUB_REPOSITORY env var.",
"en": "Repository name not set. Use DEVX_REPO_NAME or GITHUB_REPOSITORY env var.",
"pl": "Nazwa repozytorium nie jest ustawiona. Użyj DEVX_REPO_NAME lub GITHUB_REPOSITORY env var.",
"ru": "Имя репозитория не установлено. Используйте DEVX_REPO_NAME или GITHUB_REPOSITORY env var.",
"zh": "仓库名称未设置。使用 DEVX_REPO_NAME 或 GITHUB_REPOSITORY 环境变量。"
},
"Repository owner not set. Use --owner or DEVX_REPO_OWNER env var.": {
"bg": "Собственикът на хранилището не е зададен. Използвайте --owner или DEVX_REPO_OWNER env var.",
"de": "Repository-Owner nicht gesetzt. Verwende --owner oder DEVX_REPO_OWNER env var.",
"en": "Repository owner not set. Use --owner or DEVX_REPO_OWNER env var.",
"pl": "Właściciel repozytorium nie jest ustawiony. Użyj --owner lub DEVX_REPO_OWNER env var.",
"ru": "Владелец репозитория не установлен. Используйте --owner или DEVX_REPO_OWNER env var.",
"zh": "仓库所有者未设置。使用 --owner 或 DEVX_REPO_OWNER 环境变量。"
},
"Roles directory not found: {path}": {
"bg": "Roles directory not found: {path}",
"de": "Roles directory not found: {path}",
@@ -1119,6 +1519,22 @@
"ru": "Running: {scenario} on {platform}",
"zh": "Running: {scenario} on {platform}"
},
"Skip Vikunja title match check": {
"bg": "Skip Vikunja title match check",
"de": "Skip Vikunja title match check",
"en": "Skip Vikunja title match check",
"pl": "Skip Vikunja title match check",
"ru": "Skip Vikunja title match check",
"zh": "Skip Vikunja title match check"
},
"Skip branch-behind-master check": {
"bg": "Skip branch-behind-master check",
"de": "Skip branch-behind-master check",
"en": "Skip branch-behind-master check",
"pl": "Skip branch-behind-master check",
"ru": "Skip branch-behind-master check",
"zh": "Skip branch-behind-master check"
},
"Skipping commit push — no staged changes.": {
"bg": "Skipping commit push — no staged changes.",
"de": "Skipping commit push — no staged changes.",
@@ -1151,14 +1567,6 @@
"ru": "Tag is required (or use --from-tag).",
"zh": "Tag is required (or use --from-tag)."
},
"REPO argument is required (or set GITHUB_REPOSITORY env var).": {
"bg": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"de": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"en": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"pl": "Argument REPO jest wymagany (lub ustaw zmienną GITHUB_REPOSITORY).",
"ru": "REPO argument is required (or set GITHUB_REPOSITORY env var).",
"zh": "REPO argument is required (or set GITHUB_REPOSITORY env var)."
},
"Tag v{version} already existed. Publish workflow should already have been triggered.": {
"bg": "Tag v{version} already existed. Publish workflow should already have been triggered.",
"de": "Tag v{version} already existed. Publish workflow should already have been triggered.",
@@ -1255,6 +1663,22 @@
"ru": "Updated {changelog_file}",
"zh": "Updated {changelog_file}"
},
"VIKUNJA_TOKEN is not set. Required to derive PR title.": {
"bg": "VIKUNJA_TOKEN не е зададен. Необходим за извличане на PR заглавие.",
"de": "VIKUNJA_TOKEN nicht gesetzt. Erforderlich zum Ableiten des PR-Titels.",
"en": "VIKUNJA_TOKEN is not set. Required to derive PR title.",
"pl": "VIKUNJA_TOKEN nie jest ustawiony. Wymagany do pobrania tytułu PR.",
"ru": "VIKUNJA_TOKEN не установлен. Требуется для получения заголовка PR.",
"zh": "VIKUNJA_TOKEN 未设置。推导 PR 标题所需。"
},
"VIKUNJA_TOKEN is not set. Set it in .env or environment.": {
"bg": "VIKUNJA_TOKEN не е зададен. Задайте го в .env или средата.",
"de": "VIKUNJA_TOKEN nicht gesetzt. In .env oder Umgebung setzen.",
"en": "VIKUNJA_TOKEN is not set. Set it in .env or environment.",
"pl": "VIKUNJA_TOKEN nie jest ustawiony. Ustaw go w .env lub środowisku.",
"ru": "VIKUNJA_TOKEN не установлен. Установите его в .env или среде.",
"zh": "VIKUNJA_TOKEN 未设置。在 .env 或环境中设置它。"
},
"VIKUNJA_TOKEN is not set. This is required in CI to validate PR titles.": {
"bg": "VIKUNJA_TOKEN is not set. This is required in CI to validate PR titles.",
"de": "VIKUNJA_TOKEN is not set. This is required in CI to validate PR titles.",
@@ -1279,6 +1703,14 @@
"ru": "Vikunja API error (HTTP {status}): {message}. Task {task_id} was NOT updated. The merge succeeded but the Vikunja task needs manual update.",
"zh": "Vikunja API error (HTTP {status}): {message}. Task {task_id} was NOT updated. The merge succeeded but the Vikunja task needs manual update."
},
"Vikunja task {task_id} not found in project {project_id}.\n Create it first:\n python -m devx.tools.create_task --title \"Task title\"\n Or check that the task ID in the branch name is correct.": {
"bg": "Vikunja задача {task_id} не е намерена в проект {project_id}.\n Създайте я първо:\n python -m devx.tools.create_task --title \"Заглавие на задача\"\n Или проверете че ID на задачата в името на клона е правилно.",
"de": "Vikunja-Task {task_id} in Projekt {project_id} nicht gefunden.\n Zuerst erstellen:\n python -m devx.tools.create_task --title \"Task-Titel\"\n Oder prüfen, ob die Task-ID im Branch-Namen korrekt ist.",
"en": "Vikunja task {task_id} not found in project {project_id}.\n Create it first:\n python -m devx.tools.create_task --title \"Task title\"\n Or check that the task ID in the branch name is correct.",
"pl": "Zadanie Vikunja {task_id} nie znalezione w projekcie {project_id}.\n Utwórz je najpierw:\n python -m devx.tools.create_task --title \"Tytuł zadania\"\n Lub sprawdź, czy ID zadania w nazwie gałęzi jest poprawne.",
"ru": "Задача Vikunja {task_id} не найдена в проекте {project_id}.\n Сначала создайте её:\n python -m devx.tools.create_task --title \"Заголовок задачи\"\n Или проверьте, что ID задачи в имени ветки корректен.",
"zh": "在项目 {project_id} 中找不到 Vikunja 任务 {task_id}。\n 请先创建:\n python -m devx.tools.create_task --title \"任务标题\"\n 或检查分支名称中的任务 ID 是否正确。"
},
"WARNING: --skip-tests passed — skipping test verification.": {
"bg": "WARNING: --skip-tests passed — skipping test verification.",
"de": "WARNING: --skip-tests passed — skipping test verification.",
@@ -1295,6 +1727,14 @@
"ru": "ВНИМАНИЕ: Файл .taskid ({file_id}) устарел и не совпадает с именем ветки ({branch_id}). Удалите .taskid из репозитория — имя ветки — единственный источник истины.",
"zh": "警告:.taskid 文件 ({file_id}) 已弃用,与分支名称 ({branch_id}) 不一致。请从仓库中删除 .taskid — 分支名称是唯一的真实来源。"
},
"WARNING: VIKUNJA_TOKEN not set — skipping task existence check. Set it in .env to enable full validation.": {
"bg": "ПРЕДУПРЕЖДЕНИЕ: VIKUNJA_TOKEN не е зададен — пропускане на проверката за съществуване на задача. Задайте го в .env за пълна валидация.",
"de": "WARNUNG: VIKUNJA_TOKEN nicht gesetzt — Task-Existenzprüfung übersprungen. In .env setzen für volle Validierung.",
"en": "WARNING: VIKUNJA_TOKEN not set — skipping task existence check. Set it in .env to enable full validation.",
"pl": "OSTRZEŻENIE: VIKUNJA_TOKEN nie jest ustawiony — pomijanie sprawdzania istnienia zadania. Ustaw w .env, aby włączyć pełną walidację.",
"ru": "ПРЕДУПРЕЖДЕНИЕ: VIKUNJA_TOKEN не установлен — пропуск проверки существования задачи. Установите в .env для полной проверки.",
"zh": "警告: VIKUNJA_TOKEN 未设置 — 跳过任务存在性检查。在 .env 中设置以启用完整验证。"
},
"Warning: could not fetch tags from origin.": {
"bg": "Warning: could not fetch tags from origin.",
"de": "Warning: could not fetch tags from origin.",
@@ -1319,13 +1759,45 @@
"ru": "Wiki verification failed — {failures} page(s) empty or mismatched",
"zh": "Wiki verification failed — {failures} page(s) empty or mismatched"
},
"[tool.devx] missing required keys: {keys}": {
"bg": "[tool.devx] липсват задължителни ключове: {keys}",
"de": "[tool.devx] fehlt erforderliche Schlüssel: {keys}",
"en": "[tool.devx] missing required keys: {keys}",
"pl": "[tool.devx] brak wymaganych kluczy: {keys}",
"ru": "[tool.devx] отсутствуют обязательные ключи: {keys}",
"zh": "[tool.devx] 缺少必需的键: {keys}"
"Wrote tag {tag} to GITHUB_OUTPUT.": {
"bg": "Wrote tag {tag} to GITHUB_OUTPUT.",
"de": "Wrote tag {tag} to GITHUB_OUTPUT.",
"en": "Wrote tag {tag} to GITHUB_OUTPUT.",
"ru": "Wrote tag {tag} to GITHUB_OUTPUT.",
"zh": "Wrote tag {tag} to GITHUB_OUTPUT.",
"pl": "Wrote tag {tag} to GITHUB_OUTPUT."
},
"[check-dep-docs] Passed: all dependencies are documented": {
"bg": "[check-dep-docs] Passed: all dependencies are documented",
"de": "[check-dep-docs] Passed: all dependencies are documented",
"en": "[check-dep-docs] Passed: all dependencies are documented",
"pl": "[check-dep-docs] Passed: all dependencies are documented",
"ru": "[check-dep-docs] Passed: all dependencies are documented",
"zh": "[check-dep-docs] Passed: all dependencies are documented"
},
"[check-mutable-globals] Passed: no mutable path globals found": {
"bg": "[check-mutable-globals] Passed: no mutable path globals found",
"de": "[check-mutable-globals] Passed: no mutable path globals found",
"en": "[check-mutable-globals] Passed: no mutable path globals found",
"pl": "[check-mutable-globals] Passed: no mutable path globals found",
"ru": "[check-mutable-globals] Passed: no mutable path globals found",
"zh": "[check-mutable-globals] Passed: no mutable path globals found"
},
"[check_agent_docs] Passed: scanned {count} file(s), no stale references": {
"bg": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"de": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"en": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"pl": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"ru": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"zh": "[check_agent_docs] Passed: scanned {count} file(s), no stale references"
},
"[check_test_coverage] No changed files to check.": {
"bg": "[check_test_coverage] No changed files to check.",
"de": "[check_test_coverage] No changed files to check.",
"en": "[check_test_coverage] No changed files to check.",
"pl": "[check_test_coverage] No changed files to check.",
"ru": "[check_test_coverage] No changed files to check.",
"zh": "[check_test_coverage] No changed files to check."
},
"[dry-run] Would commit: release: v{version}": {
"bg": "[dry-run] Would commit: release: v{version}",
@@ -1383,6 +1855,14 @@
"ru": "[dry-run] Would update {init}",
"zh": "[dry-run] Would update {init}"
},
"[tool.devx] missing required keys: {keys}": {
"bg": "[tool.devx] липсват задължителни ключове: {keys}",
"de": "[tool.devx] fehlt erforderliche Schlüssel: {keys}",
"en": "[tool.devx] missing required keys: {keys}",
"pl": "[tool.devx] brak wymaganych kluczy: {keys}",
"ru": "[tool.devx] отсутствуют обязательные ключи: {keys}",
"zh": "[tool.devx] 缺少必需的键: {keys}"
},
"active": {
"bg": "активен",
"de": "aktiv",
@@ -1399,6 +1879,14 @@
"ru": "завершён",
"zh": "已完成"
},
"devx version mismatch across extras: {detail}": {
"bg": "несъответствие на версията на devx между extras: {detail}",
"de": "devx-Versionskonflikt zwischen Extras: {detail}",
"en": "devx version mismatch across extras: {detail}",
"pl": "niezgodność wersji devx między extras: {detail}",
"ru": "несоответствие версии devx между extras: {detail}",
"zh": "devx 版本在 extras 之间不一致: {detail}"
},
"failed": {
"bg": "неуспешен",
"de": "fehlgeschlagen",
@@ -1502,357 +1990,5 @@
"pl": "{file} już istnieje. Użyj --force, aby nadpisać.",
"ru": "{file} already exists. Use --force to overwrite.",
"zh": "{file} already exists. Use --force to overwrite."
},
"Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description": {
"bg": "Клон '{branch}' не съдържа ID на задача.\n Очакван формат: {prefix}-N-кратко-описание",
"de": "Branch '{branch}' enthält keine Task-ID.\n Erwartetes Format: {prefix}-N-kurz-beschreibung",
"en": "Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description",
"pl": "Gałąź '{branch}' nie zawiera ID zadania.\n Oczekiwany format: {prefix}-N-krótki-opis",
"ru": "Ветка '{branch}' не содержит ID задачи.\n Ожидаемый формат: {prefix}-N-краткое-описание",
"zh": "分支 '{branch}' 不包含任务 ID。\n 预期格式: {prefix}-N-简短描述"
},
"Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description\n Example: {prefix}-42-add-feature\n Fix: rename the branch or create a Vikunja task first:\n python -m devx.tools.create_task --title \"Task title\"": {
"bg": "Клон '{branch}' не съдържа ID на задача.\n Очакван формат: {prefix}-N-кратко-описание\n Пример: {prefix}-42-add-feature\n Решение: преименувайте клона или създайте Vikunja задача:\n python -m devx.tools.create_task --title \"Заглавие на задача\"",
"de": "Branch '{branch}' enthält keine Task-ID.\n Erwartetes Format: {prefix}-N-kurz-beschreibung\n Beispiel: {prefix}-42-add-feature\n Fix: Branch umbenennen oder Vikunja-Task erstellen:\n python -m devx.tools.create_task --title \"Task-Titel\"",
"en": "Branch '{branch}' does not contain a task ID.\n Expected format: {prefix}-N-short-description\n Example: {prefix}-42-add-feature\n Fix: rename the branch or create a Vikunja task first:\n python -m devx.tools.create_task --title \"Task title\"",
"pl": "Gałąź '{branch}' nie zawiera ID zadania.\n Oczekiwany format: {prefix}-N-krótki-opis\n Przykład: {prefix}-42-add-feature\n Naprawa: zmień nazwę gałęzi lub utwórz zadanie Vikunja:\n python -m devx.tools.create_task --title \"Tytuł zadania\"",
"ru": "Ветка '{branch}' не содержит ID задачи.\n Ожидаемый формат: {prefix}-N-краткое-описание\n Пример: {prefix}-42-add-feature\n Исправление: переименуйте ветку или создайте задачу Vikunja:\n python -m devx.tools.create_task --title \"Заголовок задачи\"",
"zh": "分支 '{branch}' 不包含任务 ID。\n 预期格式: {prefix}-N-简短描述\n 示例: {prefix}-42-add-feature\n 修复: 重命名分支或先创建 Vikunja 任务:\n python -m devx.tools.create_task --title \"任务标题\""
},
"Could not find Vikunja task {task_id} in project {project_id}.": {
"bg": "Не е намерена Vikunja задача {task_id} в проект {project_id}.",
"de": "Vikunja-Task {task_id} in Projekt {project_id} nicht gefunden.",
"en": "Could not find Vikunja task {task_id} in project {project_id}.",
"pl": "Nie znaleziono zadania Vikunja {task_id} w projekcie {project_id}.",
"ru": "Не найдена задача Vikunja {task_id} в проекте {project_id}.",
"zh": "在项目 {project_id} 中找不到 Vikunja 任务 {task_id}。"
},
"Could not detect current branch: {error}": {
"bg": "Не може да се определи текущия клон: {error}",
"de": "Aktueller Branch konnte nicht erkannt werden: {error}",
"en": "Could not detect current branch: {error}",
"pl": "Nie można wykryć bieżącej gałęzi: {error}",
"ru": "Не удалось определить текущую ветку: {error}",
"zh": "无法检测当前分支: {error}"
},
"Created PR #{index}: {title}\n {url}": {
"bg": "Създаден PR #{index}: {title}\n {url}",
"de": "PR erstellt #{index}: {title}\n {url}",
"en": "Created PR #{index}: {title}\n {url}",
"pl": "Utworzono PR #{index}: {title}\n {url}",
"ru": "Создан PR #{index}: {title}\n {url}",
"zh": "已创建 PR #{index}: {title}\n {url}"
},
"Created Vikunja task: {identifier} (id={task_id})": {
"bg": "Създадена Vikunja задача: {identifier} (id={task_id})",
"de": "Vikunja-Task erstellt: {identifier} (id={task_id})",
"en": "Created Vikunja task: {identifier} (id={task_id})",
"pl": "Utworzono zadanie Vikunja: {identifier} (id={task_id})",
"ru": "Создана задача Vikunja: {identifier} (id={task_id})",
"zh": "已创建 Vikunja 任务: {identifier} (id={task_id})"
},
"Next steps:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-short-description\n 3. Implement changes, commit with conventional commit format\n 4. git push -u origin HEAD\n 5. make create-pr (creates PR with title: {identifier}: {title})": {
"bg": "Следващи стъпки:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-кратко-описание\n 3. Имплементирайте промените, commit с conventional commit формат\n 4. git push -u origin HEAD\n 5. make create-pr (създава PR с заглавие: {identifier}: {title})",
"de": "Nächste Schritte:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-kurz-beschreibung\n 3. Änderungen implementieren, mit Conventional-Commit-Format committen\n 4. git push -u origin HEAD\n 5. make create-pr (erstellt PR mit Titel: {identifier}: {title})",
"en": "Next steps:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-short-description\n 3. Implement changes, commit with conventional commit format\n 4. git push -u origin HEAD\n 5. make create-pr (creates PR with title: {identifier}: {title})",
"pl": "Następne kroki:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-krótki-opis\n 3. Wprowadź zmiany, commituj w formacie conventional commit\n 4. git push -u origin HEAD\n 5. make create-pr (tworzy PR z tytułem: {identifier}: {title})",
"ru": "Следующие шаги:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-краткое-описание\n 3. Реализуйте изменения, коммитьте в conventional commit формате\n 4. git push -u origin HEAD\n 5. make create-pr (создаёт PR с заголовком: {identifier}: {title})",
"zh": "后续步骤:\n 1. git checkout master && git pull\n 2. git checkout -b {prefix}-{num}-简短描述\n 3. 实现更改,使用 conventional commit 格式提交\n 4. git push -u origin HEAD\n 5. make create-pr (创建 PR,标题: {identifier}: {title})"
},
"PR already exists: #{index} — {url}": {
"bg": "PR вече съществува: #{index} — {url}",
"de": "PR existiert bereits: #{index} — {url}",
"en": "PR already exists: #{index} — {url}",
"pl": "PR już istnieje: #{index} — {url}",
"ru": "PR уже существует: #{index} — {url}",
"zh": "PR 已存在: #{index} — {url}"
},
"Pre-push check passed: task {task_id} exists.": {
"bg": "Pre-push проверката премина: задача {task_id} съществува.",
"de": "Pre-push-Prüfung bestanden: Task {task_id} existiert.",
"en": "Pre-push check passed: task {task_id} exists.",
"pl": "Sprawdzanie pre-push zakończone: zadanie {task_id} istnieje.",
"ru": "Pre-push проверка пройдена: задача {task_id} существует.",
"zh": "Pre-push 检查通过: 任务 {task_id} 存在。"
},
"REPO_TOKEN is not set. Required to create a PR.": {
"bg": "REPO_TOKEN не е зададен. Необходим за създаване на PR.",
"de": "REPO_TOKEN nicht gesetzt. Erforderlich zum Erstellen eines PR.",
"en": "REPO_TOKEN is not set. Required to create a PR.",
"pl": "REPO_TOKEN nie jest ustawiony. Wymagany do utworzenia PR.",
"ru": "REPO_TOKEN не установлен. Требуется для создания PR.",
"zh": "REPO_TOKEN 未设置。创建 PR 所需。"
},
"Repository name not set. Use DEVX_REPO_NAME or GITHUB_REPOSITORY env var.": {
"bg": "Името на хранилището не е зададено. Използвайте DEVX_REPO_NAME или GITHUB_REPOSITORY env var.",
"de": "Repository-Name nicht gesetzt. Verwende DEVX_REPO_NAME oder GITHUB_REPOSITORY env var.",
"en": "Repository name not set. Use DEVX_REPO_NAME or GITHUB_REPOSITORY env var.",
"pl": "Nazwa repozytorium nie jest ustawiona. Użyj DEVX_REPO_NAME lub GITHUB_REPOSITORY env var.",
"ru": "Имя репозитория не установлено. Используйте DEVX_REPO_NAME или GITHUB_REPOSITORY env var.",
"zh": "仓库名称未设置。使用 DEVX_REPO_NAME 或 GITHUB_REPOSITORY 环境变量。"
},
"Repository owner not set. Use --owner or DEVX_REPO_OWNER env var.": {
"bg": "Собственикът на хранилището не е зададен. Използвайте --owner или DEVX_REPO_OWNER env var.",
"de": "Repository-Owner nicht gesetzt. Verwende --owner oder DEVX_REPO_OWNER env var.",
"en": "Repository owner not set. Use --owner or DEVX_REPO_OWNER env var.",
"pl": "Właściciel repozytorium nie jest ustawiony. Użyj --owner lub DEVX_REPO_OWNER env var.",
"ru": "Владелец репозитория не установлен. Используйте --owner или DEVX_REPO_OWNER env var.",
"zh": "仓库所有者未设置。使用 --owner 或 DEVX_REPO_OWNER 环境变量。"
},
"VIKUNJA_TOKEN is not set. Required to derive PR title.": {
"bg": "VIKUNJA_TOKEN не е зададен. Необходим за извличане на PR заглавие.",
"de": "VIKUNJA_TOKEN nicht gesetzt. Erforderlich zum Ableiten des PR-Titels.",
"en": "VIKUNJA_TOKEN is not set. Required to derive PR title.",
"pl": "VIKUNJA_TOKEN nie jest ustawiony. Wymagany do pobrania tytułu PR.",
"ru": "VIKUNJA_TOKEN не установлен. Требуется для получения заголовка PR.",
"zh": "VIKUNJA_TOKEN 未设置。推导 PR 标题所需。"
},
"VIKUNJA_TOKEN is not set. Set it in .env or environment.": {
"bg": "VIKUNJA_TOKEN не е зададен. Задайте го в .env или средата.",
"de": "VIKUNJA_TOKEN nicht gesetzt. In .env oder Umgebung setzen.",
"en": "VIKUNJA_TOKEN is not set. Set it in .env or environment.",
"pl": "VIKUNJA_TOKEN nie jest ustawiony. Ustaw go w .env lub środowisku.",
"ru": "VIKUNJA_TOKEN не установлен. Установите его в .env или среде.",
"zh": "VIKUNJA_TOKEN 未设置。在 .env 或环境中设置它。"
},
"Vikunja task {task_id} not found in project {project_id}.\n Create it first:\n python -m devx.tools.create_task --title \"Task title\"\n Or check that the task ID in the branch name is correct.": {
"bg": "Vikunja задача {task_id} не е намерена в проект {project_id}.\n Създайте я първо:\n python -m devx.tools.create_task --title \"Заглавие на задача\"\n Или проверете че ID на задачата в името на клона е правилно.",
"de": "Vikunja-Task {task_id} in Projekt {project_id} nicht gefunden.\n Zuerst erstellen:\n python -m devx.tools.create_task --title \"Task-Titel\"\n Oder prüfen, ob die Task-ID im Branch-Namen korrekt ist.",
"en": "Vikunja task {task_id} not found in project {project_id}.\n Create it first:\n python -m devx.tools.create_task --title \"Task title\"\n Or check that the task ID in the branch name is correct.",
"pl": "Zadanie Vikunja {task_id} nie znalezione w projekcie {project_id}.\n Utwórz je najpierw:\n python -m devx.tools.create_task --title \"Tytuł zadania\"\n Lub sprawdź, czy ID zadania w nazwie gałęzi jest poprawne.",
"ru": "Задача Vikunja {task_id} не найдена в проекте {project_id}.\n Сначала создайте её:\n python -m devx.tools.create_task --title \"Заголовок задачи\"\n Или проверьте, что ID задачи в имени ветки корректен.",
"zh": "在项目 {project_id} 中找不到 Vikunja 任务 {task_id}。\n 请先创建:\n python -m devx.tools.create_task --title \"任务标题\"\n 或检查分支名称中的任务 ID 是否正确。"
},
"WARNING: VIKUNJA_TOKEN not set — skipping task existence check. Set it in .env to enable full validation.": {
"bg": "ПРЕДУПРЕЖДЕНИЕ: VIKUNJA_TOKEN не е зададен — пропускане на проверката за съществуване на задача. Задайте го в .env за пълна валидация.",
"de": "WARNUNG: VIKUNJA_TOKEN nicht gesetzt — Task-Existenzprüfung übersprungen. In .env setzen für volle Validierung.",
"en": "WARNING: VIKUNJA_TOKEN not set — skipping task existence check. Set it in .env to enable full validation.",
"pl": "OSTRZEŻENIE: VIKUNJA_TOKEN nie jest ustawiony — pomijanie sprawdzania istnienia zadania. Ustaw w .env, aby włączyć pełną walidację.",
"ru": "ПРЕДУПРЕЖДЕНИЕ: VIKUNJA_TOKEN не установлен — пропуск проверки существования задачи. Установите в .env для полной проверки.",
"zh": "警告: VIKUNJA_TOKEN 未设置 — 跳过任务存在性检查。在 .env 中设置以启用完整验证。"
},
"[check-mutable-globals] Passed: no mutable path globals found": {
"bg": "[check-mutable-globals] Passed: no mutable path globals found",
"de": "[check-mutable-globals] Passed: no mutable path globals found",
"en": "[check-mutable-globals] Passed: no mutable path globals found",
"pl": "[check-mutable-globals] Passed: no mutable path globals found",
"ru": "[check-mutable-globals] Passed: no mutable path globals found",
"zh": "[check-mutable-globals] Passed: no mutable path globals found"
},
"[check_agent_docs] Passed: scanned {count} file(s), no stale references": {
"bg": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"de": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"en": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"pl": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"ru": "[check_agent_docs] Passed: scanned {count} file(s), no stale references",
"zh": "[check_agent_docs] Passed: scanned {count} file(s), no stale references"
},
"[check_test_coverage] No changed files to check.": {
"bg": "[check_test_coverage] No changed files to check.",
"de": "[check_test_coverage] No changed files to check.",
"en": "[check_test_coverage] No changed files to check.",
"pl": "[check_test_coverage] No changed files to check.",
"ru": "[check_test_coverage] No changed files to check.",
"zh": "[check_test_coverage] No changed files to check."
},
"Additional directory to scan (default: scripts, tests). Can be repeated.": {
"bg": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"de": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"en": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"pl": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"ru": "Additional directory to scan (default: scripts, tests). Can be repeated.",
"zh": "Additional directory to scan (default: scripts, tests). Can be repeated."
},
"Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master": {
"bg": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"de": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"en": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"pl": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"ru": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master",
"zh": "Branch is behind origin/master. Rebase first: git fetch origin master && git rebase origin/master"
},
"Branch name (e.g., DEVX-256-fix-foo)": {
"bg": "Branch name (e.g., DEVX-256-fix-foo)",
"de": "Branch name (e.g., DEVX-256-fix-foo)",
"en": "Branch name (e.g., DEVX-256-fix-foo)",
"pl": "Branch name (e.g., DEVX-256-fix-foo)",
"ru": "Branch name (e.g., DEVX-256-fix-foo)",
"zh": "Branch name (e.g., DEVX-256-fix-foo)"
},
"Branch name must contain a task ID.": {
"bg": "Branch name must contain a task ID.",
"de": "Branch name must contain a task ID.",
"en": "Branch name must contain a task ID.",
"pl": "Branch name must contain a task ID.",
"ru": "Branch name must contain a task ID.",
"zh": "Branch name must contain a task ID."
},
"Check that changed files have corresponding tests": {
"bg": "Check that changed files have corresponding tests",
"de": "Check that changed files have corresponding tests",
"en": "Check that changed files have corresponding tests",
"pl": "Check that changed files have corresponding tests",
"ru": "Check that changed files have corresponding tests",
"zh": "Check that changed files have corresponding tests"
},
"Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).": {
"bg": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"de": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"en": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"pl": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"ru": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found).",
"zh": "Could not fetch PR title from Gitea (REPO_TOKEN not set or PR not found)."
},
"Dependencies must have documentation comments.": {
"bg": "Dependencies must have documentation comments.",
"de": "Dependencies must have documentation comments.",
"en": "Dependencies must have documentation comments.",
"pl": "Dependencies must have documentation comments.",
"ru": "Dependencies must have documentation comments.",
"zh": "Dependencies must have documentation comments."
},
"FAILED: {count} undocumented dependency/ies": {
"bg": "FAILED: {count} undocumented dependency/ies",
"de": "FAILED: {count} undocumented dependency/ies",
"en": "FAILED: {count} undocumented dependency/ies",
"pl": "FAILED: {count} undocumented dependency/ies",
"ru": "FAILED: {count} undocumented dependency/ies",
"zh": "FAILED: {count} undocumented dependency/ies"
},
"Found {count} mutable global(s) — use factory functions or pytest fixtures.": {
"bg": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"de": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"en": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"pl": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"ru": "Found {count} mutable global(s) — use factory functions or pytest fixtures.",
"zh": "Found {count} mutable global(s) — use factory functions or pytest fixtures."
},
"Found {count} stale documentation reference(s)": {
"bg": "Found {count} stale documentation reference(s)",
"de": "Found {count} stale documentation reference(s)",
"en": "Found {count} stale documentation reference(s)",
"pl": "Found {count} stale documentation reference(s)",
"ru": "Found {count} stale documentation reference(s)",
"zh": "Found {count} stale documentation reference(s)"
},
"No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.": {
"bg": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"de": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"en": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"pl": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"ru": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description.",
"zh": "No task ID found in branch name '{branch}'. Expected format: {prefix}-N-description."
},
"Only check staged files (for pre-commit)": {
"bg": "Only check staged files (for pre-commit)",
"de": "Only check staged files (for pre-commit)",
"en": "Only check staged files (for pre-commit)",
"pl": "Only check staged files (for pre-commit)",
"ru": "Only check staged files (for pre-commit)",
"zh": "Only check staged files (for pre-commit)"
},
"PR number (to fetch title from Gitea)": {
"bg": "PR number (to fetch title from Gitea)",
"de": "PR number (to fetch title from Gitea)",
"en": "PR number (to fetch title from Gitea)",
"pl": "PR number (to fetch title from Gitea)",
"ru": "PR number (to fetch title from Gitea)",
"zh": "PR number (to fetch title from Gitea)"
},
"PR title (auto-fetched if --pr-number given)": {
"bg": "PR title (auto-fetched if --pr-number given)",
"de": "PR title (auto-fetched if --pr-number given)",
"en": "PR title (auto-fetched if --pr-number given)",
"pl": "PR title (auto-fetched if --pr-number given)",
"ru": "PR title (auto-fetched if --pr-number given)",
"zh": "PR title (auto-fetched if --pr-number given)"
},
"PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}": {
"bg": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"de": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"en": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"pl": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"ru": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}",
"zh": "PR title does not match Vikunja task title.\n Expected: {expected}\n Got: {title}"
},
"PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}": {
"bg": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"de": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"en": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"pl": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"ru": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}",
"zh": "PR title must follow format '{prefix}-N: <task title>'.\n Got: {title}"
},
"PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}": {
"bg": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"de": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"en": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"pl": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"ru": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}",
"zh": "PR title task ID mismatch.\n Branch task ID: {task_id}\n PR title: {title}"
},
"Path to pyproject.toml (default: pyproject.toml in CWD).": {
"bg": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"de": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"en": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"pl": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"ru": "Path to pyproject.toml (default: pyproject.toml in CWD).",
"zh": "Path to pyproject.toml (default: pyproject.toml in CWD)."
},
"Pre-merge validation failed.": {
"bg": "Pre-merge validation failed.",
"de": "Pre-merge validation failed.",
"en": "Pre-merge validation failed.",
"pl": "Pre-merge validation failed.",
"ru": "Pre-merge validation failed.",
"zh": "Pre-merge validation failed."
},
"Print warnings but always exit 0": {
"bg": "Print warnings but always exit 0",
"de": "Print warnings but always exit 0",
"en": "Print warnings but always exit 0",
"pl": "Print warnings but always exit 0",
"ru": "Print warnings but always exit 0",
"zh": "Print warnings but always exit 0"
},
"Repository in owner/name format": {
"bg": "Repository in owner/name format",
"de": "Repository in owner/name format",
"en": "Repository in owner/name format",
"pl": "Repository in owner/name format",
"ru": "Repository in owner/name format",
"zh": "Repository in owner/name format"
},
"Skip Vikunja title match check": {
"bg": "Skip Vikunja title match check",
"de": "Skip Vikunja title match check",
"en": "Skip Vikunja title match check",
"pl": "Skip Vikunja title match check",
"ru": "Skip Vikunja title match check",
"zh": "Skip Vikunja title match check"
},
"Skip branch-behind-master check": {
"bg": "Skip branch-behind-master check",
"de": "Skip branch-behind-master check",
"en": "Skip branch-behind-master check",
"pl": "Skip branch-behind-master check",
"ru": "Skip branch-behind-master check",
"zh": "Skip branch-behind-master check"
},
"[check-dep-docs] Passed: all dependencies are documented": {
"bg": "[check-dep-docs] Passed: all dependencies are documented",
"de": "[check-dep-docs] Passed: all dependencies are documented",
"en": "[check-dep-docs] Passed: all dependencies are documented",
"pl": "[check-dep-docs] Passed: all dependencies are documented",
"ru": "[check-dep-docs] Passed: all dependencies are documented",
"zh": "[check-dep-docs] Passed: all dependencies are documented"
},
"Wrote tag {tag} to GITHUB_OUTPUT.": {
"bg": "Wrote tag {tag} to GITHUB_OUTPUT.",
"de": "Wrote tag {tag} to GITHUB_OUTPUT.",
"en": "Wrote tag {tag} to GITHUB_OUTPUT.",
"ru": "Wrote tag {tag} to GITHUB_OUTPUT.",
"zh": "Wrote tag {tag} to GITHUB_OUTPUT.",
"pl": "Wrote tag {tag} to GITHUB_OUTPUT."
}
}