Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Automatically normalize line endings.
* text=auto

# Directories to exclude from `git archive` / `composer archive`.
/.github export-ignore
/assets export-ignore
/docs export-ignore
/tests export-ignore
/wp-assets export-ignore

# Don't include the dotfiles for distribution.
/.* export-ignore

# Root files that are not needed for distribution.
/babel.config.js export-ignore
/blueprint.json export-ignore
/composer.lock export-ignore
/package-lock.json export-ignore
/package.json export-ignore
/phpcs.xml.dist export-ignore
/phpstan.neon.dist export-ignore
/phpunit.xml.dist export-ignore
/release-please-config.json export-ignore
/tsconfig.json export-ignore
/webpack.config.js export-ignore
78 changes: 78 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# GitHub Workflows

Workflows are defined to be reusable and modular.

### Code Review: [`ci.yml`](ci.yml)

Main CI pipeline used to validate code. Based on file changes it calls the following reusable workflows:

| Reusable Workflow | What |
| --------------------------------------- | ----------------------------------------- |
| `reusable-phpcs.yml` | PHPCS linting |
| `reusable-phpstan.yml` | PHPStan static analysis |
| `reusable-phpunit.yml` | PHPUnit tests |
| `reusable-lint-css-js.yml` | ESlint, Stylelint, Prettier, tsc linting |
| `reusable-jest.yml` | Jest tests |
| `reusable-e2e.yml` | Playwright end-to-end tests |
| `reusable-build.yml` | Creates a build zip (used by playground) |
| `reusable-wp-playground-pr-preview.yml` | PR preview environment with wp-playground |

### `copilot-setup-steps.yml`

Sets up dev environment for GitHub Copilot coding agent.

### `pr-title.yml`

Triggers on PRs. Validates [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) format, required for release-please automation.

### `release.yml`

