diff --git a/.github/actions/setup-build-test/action.yml b/.github/actions/setup-build-test/action.yml new file mode 100644 index 0000000..22c0ced --- /dev/null +++ b/.github/actions/setup-build-test/action.yml @@ -0,0 +1,50 @@ +name: 'Setup, build & test' +description: 'Install Node.js and dependencies, build, validate dist packages, lint and test. Shared by CI and release workflows.' + +inputs: + licensed: + description: 'Produce a licensed (@infragistics scoped) build' + required: false + default: 'false' + verbose: + description: 'Get verbose npm output where configurable' + required: false + default: 'false' + +runs: + using: 'composite' + steps: + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '24.x' + cache: 'npm' + + - name: npm ci + shell: bash + run: npm ci ${{ inputs.verbose == 'true' && '--loglevel verbose' || '' }} + + - name: Build + shell: bash + run: npm run build ${{ inputs.verbose == 'true' && '--loglevel verbose' || '' }} + env: + # Only truthy when licensed; empty string keeps unlicensed builds unscoped. + IG_LICENSED_BUILD: ${{ inputs.licensed == 'true' && 'true' || '' }} + + - name: Validate dist packages + shell: bash + run: npm run validate:dist ${{ inputs.verbose == 'true' && '--loglevel verbose' || '' }} + + - name: Lint + shell: bash + run: npm run lint ${{ inputs.verbose == 'true' && '--loglevel verbose' || '' }} + + - name: Install Playwright browsers + shell: bash + run: npx playwright install chromium-headless-shell + + - name: Test + shell: bash + run: npm run test:ci ${{ inputs.verbose == 'true' && '--loglevel verbose' || '' }} + env: + CI: 'true' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3eee806 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,62 @@ +name: CI + +on: + pull_request: + branches: [master] + push: + branches: [master] + workflow_dispatch: + inputs: + verbose: + description: 'Get verbose output from steps - where configurable' + type: boolean + default: false + +# Cancel superseded PR runs; let master pushes each run to completion for history. +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + # Required by actions/upload-code-coverage to post coverage on the PR. + code-quality: write + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Setup, build & test + uses: ./.github/actions/setup-build-test + with: + verbose: ${{ inputs.verbose || 'false' }} + + - name: Upload code coverage + # Skip on PRs from forks, where the token can't post coverage. + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }} + uses: actions/upload-code-coverage@v1 + with: + file: coverage/cobertura-coverage.xml + language: typescript + label: React Wrappers + + - name: Upload test results artifact + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: test-report + path: test-report/junit-report.xml + if-no-files-found: warn + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: coverage + path: coverage/ + if-no-files-found: warn