mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-09-27 15:56:45 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3a55def37 |
@@ -1,12 +1,25 @@
|
|||||||
|
# `pre-commit install` installs both hook types, so contributors get the
|
||||||
|
# pre-push checks too without needing to remember `-t pre-push`.
|
||||||
|
default_install_hook_types: [pre-commit, pre-push]
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
|
# `manual` stage only: these never run on commit or push. The full ruleset in
|
||||||
|
# .ruff.toml is aspirational (~600 violations are not auto-fixable and
|
||||||
|
# ruff-format would rewrite most of the tree), so enforcing it on commit would
|
||||||
|
# permanently block edits to files like changedetectionio/__init__.py.
|
||||||
|
# CI matches this stance: it gates on E9,F63,F7,F82,INT and runs the rest with
|
||||||
|
# --exit-zero. Run on demand with:
|
||||||
|
# pre-commit run --hook-stage manual --all-files
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.11.2
|
rev: v0.11.2
|
||||||
hooks:
|
hooks:
|
||||||
# Lint (and apply safe fixes)
|
# Lint (and apply safe fixes)
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: [--fix]
|
args: [--fix]
|
||||||
|
stages: [manual]
|
||||||
# Fomrat
|
# Fomrat
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
stages: [manual]
|
||||||
|
|
||||||
- repo: local
|
- repo: local
|
||||||
hooks:
|
hooks:
|
||||||
@@ -15,6 +28,7 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
entry: dennis-cmd lint --strict
|
entry: dennis-cmd lint --strict
|
||||||
files: ^changedetectionio/translations/messages\.pot$
|
files: ^changedetectionio/translations/messages\.pot$
|
||||||
|
stages: [pre-commit]
|
||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
|
|
||||||
- id: dennis-lint-po
|
- id: dennis-lint-po
|
||||||
@@ -22,4 +36,25 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
entry: dennis-cmd lint --strict --excluderules=W302
|
entry: dennis-cmd lint --strict --excluderules=W302
|
||||||
files: ^changedetectionio/translations/\w+/LC_MESSAGES/messages\.po$
|
files: ^changedetectionio/translations/\w+/LC_MESSAGES/messages\.po$
|
||||||
|
stages: [pre-commit]
|
||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
|
|
||||||
|
# Runs at commit time so a release commit that bumps __version__ without
|
||||||
|
# re-running extract_messages fails *before* the release tag is created.
|
||||||
|
# Scoped to the two files that can drift, so unrelated commits aren't blocked.
|
||||||
|
- id: translations-version-sync
|
||||||
|
name: translations catalog version matches app version
|
||||||
|
language: system
|
||||||
|
entry: python scripts/check_translations_version.py
|
||||||
|
files: ^changedetectionio/(__init__\.py|translations/messages\.pot)$
|
||||||
|
stages: [pre-commit]
|
||||||
|
pass_filenames: false
|
||||||
|
|
||||||
|
# Backstop for commits made with --no-verify, and for tag-only pushes.
|
||||||
|
- id: translations-version-sync-push
|
||||||
|
name: translations catalog version matches app version (push)
|
||||||
|
language: system
|
||||||
|
entry: python scripts/check_translations_version.py
|
||||||
|
stages: [pre-push]
|
||||||
|
pass_filenames: false
|
||||||
|
always_run: true
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ Otherwise, it's always best to PR into the `master` branch.
|
|||||||
|
|
||||||
Install the development and test dependencies with `pip install -r requirements-dev.txt`.
|
Install the development and test dependencies with `pip install -r requirements-dev.txt`.
|
||||||
|
|
||||||
|
Then activate the git hooks once with `pre-commit install` — this wires up linting on commit and a
|
||||||
|
translation catalog check on push, matching what CI enforces. Git cannot enable hooks automatically
|
||||||
|
on clone, so this step is manual.
|
||||||
|
|
||||||
Please be sure that all new functionality has a matching test!
|
Please be sure that all new functionality has a matching test!
|
||||||
|
|
||||||
Use `pytest` to validate/test, you can run the existing tests as `pytest tests/test_notification.py` for example
|
Use `pytest` to validate/test, you can run the existing tests as `pytest tests/test_notification.py` for example
|
||||||
|
|||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Bump the app version and refresh the translation catalogs in one step.
|
||||||
|
|
||||||
|
The release commit needs `__version__` and the .pot `Project-Id-Version` to agree
|
||||||
|
(extract_messages stamps the latter from the former). Doing them separately is easy
|
||||||
|
to half-forget, which then breaks the push *after* the release tag already exists.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python scripts/bump_version.py 0.60.3
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
INIT_FILE = REPO_ROOT / 'changedetectionio' / '__init__.py'
|
||||||
|
VERSION_RE = re.compile(r"""^(__version__ = )(['"])([^'"]*)\2""", re.M)
|
||||||
|
|
||||||
|
BABEL_STEPS = ['extract_messages', 'update_catalog', 'compile_catalog']
|
||||||
|
|
||||||
|
|
||||||
|
def run(*args):
|
||||||
|
print(f" $ {' '.join(args)}", flush=True)
|
||||||
|
result = subprocess.run(args, cwd=REPO_ROOT)
|
||||||
|
if result.returncode != 0:
|
||||||
|
sys.exit(f"FAILED: {' '.join(args)}")
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
if len(argv) != 2:
|
||||||
|
sys.exit(f"Usage: python {Path(__file__).name} <new-version>\n"
|
||||||
|
f"e.g. python {Path(__file__).name} 0.60.3")
|
||||||
|
|
||||||
|
new_version = argv[1].lstrip('v')
|
||||||
|
if not re.fullmatch(r'\d+\.\d+\.\d+', new_version):
|
||||||
|
sys.exit(f"Version must look like 0.60.3, got: {new_version!r}")
|
||||||
|
|
||||||
|
source = INIT_FILE.read_text(encoding='utf-8')
|
||||||
|
match = VERSION_RE.search(source)
|
||||||
|
if not match:
|
||||||
|
sys.exit(f"Could not find __version__ in {INIT_FILE.relative_to(REPO_ROOT)}")
|
||||||
|
|
||||||
|
old_version = match.group(3)
|
||||||
|
if old_version == new_version:
|
||||||
|
sys.exit(f"Version is already {new_version}")
|
||||||
|
|
||||||
|
print(f"Bumping {old_version} -> {new_version}", flush=True)
|
||||||
|
INIT_FILE.write_text(VERSION_RE.sub(
|
||||||
|
lambda m: f"{m.group(1)}{m.group(2)}{new_version}{m.group(2)}", source, count=1),
|
||||||
|
encoding='utf-8')
|
||||||
|
|
||||||
|
print("Refreshing translation catalogs:", flush=True)
|
||||||
|
for step in BABEL_STEPS:
|
||||||
|
run(sys.executable, 'setup.py', step)
|
||||||
|
|
||||||
|
run(sys.executable, str(REPO_ROOT / 'scripts' / 'check_translations_version.py'))
|
||||||
|
|
||||||
|
print(f"\nVersion {new_version} is in sync. Changed files:")
|
||||||
|
subprocess.run(['git', 'status', '--short'], cwd=REPO_ROOT)
|
||||||
|
print("\nNothing has been committed or tagged. To release, keep this chained --")
|
||||||
|
print("a failed commit must not leave a tag pointing at the wrong revision:")
|
||||||
|
print(f" git add -u && git commit -m '{new_version}' && git tag {new_version} \\")
|
||||||
|
print(f" && git push origin master && git push origin {new_version}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv))
|
||||||
Executable
+61
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Check that the version in messages.pot matches the app version.
|
||||||
|
|
||||||
|
`python setup.py extract_messages` stamps `Project-Id-Version` in the .pot
|
||||||
|
header from `changedetectionio.__version__`, so a mismatch means the version
|
||||||
|
was bumped without re-extracting the translation catalogs.
|
||||||
|
|
||||||
|
Run manually, or via the pre-push hook in .pre-commit-config.yaml.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
INIT_FILE = REPO_ROOT / 'changedetectionio' / '__init__.py'
|
||||||
|
POT_FILE = REPO_ROOT / 'changedetectionio' / 'translations' / 'messages.pot'
|
||||||
|
|
||||||
|
|
||||||
|
def get_app_version():
|
||||||
|
match = re.search(r"""^__version__ = ['"]([^'"]*)['"]""",
|
||||||
|
INIT_FILE.read_text(encoding='utf-8'), re.M)
|
||||||
|
return match.group(1) if match else None
|
||||||
|
|
||||||
|
|
||||||
|
def get_pot_version():
|
||||||
|
# "Project-Id-Version: changedetection.io 0.60.2\n"
|
||||||
|
match = re.search(r'^"Project-Id-Version: changedetection\.io ([^\\"]+)',
|
||||||
|
POT_FILE.read_text(encoding='utf-8'), re.M)
|
||||||
|
return match.group(1).strip() if match else None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app_version = get_app_version()
|
||||||
|
pot_version = get_pot_version()
|
||||||
|
|
||||||
|
if not app_version:
|
||||||
|
print(f"Could not find __version__ in {INIT_FILE.relative_to(REPO_ROOT)}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if not pot_version:
|
||||||
|
print(f"Could not find 'Project-Id-Version: changedetection.io <version>' "
|
||||||
|
f"in {POT_FILE.relative_to(REPO_ROOT)}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if app_version != pot_version:
|
||||||
|
print(f"Translation catalog version mismatch:")
|
||||||
|
print(f" app ({INIT_FILE.relative_to(REPO_ROOT)}): {app_version}")
|
||||||
|
print(f" .pot ({POT_FILE.relative_to(REPO_ROOT)}): {pot_version}")
|
||||||
|
print()
|
||||||
|
print("Refresh the catalogs and commit the result:")
|
||||||
|
print(" python setup.py extract_messages")
|
||||||
|
print(" python setup.py update_catalog")
|
||||||
|
print(" python setup.py compile_catalog")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user