From 0085fc2e66174d918f60d0a0d2d0b56ea22046dd Mon Sep 17 00:00:00 2001 From: UbiquityOS Bot Date: Sun, 19 Apr 2026 20:44:17 +0800 Subject: [PATCH] feat: convert Knip and Jest workflows to reusable workflows - Create reusable/knip.yml with configurable package manager support - Create reusable/jest.yml with configurable package manager and coverage support - Update knip.yml to use reusable workflow - Update jest-testing.yml to use reusable workflow - Remove knip-reporter.yml (integrated into reusable knip workflow) - Add documentation for reusable workflows Benefits: - Centralized maintenance across all UbiquityOS repositories - Support for bun, yarn, npm, and pnpm package managers - Configurable Node.js and Yarn versions - Reduced duplication and improved consistency --- .github/workflows/jest-testing.yml | 27 +---- .github/workflows/knip-reporter.yml | 40 -------- .github/workflows/knip.yml | 29 +----- .github/workflows/reusable/README.md | 144 +++++++++++++++++++++++++++ .github/workflows/reusable/jest.yml | 128 ++++++++++++++++++++++++ .github/workflows/reusable/knip.yml | 144 +++++++++++++++++++++++++++ 6 files changed, 425 insertions(+), 87 deletions(-) delete mode 100644 .github/workflows/knip-reporter.yml create mode 100644 .github/workflows/reusable/README.md create mode 100644 .github/workflows/reusable/jest.yml create mode 100644 .github/workflows/reusable/knip.yml diff --git a/.github/workflows/jest-testing.yml b/.github/workflows/jest-testing.yml index 5b873ed..e9a0c2c 100644 --- a/.github/workflows/jest-testing.yml +++ b/.github/workflows/jest-testing.yml @@ -1,29 +1,12 @@ name: Run Jest testing suite + on: workflow_dispatch: pull_request: -env: - NODE_ENV: "test" - jobs: testing: - permissions: write-all - runs-on: ubuntu-latest - steps: - - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - - - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - - name: Jest With Coverage - run: | - bun install --frozen-lockfile - bun run test - - - name: Add Jest Report to Summary - if: always() - run: echo "$(cat test-dashboard.md)" >> $GITHUB_STEP_SUMMARY + uses: ./.github/workflows/reusable/jest.yml + with: + package_manager: bun + enable_summary: true diff --git a/.github/workflows/knip-reporter.yml b/.github/workflows/knip-reporter.yml deleted file mode 100644 index 4dbb064..0000000 --- a/.github/workflows/knip-reporter.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Knip-reporter - -on: - workflow_run: - workflows: ["Knip"] - types: - - completed - -permissions: write-all - -jobs: - knip-reporter: - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion != 'success' }} - steps: - - uses: actions/download-artifact@v6 - with: - name: knip-results - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Read pr number - id: pr-number - uses: juliangruber/read-file-action@v1 - with: - path: ./pr-number.txt - trim: true - - - name: Report knip results to pull request - uses: ubiquity/knip-reporter@main - with: - verbose: true - comment_id: ${{ github.workflow }}-reporter - command_script_name: knip-ci - annotations: true - ignore_results: false - json_input: true - json_input_file_name: knip-results.json - pull_request_number: ${{ steps.pr-number.outputs.content }} - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index 779ef47..d422b11 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -6,28 +6,7 @@ on: jobs: run-knip: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - - - name: Install toolchain - run: bun install - - - name: Store PR number - run: echo ${{ github.event.number }} > pr-number.txt - - - name: Run Knip - run: bun run knip || bun run knip --reporter json > knip-results.json - - - name: Upload knip result - if: failure() - uses: actions/upload-artifact@v4 - with: - name: knip-results - path: | - knip-results.json - pr-number.txt + uses: ./.github/workflows/reusable/knip.yml + with: + package_manager: bun + enable_reporter: true diff --git a/.github/workflows/reusable/README.md b/.github/workflows/reusable/README.md new file mode 100644 index 0000000..59e98e1 --- /dev/null +++ b/.github/workflows/reusable/README.md @@ -0,0 +1,144 @@ +# Reusable Workflows + +This directory contains reusable GitHub workflows that can be used across multiple repositories in the UbiquityOS ecosystem. + +## Available Workflows + +### Knip Workflow + +**File:** `reusable/knip.yml` + +Reusable Knip workflow with configurable package manager support. + +#### Inputs + +| Input | Type | Default | Description | +|-------|------|---------|-------------| +| `package_manager` | string | `bun` | Package manager to use (bun, yarn, npm, pnpm) | +| `yarn_version` | string | `latest` | Yarn version (only used if package_manager is yarn) | +| `node_version` | string | `latest` | Node.js version | +| `working_directory` | string | `.` | Working directory for the workflow | +| `knip_script` | string | `knip` | Knip script name to run | +| `enable_reporter` | boolean | `true` | Enable Knip reporter for PR comments | + +#### Usage Example + +```yaml +name: Knip Check + +on: + pull_request: + workflow_dispatch: + +jobs: + knip: + uses: ubiquity-os/plugin-template/.github/workflows/reusable/knip.yml@main + with: + package_manager: bun + enable_reporter: true +``` + +#### Usage with Yarn + +```yaml +name: Knip Check + +on: + pull_request: + +jobs: + knip: + uses: ubiquity-os/plugin-template/.github/workflows/reusable/knip.yml@main + with: + package_manager: yarn + yarn_version: '3.6.0' + enable_reporter: true +``` + +--- + +### Jest Testing Workflow + +**File:** `reusable/jest.yml` + +Reusable Jest testing workflow with configurable package manager and coverage support. + +#### Inputs + +| Input | Type | Default | Description | +|-------|------|---------|-------------| +| `package_manager` | string | `bun` | Package manager to use (bun, yarn, npm, pnpm) | +| `yarn_version` | string | `latest` | Yarn version (only used if package_manager is yarn) | +| `node_version` | string | `latest` | Node.js version | +| `working_directory` | string | `.` | Working directory for the workflow | +| `test_script` | string | `test` | Test script name to run | +| `coverage` | boolean | `false` | Enable code coverage | +| `coverage_script` | string | `test:coverage` | Coverage script name (if different from test script) | +| `enable_summary` | boolean | `true` | Enable Jest summary in GitHub Actions summary | + +#### Usage Example + +```yaml +name: Test Suite + +on: + pull_request: + workflow_dispatch: + +jobs: + test: + uses: ubiquity-os/plugin-template/.github/workflows/reusable/jest.yml@main + with: + package_manager: bun + enable_summary: true +``` + +#### Usage with Coverage + +```yaml +name: Test Suite with Coverage + +on: + pull_request: + +jobs: + test: + uses: ubiquity-os/plugin-template/.github/workflows/reusable/jest.yml@main + with: + package_manager: yarn + yarn_version: '3.6.0' + coverage: true + coverage_script: 'test:coverage' + enable_summary: true +``` + +--- + +## Benefits + +1. **Centralized Maintenance**: Update workflows in one place, propagate to all repositories +2. **Consistency**: Ensure all repositories use the same testing and linting standards +3. **Flexibility**: Configure package manager, versions, and scripts per repository +4. **Reduced Duplication**: No need to maintain identical workflow files across repos + +## Migration Guide + +To migrate an existing repository to use these reusable workflows: + +1. Remove existing `knip.yml`, `knip-reporter.yml`, and `jest-testing.yml` files +2. Create new workflow files that call the reusable workflows (see examples above) +3. Test the workflows on a pull request +4. Commit and push changes + +## Permissions + +Both workflows require the following permissions: + +```yaml +permissions: + contents: read + pull-requests: write + actions: read +``` + +The Knip workflow additionally needs `actions: read` permission to download artifacts from the workflow run. diff --git a/.github/workflows/reusable/jest.yml b/.github/workflows/reusable/jest.yml new file mode 100644 index 0000000..d98d0bd --- /dev/null +++ b/.github/workflows/reusable/jest.yml @@ -0,0 +1,128 @@ +name: Reusable Jest Testing Workflow + +on: + workflow_call: + inputs: + package_manager: + description: 'Package manager to use (bun, yarn, npm, pnpm)' + required: false + default: 'bun' + type: string + yarn_version: + description: 'Yarn version (only used if package_manager is yarn)' + required: false + default: 'latest' + type: string + node_version: + description: 'Node.js version' + required: false + default: 'latest' + type: string + working_directory: + description: 'Working directory for the workflow' + required: false + default: '.' + type: string + test_script: + description: 'Test script name to run' + required: false + default: 'test' + type: string + coverage: + description: 'Enable code coverage' + required: false + default: false + type: boolean + coverage_script: + description: 'Coverage script name (if different from test script)' + required: false + default: 'test:coverage' + type: string + enable_summary: + description: 'Enable Jest summary in GitHub Actions summary' + required: false + default: true + type: boolean + +permissions: + contents: read + pull-requests: write + +env: + NODE_ENV: 'test' + +jobs: + testing: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node_version }} + + - name: Setup Bun + if: inputs.package_manager == 'bun' + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Setup Yarn + if: inputs.package_manager == 'yarn' + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node_version }} + - run: corepack enable && corepack prepare yarn@${{ inputs.yarn_version }} --activate + if: inputs.package_manager == 'yarn' + + - name: Install dependencies + working-directory: ${{ inputs.working_directory }} + run: | + if [ "${{ inputs.package_manager }}" = "bun" ]; then + bun install --frozen-lockfile + elif [ "${{ inputs.package_manager }}" = "yarn" ]; then + yarn install --frozen-lockfile + elif [ "${{ inputs.package_manager }}" = "npm" ]; then + npm ci + elif [ "${{ inputs.package_manager }}" = "pnpm" ]; then + pnpm install --frozen-lockfile + fi + + - name: Run Jest Tests + id: test-run + working-directory: ${{ inputs.working_directory }} + run: | + if [ "${{ inputs.package_manager }}" = "bun" ]; then + bun run ${{ inputs.test_script }} + elif [ "${{ inputs.package_manager }}" = "yarn" ]; then + yarn ${{ inputs.test_script }} + elif [ "${{ inputs.package_manager }}" = "npm" ]; then + npm run ${{ inputs.test_script }} + elif [ "${{ inputs.package_manager }}" = "pnpm" ]; then + pnpm run ${{ inputs.test_script }} + fi + + - name: Run Coverage (if enabled) + if: inputs.coverage + working-directory: ${{ inputs.working_directory }} + run: | + if [ "${{ inputs.package_manager }}" = "bun" ]; then + bun run ${{ inputs.coverage_script }} + elif [ "${{ inputs.package_manager }}" = "yarn" ]; then + yarn ${{ inputs.coverage_script }} + elif [ "${{ inputs.package_manager }}" = "npm" ]; then + npm run ${{ inputs.coverage_script }} + elif [ "${{ inputs.package_manager }}" = "pnpm" ]; then + pnpm run ${{ inputs.coverage_script }} + fi + + - name: Add Jest Report to Summary + if: always() && inputs.enable_summary && github.event_name == 'pull_request' + run: | + if [ -f test-dashboard.md ]; then + echo "$(cat test-dashboard.md)" >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/reusable/knip.yml b/.github/workflows/reusable/knip.yml new file mode 100644 index 0000000..d5c4e74 --- /dev/null +++ b/.github/workflows/reusable/knip.yml @@ -0,0 +1,144 @@ +name: Reusable Knip Workflow + +on: + workflow_call: + inputs: + package_manager: + description: 'Package manager to use (bun, yarn, npm, pnpm)' + required: false + default: 'bun' + type: string + yarn_version: + description: 'Yarn version (only used if package_manager is yarn)' + required: false + default: 'latest' + type: string + node_version: + description: 'Node.js version' + required: false + default: 'latest' + type: string + working_directory: + description: 'Working directory for the workflow' + required: false + default: '.' + type: string + knip_script: + description: 'Knip script name to run' + required: false + default: 'knip' + type: string + enable_reporter: + description: 'Enable Knip reporter for PR comments' + required: false + default: true + type: boolean + +permissions: + contents: read + pull-requests: write + actions: read + +jobs: + run-knip: + runs-on: ubuntu-latest + outputs: + knip_failed: ${{ steps.knip-run.conclusion == 'failure' }} + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node_version }} + + - name: Setup Bun + if: inputs.package_manager == 'bun' + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Setup Yarn + if: inputs.package_manager == 'yarn' + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node_version }} + - run: corepack enable && corepack prepare yarn@${{ inputs.yarn_version }} --activate + if: inputs.package_manager == 'yarn' + + - name: Install dependencies + working-directory: ${{ inputs.working_directory }} + run: | + if [ "${{ inputs.package_manager }}" = "bun" ]; then + bun install --frozen-lockfile + elif [ "${{ inputs.package_manager }}" = "yarn" ]; then + yarn install --frozen-lockfile + elif [ "${{ inputs.package_manager }}" = "npm" ]; then + npm ci + elif [ "${{ inputs.package_manager }}" = "pnpm" ]; then + pnpm install --frozen-lockfile + fi + + - name: Store PR number + if: github.event_name == 'pull_request' + run: echo ${{ github.event.number }} > pr-number.txt + + - name: Run Knip + id: knip-run + working-directory: ${{ inputs.working_directory }} + run: | + if [ "${{ inputs.package_manager }}" = "bun" ]; then + bun run ${{ inputs.knip_script }} || bun run ${{ inputs.knip_script }} --reporter json > knip-results.json + elif [ "${{ inputs.package_manager }}" = "yarn" ]; then + yarn ${{ inputs.knip_script }} || yarn ${{ inputs.knip_script }} --reporter json > knip-results.json + elif [ "${{ inputs.package_manager }}" = "npm" ]; then + npm run ${{ inputs.knip_script }} || npm run ${{ inputs.knip_script }} -- --reporter json > knip-results.json + elif [ "${{ inputs.package_manager }}" = "pnpm" ]; then + pnpm run ${{ inputs.knip_script }} || pnpm run ${{ inputs.knip_script }} -- --reporter json > knip-results.json + fi + + - name: Upload knip result + if: failure() + uses: actions/upload-artifact@v4 + with: + name: knip-results + path: | + knip-results.json + pr-number.txt + retention-days: 1 + + knip-reporter: + needs: run-knip + if: ${{ inputs.enable_reporter && github.event_name == 'pull_request' && needs.run-knip.outputs.knip_failed == 'true' }} + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + steps: + - uses: actions/download-artifact@v4 + with: + name: knip-results + path: ./knip-artifact + + - name: Read pr number + id: pr-number + uses: juliangruber/read-file-action@v1 + with: + path: ./knip-artifact/pr-number.txt + trim: true + + - name: Report knip results to pull request + uses: ubiquity/knip-reporter@main + with: + verbose: true + comment_id: 'knip-reporter' + command_script_name: ${{ inputs.knip_script }} + annotations: true + ignore_results: false + json_input: true + json_input_file_name: knip-artifact/knip-results.json + pull_request_number: ${{ steps.pr-number.outputs.content }} + token: ${{ secrets.GITHUB_TOKEN }}