This is an automated email from the ASF dual-hosted git repository.
jason810496 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 6e6edfd5cdc Add prek hook to auto-update copyright year in NOTICE
files (#67146)
6e6edfd5cdc is described below
commit 6e6edfd5cdc2dca8c89769112188d571a877b650
Author: Chao-Hung Wan <[email protected]>
AuthorDate: Thu Jun 11 10:14:35 2026 +0800
Add prek hook to auto-update copyright year in NOTICE files (#67146)
* feat:update_notice_year
Signed-off-by: Xch1 <[email protected]>
* remove check notice year
Signed-off-by: Xch1 <[email protected]>
* remove emoji
Signed-off-by: Xch1 <[email protected]>
* add date check and message
Signed-off-by: Xch1 <[email protected]>
* remove sort
Signed-off-by: Xch1 <[email protected]>
---------
Signed-off-by: Xch1 <[email protected]>
---
.pre-commit-config.yaml | 7 ++++
scripts/ci/prek/check_notice_files.py | 8 +++-
scripts/ci/prek/update_notice_year.py | 74 +++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 48bbc2ddc7f..917a262d5ae 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -224,6 +224,13 @@ repos:
entry: ./scripts/ci/prek/check_min_python_version.py
language: python
require_serial: true
+ - id: update-notice-year
+ name: Update NOTICE files to current year (manual)
+ entry: ./scripts/ci/prek/update_notice_year.py
+ stages: ['manual']
+ language: python
+ pass_filenames: false
+ require_serial: true
- id: check-notice-files
name: Check NOTICE files for current year and ASF references
entry: ./scripts/ci/prek/check_notice_files.py
diff --git a/scripts/ci/prek/check_notice_files.py
b/scripts/ci/prek/check_notice_files.py
index 93b5d0fdc4c..600d466d1c1 100755
--- a/scripts/ci/prek/check_notice_files.py
+++ b/scripts/ci/prek/check_notice_files.py
@@ -47,4 +47,10 @@ for notice_file in sys.argv[1:]:
print(f"❌ {notice_file}: Missing expected string: {expected!r}")
errors += 1
-sys.exit(1 if errors else 0)
+if errors:
+ print()
+ print("To fix, run: prek run update-notice-year --all-files")
+ print("Then commit the changes.")
+ sys.exit(1)
+
+sys.exit(0)
diff --git a/scripts/ci/prek/update_notice_year.py
b/scripts/ci/prek/update_notice_year.py
new file mode 100644
index 00000000000..e027e763846
--- /dev/null
+++ b/scripts/ci/prek/update_notice_year.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+# 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.
+# /// script
+# requires-python = ">=3.10, <3.11"
+# dependencies = []
+# ///
+"""
+Update the end year in NOTICE files to the current year.
+
+Replaces ``Copyright 2016-YYYY The Apache Software Foundation`` with the
+current year. Files whose copyright line already carries the current year
+are left untouched. Files that don't contain the standard ASF copyright
+line at all are skipped with a warning so that non-standard NOTICE files
+(e.g. the fab provider) are never silently corrupted.
+
+Run once a year (manual stage):
+
+ prek run update-notice-year --all-files
+"""
+
+from __future__ import annotations
+
+import re
+import sys
+from datetime import datetime
+from pathlib import Path
+
+CURRENT_YEAR = str(datetime.now().year)
+COPYRIGHT_RE = re.compile(r"(Copyright 2016-)(\d{4})( The Apache Software
Foundation)")
+
+
+def update_file(path: Path) -> bool:
+ """Return True if the file was modified."""
+ content = path.read_text()
+ match = COPYRIGHT_RE.search(content)
+ if not match:
+ print(f"{path}: no standard ASF copyright line found, skipping")
+ return False
+ if match.group(2) == CURRENT_YEAR:
+ return False
+ new_content = COPYRIGHT_RE.sub(rf"\g<1>{CURRENT_YEAR}\3", content)
+ path.write_text(new_content)
+ print(f"{path}: updated {match.group(2)} → {CURRENT_YEAR}")
+ return True
+
+
+EXCLUDE_DIRS = {"node_modules", ".git", ".venv", "__pycache__"}
+
+
+def main() -> int:
+ repo_root = Path(__file__).parents[3]
+ notice_files = [f for f in repo_root.rglob("NOTICE") if not any(part in
EXCLUDE_DIRS for part in f.parts)]
+ updated = sum(update_file(f) for f in notice_files)
+ print(f"\n{updated} file(s) updated, {len(notice_files) - updated} already
current.")
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())