Skip to content

feat: add Python pre-build license checker with --fix and --pr#5

Merged
Aias00 merged 1 commit into
mainfrom
feature/python-license-checker-with-pr-fix
Jul 8, 2026
Merged

feat: add Python pre-build license checker with --fix and --pr#5
Aias00 merged 1 commit into
mainfrom
feature/python-license-checker-with-pr-fix

Conversation

@Aias00

@Aias00 Aias00 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a Python pre-build license checker (shenyu_watcher.py) alongside the existing Java post-package checker, and fixes several issues in the Java tool. The headline new capability is a --pr action that integrates the --fix license repair into a reviewable pull-request workflow.

What's new

shenyu_watcher.py (new)

A pure-stdlib tool (no pip dependencies) that:

  • Resolves Maven runtime dependencies via mvn dependency:list, an assembled lib/ directory, or pom.xml fallback
  • Checks each against the LICENSE file using literal string matching (no false positives from license boilerplate)
  • Handles Maven classifiers, fork-URL detection, and parent-POM license resolution
  • --fix: fetches license info from Maven Central POMs and appends missing entries to the correct LICENSE section
  • --pr (implies --fix): after fixing, creates a git branch, commits only the LICENSE path, pushes, and opens a GitHub PR via gh

How --pr works

The branch is created before the fix writes to disk, so the only commit on the new branch is the LICENSE change. Path-scoped commit (git commit -- <relpath>) means unrelated dirty files in the working tree are never swept in — it only requires the LICENSE file itself to be clean. Auto-detects the git root (works when the project is a subdirectory of a larger repo, e.g. a shenyu monorepo module). If no entries are actually added (all duplicates), the branch is rolled back and no PR is opened.

python shenyu_watcher.py --pr /path/to/shenyu/shenyu-dist/shenyu-admin-dist

Java tool fixes

  • Cross-platform path separators (File.separator instead of hardcoded \\)
  • Python version check via regex + numeric compare (was a literal "Python 3.8" string match, so 3.9+ failed)
  • Prints a success message when all jars match
  • Uses commons-collections4 CollectionUtils

Other

  • .gitignore: ignore Python __pycache__/ and *.pyc
  • README.md: rewritten to document both tools, the --fix/--pr flows, exit codes, and a comparison table

Verification

  • python3 -c "import ast; ast.parse(...)" — syntax OK
  • --help shows the new --pr/--branch/--base/--remote flags
  • --fix regression: confirmed against a scratch repo (appends entry, re-check passes, no commit)
  • --pr end-to-end on a scratch git repo (with gh/push stubbed): branch created from main, commit touched only LICENSE, PR title/body generated with added entries + check context
  • Edge cases: empty-diff → rollback (no PR); dirty LICENSE → pre-flight exit code 2, no branch; symlinked project path (/tmp/private/tmp) handled via realpath normalization

Notes

  • The Java tool retains no auto-fix/PR capability (documented as a limitation).
  • This PR will need review per .asf.yaml (1 approving review + status checks on main).

🤖 Generated with Claude Code

Adds shenyu_watcher.py — a pure-stdlib tool that resolves Maven runtime
dependencies (via mvn dependency:list, an assembled lib/ dir, or pom.xml
fallback), checks them against the LICENSE file, and can auto-fix missing
entries by fetching license info from Maven Central POMs.

New --pr action integrates the fix into a reviewable workflow: after fixing
the target project's LICENSE, it creates a git branch, commits only the
LICENSE path, pushes, and opens a GitHub PR via the gh CLI. Branch creation
happens before the write so the only commit on the branch is the LICENSE
change; an empty diff (all duplicates) rolls back with no PR.

Also fixes the legacy Java tool:
- cross-platform path separators (File.separator instead of "\\")
- version comparison via regex + numeric compare (was a literal "Python 3.8" string match)
- prints a success message when all jars match
- uses commons-collections4 CollectionUtils

README rewritten to document both tools.

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 7, 2026 23:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new Python-based, pre-build license checker (shenyu_watcher.py) to validate (and optionally auto-fix) Maven dependency LICENSE declarations before packaging, while also improving the existing Java-based post-package checker’s portability and Python version detection.

Changes:

  • Added shenyu_watcher.py: resolves dependencies, checks LICENSE entries, supports --fix, and can open a GitHub PR via --pr.
  • Updated Java checker to use cross-platform path construction and improved Python version detection logic.
  • Updated documentation and repo hygiene (README.md, .gitignore) and added a new Maven dependency.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/main/java/org/apache/shenyu/ShenyuWatcher.java Improves cross-platform path handling and output behavior in the Java post-package checker.
src/main/java/org/apache/shenyu/env/CheckEnv.java Updates Python version detection to parse and compare versions rather than string matching.
shenyu_watcher.py Introduces a new pre-build Python license checker with --fix and --pr workflows.
README.md Rewritten to document both tools, usage flows, and behavior.
pom.xml Adds commons-collections4 dependency used by the Java tool update.
.gitignore Ignores Python bytecode caches/artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +45
String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
System.out.println("Start to unzip " + fileName + "...");

String destDir = filePath.substring(0, filePath.lastIndexOf("\\"));
String destDir = filePath.substring(0, filePath.lastIndexOf(File.separator));
System.err.println("The following jars need to be modified: ");
failureMatchJar.forEach(System.err::println);
} else {
System.out.println("The license is ok ");

} else {
System.err.println("The python version not 3.8");

public static boolean PYTHON_CHECK = false;

private static final Pattern pattern = Pattern.compile("Python (\\d+\\.\\d+\\.\\d+)");
Comment thread README.md

### Requirements

- Python 3.6+
Comment thread shenyu_watcher.py
root_real = os.path.realpath(git_root)
lic_real = os.path.realpath(license_path)
rel = os.path.relpath(lic_real, root_real)
if rel == "." or os.path.isabs(rel) or rel.startswith(".." + os.sep):
Comment on lines 45 to 46
InputStream inputStream = process.getInputStream();
String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
Comment on lines +48 to +52
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println(matcher.group(1));
PYTHON_CHECK = isVersionGreaterOrEqual(matcher.group(1), REQUIRED_PYTHON_VERSION);
}
Comment on lines +54 to 65
if (!PYTHON_CHECK) {
exe = "python3 -V";
}
process = Runtime.getRuntime().exec(exe);
inputStream = process.getInputStream();
str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

matcher = pattern.matcher(str);
if (matcher.find()) {
System.out.println(matcher.group(1));
PYTHON_CHECK = isVersionGreaterOrEqual(matcher.group(1), REQUIRED_PYTHON_VERSION);
}
@Aias00 Aias00 merged commit 94c1bb9 into main Jul 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants