diff --git a/.github/workflows/actions.yml b/.github/workflows/lint.yml similarity index 62% rename from .github/workflows/actions.yml rename to .github/workflows/lint.yml index fc8b719..118a056 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/lint.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://json.schemastore.org/github-workflow -name: Actions +name: Lint on: pull_request: null push: @@ -18,11 +18,10 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 1 steps: + - name: Checkout repository + uses: actions/checkout@v4 - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Run actionlint - uses: docker://rhysd/actionlint:latest - with: - args: "-color -verbose -shellcheck ''" + - name: Run actionlint + uses: docker://rhysd/actionlint:latest + with: + args: "-color -verbose -shellcheck=" diff --git a/.github/workflows/reusable-acceptance-tests.yml b/.github/workflows/reusable-acceptance-tests.yml index 71722c4..002091f 100644 --- a/.github/workflows/reusable-acceptance-tests.yml +++ b/.github/workflows/reusable-acceptance-tests.yml @@ -7,13 +7,15 @@ on: wp: required: true type: string + description: WordPress version to use in major.minor format (e.g. 6.4), or "latest" or "nightly" php: required: true type: string + description: PHP version to use in major.minor format (e.g. 8.0) node: - required: false + required: true type: boolean - default: true + description: Whether to run the Node build step jobs: test: @@ -27,10 +29,10 @@ jobs: LOCAL_WP_DEBUG: ${{ inputs.php < 8.1 && 1 || 0 }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Configure environment variables - run: | + run: | #shell echo "PHP_FPM_UID=$(id -u)" >> $GITHUB_ENV echo "PHP_FPM_GID=$(id -g)" >> $GITHUB_ENV @@ -50,28 +52,32 @@ jobs: run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Composer cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: 8.0-composer-${{ hashFiles('composer.json') }} - name: Install Composer dependencies - run: | + run: | #shell if [ "${{ inputs.wp }}" == "latest" ]; then composer install --dev --prefer-dist elif [ "${{ inputs.wp }}" == "nightly" ]; then composer require --dev --update-with-dependencies --prefer-dist roots/wordpress-full="dev-main" - else + elif [[ "${{ inputs.wp }}" =~ ^[0-9]\.[0-9]$ ]]; then composer require --dev --update-with-dependencies --prefer-dist roots/wordpress-full="~${{ inputs.wp }}.0" + else + composer require --dev --update-with-dependencies --prefer-dist roots/wordpress-full="${{ inputs.wp }}" fi - name: Setup node - uses: actions/setup-node@v3 + if: ${{ inputs.node }} + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: npm - name: Install node dependencies + if: ${{ inputs.node }} run: npm ci - name: Run the build @@ -89,7 +95,7 @@ jobs: - name: Upload test artifacts if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: acceptance-wp-${{ inputs.wp }}-php-${{ inputs.php }} path: tests/_output diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml index c93e769..1365263 100644 --- a/.github/workflows/reusable-build.yml +++ b/.github/workflows/reusable-build.yml @@ -5,13 +5,17 @@ on: workflow_call: inputs: node: - required: false + required: true type: boolean - default: true + description: Whether to run the Node build step and add the assets to the commit vendor: - required: false + required: true type: boolean - default: true + description: Whether to generate the Composer autoloader files and add them to the commit + tag: + required: true + type: boolean + description: Whether to tag the release jobs: build: @@ -22,7 +26,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install PHP if: ${{ inputs.vendor }} @@ -37,17 +41,19 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Setup node - uses: actions/setup-node@v3 + if: ${{ inputs.node }} + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: npm - name: Install Dependencies + if: ${{ inputs.node }} run: npm ci - name: Generate autoload file if: ${{ inputs.vendor }} - run: | + run: | #shell composer install composer run build-vendor git add -f vendor/autoload.php @@ -55,21 +61,39 @@ jobs: - name: Build Assets if: ${{ inputs.node }} - run: | + run: | #shell npm run build git add -f assets/* - name: Setup version run: echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV - - name: Tag - run: | - echo "Releasing version $VERSION ..." + - name: Commit + run: | #shell + echo 'Committing ...' git config user.name github-actions git config user.email github-actions@github.com git checkout -b "release-$VERSION" git commit -m "Release $VERSION" + git push origin -f "release-$VERSION" + + - name: Tag + if: ${{ inputs.tag }} + run: | #shell + echo "Releasing version $VERSION ..." git tag "$VERSION" git push --tags env: TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create zip file + if: always() + id: create-zip + run: git archive --format=zip --output=build.zip HEAD + + - name: Upload zip + uses: actions/upload-artifact@v4 + with: + name: build + path: build.zip + if: always() && steps.create-zip.outcome == 'success' diff --git a/.github/workflows/reusable-coding-standards.yml b/.github/workflows/reusable-coding-standards.yml index ca38169..32900d1 100644 --- a/.github/workflows/reusable-coding-standards.yml +++ b/.github/workflows/reusable-coding-standards.yml @@ -7,6 +7,7 @@ on: php: required: true type: string + description: PHP version to use in major.minor format (e.g. 8.0) jobs: test: @@ -17,10 +18,10 @@ jobs: timeout-minutes: 10 steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Configure environment variables - run: | + run: | #shell echo "PHP_FPM_UID=$(id -u)" >> $GITHUB_ENV echo "PHP_FPM_GID=$(id -g)" >> $GITHUB_ENV @@ -40,19 +41,19 @@ jobs: run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Composer cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ inputs.php }}-composer-${{ hashFiles('composer.json') }} - name: PHPCS and PHPStan cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: tests/cache key: ${{ inputs.php }}-phpcs-${{ hashFiles('composer.json') }} - name: Debugging - run: | + run: | #shell php --version composer --version diff --git a/.github/workflows/reusable-deploy-assets.yml b/.github/workflows/reusable-deploy-assets.yml index 81c2bbf..cc97eb0 100644 --- a/.github/workflows/reusable-deploy-assets.yml +++ b/.github/workflows/reusable-deploy-assets.yml @@ -7,17 +7,19 @@ on: plugin: required: true type: string + description: The plugin slug readme: required: true type: string + description: The plugin readme file name, either readme.md or readme.txt node: - required: false + required: true type: boolean - default: true + description: Whether to run the Node build step and add the assets to the commit vendor: - required: false + required: true type: boolean - default: true + description: Whether to generate the Composer autoloader files and add them to the commit secrets: WPORG_SVN_USERNAME: required: true @@ -33,7 +35,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install PHP if: ${{ inputs.vendor }} @@ -48,44 +50,45 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: npm - - name: Install Dependencies + - name: Install Node Dependencies run: npm ci + - name: Install Composer Dependencies + run: composer install + - name: Generate autoload file if: ${{ inputs.vendor }} - run: | - composer install + run: | #shell composer run build-vendor git add -f vendor/autoload.php git add -f vendor/composer/* - name: Build Assets if: ${{ inputs.node }} - run: | + run: | #shell npm run build git add -f assets/* - name: Populate Changelog - run: | + run: | #shell node vendor/johnbillion/plugin-infrastructure/bin/changelog.js ${{ inputs.readme }} git add ${{ inputs.readme }} env: TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Commit - run: | + run: | #shell git config user.name github-actions git config user.email github-actions@github.com git commit -m "Assets" - name: WordPress Plugin Deploy - uses: 10up/action-wordpress-plugin-asset-update@1.4.1 + uses: 10up/action-wordpress-plugin-asset-update@2.1.2 env: SVN_USERNAME: ${{ secrets.WPORG_SVN_USERNAME }} SVN_PASSWORD: ${{ secrets.WPORG_SVN_PASSWORD }} - README_NAME: ${{ inputs.readme }} diff --git a/.github/workflows/reusable-deploy-tag.yml b/.github/workflows/reusable-deploy-tag.yml index 6161da6..2a0c587 100644 --- a/.github/workflows/reusable-deploy-tag.yml +++ b/.github/workflows/reusable-deploy-tag.yml @@ -7,9 +7,19 @@ on: plugin: required: true type: string + description: The plugin slug readme: required: true type: string + description: The plugin readme file name, either readme.md or readme.txt + deploy: + required: true + type: boolean + description: Whether to deploy the release to WordPress.org + version: + required: true + type: string + description: The version number of the release secrets: WPORG_SVN_USERNAME: required: true @@ -29,23 +39,62 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Setup node - uses: actions/setup-node@v3 + - name: Populate Changelog + uses: actions/github-script@v7 + env: + FILENAME: ${{ inputs.readme }} with: - node-version-file: '.nvmrc' - cache: npm + script: | #js + const fs = require('fs'); + const { FILENAME } = process.env + const { data: releases } = await github.rest.repos.listReleases( context.repo ); - - name: Install Node Dependencies - run: npm ci + let published = releases.filter( release => + ! release.draft && ! release.prerelease + ); - - name: Install Composer Dependencies - run: composer install + let sorted = published.sort( ( a, b ) => + new Date( b.published_at ) - new Date( a.published_at ) + ); - - name: Populate Changelog - run: | - node vendor/johnbillion/plugin-infrastructure/bin/changelog.js ${{ inputs.readme }} + let changelog = sorted.map( ( release ) => { + const date = new Date( release.published_at ).toLocaleDateString( + 'en-gb', + { + year: 'numeric', + month: 'long', + day: 'numeric', + } + ); + + return [ + `### ${release.tag_name} (${date}) ###`, + '', + `${release.body}`, + ].join('\n'); + } ); + + // Show a maximum of 10 releases + changelog = changelog.slice( 0, 10 ); + + changelog.push( + '### Earlier versions ###', + `For the changelog of earlier versions, please refer to the releases page on GitHub.`, + ); + changelog.unshift('## Changelog ##'); + + // Append the changelog + try { + fs.appendFileSync( FILENAME, '\n' + changelog.join( '\n\n' ) ); + } catch ( exception ) { + console.error( exception ); + process.exitCode = 1; + } + + - name: Commit Changelog + run: | #shell git config user.name github-actions git config user.email github-actions@github.com git add ${{ inputs.readme }} @@ -54,14 +103,25 @@ jobs: TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: WordPress Plugin Deploy - uses: 10up/action-wordpress-plugin-deploy@2.1.1 + uses: 10up/action-wordpress-plugin-deploy@2.2.2 + id: deploy env: SVN_USERNAME: ${{ secrets.WPORG_SVN_USERNAME }} SVN_PASSWORD: ${{ secrets.WPORG_SVN_PASSWORD }} - README_NAME: ${{ inputs.readme }} + VERSION: ${{ inputs.version }} + with: + dry-run: ${{ ! inputs.deploy }} + generate-zip: true + + - name: Upload zip + uses: actions/upload-artifact@v4 + with: + name: deploy + path: ${{ steps.deploy.outputs.zip-path }} github: name: GitHub Milestones + if: ${{ inputs.deploy }} runs-on: ubuntu-latest permissions: issues: write @@ -69,36 +129,21 @@ jobs: steps: - name: Get next versions id: semvers - uses: WyriHaximus/github-action-next-semvers@v1.0 + uses: WyriHaximus/github-action-next-semvers@v1.2.1 with: - version: ${{ github.event.release.tag_name }} + version: ${{ inputs.version }} - name: Create next patch milestone - uses: octokit/request-action@v2.x - with: - route: POST /repos/:repository/milestones - repository: ${{ github.repository }} - title: ${{ steps.semvers.outputs.patch }} + run: gh api "/repos/${{ github.repository }}/milestones" --field "title=${{ steps.semvers.outputs.patch }}" || true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true + GITHUB_TOKEN: ${{ github.token }} - name: Create next minor milestone - uses: octokit/request-action@v2.x - with: - route: POST /repos/:repository/milestones - repository: ${{ github.repository }} - title: ${{ steps.semvers.outputs.minor }} + run: gh api "/repos/${{ github.repository }}/milestones" --field "title=${{ steps.semvers.outputs.minor }}" || true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true + GITHUB_TOKEN: ${{ github.token }} - name: Create next major milestone - uses: octokit/request-action@v2.x - with: - route: POST /repos/:repository/milestones - repository: ${{ github.repository }} - title: ${{ steps.semvers.outputs.major }} + run: gh api "/repos/${{ github.repository }}/milestones" --field "title=${{ steps.semvers.outputs.major }}" || true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - continue-on-error: true + GITHUB_TOKEN: ${{ github.token }} diff --git a/.github/workflows/reusable-integration-tests.yml b/.github/workflows/reusable-integration-tests.yml index 570d565..667b1ba 100644 --- a/.github/workflows/reusable-integration-tests.yml +++ b/.github/workflows/reusable-integration-tests.yml @@ -7,13 +7,15 @@ on: wp: required: true type: string + description: WordPress version to use in major.minor format (e.g. 6.4), or "latest" or "nightly" php: required: true type: string + description: PHP version to use in major.minor format (e.g. 8.0) node: - required: false + required: true type: boolean - default: true + description: Whether to run the Node build step jobs: test: @@ -27,10 +29,10 @@ jobs: LOCAL_WP_DEBUG: ${{ inputs.php < 8.1 && 1 || 0 }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Configure environment variables - run: | + run: | #shell echo "PHP_FPM_UID=$(id -u)" >> $GITHUB_ENV echo "PHP_FPM_GID=$(id -g)" >> $GITHUB_ENV @@ -51,31 +53,33 @@ jobs: run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - name: Composer cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ inputs.php }}-composer-${{ hashFiles('composer.json') }} - name: Debugging - run: | + run: | #shell php --version php -m composer --version docker --version - name: Install Composer dependencies - run: | + run: | #shell if [ "${{ inputs.wp }}" == "latest" ]; then composer install --dev --prefer-dist elif [ "${{ inputs.wp }}" == "nightly" ]; then composer require --dev --update-with-dependencies --prefer-dist roots/wordpress-full="dev-main" - else + elif [[ "${{ inputs.wp }}" =~ ^[0-9]\.[0-9]$ ]]; then composer require --dev --update-with-dependencies --prefer-dist roots/wordpress-full="~${{ inputs.wp }}.0" + else + composer require --dev --update-with-dependencies --prefer-dist roots/wordpress-full="${{ inputs.wp }}" fi - name: Setup node if: ${{ inputs.node }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/test-plugins.yml b/.github/workflows/test-plugins.yml new file mode 100644 index 0000000..c1f3d83 --- /dev/null +++ b/.github/workflows/test-plugins.yml @@ -0,0 +1,109 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow + +name: Test Plugins +on: + pull_request: + workflow_dispatch: + inputs: + PR_NUMBER: + description: The PR number to test + required: true + +permissions: + pull-requests: write + +jobs: + test: + name: ${{ matrix.plugin }} + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'johnbillion/plugin-infrastructure' || github.event_name == 'workflow_dispatch' + strategy: + matrix: + plugin: + - extended-cpts + - query-monitor + - user-switching + - wp-crontrol + fail-fast: false + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + + - name: Checkout repository + uses: actions/checkout@v4 + with: + repository: johnbillion/${{ matrix.plugin }} + token: ${{ secrets.PLUGINS_PUSH_TOKEN }} + + - name: Fetch the PR data + uses: actions/github-script@v7 + id: pr-data + with: + script: | #js + const pr = await github.rest.pulls.get({ + owner: 'johnbillion', + repo: 'plugin-infrastructure', + pull_number: ${{ env.PR_NUMBER }}, + }); + return { + head_repo: pr.data.head.repo.full_name, + head_branch: pr.data.head.ref, + head_sha: pr.data.head.sha, + pr_number: pr.data.number, + pr_link: pr.data.html_url, + }; + github-token: ${{ secrets.PLUGINS_PUSH_TOKEN }} + env: + PR_NUMBER: ${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.event.inputs.PR_NUMBER }} + + - name: Update tests references + run: | #shell + if [ -f .github/workflows/acceptance-tests.yml ]; then + sed -i 's|johnbillion/plugin-infrastructure/.github/workflows/reusable-acceptance-tests.yml@trunk|${{ env.HEAD_REPO }}/.github/workflows/reusable-acceptance-tests.yml@${{ env.SHA_REF }}|g' .github/workflows/acceptance-tests.yml + fi + if [ -f .github/workflows/coding-standards.yml ]; then + sed -i 's|johnbillion/plugin-infrastructure/.github/workflows/reusable-coding-standards.yml@trunk|${{ env.HEAD_REPO }}/.github/workflows/reusable-coding-standards.yml@${{ env.SHA_REF }}|g' .github/workflows/coding-standards.yml + fi + if [ -f .github/workflows/integration-tests.yml ]; then + sed -i 's|johnbillion/plugin-infrastructure/.github/workflows/reusable-integration-tests.yml@trunk|${{ env.HEAD_REPO }}/.github/workflows/reusable-integration-tests.yml@${{ env.SHA_REF }}|g' .github/workflows/integration-tests.yml + fi + env: + HEAD_REPO: ${{ fromJson( steps.pr-data.outputs.result ).head_repo }} + SHA_REF: ${{ fromJson( steps.pr-data.outputs.result ).head_sha }} + + - name: Check the changed files + run: | #shell + git diff + git status + + - name: Open PR + uses: peter-evans/create-pull-request@v6 + id: cpr + with: + token: ${{ secrets.PLUGINS_PUSH_TOKEN }} + commit-message: Update Plugin Infrastructure to ${{ env.SHA_REF }} + title: Update Plugin Infrastructure to ${{ env.HEAD_REPO }}@${{ env.BRANCH_REF }} + body: | #markdown + This PR updates [Plugin Infrastructure](https://github.com/johnbillion/plugin-infrastructure) to `${{ env.HEAD_REPO }}@${{ env.BRANCH_REF }}`. + + See ${{ env.PR_LINK }} for more details. + + This is an automated PR created by [the Test Plugins workflow](https://github.com/johnbillion/plugin-infrastructure/actions/workflows/test-plugins.yml). + branch: update-plugin-infrastructure/${{ env.HEAD_REPO }}/${{ env.BRANCH_REF }} + draft: true + env: + HEAD_REPO: ${{ fromJson( steps.pr-data.outputs.result ).head_repo }} + SHA_REF: ${{ fromJson( steps.pr-data.outputs.result ).head_sha }} + BRANCH_REF: ${{ fromJson( steps.pr-data.outputs.result ).head_branch }} + PR_LINK: ${{ fromJson( steps.pr-data.outputs.result ).pr_link }} + + - name: Set labels + run: | #shell + gh --repo johnbillion/plugin-infrastructure label create "pr:${{ matrix.plugin }}:${{ steps.cpr.outputs.pull-request-number }}" --force --color FEF2C0 + gh --repo johnbillion/plugin-infrastructure pr edit ${{ env.PR_NUMBER }} --add-label "pr:${{ matrix.plugin }}:${{ steps.cpr.outputs.pull-request-number }}" + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ fromJson( steps.pr-data.outputs.result ).pr_number }} diff --git a/.github/workflows/tidy-up.yml b/.github/workflows/tidy-up.yml new file mode 100644 index 0000000..2a99d56 --- /dev/null +++ b/.github/workflows/tidy-up.yml @@ -0,0 +1,112 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow + +name: Tidy up +on: + pull_request: + types: [closed] + +permissions: + pull-requests: write + +jobs: + find: + name: Find PRs + if: github.event.pull_request.head.repo.full_name == 'johnbillion/plugin-infrastructure' + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + prs: ${{ steps.find-prs.outputs.result }} + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + + - name: Find PRs + uses: actions/github-script@v7 + id: find-prs + with: + script: | #js + const pr = await github.rest.pulls.get({ + owner: 'johnbillion', + repo: 'plugin-infrastructure', + pull_number: context.issue.number + }); + const labels = pr.data.labels.map(label => label.name); + const prs = {}; + + for (const label of labels) { + // label is in the format "pr:{repo}:{pr_number}", i.e. "pr:query-monitor:123" + const [_, repo, pr_number] = label.split(':'); + + if (!pr_number) { + continue; + } + + await github.rest.issues.deleteLabel({ + owner: 'johnbillion', + repo: 'plugin-infrastructure', + name: label, + }); + + prs[repo] = pr_number; + } + + return prs; + github-token: ${{ secrets.PLUGINS_PUSH_TOKEN }} + + close: + name: Close PRs / ${{ matrix.plugin }} + runs-on: ubuntu-latest + needs: find + timeout-minutes: 5 + strategy: + matrix: + plugin: + - extended-cpts + - query-monitor + - user-switching + - wp-crontrol + fail-fast: false + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + + - name: Close PR + uses: actions/github-script@v7 + env: + PRS: ${{ needs.find.outputs.prs }} + with: + script: | #js + const prs = JSON.parse('${{ env.PRS }}'); + + if ( prs.hasOwnProperty('${{ matrix.plugin }}') ) { + const pr_number = prs['${{ matrix.plugin }}']; + + // Fetch the PR + const pr = await github.rest.pulls.get({ + owner: 'johnbillion', + repo: '${{ matrix.plugin }}', + pull_number: pr_number, + }); + + // Close the PR + await github.rest.pulls.update({ + owner: 'johnbillion', + repo: '${{ matrix.plugin }}', + pull_number: pr_number, + state: 'closed', + }); + + // Delete its branch + await github.rest.git.deleteRef({ + owner: 'johnbillion', + repo: '${{ matrix.plugin }}', + ref: `heads/${pr.data.head.ref}`, + }); + } else { + console.log(`No PR found for ${{ matrix.plugin }}`); + } + github-token: ${{ secrets.PLUGINS_PUSH_TOKEN }} diff --git a/.gitignore b/.gitignore index 153a4e6..80feb38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Files -composer.lock +/composer.lock # Directories -vendor +/vendor +/node_modules diff --git a/README.md b/README.md index 67c4b60..25d1caf 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ # Plugin Infrastructure -Reusable infrastructure relating to testing, building, and deploying my WordPress plugins (see the "Used by" section in the sidebar). +Reusable infrastructure relating to testing, building, and deploying my WordPress plugins (see the "Used by" section below). -Provided without support, warranty, backwards compatibility, or support for any plugin that isn't one of mine. +Provided without support, warranty, guarantee, backwards compatibility, fitness for purpose, resilience, safety, sanity, beauty, or support for any plugin that isn't one of mine. + +## Used by + +* [Extended CPTs](https://github.com/johnbillion/extended-cpts) +* [Query Monitor](https://github.com/johnbillion/query-monitor) +* [User Switching](https://github.com/johnbillion/user-switching) +* [WP Crontrol](https://github.com/johnbillion/wp-crontrol) ## Licence diff --git a/bin/acceptance-tests b/bin/acceptance-tests index a2b70c9..5ee71c4 100755 --- a/bin/acceptance-tests +++ b/bin/acceptance-tests @@ -13,7 +13,6 @@ export COMPOSE_PROJECT_NAME=${PLUGIN} echo "Starting up..." # Prep: -docker compose --profile acceptance-tests up -d WP_PORT="$(docker inspect --type=container --format='{{(index .NetworkSettings.Ports "80/tcp" 0).HostPort}}' ${PLUGIN}-server)" CHROME_PORT="$(docker inspect --type=container --format='{{(index .NetworkSettings.Ports "4444/tcp" 0).HostPort}}' ${PLUGIN}-chrome)" DATABASE_PORT="$(docker inspect --type=container --format='{{(index .NetworkSettings.Ports "3306/tcp" 0).HostPort}}' ${PLUGIN}-database)" @@ -26,7 +25,7 @@ wp() { # Wait for Selenium: while ! curl -sSL "http://localhost:${CHROME_PORT}/wd/hub/status" 2>&1 | grep '"ready": true' >/dev/null; do echo 'Waiting for Selenium...' - sleep 1 + sleep 3 done # Reset or install the test database: diff --git a/bin/build-vendor b/bin/build-vendor index 048677f..46ab268 100755 --- a/bin/build-vendor +++ b/bin/build-vendor @@ -9,13 +9,25 @@ composer remove composer/installers --update-no-dev composer dump-autoload --no-dev # Wrap the call to `setClassMapAuthoritative` in a `method_exists` check: -sed -i.bak 's/\$loader->setClassMapAuthoritative(true);/if (method_exists(\$loader,"setClassMapAuthoritative")){\n \$loader->setClassMapAuthoritative(true);\n }/' "${PWD}/vendor/composer/autoload_real.php" +sed -i.bak 's/^ \$loader->setClassMapAuthoritative(true);/ if (method_exists(\$loader,"setClassMapAuthoritative")){\n \$loader->setClassMapAuthoritative(true);\n }/' "${PWD}/vendor/composer/autoload_real.php" rm "${PWD}/vendor/composer/autoload_real.php.bak" +# Confirm that the change was successful: +if ! grep -q 'method_exists(\$loader,"setClassMapAuthoritative")' "${PWD}/vendor/composer/autoload_real.php" >/dev/null; then + echo 'setClassMapAuthoritative replacement failed' + exit 1 +fi + # Remove autoloading for `\Composer\InstalledVersions`: sed -i.bak '/Composer\\\\InstalledVersions/d' "${PWD}/vendor/composer/autoload_static.php" rm "${PWD}/vendor/composer/autoload_static.php.bak" +# Confirm that the change was successful: +if grep -q 'Composer\\\\InstalledVersions' "${PWD}/vendor/composer/autoload_static.php" >/dev/null; then + echo 'Composer\InstalledVersions deletion failed' + exit 1 +fi + # Remove files not needed for deployment: rm -f "${PWD}/vendor/composer/autoload_classmap.php" rm -f "${PWD}/vendor/composer/autoload_files.php" diff --git a/bin/changelog.js b/bin/changelog.js deleted file mode 100644 index 92ff148..0000000 --- a/bin/changelog.js +++ /dev/null @@ -1,46 +0,0 @@ -const github = require('@actions/github'); -const semver = require('semver'); -const replace = require('replace-in-file'); - -const filename = process.argv[2] || 'readme.md'; -const myToken = process.env.TOKEN; - -async function run() { - const api = new github.GitHub(myToken); - - const { data: releases } = await api.repos.listReleases( github.context.repo ); - - let published = releases.filter( release => - ! release.draft && ! release.prerelease - ); - - let sorted = published.sort( ( a, b ) => - semver.rcompare( semver.coerce( a.tag_name ), semver.coerce( b.tag_name ) ) - ); - - let changelog = sorted.reduce( ( changelog, release ) => - `${changelog} - -### ${release.tag_name} ### - -${release.body}` - , '## Changelog ##' ); - - try { - const results = await replace( { - files: filename, - from: '', - to: changelog, - } ); - - if ( results.filter( result => ! result.hasChanged ).length ) { - console.error( 'No replacements made' ); - process.exitCode = 1; - } - } catch( exception ) { - console.error( exception ); - process.exitCode = 1; - } -} - -run(); diff --git a/bin/tests-destroy b/bin/tests-destroy new file mode 100755 index 0000000..5581ced --- /dev/null +++ b/bin/tests-destroy @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# -e Exit immediately if a pipeline returns a non-zero status +# -o pipefail Produce a failure return code if any command errors +set -eo pipefail + +# Args +PLUGIN=${PWD##*/} + +# Environment variables +export COMPOSE_PROJECT_NAME=${PLUGIN} + +docker compose down --volumes --remove-orphans diff --git a/bin/tests-start b/bin/tests-start new file mode 100755 index 0000000..f748d6f --- /dev/null +++ b/bin/tests-start @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# -e Exit immediately if a pipeline returns a non-zero status +# -o pipefail Produce a failure return code if any command errors +set -eo pipefail + +# Args +PLUGIN=${PWD##*/} + +# Environment variables +export COMPOSE_PROJECT_NAME=${PLUGIN} + +docker compose up -d diff --git a/bin/tests-stop b/bin/tests-stop new file mode 100755 index 0000000..2b44142 --- /dev/null +++ b/bin/tests-stop @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# -e Exit immediately if a pipeline returns a non-zero status +# -o pipefail Produce a failure return code if any command errors +set -eo pipefail + +# Args +PLUGIN=${PWD##*/} + +# Environment variables +export COMPOSE_PROJECT_NAME=${PLUGIN} + +docker compose down diff --git a/composer.json b/composer.json index 607736e..91f3ca7 100644 --- a/composer.json +++ b/composer.json @@ -16,29 +16,24 @@ } ], "require": { - "php": ">=5.6" + "php": ">=7.4" }, "require-dev": { - "ergebnis/composer-normalize": "^2" }, "bin": [ "bin/acceptance-tests", "bin/build-vendor", - "bin/integration-tests" + "bin/integration-tests", + "bin/tests-destroy", + "bin/tests-start", + "bin/tests-stop" ], "config": { - "allow-plugins": { - "ergebnis/composer-normalize": true - }, "sort-packages": true }, "scripts": { - "post-update-cmd": [ - "composer normalize --quiet" - ], "test": [ - "composer validate --strict --no-check-lock", - "composer normalize --dry-run" + "composer validate --strict --no-check-lock" ] } } diff --git a/tests/nginx.conf b/config/nginx.conf similarity index 100% rename from tests/nginx.conf rename to config/nginx.conf diff --git a/tests/php-config.ini b/config/php-config.ini similarity index 100% rename from tests/php-config.ini rename to config/php-config.ini diff --git a/tests/wp-config.php b/config/wp-config.php similarity index 78% rename from tests/wp-config.php rename to config/wp-config.php index 78e85c4..f199362 100644 --- a/tests/wp-config.php +++ b/config/wp-config.php @@ -5,6 +5,20 @@ mysqli_report( MYSQLI_REPORT_OFF ); +// Force the wp-admin area to use 'mobile' mode so list table row actions are shown. +$GLOBALS['wp_filter'] = array( + 'admin_body_class' => array( + 10 => array( + array( + 'accepted_args' => 1, + 'function' => function( $classes ) { + return $classes .= ' mobile'; + }, + ), + ), + ), +); + define( 'WP_DEBUG', ! empty( getenv( 'WORDPRESS_DEBUG' ) ) ); // Prevent WP-Cron doing its thing during testing. diff --git a/package.json b/package.json deleted file mode 100644 index ad90a23..0000000 --- a/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "plugin-infrastructure", - "description": "Reusable infrastructure relating to testing, building, and deploying my WordPress plugins", - "version": "1.0.0", - "license": "MIT", - "private": true, - "author": "John Blackbourn", - "repository": "johnbillion/plugin-infrastructure", - "engines": { - "node": ">=16" - }, - "dependencies": { - "@actions/github": "^2", - "replace-in-file": "^5", - "semver": "^7" - } -} diff --git a/phpstan/stubs.php b/phpstan/stubs.php index 8cdf640..8d7867e 100644 --- a/phpstan/stubs.php +++ b/phpstan/stubs.php @@ -8,9 +8,7 @@ define( 'DB_USER', '' ); define( 'SAVEQUERIES', false ); -define( 'WP_CONTENT_DIR', '' ); define( 'WP_MEMORY_LIMIT', '' ); -define( 'WP_PLUGIN_DIR', '' ); define( 'WPINC', '' ); define( 'AUTH_COOKIE', '' ); diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index ad33189..dcc0ab5 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.1' - services: server: @@ -12,8 +10,8 @@ services: - php volumes: - ./vendor/wordpress/wordpress:/var/www/html/:rw - - ./vendor/johnbillion/plugin-infrastructure/tests/wp-config.php:/var/www/html/wp-config.php - - ./vendor/johnbillion/plugin-infrastructure/tests/nginx.conf:/etc/nginx/templates/default.conf.template + - ./vendor/johnbillion/plugin-infrastructure/config/wp-config.php:/var/www/html/wp-config.php + - ./vendor/johnbillion/plugin-infrastructure/config/nginx.conf:/etc/nginx/templates/default.conf.template - ./:/var/www/html/wp-content/plugins/${COMPOSE_PROJECT_NAME}:rw php: @@ -33,8 +31,8 @@ services: init: true volumes: - ./vendor/wordpress/wordpress:/var/www/html/:rw - - ./vendor/johnbillion/plugin-infrastructure/tests/wp-config.php:/var/www/html/wp-config.php - - ./vendor/johnbillion/plugin-infrastructure/tests/php-config.ini:/usr/local/etc/php/conf.d/php-config.ini + - ./vendor/johnbillion/plugin-infrastructure/config/wp-config.php:/var/www/html/wp-config.php + - ./vendor/johnbillion/plugin-infrastructure/config/php-config.ini:/usr/local/etc/php/conf.d/php-config.ini - ./:/var/www/html/wp-content/plugins/${COMPOSE_PROJECT_NAME}:rw database: @@ -72,15 +70,13 @@ services: init: true volumes: - ./vendor/wordpress/wordpress:/var/www/:rw - - ./vendor/johnbillion/plugin-infrastructure/tests/wp-config.php:/var/www/wp-config.php - - ./vendor/johnbillion/plugin-infrastructure/tests/php-config.ini:/usr/local/etc/php/conf.d/php-config.ini + - ./vendor/johnbillion/plugin-infrastructure/config/wp-config.php:/var/www/wp-config.php + - ./vendor/johnbillion/plugin-infrastructure/config/php-config.ini:/usr/local/etc/php/conf.d/php-config.ini - ./:/var/www/wp-content/plugins/${COMPOSE_PROJECT_NAME}:rw chrome: image: seleniarm/standalone-chromium container_name: ${COMPOSE_PROJECT_NAME}-chrome - profiles: - - acceptance-tests depends_on: - server ports: