This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git


The following commit(s) were added to refs/heads/main by this push:
     new 52e202f  Control dependencies more carefully and ensure frequent 
updates
52e202f is described below

commit 52e202f2deae74d38bc60849736339b2ab919de8
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Dec 17 19:39:52 2025 +0000

    Control dependencies more carefully and ensure frequent updates
---
 .pre-commit-config.yaml                    | 38 ++++++++++------
 .pre-commit-light.yaml                     |  6 +--
 Makefile                                   | 30 ++++++------
 notes/development.md                       |  8 ++--
 scripts/check_when_dependencies_updated.py | 73 ++++++++++++++++++++++++++++++
 uv.lock                                    |  3 ++
 6 files changed, 121 insertions(+), 37 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b268463..5539c1f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,7 +3,7 @@ repos:
 - repo: meta
   hooks:
     - id: check-hooks-apply
-      name: run check hooks apply
+      name: check that hooks apply
       description: check that all the hooks apply to the repository
 - repo: https://github.com/pre-commit/pre-commit-hooks
   rev: v6.0.0
@@ -30,7 +30,7 @@ repos:
   rev: v1.5.5
   hooks:
     - id: insert-license
-      name: Add license for all Python files
+      name: add a license for all Python files
       files: ^(atr|scripts|tests)/(.*\.py$|.*\.pyi)$
       args:
         - --comment-style
@@ -39,7 +39,7 @@ repos:
         - scripts/ci/LICENSE-template.txt
         - --fuzzy-match-generates-todo
     - id: insert-license
-      name: Add license for JS and TS files
+      name: add a license for JS and TS files
       files: ^atr/static/(js/src/.*\.js|ts/.*\.ts)$
       args:
         - --comment-style
@@ -51,7 +51,7 @@ repos:
   rev: v0.47.0
   hooks:
     - id: markdownlint
-      name: run markdownlint
+      name: run Markdown lints
       description: check Markdown files with markdownlint
       args: [--config=.github/linters/.markdown-lint.yml]
       types: [markdown]
@@ -105,7 +105,7 @@ repos:
   rev: v1.33.0
   hooks:
     - id: oxlint
-      name: Oxlint JS Linter
+      name: lint JS files with Oxlint
       types: [javascript]
       files: ^atr/static/js/src/.*\.js$
       args:
@@ -134,21 +134,21 @@ repos:
 - repo: local
   hooks:
     - id: ruff
-      name: Ruff Linter
-      entry: uv run ruff check --fix
+      name: lint Python files with Ruff
+      entry: uv run --frozen ruff check --fix
       language: system
       types: [python]
 
     - id: ruff-format
-      name: Ruff Formatter
-      entry: uv run ruff format --force-exclude
+      name: format Python files with Ruff
+      entry: uv run --frozen ruff format --force-exclude
       language: system
       types: [python]
 
     - id: biome-format
       # Install biome from https://biomejs.dev/guides/manual-installation/
       # Avoid using NPM to install it until #359 is resolved
-      name: Biome JS Formatter
+      name: format JS files with Biome
       entry: biome format --write --files-ignore-unknown=true 
--no-errors-on-unmatched --colors=off
       language: system
       types: [javascript]
@@ -157,24 +157,32 @@ repos:
     - id: biome-check
       # Install biome from https://biomejs.dev/guides/manual-installation/
       # Avoid using NPM to install it until #359 is resolved
-      name: Biome JS Linter
+      name: lint JS files with Biome
       entry: biome check --write --error-on-warnings 
--files-ignore-unknown=true --no-errors-on-unmatched --colors=off
       language: system
       types: [javascript]
       files: ^atr/static/js/src/.*\.js$
 
     - id: pyright
-      name: Pyright Type Check
-      entry: uv run pyright
+      name: type check Python files with Pyright
+      entry: uv run --frozen pyright
       language: system
       require_serial: true
       types: [python]
       exclude: ^tests/
 
     - id: jinja-route-check
-      name: Jinja Route Checker
+      name: check Jinja2 routes
       description: Check whether routes used in Jinja2 templates actually exist
