| # 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: _common |
| on: |
| workflow_call: |
| inputs: |
| skip_pr_title: |
| type: boolean |
| required: false |
| default: false |
| description: "Skip PR title check (for push events)" |
| |
| permissions: |
| contents: read |
| pull-requests: read |
| |
| jobs: |
| rust-versions: |
| name: Check Rust versions sync |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - uses: actions/checkout@v4 |
| |
| - name: Check Rust versions are synchronized |
| run: | |
| # Use the sync-rust-version.sh script in check mode |
| if ! bash scripts/sync-rust-version.sh --check; then |
| echo "" |
| echo "โ Rust versions are not synchronized!" |
| echo "" |
| echo "To fix this issue, run:" |
| echo " ./scripts/sync-rust-version.sh --fix" |
| echo "" |
| echo "This script will automatically update all Dockerfiles to match rust-toolchain.toml" |
| exit 1 |
| fi |
| |
| pr-title: |
| name: Check PR Title |
| if: github.event_name == 'pull_request' && !inputs.skip_pr_title |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - name: Validate PR Title |
| uses: amannn/action-semantic-pull-request@v5 |
| env: |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| with: |
| types: | |
| feat |
| fix |
| docs |
| style |
| refactor |
| perf |
| test |
| build |
| ci |
| chore |
| revert |
| repo |
| deps |
| |
| license-headers: |
| name: Check license headers |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - uses: actions/checkout@v4 |
| |
| - name: Check Apache license headers |
| run: | |
| echo "๐ Checking license headers..." |
| |
| # Pull the addlicense image |
| docker pull ghcr.io/google/addlicense:latest |
| |
| # Run the check |
| if docker run --rm -v ${{ github.workspace }}:/src -w /src \ |
| ghcr.io/google/addlicense:latest \ |
| -check -f ASF_LICENSE.txt . > missing_files.txt 2>&1; then |
| echo "โ
All files have proper license headers" |
| else |
| file_count=$(wc -l < missing_files.txt) |
| echo "โ Found $file_count files missing license headers:" |
| echo "" |
| cat missing_files.txt | sed 's/^/ โข /' |
| echo "" |
| echo "๐ก Run 'addlicense -f ASF_LICENSE.txt .' to fix automatically" |
| |
| # Add to summary |
| echo "## โ License Headers Missing" >> $GITHUB_STEP_SUMMARY |
| echo "" >> $GITHUB_STEP_SUMMARY |
| echo "The following files are missing Apache license headers:" >> $GITHUB_STEP_SUMMARY |
| echo '```' >> $GITHUB_STEP_SUMMARY |
| cat missing_files.txt >> $GITHUB_STEP_SUMMARY |
| echo '```' >> $GITHUB_STEP_SUMMARY |
| echo 'Please call `just licenses-fix` to fix automatically.' >> $GITHUB_STEP_SUMMARY |
| |
| exit 1 |
| fi |
| |
| license-list: |
| name: Check licenses list |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - uses: actions/checkout@v4 |
| |
| - name: Setup Rust toolchain |
| uses: ./.github/actions/utils/setup-rust-with-cache |
| with: |
| enabled: "false" # Don't need cache for just checking licenses |
| |
| - run: scripts/licenses-list.sh --check |
| |
| markdown: |
| name: Markdown lint |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - uses: actions/checkout@v4 |
| |
| - name: Setup Node.js |
| uses: actions/setup-node@v4 |
| with: |
| node-version: '23' |
| |
| - name: Install markdownlint-cli |
| run: npm install -g markdownlint-cli |
| |
| - name: Run markdownlint |
| run: | |
| echo "๐ Checking markdown files..." |
| |
| # Create config if it doesn't exist |
| if [ ! -f ".markdownlint.yml" ]; then |
| cat > .markdownlint.yml << 'EOF' |
| # Markdown lint configuration |
| default: true |
| MD013: |
| line_length: 120 |
| tables: false |
| MD033: |
| allowed_elements: [details, summary, img] |
| MD041: false # First line in file should be a top level heading |
| EOF |
| fi |
| |
| # Run the linter |
| if markdownlint '**/*.md' --ignore-path .gitignore; then |
| echo "โ
All markdown files are properly formatted" |
| else |
| echo "โ Markdown linting failed" |
| echo "๐ก Run 'markdownlint **/*.md --fix' to auto-fix issues" |
| exit 1 |
| fi |
| |
| shellcheck: |
| name: Shell scripts lint |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - name: Checkout code |
| uses: actions/checkout@v4 |
| |
| - name: Install shellcheck |
| run: | |
| sudo apt-get update --yes && sudo apt-get install --yes shellcheck |
| |
| - name: Check shell scripts |
| run: | |
| echo "๐ Checking shell scripts..." |
| |
| # Find all shell scripts excluding certain directories |
| if find . -type f -name "*.sh" \ |
| -not -path "./target/*" \ |
| -not -path "./node_modules/*" \ |
| -not -path "./.git/*" \ |
| -not -path "./foreign/node/node_modules/*" \ |
| -not -path "./foreign/python/.venv/*" \ |
| -exec shellcheck -S warning {} +; then |
| echo "โ
All shell scripts passed shellcheck" |
| else |
| echo "โ Shellcheck found issues in shell scripts" |
| echo "๐ก Fix the issues reported above" |
| exit 1 |
| fi |
| |
| trailing-whitespace: |
| name: Check trailing whitespace |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - name: Checkout code |
| uses: actions/checkout@v4 |
| with: |
| fetch-depth: 0 # Need full history to get diff |
| |
| - name: Check for trailing whitespace in changed files |
| run: | |
| echo "๐ Checking for trailing whitespace in changed files..." |
| |
| # Get list of changed files in PR |
| if [ "${{ github.event_name }}" = "pull_request" ]; then |
| git fetch --no-tags --depth=1 origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }} || true |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" |
| CHANGED_FILES=$(git diff --name-only --diff-filter=ACM "$BASE_SHA"...HEAD || true) |
| else |
| CHANGED_FILES=$(git diff --name-only --diff-filter=ACM HEAD~1) |
| fi |
| |
| if [ -z "$CHANGED_FILES" ]; then |
| echo "No files changed to check" |
| exit 0 |
| fi |
| |
| echo "Files to check:" |
| echo "$CHANGED_FILES" | sed 's/^/ โข /' |
| echo "" |
| |
| # Check each changed file for trailing whitespace |
| FILES_WITH_TRAILING="" |
| for file in $CHANGED_FILES; do |
| # Skip if file doesn't exist (might be deleted) |
| if [ ! -f "$file" ]; then |
| continue |
| fi |
| |
| # Skip binary files |
| if file "$file" | grep -qE "binary|data|executable|compressed"; then |
| continue |
| fi |
| |
| # Check for trailing whitespace |
| if grep -q '[[:space:]]$' "$file" 2>/dev/null; then |
| FILES_WITH_TRAILING="$FILES_WITH_TRAILING $file" |
| fi |
| done |
| |
| if [ -z "$FILES_WITH_TRAILING" ]; then |
| echo "โ
No trailing whitespace found in changed files" |
| else |
| echo "โ Found trailing whitespace in the following changed files:" |
| echo "" |
| for file in $FILES_WITH_TRAILING; do |
| echo " โข $file" |
| # Show lines with trailing whitespace (limit to first 5 occurrences per file) |
| grep -n '[[:space:]]$' "$file" | head -5 | while IFS=: read -r line_num content; do |
| # Show the line with visible whitespace markers |
| visible_content=$(echo "$content" | sed 's/ /ยท/g; s/\t/โ/g') |
| echo " Line $line_num: '${visible_content}'" |
| done |
| TOTAL_LINES=$(grep -c '[[:space:]]$' "$file") |
| if [ "$TOTAL_LINES" -gt 5 ]; then |
| echo " ... and $((TOTAL_LINES - 5)) more lines" |
| fi |
| echo "" |
| done |
| |
| echo "๐ก To fix trailing whitespace in these files:" |
| echo " โข VSCode: Enable 'files.trimTrailingWhitespace' setting" |
| echo " โข Fix specific file: sed -i 's/[[:space:]]*$//' <filename>" |
| echo " โข Fix all changed files:" |
| echo " for f in$FILES_WITH_TRAILING; do sed -i 's/[[:space:]]*$//' \$f; done" |
| exit 1 |
| fi |
| |
| trailing-newline: |
| name: Check trailing newline |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - name: Checkout code |
| uses: actions/checkout@v4 |
| with: |
| fetch-depth: 0 # Need full history to get diff |
| |
| - name: Check for trailing newline in changed text files |
| run: | |
| echo "๐ Checking for trailing newline in changed text files..." |
| |
| # Get list of changed files in PR |
| if [ "${{ github.event_name }}" = "pull_request" ]; then |
| git fetch --no-tags --depth=1 origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }} || true |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" |
| CHANGED_FILES=$(git diff --name-only --diff-filter=ACM "$BASE_SHA"...HEAD || true) |
| else |
| CHANGED_FILES=$(git diff --name-only --diff-filter=ACM HEAD~1) |
| fi |
| |
| if [ -z "$CHANGED_FILES" ]; then |
| echo "No files changed to check" |
| exit 0 |
| fi |
| |
| echo "Files to check:" |
| echo "$CHANGED_FILES" | sed 's/^/ โข /' |
| echo "" |
| |
| # Check each changed file for missing trailing newline |
| FILES_WITHOUT_NEWLINE="" |
| for file in $CHANGED_FILES; do |
| # Skip if file doesn't exist (might be deleted) |
| if [ ! -f "$file" ]; then |
| continue |
| fi |
| |
| # Skip binary files |
| if file "$file" | grep -qE "binary|data|executable|compressed"; then |
| continue |
| fi |
| |
| # Skip empty files |
| if [ ! -s "$file" ]; then |
| continue |
| fi |
| |
| # Check if file ends with a newline |
| # Use tail to get last byte and od to check if it's a newline (0x0a) |
| if [ -n "$(tail -c 1 "$file" | od -An -tx1 | grep -v '0a')" ]; then |
| FILES_WITHOUT_NEWLINE="$FILES_WITHOUT_NEWLINE $file" |
| fi |
| done |
| |
| if [ -z "$FILES_WITHOUT_NEWLINE" ]; then |
| echo "โ
All changed text files have trailing newlines" |
| else |
| echo "โ Found text files without trailing newline:" |
| echo "" |
| for file in $FILES_WITHOUT_NEWLINE; do |
| echo " โข $file" |
| # Show last few characters of the file for context |
| echo -n " Last characters: '" |
| tail -c 20 "$file" | tr '\n' 'โต' | sed 's/\t/โ/g' |
| echo "'" |
| echo "" |
| done |
| |
| echo "๐ก To add trailing newlines to these files:" |
| echo " โข VSCode: Enable 'files.insertFinalNewline' setting" |
| echo " โข Fix specific file: echo >> <filename>" |
| echo " โข Fix all files:" |
| echo " for f in$FILES_WITHOUT_NEWLINE; do [ -n \"\$(tail -c 1 \"\$f\")\" ] && echo >> \"\$f\"; done" |
| exit 1 |
| fi |
| |
| summary: |
| name: Common checks summary |
| needs: [rust-versions, pr-title, license-headers, license-list, markdown, shellcheck, trailing-whitespace, trailing-newline] |
| if: always() |
| runs-on: ubuntu-latest |
| env: |
| IGGY_CI_BUILD: true |
| steps: |
| - name: Summary |
| run: | |
| echo "## ๐ Common Checks Summary" >> $GITHUB_STEP_SUMMARY |
| echo "" >> $GITHUB_STEP_SUMMARY |
| echo "| Check | Status | Description |" >> $GITHUB_STEP_SUMMARY |
| echo "|-------|--------|-------------|" >> $GITHUB_STEP_SUMMARY |
| |
| # PR-specific checks |
| if [ "${{ github.event_name }}" = "pull_request" ]; then |
| PR_TITLE="${{ needs.pr-title.result }}" |
| |
| # Add emoji based on status |
| if [ "$PR_TITLE" = "success" ]; then |
| echo "| โ
PR Title | success | Follows conventional format |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$PR_TITLE" = "failure" ]; then |
| echo "| โ PR Title | failure | Must follow conventional format |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ PR Title | $PR_TITLE | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| else |
| echo "| โญ๏ธ PR Title | skipped | Not a pull request |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| # Always-run checks |
| RUST_VERSIONS="${{ needs.rust-versions.result }}" |
| LICENSE_HEADERS="${{ needs.license-headers.result }}" |
| LICENSE_LIST="${{ needs.license-list.result }}" |
| MARKDOWN="${{ needs.markdown.result }}" |
| |
| if [ "$RUST_VERSIONS" = "success" ]; then |
| echo "| โ
Rust Versions | success | All Rust versions synchronized |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$RUST_VERSIONS" = "failure" ]; then |
| echo "| โ Rust Versions | failure | Rust versions mismatch in Dockerfiles |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ Rust Versions | $RUST_VERSIONS | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| if [ "$LICENSE_HEADERS" = "success" ]; then |
| echo "| โ
License Headers | success | All files have Apache headers |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$LICENSE_HEADERS" = "failure" ]; then |
| echo "| โ License Headers | failure | Missing Apache license headers |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ License Headers | $LICENSE_HEADERS | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| if [ "$LICENSE_LIST" = "success" ]; then |
| echo "| โ
License List | success | Dependencies licenses validated |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$LICENSE_LIST" = "failure" ]; then |
| echo "| โ License List | failure | License list needs update |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ License List | $LICENSE_LIST | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| if [ "$MARKDOWN" = "success" ]; then |
| echo "| โ
Markdown Lint | success | All markdown files are valid |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$MARKDOWN" = "failure" ]; then |
| echo "| โ Markdown Lint | failure | Markdown formatting issues found |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ Markdown Lint | $MARKDOWN | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| SHELLCHECK="${{ needs.shellcheck.result }}" |
| if [ "$SHELLCHECK" = "success" ]; then |
| echo "| โ
Shellcheck | success | All shell scripts are valid |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$SHELLCHECK" = "failure" ]; then |
| echo "| โ Shellcheck | failure | Shell script issues found |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ Shellcheck | $SHELLCHECK | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| TRAILING="${{ needs.trailing-whitespace.result }}" |
| if [ "$TRAILING" = "success" ]; then |
| echo "| โ
Trailing Whitespace | success | No trailing whitespace found |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$TRAILING" = "failure" ]; then |
| echo "| โ Trailing Whitespace | failure | Trailing whitespace detected |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ Trailing Whitespace | $TRAILING | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| TRAILING_NL="${{ needs.trailing-newline.result }}" |
| if [ "$TRAILING_NL" = "success" ]; then |
| echo "| โ
Trailing Newline | success | All text files have trailing newlines |" >> $GITHUB_STEP_SUMMARY |
| elif [ "$TRAILING_NL" = "failure" ]; then |
| echo "| โ Trailing Newline | failure | Missing trailing newlines detected |" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "| โญ๏ธ Trailing Newline | $TRAILING_NL | Check skipped |" >> $GITHUB_STEP_SUMMARY |
| fi |
| |
| echo "" >> $GITHUB_STEP_SUMMARY |
| |
| # Overall status |
| if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then |
| echo "### โ Some checks failed" >> $GITHUB_STEP_SUMMARY |
| echo "Please review the failed checks above and fix the issues." >> $GITHUB_STEP_SUMMARY |
| elif [[ "${{ contains(needs.*.result, 'skipped') }}" == "true" ]]; then |
| echo "### โ ๏ธ Some checks were skipped" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "### โ
All checks passed!" >> $GITHUB_STEP_SUMMARY |
| fi |