From 876ab4a8da5628fc1a4b48686b8640cf252b5812 Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Wed, 1 Jul 2026 22:09:13 +0000 Subject: [PATCH 1/9] Add Java Format CI check for pull requests Add a workflow that enforces dev/CodeStyle_eclipse.xml on the Java files changed by a pull request. It applies the Eclipse formatter (via formatter-maven-plugin) to only the changed src/main/java and src/test/java files and fails if that produces any diff, printing the required changes. Also add dev/format-changed.sh, a helper that runs the same scoped formatting locally on the files you changed relative to the base branch (plus staged/unstaged/untracked edits). This avoids a bare `mvn formatter:format`, which would reformat the entire tree. The check is scoped to the PR diff rather than the whole tree because the existing sources are not yet fully formatter-clean; this lets the codebase converge file-by-file without failing unrelated PRs. --- .github/workflows/javaFormat.yml | 102 +++++++++++++++++++++++++++++++ dev/format-changed.sh | 84 +++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 .github/workflows/javaFormat.yml create mode 100755 dev/format-changed.sh diff --git a/.github/workflows/javaFormat.yml b/.github/workflows/javaFormat.yml new file mode 100644 index 00000000000..fa4748003a5 --- /dev/null +++ b/.github/workflows/javaFormat.yml @@ -0,0 +1,102 @@ +#------------------------------------------------------------- +# +# 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. +# +#------------------------------------------------------------- + +name: Java Format + +# Only the Java files changed by a pull request are checked: the Eclipse +# formatter (dev/CodeStyle_eclipse.xml) is applied to them and the job fails if +# that produces any change. The existing tree is not yet fully formatter-clean, +# so validating everything would fail unrelated PRs; scoping to the diff keeps +# the check actionable and lets the codebase converge file-by-file. + +on: + pull_request: + paths: + - '**/*.java' + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + java_format: + name: Java Format Check + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Setup Java 17 adopt + uses: actions/setup-java@v5 + with: + distribution: adopt + java-version: '17' + cache: 'maven' + + - name: Determine changed Java files + id: changed + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + run: | + # PR changes = diff between the merge-base and HEAD, limited to still + # present (.java) files under the two maven source roots. + INCLUDES=$(git diff --name-only --diff-filter=ACMR "$BASE_SHA"...HEAD \ + | grep -E '^src/(main|test)/java/.+\.java$' \ + | sed -E 's#^src/(main|test)/java/##' \ + | paste -sd, - || true) + echo "includes=$INCLUDES" >> "$GITHUB_OUTPUT" + if [ -z "$INCLUDES" ]; then + echo "No changed Java source files to check." + else + echo "Checking formatting of:" + echo "$INCLUDES" | tr ',' '\n' | sed 's/^/ /' + fi + + - name: Apply Eclipse formatter to changed files + if: steps.changed.outputs.includes != '' + run: | + mvn -ntp -B \ + net.revelc.code.formatter:formatter-maven-plugin:2.24.1:format \ + -Dconfigfile="$PWD/dev/CodeStyle_eclipse.xml" \ + -Dmaven.compiler.source=17 -Dmaven.compiler.target=17 \ + -Dformatter.includes="${{ steps.changed.outputs.includes }}" + + - name: Fail if formatting changed anything + if: steps.changed.outputs.includes != '' + run: | + if git diff --quiet; then + echo "All changed Java files are correctly formatted." + exit 0 + fi + echo "::error::Some changed Java files are not formatted per dev/CodeStyle_eclipse.xml." + echo "Format only your changed files locally and commit the result:" + echo "" + echo " dev/format-changed.sh" + echo "" + echo "(Do NOT run a bare 'mvn formatter:format' -- it reformats the whole tree.)" + echo "" + echo "Required formatting changes (apply this diff):" + git --no-pager diff + exit 1 diff --git a/dev/format-changed.sh b/dev/format-changed.sh new file mode 100755 index 00000000000..1c7f2e37cad --- /dev/null +++ b/dev/format-changed.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +#------------------------------------------------------------- +# +# 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. +# +#------------------------------------------------------------- +# +# Apply the Eclipse formatter (dev/CodeStyle_eclipse.xml) to ONLY the Java files +# you changed -- the same scope the "Java Format" CI check enforces. +# +# A bare `mvn formatter:format` would reformat EVERY .java file under the source +# roots, and the existing tree is not yet fully formatter-clean, so that would +# produce a huge unrelated diff. This script instead formats just the files that +# differ from the base branch (plus your staged/unstaged/untracked changes). +# +# "Changed" = files that differ from the base branch (the merge target), plus +# your staged/unstaged/untracked edits. The base defaults to upstream/main (the +# apache/systemds PR target); run `git fetch upstream main` first so the diff is +# accurate. If the base ref is stale/behind your branch point, the merge-base +# drifts and unrelated files get pulled in -- pass an explicit, current base ref +# in that case. +# +# Usage: +# dev/format-changed.sh [base-ref] +# base-ref branch/commit to diff against (default: upstream/main, else +# origin/main, else main) +# +set -euo pipefail + +FMT_VERSION="2.24.1" +CONFIG="dev/CodeStyle_eclipse.xml" + +cd "$(git rev-parse --show-toplevel)" + +BASE_REF="${1:-}" +if [ -z "$BASE_REF" ]; then + for r in upstream/main origin/main main; do + if git rev-parse --verify --quiet "$r" >/dev/null; then BASE_REF="$r"; break; fi + done +fi +if [ -z "$BASE_REF" ]; then + echo "Could not determine a base ref; pass one explicitly: dev/format-changed.sh " >&2 + exit 2 +fi + +MERGE_BASE="$(git merge-base "$BASE_REF" HEAD 2>/dev/null || echo "$BASE_REF")" + +# committed-on-branch + working-tree (staged/unstaged) + untracked new files, +# limited to still-present .java files under the two maven source roots +FILES=$( { git diff --name-only --diff-filter=ACMR "$MERGE_BASE"...HEAD; + git diff --name-only --diff-filter=ACMR HEAD; + git ls-files --others --exclude-standard; } \ + | sort -u | grep -E '^src/(main|test)/java/.+\.java$' || true ) + +if [ -z "$FILES" ]; then + echo "No changed Java source files to format (base: $BASE_REF)." + exit 0 +fi + +INCLUDES=$(echo "$FILES" | sed -E 's#^src/(main|test)/java/##' | paste -sd, -) + +echo "Formatting changed Java files (base: $BASE_REF):" +echo "$FILES" | sed 's/^/ /' + +mvn -ntp -B \ + net.revelc.code.formatter:formatter-maven-plugin:${FMT_VERSION}:format \ + -Dconfigfile="$CONFIG" \ + -Dmaven.compiler.source=17 -Dmaven.compiler.target=17 \ + -Dformatter.includes="$INCLUDES" From 04727bcd6e7238e8e318616ac9e05fa56a63625a Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Wed, 1 Jul 2026 22:46:00 +0000 Subject: [PATCH 2/9] TEMP: probe commit to exercise the Java Format CI check Not for merge. Three scenarios to observe the check: 1. DMLRuntimeException.java: pre-existing file that is not formatter-clean, with a correctly-formatted method appended. 2. FormatProbeBroken.java: correctly-formatted file with one method that has blatant style violations. 3. FormatProbeClean.java: fully correctly-formatted new file. --- .../sysds/runtime/DMLRuntimeException.java | 4 ++ .../component/format/FormatProbeBroken.java | 37 +++++++++++++++++++ .../component/format/FormatProbeClean.java | 36 ++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java create mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java diff --git a/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java b/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java index 1f7bdccdc4c..8bae14cd051 100644 --- a/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java +++ b/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java @@ -43,4 +43,8 @@ public DMLRuntimeException(Throwable e) { public DMLRuntimeException(String string, Exception ex){ super(string,ex); } + + public String describe(int code) { + return "DMLRuntimeException code=" + code + ", message=" + getMessage(); + } } diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java new file mode 100644 index 00000000000..e5f06bef860 --- /dev/null +++ b/src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.apache.sysds.test.component.format; + +/** + * Temporary probe used to verify the Java Format CI check: this class is correctly formatted except for one method with + * blatant style violations, which the check MUST flag. + */ +public class FormatProbeBroken { + + public int add(int a, int b) { + int result = a + b; + return result; + } + + public int mul( int a,int b ){ + int result=a*b ; + return result ; + } +} diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java new file mode 100644 index 00000000000..ea2b95b8e12 --- /dev/null +++ b/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.sysds.test.component.format; + +/** + * Temporary probe used to verify the Java Format CI check: this file is written to comply with + * dev/CodeStyle_eclipse.xml and should therefore NOT be flagged. + */ +public class FormatProbeClean { + + public int add(int a, int b) { + int result = a + b; + return result; + } + + public String describe(int a, int b) { + return "sum=" + add(a, b); + } +} From 3484a10ce13225501dcd303dfbf87b15329d3c47 Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Thu, 2 Jul 2026 11:58:28 +0000 Subject: [PATCH 3/9] Scope Java format check to PR-edited lines only The Eclipse formatter only operates on whole files, so checking changed files reformatted their pre-existing (not-yet-clean) lines and produced an over-aggressive diff on lines the PR never touched. Add dev/format_changed.py, which formats each changed file but keeps only the formatting changes that fall on the lines the PR actually edited (via git diff line ranges intersected with difflib opcodes). It supports: --check: fail only if an edited line is mis-formatted (used by CI) --fix: apply formatting to only the edited-line regions Wire javaFormat.yml to run the --check mode and make dev/format-changed.sh delegate to --fix, so both CI and the local helper share identical line-scoped behavior. --- .github/workflows/javaFormat.yml | 63 +++------- dev/format-changed.sh | 64 +++------- dev/format_changed.py | 193 +++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+), 96 deletions(-) create mode 100755 dev/format_changed.py diff --git a/.github/workflows/javaFormat.yml b/.github/workflows/javaFormat.yml index fa4748003a5..26b24c1c7f3 100644 --- a/.github/workflows/javaFormat.yml +++ b/.github/workflows/javaFormat.yml @@ -21,11 +21,12 @@ name: Java Format -# Only the Java files changed by a pull request are checked: the Eclipse -# formatter (dev/CodeStyle_eclipse.xml) is applied to them and the job fails if -# that produces any change. The existing tree is not yet fully formatter-clean, -# so validating everything would fail unrelated PRs; scoping to the diff keeps -# the check actionable and lets the codebase converge file-by-file. +# Only the exact lines a pull request edits are checked: the Eclipse formatter +# (dev/CodeStyle_eclipse.xml) is applied and the job fails only if it would +# change a line the PR touched. The existing tree is not yet fully +# formatter-clean, so validating whole files (let alone the whole tree) would +# fail unrelated PRs; scoping to the edited lines keeps the check actionable and +# lets the codebase converge line-by-line. on: pull_request: @@ -55,48 +56,18 @@ jobs: java-version: '17' cache: 'maven' - - name: Determine changed Java files - id: changed + - name: Check formatting of PR-edited lines env: BASE_SHA: ${{ github.event.pull_request.base.sha }} run: | - # PR changes = diff between the merge-base and HEAD, limited to still - # present (.java) files under the two maven source roots. - INCLUDES=$(git diff --name-only --diff-filter=ACMR "$BASE_SHA"...HEAD \ - | grep -E '^src/(main|test)/java/.+\.java$' \ - | sed -E 's#^src/(main|test)/java/##' \ - | paste -sd, - || true) - echo "includes=$INCLUDES" >> "$GITHUB_OUTPUT" - if [ -z "$INCLUDES" ]; then - echo "No changed Java source files to check." - else - echo "Checking formatting of:" - echo "$INCLUDES" | tr ',' '\n' | sed 's/^/ /' + # Fails only if the Eclipse formatter would change a line this PR edited. + # See dev/format_changed.py for the line-scoping logic. + if ! python3 dev/format_changed.py --check "$BASE_SHA"; then + echo "::error::Some lines edited by this PR are not formatted per dev/CodeStyle_eclipse.xml." + echo "Fix only your edited lines locally and commit the result:" + echo "" + echo " dev/format-changed.sh" + echo "" + echo "(Do NOT run a bare 'mvn formatter:format' -- it reformats the whole tree.)" + exit 1 fi - - - name: Apply Eclipse formatter to changed files - if: steps.changed.outputs.includes != '' - run: | - mvn -ntp -B \ - net.revelc.code.formatter:formatter-maven-plugin:2.24.1:format \ - -Dconfigfile="$PWD/dev/CodeStyle_eclipse.xml" \ - -Dmaven.compiler.source=17 -Dmaven.compiler.target=17 \ - -Dformatter.includes="${{ steps.changed.outputs.includes }}" - - - name: Fail if formatting changed anything - if: steps.changed.outputs.includes != '' - run: | - if git diff --quiet; then - echo "All changed Java files are correctly formatted." - exit 0 - fi - echo "::error::Some changed Java files are not formatted per dev/CodeStyle_eclipse.xml." - echo "Format only your changed files locally and commit the result:" - echo "" - echo " dev/format-changed.sh" - echo "" - echo "(Do NOT run a bare 'mvn formatter:format' -- it reformats the whole tree.)" - echo "" - echo "Required formatting changes (apply this diff):" - git --no-pager diff - exit 1 diff --git a/dev/format-changed.sh b/dev/format-changed.sh index 1c7f2e37cad..8415c5ac574 100755 --- a/dev/format-changed.sh +++ b/dev/format-changed.sh @@ -20,20 +20,21 @@ # #------------------------------------------------------------- # -# Apply the Eclipse formatter (dev/CodeStyle_eclipse.xml) to ONLY the Java files -# you changed -- the same scope the "Java Format" CI check enforces. +# Apply the Eclipse formatter (dev/CodeStyle_eclipse.xml) to ONLY the lines you +# edited -- the exact scope the "Java Format" CI check enforces. # # A bare `mvn formatter:format` would reformat EVERY .java file under the source -# roots, and the existing tree is not yet fully formatter-clean, so that would -# produce a huge unrelated diff. This script instead formats just the files that -# differ from the base branch (plus your staged/unstaged/untracked changes). -# -# "Changed" = files that differ from the base branch (the merge target), plus -# your staged/unstaged/untracked edits. The base defaults to upstream/main (the -# apache/systemds PR target); run `git fetch upstream main` first so the diff is -# accurate. If the base ref is stale/behind your branch point, the merge-base -# drifts and unrelated files get pulled in -- pass an explicit, current base ref -# in that case. +# roots, and even scoping to changed *files* would reformat their pre-existing +# (not-yet-clean) lines. The existing tree is not fully formatter-clean, so both +# would produce a large unrelated diff. This delegates to dev/format_changed.py, +# which formats each changed file but keeps only the changes that land on the +# lines you actually edited. +# +# "Changed" = lines that differ from the base branch (the merge target), +# including your committed-on-branch, staged, unstaged and untracked edits. The +# base defaults to upstream/main (the apache/systemds PR target); run +# `git fetch upstream main` first so the diff is accurate, or pass an explicit, +# current base ref if the default is stale/behind your branch point. # # Usage: # dev/format-changed.sh [base-ref] @@ -42,43 +43,6 @@ # set -euo pipefail -FMT_VERSION="2.24.1" -CONFIG="dev/CodeStyle_eclipse.xml" - cd "$(git rev-parse --show-toplevel)" -BASE_REF="${1:-}" -if [ -z "$BASE_REF" ]; then - for r in upstream/main origin/main main; do - if git rev-parse --verify --quiet "$r" >/dev/null; then BASE_REF="$r"; break; fi - done -fi -if [ -z "$BASE_REF" ]; then - echo "Could not determine a base ref; pass one explicitly: dev/format-changed.sh " >&2 - exit 2 -fi - -MERGE_BASE="$(git merge-base "$BASE_REF" HEAD 2>/dev/null || echo "$BASE_REF")" - -# committed-on-branch + working-tree (staged/unstaged) + untracked new files, -# limited to still-present .java files under the two maven source roots -FILES=$( { git diff --name-only --diff-filter=ACMR "$MERGE_BASE"...HEAD; - git diff --name-only --diff-filter=ACMR HEAD; - git ls-files --others --exclude-standard; } \ - | sort -u | grep -E '^src/(main|test)/java/.+\.java$' || true ) - -if [ -z "$FILES" ]; then - echo "No changed Java source files to format (base: $BASE_REF)." - exit 0 -fi - -INCLUDES=$(echo "$FILES" | sed -E 's#^src/(main|test)/java/##' | paste -sd, -) - -echo "Formatting changed Java files (base: $BASE_REF):" -echo "$FILES" | sed 's/^/ /' - -mvn -ntp -B \ - net.revelc.code.formatter:formatter-maven-plugin:${FMT_VERSION}:format \ - -Dconfigfile="$CONFIG" \ - -Dmaven.compiler.source=17 -Dmaven.compiler.target=17 \ - -Dformatter.includes="$INCLUDES" +exec python3 dev/format_changed.py --fix "$@" diff --git a/dev/format_changed.py b/dev/format_changed.py new file mode 100755 index 00000000000..1ffbc0c66b9 --- /dev/null +++ b/dev/format_changed.py @@ -0,0 +1,193 @@ +#!/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. +# +# ------------------------------------------------------------- +# +# Line-scoped Java formatting against dev/CodeStyle_eclipse.xml. +# +# The Eclipse formatter only works on whole files, and the existing tree is not +# fully formatter-clean, so formatting a whole edited file would flag lines the +# PR never touched. This script therefore formats each changed file but keeps +# only the formatting changes that fall on the lines the PR edited (like +# clang-format-diff): it diffs the original against the fully-formatted version +# and restricts the result to the changed line ranges. +# +# --check (default): print the changed-line formatting fixes and exit 1 if any. +# --fix : apply only the changed-line formatting fixes in place. +# +# Usage: dev/format_changed.py [--check|--fix] [base-ref] +# +import difflib +import os +import re +import subprocess +import sys + +FMT_VERSION = "2.24.1" +CONFIG = "dev/CodeStyle_eclipse.xml" +SRC_RE = re.compile(r"^src/(main|test)/java/.+\.java$") + + +def sh(*args, check=False): + return subprocess.run(args, capture_output=True, text=True, check=check).stdout + + +def resolve_base(explicit): + if explicit: + return explicit + for ref in ("upstream/main", "origin/main", "main"): + if subprocess.run(["git", "rev-parse", "--verify", "--quiet", ref], + capture_output=True).returncode == 0: + return ref + sys.exit("Could not determine a base ref; pass one explicitly.") + + +def changed_ranges(mergebase, path): + # line ranges (1-based, inclusive) touched on the working-tree side, i.e. + # committed-on-branch plus staged/unstaged edits, relative to the base. + out = sh("git", "diff", "-U0", mergebase, "--", path) + ranges = [] + for line in out.splitlines(): + m = re.match(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", line) + if m: + start = int(m.group(1)) + count = int(m.group(2)) if m.group(2) is not None else 1 + if count > 0: + ranges.append((start, start + count - 1)) + return ranges + + +def overlaps(i1, i2, ranges): + # original-side region [i1, i2) (0-based half-open) vs 1-based inclusive ranges + lo, hi = i1 + 1, i2 # convert to 1-based inclusive; insert (i1==i2) -> lo>hi + for (s, e) in ranges: + if i1 == i2: # pure insertion between original lines i1 and i1+1 + if s - 1 <= i1 <= e: + return True + elif not (hi < s or lo > e): + return True + return False + + +def main(): + args = [a for a in sys.argv[1:]] + mode = "check" + if "--fix" in args: + mode = "fix" + args.remove("--fix") + if "--check" in args: + args.remove("--check") + base = resolve_base(args[0] if args else None) + + os.chdir(sh("git", "rev-parse", "--show-toplevel").strip()) + mergebase = sh("git", "merge-base", base, "HEAD").strip() or base + + files = [f for f in sh("git", "diff", "--name-only", "--diff-filter=ACMR", + mergebase, "--").splitlines() if SRC_RE.match(f)] + # include untracked new java files too (local pre-commit use) + files += [f for f in sh("git", "ls-files", "--others", "--exclude-standard").splitlines() + if SRC_RE.match(f) and f not in files] + if not files: + print(f"No changed Java source files (base: {base}).") + return 0 + + # snapshot originals so we can format in place then restore exactly, without + # disturbing any unrelated working-tree state + original = {f: open(f, encoding="utf-8").read() for f in files} + + # capture the PR-edited line ranges BEFORE we reformat the working tree, + # otherwise git would report the whole reformatted file as changed + ranges_by_file = {} + for f in files: + ranges = changed_ranges(mergebase, f) + if not ranges: + base_has = subprocess.run(["git", "cat-file", "-e", f"{mergebase}:{f}"], + capture_output=True).returncode == 0 + if not base_has: # brand-new/untracked file: treat every line as edited + ranges = [(1, max(1, len(original[f].splitlines())))] + ranges_by_file[f] = ranges + + includes = ",".join(re.sub(r"^src/(main|test)/java/", "", f) for f in files) + subprocess.run(["mvn", "-q", "-ntp", "-B", + f"net.revelc.code.formatter:formatter-maven-plugin:{FMT_VERSION}:format", + f"-Dconfigfile={os.getcwd()}/{CONFIG}", + "-Dmaven.compiler.source=17", "-Dmaven.compiler.target=17", + f"-Dformatter.includes={includes}"], check=True) + + formatted = {f: open(f, encoding="utf-8").read() for f in files} + + any_issue = False + for f in files: + a = original[f].splitlines(keepends=True) + b = formatted[f].splitlines(keepends=True) + ranges = ranges_by_file[f] + + sm = difflib.SequenceMatcher(None, a, b, autojunk=False) + result = [] + kept_hunks = [] + for tag, i1, i2, j1, j2 in sm.get_opcodes(): + if tag == "equal": + result.extend(a[i1:i2]) + elif overlaps(i1, i2, ranges): + result.extend(b[j1:j2]) + kept_hunks.append((tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) + else: + result.extend(a[i1:i2]) + + # In fix mode, always write the reconstructed content: for non-flagged + # files this equals the original (undoing mvn's whole-file reformat); + # for flagged files it applies only the changed-line formatting. + if mode == "fix": + with open(f, "w", encoding="utf-8") as out: + out.write("".join(result)) + + if not kept_hunks: + continue + any_issue = True + if mode == "check": + print(f"\n--- a/{f}") + print(f"+++ b/{f}") + for tag, i1, i2, j1, j2, olds, news in kept_hunks: + print(f"@@ -{i1 + 1},{len(olds)} +{i1 + 1},{len(news)} @@ (changed lines)") + for ln in olds: + print("-" + ln.rstrip("\n")) + for ln in news: + print("+" + ln.rstrip("\n")) + + # in check mode we only inspected; restore every file to its original content + if mode == "check": + for f in files: + with open(f, "w", encoding="utf-8") as out: + out.write(original[f]) + + if any_issue and mode == "check": + print("\nERROR: the changes above are required on lines this PR edited " + "(per dev/CodeStyle_eclipse.xml).") + print("Fix locally with: dev/format-changed.sh") + return 1 + if any_issue and mode == "fix": + print("Applied changed-line formatting. Review and commit the result.") + else: + print("All PR-edited Java lines are correctly formatted.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 29a2779b24af0d241708f9cf8c2ef79087de0b2f Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Thu, 2 Jul 2026 13:41:59 +0000 Subject: [PATCH 4/9] TEMP: more format probes to exercise line-scoped check Add varied scenarios to verify the Java Format check flags only PR-edited lines: - FormatProbeErrors: new file with four distinct code-style violations - FormatProbeOk2: new fully-compliant file (must pass) - FormatProbeClean: append one clean and one broken method (only the broken one must be flagged) - DMLRuntimeException: break only the previously-clean describe line so its pre-existing unformatted lines must remain unflagged --- .../sysds/runtime/DMLRuntimeException.java | 2 +- .../component/format/FormatProbeClean.java | 8 ++++ .../component/format/FormatProbeErrors.java | 45 +++++++++++++++++++ .../test/component/format/FormatProbeOk2.java | 32 +++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java create mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java diff --git a/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java b/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java index 8bae14cd051..536c4f54597 100644 --- a/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java +++ b/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java @@ -45,6 +45,6 @@ public DMLRuntimeException(String string, Exception ex){ } public String describe(int code) { - return "DMLRuntimeException code=" + code + ", message=" + getMessage(); + return "DMLRuntimeException code="+code+", message="+getMessage() ; } } diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java index ea2b95b8e12..56da6280f3e 100644 --- a/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java +++ b/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java @@ -33,4 +33,12 @@ public int add(int a, int b) { public String describe(int a, int b) { return "sum=" + add(a, b); } + + public int sub(int a, int b) { + return a - b; + } + + public int div( int a,int b ){ + return a/b ; + } } diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java new file mode 100644 index 00000000000..658ab05144d --- /dev/null +++ b/src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +package org.apache.sysds.test.component.format; + +/** Temporary probe with several distinct formatting mistakes to be flagged. */ +public class FormatProbeErrors { + + // missing spaces around operators + public int operators(int a, int b) { + return a+b*2; + } + + // Allman-style brace and extra spaces in the signature + public int brace( int a ) + { + return a; + } + + // over-indented body + public int indent(int a) { + return a; + } + + // missing space after comma in parameter list + public int comma(int a,int b) { + return a + b; + } +} diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java new file mode 100644 index 00000000000..9f192cab232 --- /dev/null +++ b/src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package org.apache.sysds.test.component.format; + +/** Fully compliant probe; it must NOT be flagged even though it is a new file. */ +public class FormatProbeOk2 { + + public int square(int a) { + return a * a; + } + + public int cube(int a) { + return a * a * a; + } +} From ba4d66d90b5eea1598792f4ab4a6a97317ae3e35 Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Thu, 2 Jul 2026 13:43:44 +0000 Subject: [PATCH 5/9] Add file exemption list to Java format check Introduce dev/format-exclude.txt, a list of glob patterns for files whose non-standard layout is intentional and must not be reformatted (e.g. DMLConfig.java's hand-aligned constants). dev/format_changed.py loads the list and skips matching files in both --check and --fix, matching each pattern against the repo-relative path and the bare file name. --- dev/format-exclude.txt | 14 ++++++++++++++ dev/format_changed.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 dev/format-exclude.txt diff --git a/dev/format-exclude.txt b/dev/format-exclude.txt new file mode 100644 index 00000000000..bada401954a --- /dev/null +++ b/dev/format-exclude.txt @@ -0,0 +1,14 @@ +# Files exempt from the Java Format check (dev/format_changed.py). +# +# One pattern per line; blank lines and lines starting with '#' are ignored. +# Each pattern is matched (glob / fnmatch) against the repo-relative path AND +# against the bare file name, so both of these work: +# +# src/main/java/org/apache/sysds/conf/DMLConfig.java +# *DMLConfig.java +# +# Use this only for files whose non-standard layout is intentional and must not +# be reformatted (e.g. hand-aligned tables of constants). + +# Hand-aligned configuration constants; intentional non-standard formatting. +src/main/java/org/apache/sysds/conf/DMLConfig.java diff --git a/dev/format_changed.py b/dev/format_changed.py index 1ffbc0c66b9..86dd80756e4 100755 --- a/dev/format_changed.py +++ b/dev/format_changed.py @@ -35,6 +35,7 @@ # Usage: dev/format_changed.py [--check|--fix] [base-ref] # import difflib +import fnmatch import os import re import subprocess @@ -42,6 +43,7 @@ FMT_VERSION = "2.24.1" CONFIG = "dev/CodeStyle_eclipse.xml" +EXCLUDE_FILE = "dev/format-exclude.txt" SRC_RE = re.compile(r"^src/(main|test)/java/.+\.java$") @@ -49,6 +51,22 @@ def sh(*args, check=False): return subprocess.run(args, capture_output=True, text=True, check=check).stdout +def load_excludes(): + # glob patterns of files exempt from the style check, one per line + patterns = [] + if os.path.exists(EXCLUDE_FILE): + for line in open(EXCLUDE_FILE, encoding="utf-8"): + s = line.strip() + if s and not s.startswith("#"): + patterns.append(s) + return patterns + + +def is_excluded(path, patterns): + base = os.path.basename(path) + return any(fnmatch.fnmatch(path, p) or fnmatch.fnmatch(base, p) for p in patterns) + + def resolve_base(explicit): if explicit: return explicit @@ -104,8 +122,17 @@ def main(): # include untracked new java files too (local pre-commit use) files += [f for f in sh("git", "ls-files", "--others", "--exclude-standard").splitlines() if SRC_RE.match(f) and f not in files] + + excludes = load_excludes() + skipped = [f for f in files if is_excluded(f, excludes)] + files = [f for f in files if not is_excluded(f, excludes)] + if skipped: + print(f"Skipping style-exempt files ({EXCLUDE_FILE}):") + for f in skipped: + print(f" {f}") + if not files: - print(f"No changed Java source files (base: {base}).") + print(f"No changed Java source files to check (base: {base}).") return 0 # snapshot originals so we can format in place then restore exactly, without From f798135d415ac943dec9c1a7e1f4ae78ecfdc309 Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Thu, 2 Jul 2026 14:40:29 +0000 Subject: [PATCH 6/9] Harden Java format checker: data-safety, loud errors, tests Address review findings on the line-scoped format check: - Always restore working-tree files via try/finally so an mvn failure or interrupt never leaves whole-file reformatting on disk (previously the restore only ran on the happy path, risking loss of uncommitted/untracked content in --check and --fix). - Fail loudly on git errors instead of swallowing stderr and reporting a false "clean" pass; validate the resolved base ref up front. - Reject unknown flags and extra positional args instead of silently treating them as the base ref. - Extract pure helpers (parse_hunks, line_scoped_result, overlaps) and add dev/tests/test_format_changed.py; run it in CI via a pytest step. Batch the per-file git diff into a single call. - Byte-exact file IO (newline="") so restores never rewrite line endings; use context-managed reads/writes; dedupe the src-root prefix; emit a friendly message when mvn is unavailable. - Add permissions: contents: read and expand the workflow trigger paths to cover the checker and its tests. --- .github/workflows/javaFormat.yml | 18 ++ dev/format-changed.sh | 10 +- dev/format_changed.py | 312 ++++++++++++++++++++----------- dev/tests/test_format_changed.py | 150 +++++++++++++++ 4 files changed, 381 insertions(+), 109 deletions(-) create mode 100644 dev/tests/test_format_changed.py diff --git a/.github/workflows/javaFormat.yml b/.github/workflows/javaFormat.yml index 26b24c1c7f3..a93e4f3fc92 100644 --- a/.github/workflows/javaFormat.yml +++ b/.github/workflows/javaFormat.yml @@ -32,9 +32,17 @@ on: pull_request: paths: - '**/*.java' + - 'dev/format_changed.py' + - 'dev/format-changed.sh' + - 'dev/format-exclude.txt' + - 'dev/tests/**' + - '.github/workflows/javaFormat.yml' branches: - main +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} @@ -56,6 +64,16 @@ jobs: java-version: '17' cache: 'maven' + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Unit-test the format checker + run: | + python -m pip install --quiet pytest + python -m pytest dev/tests -q + - name: Check formatting of PR-edited lines env: BASE_SHA: ${{ github.event.pull_request.base.sha }} diff --git a/dev/format-changed.sh b/dev/format-changed.sh index 8415c5ac574..a49192e3d29 100755 --- a/dev/format-changed.sh +++ b/dev/format-changed.sh @@ -31,15 +31,15 @@ # lines you actually edited. # # "Changed" = lines that differ from the base branch (the merge target), -# including your committed-on-branch, staged, unstaged and untracked edits. The -# base defaults to upstream/main (the apache/systemds PR target); run +# including your committed-on-branch, staged, unstaged and untracked edits. Run # `git fetch upstream main` first so the diff is accurate, or pass an explicit, -# current base ref if the default is stale/behind your branch point. +# current base ref if the default is stale/behind your branch point. The base-ref +# fallback order lives in one place: see resolve_base() in dev/format_changed.py. # # Usage: # dev/format-changed.sh [base-ref] -# base-ref branch/commit to diff against (default: upstream/main, else -# origin/main, else main) +# base-ref branch/commit to diff against (default: resolved by +# dev/format_changed.py) # set -euo pipefail diff --git a/dev/format_changed.py b/dev/format_changed.py index 86dd80756e4..ce8b7acccff 100755 --- a/dev/format_changed.py +++ b/dev/format_changed.py @@ -44,21 +44,49 @@ FMT_VERSION = "2.24.1" CONFIG = "dev/CodeStyle_eclipse.xml" EXCLUDE_FILE = "dev/format-exclude.txt" -SRC_RE = re.compile(r"^src/(main|test)/java/.+\.java$") +SRC_PREFIX = r"src/(main|test)/java/" +SRC_RE = re.compile(r"^" + SRC_PREFIX + r".+\.java$") -def sh(*args, check=False): - return subprocess.run(args, capture_output=True, text=True, check=check).stdout +# --- small process / IO helpers ------------------------------------------------ +def git(*args, check=True): + # core.quotePath=false so non-ASCII paths are emitted verbatim (not \NNN + # escaped), otherwise SRC_RE would silently skip them and bypass the check. + proc = subprocess.run(["git", "-c", "core.quotePath=false", *args], + capture_output=True, text=True) + if check and proc.returncode != 0: + sys.exit(f"ERROR: `git {' '.join(args)}` failed:\n{proc.stderr.strip()}") + return proc.stdout + + +def read_text(path): + # newline="" keeps line endings byte-exact so a check-mode restore (or a + # fix-mode non-flagged file) round-trips without CRLF->LF rewrites. + with open(path, encoding="utf-8", newline="") as fh: + return fh.read() + + +def write_text(path, text): + with open(path, "w", encoding="utf-8", newline="") as fh: + fh.write(text) + + +def strip_src_prefix(path): + return re.sub(r"^" + SRC_PREFIX, "", path) + + +# --- exemption list ------------------------------------------------------------ def load_excludes(): # glob patterns of files exempt from the style check, one per line patterns = [] if os.path.exists(EXCLUDE_FILE): - for line in open(EXCLUDE_FILE, encoding="utf-8"): - s = line.strip() - if s and not s.startswith("#"): - patterns.append(s) + with open(EXCLUDE_FILE, encoding="utf-8") as fh: + for line in fh: + s = line.strip() + if s and not s.startswith("#"): + patterns.append(s) return patterns @@ -67,28 +95,85 @@ def is_excluded(path, patterns): return any(fnmatch.fnmatch(path, p) or fnmatch.fnmatch(base, p) for p in patterns) +# --- git ref / file discovery -------------------------------------------------- + +def ref_exists(ref): + return subprocess.run(["git", "rev-parse", "--verify", "--quiet", ref + "^{commit}"], + capture_output=True).returncode == 0 + + def resolve_base(explicit): if explicit: + if not ref_exists(explicit): + sys.exit(f"Base ref not found: {explicit}") return explicit for ref in ("upstream/main", "origin/main", "main"): - if subprocess.run(["git", "rev-parse", "--verify", "--quiet", ref], - capture_output=True).returncode == 0: + if ref_exists(ref): return ref sys.exit("Could not determine a base ref; pass one explicitly.") -def changed_ranges(mergebase, path): - # line ranges (1-based, inclusive) touched on the working-tree side, i.e. - # committed-on-branch plus staged/unstaged edits, relative to the base. - out = sh("git", "diff", "-U0", mergebase, "--", path) +def merge_base(base): + mb = git("merge-base", base, "HEAD", check=False).strip() + return mb or base + + +def base_has(mergebase, path): + return subprocess.run(["git", "cat-file", "-e", f"{mergebase}:{path}"], + capture_output=True).returncode == 0 + + +def discover_files(mergebase): + tracked = [f for f in git("diff", "--name-only", "--diff-filter=ACMR", + mergebase, "--").splitlines() if SRC_RE.match(f)] + untracked = [f for f in git("ls-files", "--others", "--exclude-standard").splitlines() + if SRC_RE.match(f)] + seen = set(tracked) + files = tracked + [f for f in untracked if f not in seen] + + patterns = load_excludes() + skipped = [f for f in files if is_excluded(f, patterns)] + files = [f for f in files if not is_excluded(f, patterns)] + return files, skipped, set(untracked) + + +# --- changed-line ranges (pure parsing, unit-tested) --------------------------- + +def _hunk_range(header): + # parse the new-side (+) range of a `@@ -a,b +c,d @@` unified-diff header; + # returns a 1-based inclusive (start, end), or None for pure deletions / non-headers + m = re.match(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", header) + if not m: + return None + start = int(m.group(1)) + count = int(m.group(2)) if m.group(2) is not None else 1 + return (start, start + count - 1) if count > 0 else None + + +def parse_hunks(diff_text): + # all new-side ranges in a single-file unified diff (used by tests and below) ranges = [] + for line in diff_text.splitlines(): + r = _hunk_range(line) + if r is not None: + ranges.append(r) + return ranges + + +def changed_ranges(mergebase, files): + # one batched `git diff` for all files, split per file on the `+++ b/` header + ranges = {f: [] for f in files} + if not files: + return ranges + out = git("diff", "-U0", mergebase, "--", *files) + current = None for line in out.splitlines(): - m = re.match(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", line) - if m: - start = int(m.group(1)) - count = int(m.group(2)) if m.group(2) is not None else 1 - if count > 0: - ranges.append((start, start + count - 1)) + if line.startswith("+++ b/"): + current = line[len("+++ b/"):] + elif current is not None: + r = _hunk_range(line) + if r is not None and current in ranges: + ranges[current].append(r) return ranges @@ -104,112 +189,131 @@ def overlaps(i1, i2, ranges): return False -def main(): - args = [a for a in sys.argv[1:]] +def line_scoped_result(original_text, formatted_text, ranges): + # reconstruct a file that keeps original content everywhere except on the + # formatting hunks that intersect the PR-edited ranges; returns the new text + # plus the kept hunks (for reporting). Pure function -- no IO. + a = original_text.splitlines(keepends=True) + b = formatted_text.splitlines(keepends=True) + sm = difflib.SequenceMatcher(None, a, b, autojunk=False) + result = [] + kept = [] + for tag, i1, i2, j1, j2 in sm.get_opcodes(): + if tag == "equal": + result.extend(a[i1:i2]) + elif overlaps(i1, i2, ranges): + result.extend(b[j1:j2]) + kept.append((i1, len(a[i1:i2]), len(b[j1:j2]), a[i1:i2], b[j1:j2])) + else: + result.extend(a[i1:i2]) + return "".join(result), kept + + +# --- formatter ----------------------------------------------------------------- + +def run_formatter(files): + includes = ",".join(strip_src_prefix(f) for f in files) + subprocess.run(["mvn", "-q", "-ntp", "-B", + f"net.revelc.code.formatter:formatter-maven-plugin:{FMT_VERSION}:format", + f"-Dconfigfile={os.getcwd()}/{CONFIG}", + "-Dmaven.compiler.source=17", "-Dmaven.compiler.target=17", + f"-Dformatter.includes={includes}"], check=True) + + +def print_report(path, kept): + print(f"\n--- a/{path}") + print(f"+++ b/{path}") + for i1, n_old, n_new, olds, news in kept: + print(f"@@ -{i1 + 1},{n_old} +{i1 + 1},{n_new} @@ (changed lines)") + for ln in olds: + print("-" + ln.rstrip("\n")) + for ln in news: + print("+" + ln.rstrip("\n")) + + +# --- CLI ----------------------------------------------------------------------- + +def parse_args(argv): mode = "check" - if "--fix" in args: - mode = "fix" - args.remove("--fix") - if "--check" in args: - args.remove("--check") - base = resolve_base(args[0] if args else None) + positionals = [] + for a in argv: + if a == "--fix": + mode = "fix" + elif a == "--check": + mode = "check" + elif a.startswith("-"): + sys.exit(f"Unknown option: {a} (usage: format_changed.py [--check|--fix] [base-ref])") + else: + positionals.append(a) + if len(positionals) > 1: + sys.exit(f"Expected at most one base ref, got: {positionals}") + return mode, (positionals[0] if positionals else None) - os.chdir(sh("git", "rev-parse", "--show-toplevel").strip()) - mergebase = sh("git", "merge-base", base, "HEAD").strip() or base - files = [f for f in sh("git", "diff", "--name-only", "--diff-filter=ACMR", - mergebase, "--").splitlines() if SRC_RE.match(f)] - # include untracked new java files too (local pre-commit use) - files += [f for f in sh("git", "ls-files", "--others", "--exclude-standard").splitlines() - if SRC_RE.match(f) and f not in files] +def compute_ranges(mergebase, files, untracked, originals): + batched = changed_ranges(mergebase, files) + ranges_by_file = {} + for f in files: + r = batched[f] + if not r and (f in untracked or not base_has(mergebase, f)): + # brand-new/untracked file has no base version: treat every line as edited + r = [(1, max(1, len(originals[f].splitlines())))] + ranges_by_file[f] = r + return ranges_by_file - excludes = load_excludes() - skipped = [f for f in files if is_excluded(f, excludes)] - files = [f for f in files if not is_excluded(f, excludes)] + +def main(): + mode, base_arg = parse_args(sys.argv[1:]) + os.chdir(git("rev-parse", "--show-toplevel").strip()) + base = resolve_base(base_arg) + mergebase = merge_base(base) + + files, skipped, untracked = discover_files(mergebase) if skipped: print(f"Skipping style-exempt files ({EXCLUDE_FILE}):") for f in skipped: print(f" {f}") - if not files: print(f"No changed Java source files to check (base: {base}).") return 0 - # snapshot originals so we can format in place then restore exactly, without - # disturbing any unrelated working-tree state - original = {f: open(f, encoding="utf-8").read() for f in files} + originals = {f: read_text(f) for f in files} + ranges_by_file = compute_ranges(mergebase, files, untracked, originals) - # capture the PR-edited line ranges BEFORE we reformat the working tree, - # otherwise git would report the whole reformatted file as changed - ranges_by_file = {} - for f in files: - ranges = changed_ranges(mergebase, f) - if not ranges: - base_has = subprocess.run(["git", "cat-file", "-e", f"{mergebase}:{f}"], - capture_output=True).returncode == 0 - if not base_has: # brand-new/untracked file: treat every line as edited - ranges = [(1, max(1, len(original[f].splitlines())))] - ranges_by_file[f] = ranges - - includes = ",".join(re.sub(r"^src/(main|test)/java/", "", f) for f in files) - subprocess.run(["mvn", "-q", "-ntp", "-B", - f"net.revelc.code.formatter:formatter-maven-plugin:{FMT_VERSION}:format", - f"-Dconfigfile={os.getcwd()}/{CONFIG}", - "-Dmaven.compiler.source=17", "-Dmaven.compiler.target=17", - f"-Dformatter.includes={includes}"], check=True) + reports = [] + wrote_fix = False + try: + try: + run_formatter(files) + except subprocess.CalledProcessError as e: + sys.exit(f"ERROR: could not run the Eclipse formatter (is `mvn` on PATH?): {e}") - formatted = {f: open(f, encoding="utf-8").read() for f in files} + results = {} + for f in files: + result, kept = line_scoped_result(originals[f], read_text(f), ranges_by_file[f]) + results[f] = result + if kept: + reports.append((f, kept)) - any_issue = False - for f in files: - a = original[f].splitlines(keepends=True) - b = formatted[f].splitlines(keepends=True) - ranges = ranges_by_file[f] - - sm = difflib.SequenceMatcher(None, a, b, autojunk=False) - result = [] - kept_hunks = [] - for tag, i1, i2, j1, j2 in sm.get_opcodes(): - if tag == "equal": - result.extend(a[i1:i2]) - elif overlaps(i1, i2, ranges): - result.extend(b[j1:j2]) - kept_hunks.append((tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) - else: - result.extend(a[i1:i2]) - - # In fix mode, always write the reconstructed content: for non-flagged - # files this equals the original (undoing mvn's whole-file reformat); - # for flagged files it applies only the changed-line formatting. if mode == "fix": - with open(f, "w", encoding="utf-8") as out: - out.write("".join(result)) - - if not kept_hunks: - continue - any_issue = True - if mode == "check": - print(f"\n--- a/{f}") - print(f"+++ b/{f}") - for tag, i1, i2, j1, j2, olds, news in kept_hunks: - print(f"@@ -{i1 + 1},{len(olds)} +{i1 + 1},{len(news)} @@ (changed lines)") - for ln in olds: - print("-" + ln.rstrip("\n")) - for ln in news: - print("+" + ln.rstrip("\n")) - - # in check mode we only inspected; restore every file to its original content - if mode == "check": - for f in files: - with open(f, "w", encoding="utf-8") as out: - out.write(original[f]) + for f in files: + write_text(f, results[f]) + wrote_fix = True + finally: + # never leave mvn's whole-file reformat on disk: check mode is read-only, + # and fix mode must restore originals unless it fully wrote the scoped results + if mode == "check" or (mode == "fix" and not wrote_fix): + for f in files: + write_text(f, originals[f]) - if any_issue and mode == "check": + if reports and mode == "check": + for path, kept in reports: + print_report(path, kept) print("\nERROR: the changes above are required on lines this PR edited " "(per dev/CodeStyle_eclipse.xml).") print("Fix locally with: dev/format-changed.sh") return 1 - if any_issue and mode == "fix": + if reports and mode == "fix": print("Applied changed-line formatting. Review and commit the result.") else: print("All PR-edited Java lines are correctly formatted.") diff --git a/dev/tests/test_format_changed.py b/dev/tests/test_format_changed.py new file mode 100644 index 00000000000..dda2c26db66 --- /dev/null +++ b/dev/tests/test_format_changed.py @@ -0,0 +1,150 @@ +# ------------------------------------------------------------- +# +# 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. +# +# ------------------------------------------------------------- +# +# Unit tests for the pure logic in dev/format_changed.py (the line-scoping math, +# hunk parsing, and exclude matching). Run with: python -m pytest dev/tests +# +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +import format_changed as fc # noqa: E402 + + +# --- overlaps: replace/delete regions vs edited ranges ------------------------- + +def test_overlaps_replace_region_hits_and_misses(): + # replace of original lines 5..7 -> 0-based half-open [4, 7) + assert fc.overlaps(4, 7, [(6, 6)]) is True # inside + assert fc.overlaps(4, 7, [(5, 5)]) is True # first line of region + assert fc.overlaps(4, 7, [(7, 7)]) is True # last line of region + assert fc.overlaps(4, 7, [(4, 4)]) is False # one before + assert fc.overlaps(4, 7, [(8, 8)]) is False # one after + assert fc.overlaps(4, 7, [(1, 2)]) is False # entirely before + assert fc.overlaps(4, 7, [(8, 9)]) is False # entirely after + + +def test_overlaps_multiple_ranges(): + assert fc.overlaps(4, 7, [(1, 2), (7, 9)]) is True + assert fc.overlaps(4, 7, [(1, 2), (10, 11)]) is False + + +# --- overlaps: pure insertions (i1 == i2) ------------------------------------- + +def test_overlaps_pure_insertion_boundaries(): + # insertion at 0-based index 5 = between 1-based lines 5 and 6 + assert fc.overlaps(5, 5, [(5, 5)]) is True # i1 == e + assert fc.overlaps(5, 5, [(6, 6)]) is True # i1 == s - 1 + assert fc.overlaps(5, 5, [(7, 7)]) is False # below the range + assert fc.overlaps(5, 5, [(3, 4)]) is False # above the range + assert fc.overlaps(0, 0, [(1, 1)]) is True # insert before the first line + + +# --- _hunk_range / parse_hunks ------------------------------------------------ + +def test_hunk_range_multiline(): + assert fc._hunk_range("@@ -1,3 +10,4 @@") == (10, 13) + + +def test_hunk_range_missing_count_defaults_to_one(): + assert fc._hunk_range("@@ -0,0 +5 @@") == (5, 5) + + +def test_hunk_range_pure_deletion_is_none(): + assert fc._hunk_range("@@ -4,2 +3,0 @@") is None + + +def test_hunk_range_non_header_is_none(): + assert fc._hunk_range("+ some added line") is None + assert fc._hunk_range("public int mul(int a) {") is None + + +def test_parse_hunks_collects_all_ranges(): + diff = ( + "diff --git a/X.java b/X.java\n" + "--- a/X.java\n" + "+++ b/X.java\n" + "@@ -1,1 +1,1 @@\n" + "-a\n+a \n" + "@@ -10,0 +11,2 @@\n" + "+x\n+y\n" + "@@ -20,2 +22,0 @@\n" # pure deletion -> skipped + ) + assert fc.parse_hunks(diff) == [(1, 1), (11, 12)] + + +# --- exclude matching --------------------------------------------------------- + +def test_is_excluded_by_full_path(): + p = "src/main/java/org/apache/sysds/conf/DMLConfig.java" + assert fc.is_excluded(p, [p]) is True + + +def test_is_excluded_by_basename_glob(): + p = "src/main/java/org/apache/sysds/conf/DMLConfig.java" + assert fc.is_excluded(p, ["*DMLConfig.java"]) is True + + +def test_is_excluded_no_match(): + assert fc.is_excluded("src/main/java/Foo.java", ["*DMLConfig.java"]) is False + assert fc.is_excluded("src/main/java/Foo.java", []) is False + + +def test_load_excludes_skips_comments_and_blanks(tmp_path, monkeypatch): + f = tmp_path / "exclude.txt" + f.write_text("# a comment\n\n \nsrc/main/java/Foo.java\n *Bar.java \n", + encoding="utf-8") + monkeypatch.setattr(fc, "EXCLUDE_FILE", str(f)) + assert fc.load_excludes() == ["src/main/java/Foo.java", "*Bar.java"] + + +def test_load_excludes_missing_file_returns_empty(tmp_path, monkeypatch): + monkeypatch.setattr(fc, "EXCLUDE_FILE", str(tmp_path / "does-not-exist.txt")) + assert fc.load_excludes() == [] + + +# --- strip_src_prefix --------------------------------------------------------- + +def test_strip_src_prefix(): + assert fc.strip_src_prefix("src/main/java/org/A.java") == "org/A.java" + assert fc.strip_src_prefix("src/test/java/org/A.java") == "org/A.java" + + +# --- line_scoped_result: only edited-line formatting is kept ------------------ + +def test_line_scoped_result_keeps_only_edited_lines(): + # lines 1 and 3 are mis-formatted; an unchanged line 2 separates them so + # difflib yields distinct hunks. Only line 3 is "edited", so line 1 (a + # pre-existing violation the PR did not touch) must stay original. + original = "int a=1;\nint ok = 0;\nint b=2;\n" + formatted = "int a = 1;\nint ok = 0;\nint b = 2;\n" + result, kept = fc.line_scoped_result(original, formatted, [(3, 3)]) + assert result == "int a=1;\nint ok = 0;\nint b = 2;\n" + assert len(kept) == 1 + + +def test_line_scoped_result_no_edited_lines_is_noop(): + original = "int a=1;\nint b=2;\n" + formatted = "int a = 1;\nint b = 2;\n" + result, kept = fc.line_scoped_result(original, formatted, []) + assert result == original + assert kept == [] From c1b7614d14ce6e69cbbc0225530c532050271b46 Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Thu, 2 Jul 2026 14:42:38 +0000 Subject: [PATCH 7/9] Merge Java Format check into the Java Codestyle workflow Consolidate the two Java style gates into one workflow file with two jobs so each still reports its own status: - java_checkstyle: whole-tree checkstyle, on push and pull_request - java_format: line-scoped Eclipse-formatter check plus its pytest, gated to pull_request since it needs the PR base commit Remove the standalone javaFormat.yml. --- .github/workflows/javaCodestyle.yml | 61 ++++++++++++++++++- .github/workflows/javaFormat.yml | 91 ----------------------------- 2 files changed, 58 insertions(+), 94 deletions(-) delete mode 100644 .github/workflows/javaFormat.yml diff --git a/.github/workflows/javaCodestyle.yml b/.github/workflows/javaCodestyle.yml index 7dedc5f4865..a63e3298760 100644 --- a/.github/workflows/javaCodestyle.yml +++ b/.github/workflows/javaCodestyle.yml @@ -21,6 +21,16 @@ name: Java Codestyle +# Two Java style gates share this workflow: +# * Checkstyle -- whole-tree rule check (dev/checkstyle), on push and PR. +# * Java Format -- Eclipse formatter (dev/CodeStyle_eclipse.xml) applied to +# ONLY the lines a PR edits; fails if any edited line would +# change. The tree is not yet fully formatter-clean, so +# scoping to edited lines keeps it actionable and lets the +# codebase converge line-by-line. This gate needs the PR +# base commit, so it runs on pull_request only. +# They are separate jobs so each reports its own pass/fail status. + on: push: paths-ignore: @@ -28,7 +38,6 @@ on: - '*.md' - '*.html' - 'src/main/python/**' - - 'dev/**' branches: - main pull_request: @@ -37,16 +46,18 @@ on: - '*.md' - '*.html' - 'src/main/python/**' - - 'dev/**' branches: - main +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - java_codestyle: + java_checkstyle: name: Java Checkstyle runs-on: ubuntu-latest steps: @@ -62,3 +73,47 @@ jobs: - name: Run Checkstyle run: mvn -ntp -B -Dcheckstyle.skip=false checkstyle:check + + java_format: + name: Java Format Check + # line-scoped to the PR diff -> needs the pull_request base commit + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Setup Java 17 adopt + uses: actions/setup-java@v5 + with: + distribution: adopt + java-version: '17' + cache: 'maven' + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Unit-test the format checker + run: | + python -m pip install --quiet pytest + python -m pytest dev/tests -q + + - name: Check formatting of PR-edited lines + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + run: | + # Fails only if the Eclipse formatter would change a line this PR edited. + # See dev/format_changed.py for the line-scoping logic. + if ! python3 dev/format_changed.py --check "$BASE_SHA"; then + echo "::error::Some lines edited by this PR are not formatted per dev/CodeStyle_eclipse.xml." + echo "Fix only your edited lines locally and commit the result:" + echo "" + echo " dev/format-changed.sh" + echo "" + echo "(Do NOT run a bare 'mvn formatter:format' -- it reformats the whole tree.)" + exit 1 + fi diff --git a/.github/workflows/javaFormat.yml b/.github/workflows/javaFormat.yml deleted file mode 100644 index a93e4f3fc92..00000000000 --- a/.github/workflows/javaFormat.yml +++ /dev/null @@ -1,91 +0,0 @@ -#------------------------------------------------------------- -# -# 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. -# -#------------------------------------------------------------- - -name: Java Format - -# Only the exact lines a pull request edits are checked: the Eclipse formatter -# (dev/CodeStyle_eclipse.xml) is applied and the job fails only if it would -# change a line the PR touched. The existing tree is not yet fully -# formatter-clean, so validating whole files (let alone the whole tree) would -# fail unrelated PRs; scoping to the edited lines keeps the check actionable and -# lets the codebase converge line-by-line. - -on: - pull_request: - paths: - - '**/*.java' - - 'dev/format_changed.py' - - 'dev/format-changed.sh' - - 'dev/format-exclude.txt' - - 'dev/tests/**' - - '.github/workflows/javaFormat.yml' - branches: - - main - -permissions: - contents: read - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -jobs: - java_format: - name: Java Format Check - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v7 - with: - fetch-depth: 0 - - - name: Setup Java 17 adopt - uses: actions/setup-java@v5 - with: - distribution: adopt - java-version: '17' - cache: 'maven' - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Unit-test the format checker - run: | - python -m pip install --quiet pytest - python -m pytest dev/tests -q - - - name: Check formatting of PR-edited lines - env: - BASE_SHA: ${{ github.event.pull_request.base.sha }} - run: | - # Fails only if the Eclipse formatter would change a line this PR edited. - # See dev/format_changed.py for the line-scoping logic. - if ! python3 dev/format_changed.py --check "$BASE_SHA"; then - echo "::error::Some lines edited by this PR are not formatted per dev/CodeStyle_eclipse.xml." - echo "Fix only your edited lines locally and commit the result:" - echo "" - echo " dev/format-changed.sh" - echo "" - echo "(Do NOT run a bare 'mvn formatter:format' -- it reformats the whole tree.)" - exit 1 - fi From 9eec3b1d439272ee5f60149b10ff0311c2c1462e Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Thu, 2 Jul 2026 16:03:43 +0000 Subject: [PATCH 8/9] Add Apache license header to dev/format-exclude.txt The Apache RAT license check flagged dev/format-exclude.txt for a missing license header. Add the standard ASF header as comment lines; the exclude parser already ignores '#' lines, so behavior is unchanged. --- dev/format-exclude.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dev/format-exclude.txt b/dev/format-exclude.txt index bada401954a..dd3d9749eed 100644 --- a/dev/format-exclude.txt +++ b/dev/format-exclude.txt @@ -1,3 +1,24 @@ +#------------------------------------------------------------- +# +# 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. +# +#------------------------------------------------------------- + # Files exempt from the Java Format check (dev/format_changed.py). # # One pattern per line; blank lines and lines starting with '#' are ignored. From a2ed3ac2c6d798b72d849361aa1dff4ecbe2ee1e Mon Sep 17 00:00:00 2001 From: Sebastian Baunsgaard Date: Fri, 3 Jul 2026 17:08:22 +0000 Subject: [PATCH 9/9] Remove temporary Java Format probe files Drop the throwaway scaffolding used to exercise the Java Format check (FormatProbe* test classes and the probe method on DMLRuntimeException), restoring src to match upstream. The check itself is verified and approved. --- .../sysds/runtime/DMLRuntimeException.java | 4 -- .../component/format/FormatProbeBroken.java | 37 --------------- .../component/format/FormatProbeClean.java | 44 ------------------ .../component/format/FormatProbeErrors.java | 45 ------------------- .../test/component/format/FormatProbeOk2.java | 32 ------------- 5 files changed, 162 deletions(-) delete mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java delete mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java delete mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java delete mode 100644 src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java diff --git a/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java b/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java index 536c4f54597..1f7bdccdc4c 100644 --- a/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java +++ b/src/main/java/org/apache/sysds/runtime/DMLRuntimeException.java @@ -43,8 +43,4 @@ public DMLRuntimeException(Throwable e) { public DMLRuntimeException(String string, Exception ex){ super(string,ex); } - - public String describe(int code) { - return "DMLRuntimeException code="+code+", message="+getMessage() ; - } } diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java deleted file mode 100644 index e5f06bef860..00000000000 --- a/src/test/java/org/apache/sysds/test/component/format/FormatProbeBroken.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - */ - -package org.apache.sysds.test.component.format; - -/** - * Temporary probe used to verify the Java Format CI check: this class is correctly formatted except for one method with - * blatant style violations, which the check MUST flag. - */ -public class FormatProbeBroken { - - public int add(int a, int b) { - int result = a + b; - return result; - } - - public int mul( int a,int b ){ - int result=a*b ; - return result ; - } -} diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java deleted file mode 100644 index 56da6280f3e..00000000000 --- a/src/test/java/org/apache/sysds/test/component/format/FormatProbeClean.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -package org.apache.sysds.test.component.format; - -/** - * Temporary probe used to verify the Java Format CI check: this file is written to comply with - * dev/CodeStyle_eclipse.xml and should therefore NOT be flagged. - */ -public class FormatProbeClean { - - public int add(int a, int b) { - int result = a + b; - return result; - } - - public String describe(int a, int b) { - return "sum=" + add(a, b); - } - - public int sub(int a, int b) { - return a - b; - } - - public int div( int a,int b ){ - return a/b ; - } -} diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java deleted file mode 100644 index 658ab05144d..00000000000 --- a/src/test/java/org/apache/sysds/test/component/format/FormatProbeErrors.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package org.apache.sysds.test.component.format; - -/** Temporary probe with several distinct formatting mistakes to be flagged. */ -public class FormatProbeErrors { - - // missing spaces around operators - public int operators(int a, int b) { - return a+b*2; - } - - // Allman-style brace and extra spaces in the signature - public int brace( int a ) - { - return a; - } - - // over-indented body - public int indent(int a) { - return a; - } - - // missing space after comma in parameter list - public int comma(int a,int b) { - return a + b; - } -} diff --git a/src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java b/src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java deleted file mode 100644 index 9f192cab232..00000000000 --- a/src/test/java/org/apache/sysds/test/component/format/FormatProbeOk2.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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. - */ - -package org.apache.sysds.test.component.format; - -/** Fully compliant probe; it must NOT be flagged even though it is a new file. */ -public class FormatProbeOk2 { - - public int square(int a) { - return a * a; - } - - public int cube(int a) { - return a * a * a; - } -}