-      entry: uv run python scripts/lint/jinja_route_checker.py
+      entry: uv run --frozen python scripts/lint/jinja_route_checker.py
+      language: system
+      pass_filenames: false
+      always_run: true
+
+    - id: check-when-dependencies-updated
+      name: check when dependencies were updated
+      description: Verify that dependencies were updated within the configured 
timeframe, for ASVS 15.2.1
+      entry: uv run --frozen python scripts/check_when_dependencies_updated.py
       language: system
       pass_filenames: false
       always_run: true
diff --git a/.pre-commit-light.yaml b/.pre-commit-light.yaml
index 3de3bd1..92e83c7 100644
--- a/.pre-commit-light.yaml
+++ b/.pre-commit-light.yaml
@@ -3,19 +3,19 @@ repos:
 - repo: local
   hooks:
     - id: ruff
-      name: Ruff Linter
+      name: ruff linter
       entry: ruff check --fix
       language: system
       types: [python]
 
     - id: ruff-format
-      name: Ruff Formatter
+      name: ruff formatter
       entry: ruff format --force-exclude
       language: system
       types: [python]
 
     - id: pyright
-      name: Pyright Type Check
+      name: pyright type check
       entry: pyright
       language: system
       require_serial: true
diff --git a/Makefile b/Makefile
index 1c3beed..3172f7e 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,7 @@ bump-bootstrap:
 
 certs:
        if test ! -f state/cert.pem || test ! -f state/key.pem; \
-       then uv run scripts/generate-certificates; \
+       then uv run --frozen scripts/generate-certificates; \
        fi
 
 certs-local:
@@ -45,7 +45,7 @@ certs-local:
 
 check:
        git add -A
-       uv run pre-commit run --all-files
+       uv run --frozen pre-commit run --all-files
 
 check-extra:
        @git add -A
@@ -54,11 +54,11 @@ check-extra:
 
 check-heavy:
        git add -A
-       uv run pre-commit run --all-files --config .pre-commit-heavy.yaml
+       uv run --frozen pre-commit run --all-files --config 
.pre-commit-heavy.yaml
 
 check-light:
        git add -A
-       uv run pre-commit run --all-files --config .pre-commit-light.yaml
+       uv run --frozen pre-commit run --all-files --config 
.pre-commit-light.yaml
 
 commit:
        git add -A
@@ -68,16 +68,16 @@ commit:
 
 docs:
        mkdir -p docs
