diff --git a/.github/workflows/formatter.yml b/.github/workflows/formatter.yml deleted file mode 100644 index 9faa35ef3ab..00000000000 --- a/.github/workflows/formatter.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: Formatter - -on: - pull_request_target: - types: [opened, synchronize, reopened] - -# Cancel previous runs if a new one is triggered -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -permissions: - contents: read - pull-requests: write - issues: write - -jobs: - check-permissions: - uses: ./.github/workflows/check-permissions.yml - - formatter: - needs: check-permissions - name: Verify Java code format - runs-on: ubuntu-latest - timeout-minutes: 120 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 0 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - cache: 'maven' - - - name: Run formatter - id: formatter - run: | - echo "Running formatter..." - mvn -B -q spotless:apply -P benchmark 2>&1 | grep -v null || true - - # Check for modified files - files=$(git status --porcelain | awk '{print $2}') - modified=$(echo "$files" | wc -w | xargs) - - echo "modified=$modified" >> $GITHUB_OUTPUT - - if [ "$modified" -gt 0 ]; then - echo "Modified files:" - echo "$files" - git diff > formatter-diff.txt - echo "files<> $GITHUB_OUTPUT - echo "$files" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - fi - - - name: Upload formatter diff - if: steps.formatter.outputs.modified != '0' - uses: actions/upload-artifact@v4 - with: - name: formatter-diff - path: formatter-diff.txt - retention-days: 30 - - - name: Find existing comment - if: steps.formatter.outputs.modified != '0' - uses: peter-evans/find-comment@v3 - id: find-comment - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: '' - - - name: Create or update comment - if: steps.formatter.outputs.modified != '0' - uses: peter-evans/create-or-update-comment@v4 - with: - comment-id: ${{ steps.find-comment.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - edit-mode: replace - body: | - - ### Format Checker Report - - ![BLOCKER][BLOCKER] There are **${{ steps.formatter.outputs.modified }} files** with format errors - - [BLOCKER]: https://sonarsource.github.io/sonar-github/severity-blocker.png 'Severity: BLOCKER' - - - To see a complete report of formatting issues, download the [differences artifact](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) - - - To fix the build, please run `mvn spotless:apply` in your branch and commit the changes. - - - Optionally you might add the following line in your `.git/hooks/pre-commit` file: - - mvn spotless:apply - - Here is the list of files with format issues in your PR: - - ``` - ${{ steps.formatter.outputs.files }} - ``` - - - name: Delete comment if formatting is correct - if: steps.formatter.outputs.modified == '0' && steps.find-comment.outputs.comment-id != '' - uses: actions/github-script@v7 - with: - script: | - github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: ${{ steps.find-comment.outputs.comment-id }} - }) - - - name: Fail if formatting issues exist - if: steps.formatter.outputs.modified != '0' - run: | - echo "::error::There are ${{ steps.formatter.outputs.modified }} files with format errors" - exit 1 diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index e7779d92af3..b8fdbeb227f 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -6,7 +6,9 @@ on: pull_request_target: types: [opened, synchronize, reopened, edited] permissions: - contents: read + contents: write + pull-requests: write + issues: write concurrency: group: ${{ github.head_ref }} || ${{ github.ref_name }} cancel-in-progress: true @@ -14,12 +16,157 @@ env: HEAD_REF: ${{ github.head_ref }} REF_NAME: ${{ github.ref_name }} HEAD_SHA: ${{ github.event.pull_request.head.sha }} + USE_FORMATTED_CODE: false jobs: check-permissions: uses: ./.github/workflows/check-permissions.yml - build: + formatter: needs: check-permissions + if: github.event_name == 'pull_request_target' + name: Format and auto-commit + runs-on: ubuntu-latest + timeout-minutes: 120 + outputs: + changes_committed: ${{ steps.commit-changes.outputs.changes_committed }} + + steps: + - name: Check for required token + run: | + if [ -z "${{ secrets.VAADIN_BOT_TOKEN }}" ]; then + echo "::error::VAADIN_BOT_TOKEN secret is required for formatter to trigger workflows after committing changes" + exit 1 + fi + + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + token: ${{ secrets.VAADIN_BOT_TOKEN }} + fetch-depth: 2 + + - name: Check if last commit was from formatter bot + id: check-loop + run: | + last_commit_author=$(git log -1 --pretty=format:'%an') + echo "Last commit author: $last_commit_author" + + if [ "$last_commit_author" = "github-actions[bot]" ]; then + echo "Last commit was from formatter bot - formatting verification passed" + echo "loop_detected=true" >> $GITHUB_OUTPUT + exit 0 + fi + echo "loop_detected=false" >> $GITHUB_OUTPUT + + - name: Set up JDK 21 + if: steps.check-loop.outputs.loop_detected == 'false' + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Run formatter + if: steps.check-loop.outputs.loop_detected == 'false' + id: formatter + run: | + echo "Running formatter..." + mvn -B -q spotless:apply -P benchmark 2>&1 | grep -v null || true + + # Check for modified files + files=$(git status --porcelain | awk '{print $2}') + modified=$(echo "$files" | wc -w | xargs) + + echo "modified=$modified" >> $GITHUB_OUTPUT + + if [ "$modified" -gt 0 ]; then + echo "Modified files:" + echo "$files" + echo "files<> $GITHUB_OUTPUT + echo "$files" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + fi + + - name: Commit and push changes + id: commit-changes + if: steps.check-loop.outputs.loop_detected == 'false' && steps.formatter.outputs.modified != '0' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Add only the files modified by the formatter + git add -u + git commit -m "chore: apply code formatting with spotless" + + git push + + echo "changes_committed=true" >> $GITHUB_OUTPUT + echo "✅ Formatting changes committed and pushed. Workflow will retrigger automatically." >> $GITHUB_STEP_SUMMARY + + - name: Generate diff for artifact + if: steps.formatter.outputs.modified != '0' + run: | + git diff HEAD~1 > formatter-diff.txt + + - name: Upload formatter diff + if: steps.formatter.outputs.modified != '0' + uses: actions/upload-artifact@v4 + with: + name: formatter-diff + path: formatter-diff.txt + retention-days: 30 + + - name: Find existing comment + uses: peter-evans/find-comment@v3 + id: find-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '' + + - name: Create or update comment for committed changes + if: steps.formatter.outputs.modified != '0' + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + edit-mode: replace + body: | + + ### ✅ Formatter Auto-Applied + + Formatting issues were detected and **automatically fixed**. Changes have been committed to this PR. + + The formatting changes affected **${{ steps.formatter.outputs.modified }} files**. + + Files modified: + ``` + ${{ steps.formatter.outputs.files }} + ``` + + Please pull the latest changes before continuing work on this branch. + + - name: Delete comment if formatting is correct + if: steps.formatter.outputs.modified == '0' && steps.find-comment.outputs.comment-id != '' + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ steps.find-comment.outputs.comment-id }} + }) + + - name: Stop workflow if changes were committed + if: steps.commit-changes.outputs.changes_committed == 'true' + run: | + echo "::notice::Formatting changes committed. Stopping this workflow run. A new workflow will be triggered automatically." + exit 1 + + build: + needs: [check-permissions, formatter] + if: always() && needs.check-permissions.result == 'success' && needs.formatter.result == 'success' timeout-minutes: 30 runs-on: ubuntu-24.04 outputs: diff --git a/flow-server/src/main/java/com/vaadin/flow/function/SerializableBiFunction.java b/flow-server/src/main/java/com/vaadin/flow/function/SerializableBiFunction.java index d53d7bb75dc..af41f9fe4ad 100644 --- a/flow-server/src/main/java/com/vaadin/flow/function/SerializableBiFunction.java +++ b/flow-server/src/main/java/com/vaadin/flow/function/SerializableBiFunction.java @@ -1,3 +1,4 @@ + /* * Copyright 2000-2025 Vaadin Ltd. * @@ -13,8 +14,6 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.function; - import java.io.Serializable; import java.util.function.BiFunction; import java.util.function.Function; @@ -36,5 +35,5 @@ @FunctionalInterface public interface SerializableBiFunction extends BiFunction, Serializable { - // Only method inherited from BiFunction + // Only method inherited from BiFunction abc }