Triggers on push to `main`. Uses [release-please](https://github.com/googleapis/release-please) to automate releases based on conventional commits.

When a release is created, it builds the plugin via `reusable-build.yml` and uploads the zip artifact to the GitHub release.

## Configuration

1. `php-version`
2. `ci.yml:phpunit` matrix.

### Secrets

| Secret | Required By | Notes |
| --------------- | ------------------------------------------- | ---------------------------------------------------- |
| `CODECOV_TOKEN` | `reusable-phpunit.yml`, `reusable-jest.yml` | Optional — coverage uploads fail silently without it |

### PR Previews

WordPress Playground requires a public URL for the plugin zip. By default, the GitHub action will attach release assets to the `ci-artifacts` release; after the first run, a draft release will be created which you must publish (as a pre-release) before PR Previews will work.

For private repositories, you can configure [`WordPress/action-wp-playground-pr-preview/.github/actions/expose-artifact-on-public-url`](https://github.com/WordPress/action-wp-playground-pr-preview) to expose the artifact on a publicly accessible URL without needing to publish a release, e.g. an S3 bucket or temporary server.

### Testing Workflows Locally

You can use [act](https://github.com/nektos/act) to test GitHub workflows locally. The examples below use inline inputs and inline secrets only (no external JSON or .env files).

```bash
# List workflows available in this repo
act -l

# Run the full CI as a push event (map ubuntu-24.04 to an act-compatible image)
act push -P ubuntu-24.04=catthehacker/ubuntu:act-latest

# Run the `detect` job for a pull request event
act pull_request -j detect -P ubuntu-24.04=catthehacker/ubuntu:act-latest

# Trigger `ci.yml` via workflow_dispatch and run the `phpunit` job with specific inputs and secrets
act workflow_dispatch \
--input php-version=8.2 \
--input wp-version=latest \
--input coverage=true \
-j phpunit \
-s CODECOV_TOKEN=your_codecov_token_here \
-s GITHUB_TOKEN=your_github_token_here \
-P ubuntu-24.04=catthehacker/ubuntu:act-latest
```

## Private Runners

@todo
189 changes: 189 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: CI

on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true

permissions: {}

jobs:
detect:
name: Detect Changes
runs-on: ubuntu-24.04
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
permissions:
contents: read
pull-requests: read
outputs:
php: ${{ steps.filter.outputs.php }}
phpcs: ${{ steps.filter.outputs.phpcs }}
phpstan: ${{ steps.filter.outputs.phpstan }}
phpunit: ${{ steps.filter.outputs.phpunit }}
js: ${{ steps.filter.outputs.js }}
css: ${{ steps.filter.outputs.css }}
e2e: ${{ steps.filter.outputs.e2e }}
jest: ${{ steps.filter.outputs.jest }}

steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false

- name: Detect file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
with:
filters: |
php:
- '**.php'
- 'composer.*'
phpcs:
- '.github/workflows/reusable-phpcs.yml'
- 'phpcs.xml.dist'
phpstan:
- '.github/workflows/reusable-phpstan.yml'
- 'phpstan.neon.dist'
phpunit:
- 'tests/**/*.php'
- '.github/workflows/reusable-phpunit.yml'
- 'phpunit.xml.dist'
- '.wp-env*.json'
- 'package*.json'
js:
- .github/workflows/reusable-lint-css-js.yml
- '**.cjs'
- '**.js'
- '**.jsx'
- '**.mjs'
- '**.cts'
- '**.mts'
- '**.ts'
- '**.tsx'
- 'package*.json'
- '.eslintrc*'
- 'tsconfig*.json'
css:
- .github/workflows/reusable-lint-css-js.yml
- '**.css'
- '**.scss'
- '.stylelintignore'
- '.stylelintrc*'
e2e:
- '.github/workflows/reusable-e2e.yml'
- 'tests/e2e/**/*'
- 'playwright.config.ts'
- '.wp-env*.json'
- 'package*.json'
jest:
- '.github/workflows/reusable-jest.yml'
- 'assets/src/**/__tests__/**/*'
- 'assets/src/**/*.test.ts'
- 'assets/src/**/*.test.tsx'
- 'assets/src/**/*.spec.ts'
- 'assets/src/**/*.spec.tsx'
- 'tests/js/**/*'
- 'jest.config.js'
- 'package*.json'

phpcs:
name: PHPCS
needs: detect
if: needs.detect.outputs.php == 'true' || needs.detect.outputs.phpcs == 'true'
uses: ./.github/workflows/reusable-phpcs.yml
permissions:
contents: read
with:
php-version: '8.3'

phpstan:
name: PHPStan
needs: detect
if: needs.detect.outputs.php == 'true' || needs.detect.outputs.phpstan == 'true'
uses: ./.github/workflows/reusable-phpstan.yml
permissions:
contents: read
with:
php-version: '8.3'

lint-css-js:
name: CSS/JS Lint
needs: detect
if: needs.detect.outputs.css == 'true' || needs.detect.outputs.js == 'true'
uses: ./.github/workflows/reusable-lint-css-js.yml
permissions:
contents: read

jest:
name: Jest Unit Tests
needs: detect
if: needs.detect.outputs.js == 'true' || needs.detect.outputs.jest == 'true'
uses: ./.github/workflows/reusable-jest.yml
permissions:
contents: read
with:
coverage: true

phpunit:
name: PHPUnit (PHP ${{ matrix.php }}, WP ${{ matrix.wp }})
needs: detect
if: needs.detect.outputs.php == 'true' || needs.detect.outputs.phpunit == 'true'
uses: ./.github/workflows/reusable-phpunit.yml
permissions:
contents: read
strategy:
fail-fast: false
matrix:
php: ['8.4', '8.3', '8.2']
wp: ['latest']
include:
- php: '8.4'
wp: 'latest'
coverage: true
with:
php-version: ${{ matrix.php }}
wp-version: ${{ matrix.wp }}
coverage: ${{ matrix.coverage == true }}
secrets: inherit

e2e:
name: E2E Tests
needs: detect
if: needs.detect.outputs.php == 'true' || needs.detect.outputs.e2e == 'true' || needs.detect.outputs.js == 'true' || needs.detect.outputs.css == 'true'
uses: ./.github/workflows/reusable-e2e.yml
permissions:
contents: read
with:
php-version: '8.3'

build-plugin-zip:
name: Build Plugin Zip
permissions:
contents: read
uses: ./.github/workflows/reusable-build.yml
with:
php-version: '8.3'
artifact-name: onedesign-pr${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
secrets: inherit

playground-preview:
name: Playground Preview
needs: build-plugin-zip
if: github.event_name == 'pull_request'
uses: ./.github/workflows/reusable-wp-playground-pr-preview.yml
permissions:
actions: read
contents: write
pull-requests: write
with:
run-id: ${{ github.run_id }}
artifact-prefix: 'onedesign-pr'
artifact-filename: 'onedesign.zip'
Loading
Loading