-       uv run python3 scripts/docs_check.py
+       uv run --frozen python3 scripts/docs_check.py
        rm -f docs/*.html
-       uv run python3 scripts/docs_build.py
+       uv run --frozen python3 scripts/docs_build.py
        for fn in atr/docs/*.md; do out=$${fn#atr/}; cmark "$$fn" > 
"$${out%.md}.html"; done
-       uv run python3 scripts/docs_post_process.py docs/*.html
-       uv run python3 scripts/docs_check.py
+       uv run --frozen python3 scripts/docs_post_process.py docs/*.html
+       uv run --frozen python3 scripts/docs_check.py
 
 generate-version:
        @rm -f atr/version.py
-       @uv run python3 atr/metadata.py > /tmp/version.py
+       @uv run --frozen python3 atr/metadata.py > /tmp/version.py
        @mv /tmp/version.py atr/version.py
        @cat atr/version.py
 
@@ -101,23 +101,23 @@ run-playwright-slow:
        docker run --net=host -it atr-playwright python3 test.py --tidy
 
 serve:
-       SSH_HOST=127.0.0.1 uv run hypercorn --bind $(BIND) \
+       SSH_HOST=127.0.0.1 uv run --frozen hypercorn --bind $(BIND) \
          --keyfile localhost.apache.org+3-key.pem --certfile 
localhost.apache.org+3.pem \
          atr.server:app --debug --reload
 
 serve-local:
        APP_HOST=localhost.apache.org:8080 SECRET_KEY=insecure-local-key \
-         ALLOW_TESTS=1 SSH_HOST=127.0.0.1 uv run hypercorn --bind $(BIND) \
+         ALLOW_TESTS=1 SSH_HOST=127.0.0.1 uv run --frozen hypercorn --bind 
$(BIND) \
          --keyfile localhost.apache.org+3-key.pem --certfile 
localhost.apache.org+3.pem \
          atr.server:app --debug --reload
 
 sync:
-       uv sync --no-dev
+       uv sync --frozen --no-dev
 
 sync-all:
-       uv sync --all-groups
+       uv sync --frozen --all-groups
 
 update-deps:
        pre-commit autoupdate || :
-       uv lock --upgrade
-       uv sync --all-groups
+       uv lock --upgrade --exclude-newer "$$(date -u +%Y-%m-%dT%H:%M:%SZ)"
+       uv sync --frozen --all-groups
diff --git a/notes/development.md b/notes/development.md
index fce0745..e840099 100644
--- a/notes/development.md
+++ b/notes/development.md
@@ -5,14 +5,14 @@ You will need to have a working [Python 
3.13](https://www.python.org/downloads/r
 Ensure that you have the pre-commit hook installed:
 
 ```shell
-make sync PYTHON="$(which python3)"
-poetry run pre-commit install
+make sync-all
+uv run --frozen pre-commit install
 ```
 
-To run the project, use the following commands, which will add a local CA root 
to your OS and browser certificate qstore if using Firefox:
+To run the project, use the following commands, which will add a local CA root 
to your OS and browser certificate store if using Firefox:
 
 ```shell
-uv sync --all-groups
+make sync-all
 make certs-local
 make serve
 ```
diff --git a/scripts/check_when_dependencies_updated.py 
b/scripts/check_when_dependencies_updated.py
new file mode 100755
index 0000000..39e77c2
--- /dev/null
+++ b/scripts/check_when_dependencies_updated.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import datetime
+import pathlib
+import sys
+from typing import Final
+
+_MAX_AGE_DAYS: Final[int] = 30
+
+
+def main() -> None:
+    lock_path = pathlib.Path("uv.lock")
+    if not lock_path.exists():
+        print("ERROR: uv.lock not found", file=sys.stderr)
+        sys.exit(1)
+
+    exclude_newer = _parse_exclude_newer(lock_path)
+    if exclude_newer is None:
+        print("ERROR: No exclude-newer timestamp in uv.lock", file=sys.stderr)
+        print("Run: make update-deps", file=sys.stderr)
+        sys.exit(1)
+
+    timestamp = _parse_timestamp(exclude_newer)
+    if timestamp is None:
+        print(f"ERROR: Could not parse timestamp: {exclude_newer}", 
file=sys.stderr)
+        sys.exit(1)
+
+    now = datetime.datetime.now(datetime.UTC)
+    age = now - timestamp
+
+    if age > datetime.timedelta(days=_MAX_AGE_DAYS):
+        print(f"ERROR: Dependencies are {age.days} days old (the limit is 
{_MAX_AGE_DAYS} days)", file=sys.stderr)
+        print(f"Last updated: {exclude_newer}", file=sys.stderr)
+        print("Run: make update-deps", file=sys.stderr)
+        sys.exit(1)
+
+    print(f"OK: Dependencies are {age.days} days old (the limit is 
{_MAX_AGE_DAYS} days)")
+
+
+def _parse_exclude_newer(lock_path: pathlib.Path) -> str | None:
+    for line in lock_path.read_text(encoding="utf-8").splitlines():
+        if line.startswith("exclude-newer"):
+            _, _, value = line.partition("=")
+            return value.strip().strip('"')
+    return None
+
+
+def _parse_timestamp(timestamp_str: str) -> datetime.datetime | None:
+    try:
+        return datetime.datetime.fromisoformat(timestamp_str.replace("Z", 
"+00:00"))
+    except ValueError:
+        return None
+
+
+if __name__ == "__main__":
+    main()
diff --git a/uv.lock b/uv.lock
index 004d219..1ee4d34 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,6 +2,9 @@ version = 1
 revision = 3
 requires-python = "==3.13.*"
 
+[options]
+exclude-newer = "2025-12-17T17:16:16Z"
+
 [[package]]
 name = "aiofiles"
 version = "24.1.0"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to