OpenMetadata/.github/workflows/ui-checkstyle.yml
Aniket Katkar 12ce3b614d
Chore(UI): consolidated UI checkstyle fix commands and modify workflow comment (#27402)
* feat: add consolidated UI checkstyle commands for all and changed files

* update prt to pr

* test commit to fail ui-checkstyle

* update the comment

* Revert "test commit to fail ui-checkstyle"

This reverts commit ed056f0629.

* Revert "update prt to pr"

This reverts commit 0666fa51a3.

* Worked on comments

* pull request target remove

* Revert "pull request target remove"

This reverts commit b61e98c16b.

* Worked on comments
2026-04-16 17:18:22 +05:30

614 lines
26 KiB
YAML

# Copyright 2021 Collate
# Licensed 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: UI Checkstyle
on:
merge_group:
pull_request_target:
types:
- opened
- synchronize
- reopened
- ready_for_review
- labeled
paths:
- "openmetadata-ui/src/main/resources/ui/**"
- "openmetadata-spec/src/main/resources/json/schema/**"
- ".github/workflows/ui-checkstyle.yml"
- openmetadata-ui/src/main/resources/ui/playwright/**
- openmetadata-ui/src/main/resources/ui/eslint.config.mjs
- "openmetadata-ui-core-components/src/main/resources/ui/**"
permissions:
contents: read
concurrency:
group: ui-checkstyle-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
UI_WORKING_DIRECTORY: openmetadata-ui/src/main/resources/ui
CORE_COMPONENTS_WORKING_DIRECTORY: openmetadata-ui-core-components/src/main/resources/ui
jobs:
# ──────────────────────────────────────────────────────────────────────────
# Job 0: Authorize
# ──────────────────────────────────────────────────────────────────────────
authorize:
if: |
github.event_name == 'merge_group' ||
(github.event_name == 'pull_request_target' &&
(github.event.action != 'labeled' || github.event.label.name == 'safe to test'))
runs-on: ubuntu-latest
steps:
- name: Wait for the labeler
uses: lewagon/wait-on-check-action@v1.3.4
if: ${{ github.event_name == 'pull_request_target' }}
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
check-name: Team Label
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 90
- name: Verify PR labels
uses: jesusvasquez333/verify-pr-label-action@v1.4.0
if: ${{ github.event_name == 'pull_request_target' }}
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
valid-labels: "safe to test"
pull-request-number: "${{ github.event.pull_request.number }}"
disable-reviews: true
# ──────────────────────────────────────────────────────────────────────────
# Common setup steps reused across all parallel check jobs via a shared
# composite-like pattern: each job does its own checkout + yarn install
# (fast due to yarn cache from actions/setup-node).
# ──────────────────────────────────────────────────────────────────────────
# ──────────────────────────────────────────────────────────────────────────
# Job 1: Lint — ESLint + Prettier + Organise Imports (src)
# ──────────────────────────────────────────────────────────────────────────
lint-src:
needs: authorize
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
changed_files: ${{ steps.lint.outputs.changed_files }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
fetch-depth: 0
filter: blob:none
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: Get changed src files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323
with:
path: ${{ env.UI_WORKING_DIRECTORY }}
files_ignore: |
src/generated/**
files: |
src/**/*.{ts,tsx,js,jsx,json}
- name: ESLint + Prettier + Organise Imports
id: lint
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
if [ -z "$CHANGED_FILES" ]; then
echo "No added or modified files to process."
exit 0
fi
TS_FILES=$(echo "$CHANGED_FILES" | tr ' ' '\n' | awk '/\.(ts|tsx|js|jsx)$/ { printf "%s ", $0 }')
if [ -n "$TS_FILES" ]; then
yarn organize-imports:cli $TS_FILES
fi
yarn lint:base --fix $CHANGED_FILES
yarn pretty:base --write $CHANGED_FILES
if [ -n "$(git status --porcelain)" ]; then
FILES=$(git status --porcelain | awk '{print " - `" $2 "`"}' | head -30)
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
git checkout -- .
git clean -fd
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 2: Licence Header Check (all changed files)
# ──────────────────────────────────────────────────────────────────────────
license-header:
needs: authorize
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
changed_files: ${{ steps.license.outputs.changed_files }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
fetch-depth: 0
filter: blob:none
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: Get all changed files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323
with:
path: ${{ env.UI_WORKING_DIRECTORY }}
- name: Licence Header Check
id: license
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
env:
CHANGED_FILES_ALL: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
if [ -z "$CHANGED_FILES_ALL" ]; then
echo "No added or modified files to process."
exit 0
fi
yarn license-header-fix $CHANGED_FILES_ALL
if [ -n "$(git status --porcelain)" ]; then
FILES=$(git status --porcelain | awk '{print " - `" $2 "`"}' | head -30)
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
git checkout -- .
git clean -fd
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 3: TypeScript Type Check (src)
# ──────────────────────────────────────────────────────────────────────────
tsc-src:
needs: authorize
if: false # TODO: re-enable once tsc errors are resolved
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: TypeScript Type Check (src)
id: tsc
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: |
if ! yarn tsc:check > /tmp/tsc_output.txt 2>&1; then
ERRORS=$(head -50 /tmp/tsc_output.txt | sed 's/`/\`/g')
echo "tsc_errors<<EOF" >> "$GITHUB_OUTPUT"
echo "$ERRORS" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 4: I18n Sync
# ──────────────────────────────────────────────────────────────────────────
i18n-sync:
needs: authorize
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
changed_files: ${{ steps.i18n.outputs.changed_files }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: I18n Sync
id: i18n
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: |
yarn i18n
if [ -n "$(git status --porcelain)" ]; then
FILES=$(git status --porcelain | awk '{print " - `" $2 "`"}' | head -20)
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
git checkout -- .
git clean -fd
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 5: generate:app-docs
# ──────────────────────────────────────────────────────────────────────────
app-docs:
needs: authorize
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
changed_files: ${{ steps.docs.outputs.changed_files }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: generate:app-docs
id: docs
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: |
yarn generate:app-docs
if [ -n "$(git status --porcelain)" ]; then
FILES=$(git status --porcelain | awk '{print " - `" $2 "`"}' | head -20)
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
git checkout -- .
git clean -fd
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 6: Playwright — ESLint + Prettier + Organise Imports
# ──────────────────────────────────────────────────────────────────────────
lint-playwright:
needs: authorize
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
changed_files: ${{ steps.lint.outputs.changed_files }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
fetch-depth: 0
filter: blob:none
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: Get changed Playwright files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323
with:
path: ${{ env.UI_WORKING_DIRECTORY }}
files_ignore: |
playwright/test-data/**
files: |
playwright/**/*.{ts,tsx,js,jsx}
- name: ESLint + Prettier + Organise Imports (playwright)
id: lint
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
if [ -z "$CHANGED_FILES" ]; then
echo "No added or modified files to process."
exit 0
fi
yarn organize-imports:cli $CHANGED_FILES
yarn lint:base --fix $CHANGED_FILES
yarn pretty:base --write $CHANGED_FILES
if [ -n "$(git status --porcelain)" ]; then
FILES=$(git status --porcelain | awk '{print " - `" $2 "`"}' | head -30)
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
git checkout -- .
git clean -fd
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 7: Playwright — TypeScript Type Check
# ──────────────────────────────────────────────────────────────────────────
tsc-playwright:
needs: authorize
if: false # TODO: re-enable once playwright tsc errors are resolved
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
fetch-depth: 0
filter: blob:none
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.UI_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.UI_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Antlr4 CLI
run: sudo make install_antlr_cli
- name: Install Yarn Packages
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: Get changed Playwright files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323
with:
path: ${{ env.UI_WORKING_DIRECTORY }}
files_ignore: |
playwright/test-data/**
files: |
playwright/**/*.{ts,tsx,js,jsx}
- name: TypeScript Type Check (playwright)
id: tsc
working-directory: ${{ env.UI_WORKING_DIRECTORY }}
run: |
if [ -z "$CHANGED_FILES" ]; then
echo "No added or modified files to process."
exit 0
fi
if ! yarn tsc:playwright > /tmp/tsc_output.txt 2>&1; then
ERRORS=$(head -50 /tmp/tsc_output.txt | sed 's/`/\`/g')
echo "tsc_errors<<EOF" >> "$GITHUB_OUTPUT"
echo "$ERRORS" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 8: Core Components — ESLint + Prettier
# ──────────────────────────────────────────────────────────────────────────
lint-core-components:
needs: authorize
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
changed_files: ${{ steps.lint.outputs.changed_files }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'merge_group' && github.sha || github.event.pull_request.head.sha }}
fetch-depth: 0
filter: blob:none
- uses: actions/setup-node@v4
with:
node-version-file: "${{ env.CORE_COMPONENTS_WORKING_DIRECTORY }}/.nvmrc"
cache: yarn
cache-dependency-path: "${{ env.CORE_COMPONENTS_WORKING_DIRECTORY }}/yarn.lock"
- name: Install Yarn Packages
working-directory: ${{ env.CORE_COMPONENTS_WORKING_DIRECTORY }}
run: yarn install --frozen-lockfile
- name: Get changed core-components files
id: changed-files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323
with:
path: ${{ env.CORE_COMPONENTS_WORKING_DIRECTORY }}
files: |
src/**/*.{ts,tsx,js,jsx,json}
- name: ESLint + Prettier (core-components)
id: lint
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ${{ env.CORE_COMPONENTS_WORKING_DIRECTORY }}
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
if [ -z "${CHANGED_FILES// }" ]; then
echo "No added or modified files to process."
exit 0
fi
yarn lint:base --fix $CHANGED_FILES
yarn pretty:base --write $CHANGED_FILES
if [ -n "$(git status --porcelain)" ]; then
FILES=$(git status --porcelain | awk '{print " - `" $2 "`"}' | head -30)
echo "changed_files<<EOF" >> "$GITHUB_OUTPUT"
echo "$FILES" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
git checkout -- .
git clean -fd
exit 1
fi
# ──────────────────────────────────────────────────────────────────────────
# Job 9: Report — Post single consolidated summary comment
# ──────────────────────────────────────────────────────────────────────────
report:
needs: [authorize, lint-src, license-header, i18n-sync, app-docs, lint-playwright, lint-core-components]
if: ${{ always() && needs.authorize.result == 'success' && github.event_name == 'pull_request_target' }}
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Find existing summary comment
uses: peter-evans/find-comment@v3
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: github-actions[bot]
body-includes: '<!-- check:ui-checkstyle-summary -->'
- name: Post or update summary comment
uses: actions/github-script@v7
with:
script: |
const checks = [
{
name: 'ESLint + Prettier + Organise Imports (src)',
reason: 'One or more source files have linting or formatting issues.',
result: '${{ needs.lint-src.result }}',
files: ${{ toJSON(needs.lint-src.outputs.changed_files) }} || '',
},
{
name: 'Licence Header',
reason: 'One or more files are missing or have an outdated Apache 2.0 licence header.',
result: '${{ needs.license-header.result }}',
files: ${{ toJSON(needs.license-header.outputs.changed_files) }} || '',
},
{
name: 'I18n Sync',
reason: 'Translation locale files are out of sync with `en-us.json`.',
result: '${{ needs.i18n-sync.result }}',
files: ${{ toJSON(needs.i18n-sync.outputs.changed_files) }} || '',
},
{
name: 'App Docs',
reason: 'Generated application docs are stale and need to be regenerated.',
result: '${{ needs.app-docs.result }}',
files: ${{ toJSON(needs.app-docs.outputs.changed_files) }} || '',
},
{
name: 'Playwright — ESLint + Prettier + Organise Imports',
reason: 'One or more Playwright test files have linting or formatting issues.',
result: '${{ needs.lint-playwright.result }}',
files: ${{ toJSON(needs.lint-playwright.outputs.changed_files) }} || '',
},
{
name: 'Core Components — ESLint + Prettier',
reason: 'One or more core-component files have linting or formatting issues.',
result: '${{ needs.lint-core-components.result }}',
files: ${{ toJSON(needs.lint-core-components.outputs.changed_files) }} || '',
},
];
const failures = checks.filter(c => c.result === 'failure');
const commentId = '${{ steps.fc.outputs.comment-id }}';
if (failures.length === 0) {
if (commentId) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: parseInt(commentId, 10),
});
}
return;
}
const sections = failures.map(c => {
const lines = [`#### ❌ ${c.name}`, c.reason];
if (c.files && c.files.trim()) {
lines.push('', '<details><summary>Affected files</summary>', '', c.files.trim(), '', '</details>');
}
return lines.join('\n');
});
const body = [
'<!-- check:ui-checkstyle-summary -->',
'### ❌ UI Checkstyle Failed',
'',
...sections.flatMap(s => [s, '']),
'---',
'**Fix locally (fast — only checks files changed in this branch):**',
'```bash',
'make ui-checkstyle-changed',
'```',
].join('\n');
if (commentId) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: parseInt(commentId, 10),
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}