-
Notifications
You must be signed in to change notification settings - Fork 0
feature(76471): enforce Java version consistency check & running unit tests inside Docker #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bogdandina
wants to merge
10
commits into
main
Choose a base branch
from
feature/76471_enforce-java-version-consistency-check
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
5202fb2
feat(76477): remove the jarArtifactName and jarArtifact Path and hard…
bogdandina 24d8508
feat(76471): check Java version alignment between Dockerfile and pom.xml
bogdandina d640521
feat(76471): fix the .gitignore and remove the scripts/__pycache__
bogdandina 02eb2fa
fix(76471): fix shared workflow scripts checkout using hardcoded repo…
bogdandina de67a1a
feature(76471): update .gitignore
bogdandina f435846
feat(76471): potential fix
bogdandina 06a10b5
test(76471): add unit tests for validate_java_version_consistency.py …
bogdandina 22945f1
feat(76455): inline the test layer of the Dockerfile in the CI/CD for…
bogdandina 1d8679c
feat(76471): fixes after PR review
bogdandina 885a6fa
feat(76471): fixes++
bogdandina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,5 @@ | ||
| .idea | ||
| /AGENTS.md | ||
| scripts/__pycache__ | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| .claude |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| import os | ||
| import re | ||
| import subprocess | ||
| import sys | ||
|
|
||
|
|
||
| def normalize_java_version(value): | ||
bogdandina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if not value: | ||
| return None | ||
|
|
||
| cleaned = value.strip().strip('"\'') | ||
| if not cleaned or cleaned.startswith('${'): | ||
| return None | ||
|
|
||
| cleaned = cleaned.replace('JavaVersion.VERSION_', '') | ||
|
|
||
| if cleaned.startswith('1.'): | ||
| parts = cleaned.split('.') | ||
| if len(parts) > 1 and parts[1].isdigit(): | ||
| return parts[1] | ||
|
|
||
| match = re.search(r'(\d+)', cleaned) | ||
| if match: | ||
| return str(int(match.group(1))) | ||
|
|
||
| return None | ||
|
|
||
|
|
||
| def extract_java_version_from_docker_tag(tag): | ||
| patterns = ( | ||
| r'(?:^|[._-])(\d+)(?:[._-])java(?:[._-])(jre|jdk)(?:$|[._-])', | ||
| r'(?:^|[._-])java(?:[._-])(\d+)(?:$|[._-])', | ||
| r'(?:^|[._-])(\d+)(?:[._-])(jre|jdk)(?:$|[._-])', | ||
| r'^(\d+)$', | ||
| ) | ||
|
|
||
| for pattern in patterns: | ||
| match = re.search(pattern, tag, re.IGNORECASE) | ||
| if match: | ||
| return normalize_java_version(match.group(1)) | ||
|
|
||
| return None | ||
|
|
||
|
|
||
| def resolve_args(value, args): | ||
| def replace(match): | ||
| variable_name = match.group(1) or match.group(2) | ||
| return args.get(variable_name, match.group(0)) | ||
|
|
||
| return re.sub(r'\$\{([^}]+)\}|\$(\w+)', replace, value) | ||
|
|
||
|
|
||
| def parse_docker_java_version(dockerfile_path): | ||
| args = {} | ||
| images = [] | ||
|
|
||
| with open(dockerfile_path, encoding='utf-8') as dockerfile: | ||
| for raw_line in dockerfile: | ||
| line = raw_line.split('#', 1)[0].strip() | ||
| if not line: | ||
| continue | ||
|
|
||
| arg_match = re.match(r'^ARG\s+([A-Za-z_][A-Za-z0-9_]*)=(.+)$', line, re.IGNORECASE) | ||
bogdandina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if arg_match: | ||
| args[arg_match.group(1)] = arg_match.group(2).strip() | ||
| continue | ||
|
|
||
| from_match = re.match(r'^FROM\s+([^\s]+)', line, re.IGNORECASE) | ||
| if from_match: | ||
| image = resolve_args(from_match.group(1).strip(), args) | ||
| images.append(image) | ||
|
|
||
| runtime_images = [image for image in images if image.lower() != 'scratch'] | ||
| if not runtime_images: | ||
| raise RuntimeError('Could not find a runtime image in Dockerfile.') | ||
|
|
||
| image_ref = runtime_images[-1].split('@', 1)[0] | ||
| last_slash = image_ref.rfind('/') | ||
| last_colon = image_ref.rfind(':') | ||
|
|
||
| if last_colon <= last_slash: | ||
| raise RuntimeError(f'Could not determine the Java tag from Docker image "{image_ref}".') | ||
|
|
||
| tag = image_ref[last_colon + 1 :] | ||
| java_version = extract_java_version_from_docker_tag(tag) | ||
| if not java_version: | ||
| raise RuntimeError( | ||
| 'Could not determine the Java version from Docker tag ' | ||
| f'"{tag}". Expected a tag like "25", "25-jdk", or "1.0.2-25-java-jre".' | ||
| ) | ||
|
|
||
| return java_version, image_ref | ||
|
|
||
|
|
||
| def evaluate_maven_property(expression): | ||
| result = subprocess.run( | ||
| [ | ||
| 'mvn', | ||
| '-q', | ||
| '-DforceStdout', | ||
| '-Dstyle.color=never', | ||
| 'help:evaluate', | ||
| f'-Dexpression={expression}', | ||
| ], | ||
| capture_output=True, | ||
| text=True, | ||
| check=False, | ||
| ) | ||
|
|
||
| if result.returncode != 0: | ||
| return None | ||
|
|
||
| lines = [line.strip() for line in result.stdout.splitlines() if line.strip()] | ||
| lines = [line for line in lines if not line.startswith('[')] | ||
| return lines[-1] if lines else None | ||
|
|
||
|
|
||
| def parse_maven_java_version(): | ||
| for expression in ( | ||
| 'maven.compiler.release', | ||
| 'maven.compiler.target', | ||
| 'java.version', | ||
| ): | ||
| value = evaluate_maven_property(expression) | ||
| normalized = normalize_java_version(value) | ||
| if normalized: | ||
| return normalized, f'pom.xml ({expression}={value})' | ||
|
|
||
| raise RuntimeError( | ||
| 'Could not determine the Java version from pom.xml. ' | ||
| 'Expected maven.compiler.release, maven.compiler.target, or java.version.' | ||
| ) | ||
|
|
||
|
|
||
| def parse_gradle_java_version(gradle_path): | ||
| with open(gradle_path, encoding='utf-8') as gradle_file: | ||
| content = gradle_file.read() | ||
|
|
||
| patterns = [ | ||
| r'jvmTarget\s*=\s*["\']([^"\']+)["\']', | ||
| r'jvmTarget\s*=\s*JavaVersion\.VERSION_?(\d+)', | ||
| r'languageVersion(?:\.set)?\s*\(?\s*JavaLanguageVersion\.of\((\d+)\)\s*\)?', | ||
| r'sourceCompatibility\s*=\s*JavaVersion\.VERSION_?(\d+)', | ||
| r'targetCompatibility\s*=\s*JavaVersion\.VERSION_?(\d+)', | ||
| ] | ||
|
|
||
| for pattern in patterns: | ||
| match = re.search(pattern, content, re.MULTILINE | re.DOTALL) | ||
| if match: | ||
| value = match.group(1) | ||
| normalized = normalize_java_version(value) | ||
| if normalized: | ||
| return normalized, f'{os.path.basename(gradle_path)} ({value})' | ||
|
|
||
| raise RuntimeError( | ||
| 'Could not determine the Java version from the Gradle build file. ' | ||
| 'Expected compileKotlin.kotlinOptions.jvmTarget or java.toolchain.languageVersion.' | ||
| ) | ||
|
|
||
|
|
||
| def main(): | ||
| dockerfile_path = os.path.join(os.getcwd(), 'Dockerfile') | ||
| if not os.path.exists(dockerfile_path): | ||
| raise RuntimeError(f'Dockerfile not found at {dockerfile_path}.') | ||
|
|
||
| docker_version, docker_image = parse_docker_java_version(dockerfile_path) | ||
|
|
||
| pom_path = os.path.join(os.getcwd(), 'pom.xml') | ||
| gradle_paths = [ | ||
| os.path.join(os.getcwd(), 'build.gradle.kts'), | ||
| os.path.join(os.getcwd(), 'build.gradle'), | ||
| ] | ||
|
|
||
| if os.path.exists(pom_path): | ||
| build_version, build_source = parse_maven_java_version() | ||
| else: | ||
| existing_gradle_paths = [path for path in gradle_paths if os.path.exists(path)] | ||
| if not existing_gradle_paths: | ||
| raise RuntimeError( | ||
| 'Could not find pom.xml, build.gradle.kts, or build.gradle in the working directory.' | ||
| ) | ||
| build_version, build_source = parse_gradle_java_version(existing_gradle_paths[0]) | ||
|
|
||
| if docker_version != build_version: | ||
| print( | ||
| 'Java version mismatch: ' | ||
| f'Dockerfile uses Java {docker_version} ({docker_image}), ' | ||
| f'but {build_source} resolves to Java {build_version}.', | ||
| file=sys.stderr, | ||
| ) | ||
| sys.exit(1) | ||
|
|
||
| print( | ||
| 'Java version check passed: ' | ||
| f'Dockerfile uses Java {docker_version} and {build_source} matches.' | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| main() | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.