├── .github ├── codeql-config.yml ├── renovate.json └── workflows │ ├── audit-signatures.yml │ ├── ci-integration.yml │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── dependency-review.yml │ └── package-audit.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── SECURITY.md ├── action.yml ├── dist ├── post │ └── index.js └── setup │ └── index.js ├── eslint.config.mjs ├── package-lock.json ├── package.json ├── src ├── main.ts ├── post.ts ├── utils.ts ├── wpapi.ts └── wputils.ts ├── test ├── mocks │ └── wpapi.ts ├── utils.spec.ts └── wputils.spec.ts ├── tsconfig.json └── wptest ├── .gitignore ├── composer.json ├── composer.lock ├── phpunit.xml ├── plugin.php └── tests ├── bootstrap.php └── test-plugin.php /.github/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL Config 2 | 3 | paths: 4 | - src/ 5 | 6 | paths-ignore: 7 | - dist 8 | - lib 9 | - wptest 10 | - node_modules 11 | 12 | queries: 13 | - uses: security-and-quality 14 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>sjinks/.github:renovate-config" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/audit-signatures.yml: -------------------------------------------------------------------------------- 1 | name: Audit Signatures 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | audit: 15 | name: Verify Signatures and Provenance Statements 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: read 19 | steps: 20 | - name: Harden Runner 21 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 22 | with: 23 | disable-sudo: true 24 | allowed-endpoints: > 25 | api.github.com:443 26 | github.com:443 27 | objects.githubusercontent.com:443 28 | nodejs.org:443 29 | registry.npmjs.org:443 30 | tuf-repo-cdn.sigstore.dev:443 31 | 32 | - name: Checkout 33 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 34 | 35 | - name: Setup Node.js environment 36 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 37 | with: 38 | node-version: lts/* 39 | 40 | - name: Install latest npm 41 | run: npm install -g npm@latest 42 | 43 | - name: Install dependencies 44 | run: npm ci 45 | 46 | - name: Run audit 47 | run: npm audit signatures 48 | -------------------------------------------------------------------------------- /.github/workflows/ci-integration.yml: -------------------------------------------------------------------------------- 1 | name: Integration Testing 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | integration: 15 | name: Integration testing 16 | permissions: 17 | contents: read 18 | runs-on: ubuntu-latest 19 | services: 20 | mysql: 21 | image: mariadb:latest 22 | ports: 23 | - '3306:3306' 24 | env: 25 | MYSQL_ROOT_PASSWORD: wordpress 26 | MARIADB_INITDB_SKIP_TZINFO: 1 27 | MYSQL_USER: wordpress 28 | MYSQL_PASSWORD: wordpress 29 | MYSQL_DATABASE: wordpress_test 30 | steps: 31 | - name: Harden Runner 32 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 33 | with: 34 | egress-policy: block 35 | allowed-endpoints: > 36 | api.github.com:443 37 | api.wordpress.org:80 38 | api.wordpress.org:443 39 | archive.ubuntu.com:80 40 | azure.archive.ubuntu.com:80 41 | cdn.fwupd.org:443 42 | esm.ubuntu.com:443 43 | esm.ubuntu.com:80 44 | motd.ubuntu.com:80 45 | packages.microsoft.com:443 46 | packages.microsoft.com:80 47 | ppa.launchpad.net:80 48 | ppa.launchpadcontent.net:80 49 | security.ubuntu.com:80 50 | wordpress.org:443 51 | develop.svn.wordpress.org:443 52 | plugins.svn.wordpress.org:443 53 | github.com:443 54 | objects.githubusercontent.com:443 55 | packagist.org:443 56 | 57 | - name: Install subversion 58 | run: sudo apt-get update && sudo apt-get -y install subversion 59 | 60 | - name: Check out the source code 61 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 62 | 63 | - name: Set up PHP 64 | uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # 2.32.0 65 | with: 66 | coverage: none 67 | php-version: "8.2" 68 | 69 | - name: Install PHP Dependencies 70 | uses: ramsey/composer-install@a2636af0004d1c0499ffca16ac0b4cc94df70565 # 3.1.0 71 | with: 72 | working-directory: wptest 73 | 74 | - name: Set up WordPress and WordPress Test Library 75 | uses: ./ 76 | with: 77 | version: latest 78 | 79 | - name: Verify MariaDB connection 80 | run: | 81 | while ! mysqladmin ping -h 127.0.0.1 -P ${{ job.services.mysql.ports[3306] }} --silent; do 82 | sleep 1 83 | done 84 | timeout-minutes: 1 85 | 86 | - name: Run tests 87 | run: vendor/bin/phpunit 88 | working-directory: wptest 89 | 90 | - name: Set up WordPress and WordPress Test Library (from the tool cache) 91 | uses: ./ 92 | with: 93 | version: latest 94 | 95 | - name: Rerun tests 96 | run: vendor/bin/phpunit 97 | working-directory: wptest 98 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: 'Build and Test' 2 | 3 | on: 4 | push: 5 | workflow_dispatch: 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | build: 12 | name: Build 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: read 16 | steps: 17 | - name: Harden Runner 18 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 19 | with: 20 | disable-sudo: true 21 | disable-file-monitoring: true 22 | egress-policy: block 23 | allowed-endpoints: > 24 | api.github.com:443 25 | github.com:443 26 | nodejs.org:443 27 | registry.npmjs.org:443 28 | 29 | - name: Check out the source code 30 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 31 | 32 | - name: Setup Node.js environment 33 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 34 | with: 35 | node-version-file: package.json 36 | cache: npm 37 | 38 | - name: Install dependencies 39 | run: npm ci 40 | 41 | - name: Build 42 | run: npm run all 43 | 44 | test: 45 | name: Test 46 | runs-on: ubuntu-latest 47 | permissions: 48 | contents: read 49 | steps: 50 | - name: Harden Runner 51 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 52 | with: 53 | egress-policy: block 54 | allowed-endpoints: > 55 | api.wordpress.org:80 56 | api.wordpress.org:443 57 | archive.ubuntu.com:80 58 | azure.archive.ubuntu.com:80 59 | cdn.fwupd.org:443 60 | esm.ubuntu.com:443 61 | esm.ubuntu.com:80 62 | motd.ubuntu.com:80 63 | packages.microsoft.com:443 64 | packages.microsoft.com:80 65 | ppa.launchpad.net:80 66 | ppa.launchpadcontent.net:80 67 | security.ubuntu.com:80 68 | wordpress.org:443 69 | develop.svn.wordpress.org:443 70 | plugins.svn.wordpress.org:443 71 | github.com:443 72 | 73 | - name: Install subversion 74 | run: sudo apt-get update && sudo apt-get -y install subversion 75 | 76 | - name: Check out the source code 77 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 78 | 79 | - name: Set up WordPress and WordPress Test Library 80 | uses: ./ 81 | with: 82 | version: latest 83 | dir: /tmp 84 | 85 | - name: Verify 86 | run: | 87 | test -e /tmp/wordpress 88 | test -e /tmp/wordpress-tests-lib 89 | test -f /tmp/wordpress-tests-lib/wp-tests-config.php 90 | 91 | check-dist: 92 | name: Check dist 93 | runs-on: ubuntu-latest 94 | permissions: 95 | contents: write 96 | steps: 97 | - name: Harden Runner 98 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 99 | with: 100 | disable-sudo: true 101 | disable-file-monitoring: true 102 | egress-policy: block 103 | allowed-endpoints: > 104 | api.github.com:443 105 | github.com:443 106 | nodejs.org:443 107 | registry.npmjs.org:443 108 | 109 | - name: Check out the source code 110 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 111 | with: 112 | token: ${{ secrets.REPOSITORY_ACCESS_TOKEN }} 113 | 114 | - name: Setup Node.js environment 115 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 116 | with: 117 | node-version-file: package.json 118 | cache: npm 119 | 120 | - name: Install dependencies 121 | run: npm ci 122 | 123 | - name: Rebuild the dist/ directory 124 | run: npm run package 125 | 126 | - name: Check the diff 127 | run: | 128 | if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then 129 | echo "::warning::There are changes in the built files." 130 | if [ "${{ github.event.head_commit.committer.email }}" != "actions@github.com" ]; then 131 | git config user.name "GitHub Actions" 132 | git config user.email actions@github.com 133 | git config push.default "current" 134 | git add dist/ 135 | git commit -m "chore: regenerate dist" 136 | git push 137 | else 138 | echo "::error::Aborting to avoid the loop." 139 | exit 1 140 | fi 141 | fi 142 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL Analysis 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | schedule: 11 | - cron: '24 5 * * 6' 12 | workflow_dispatch: 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | analyze: 19 | name: Static Code Analysis with CodeQL 20 | permissions: 21 | actions: read 22 | contents: read 23 | security-events: write 24 | runs-on: ubuntu-latest 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | language: 29 | - javascript 30 | - actions 31 | steps: 32 | - name: Harden Runner 33 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 34 | with: 35 | disable-sudo: true 36 | egress-policy: block 37 | allowed-endpoints: > 38 | api.github.com:443 39 | github.com:443 40 | uploads.github.com:443 41 | objects.githubusercontent.com:443 42 | 43 | - name: Checkout repository 44 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 45 | 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 48 | with: 49 | languages: ${{ matrix.language }} 50 | config-file: ./.github/codeql-config.yml 51 | 52 | - name: Perform CodeQL Analysis 53 | uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 54 | with: 55 | category: "/language:${{ matrix.language }}" 56 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: Dependency Review 2 | 3 | on: 4 | pull_request: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | dependency-review: 11 | runs-on: ubuntu-latest 12 | name: Review Dependencies 13 | permissions: 14 | contents: read 15 | pull-requests: write 16 | steps: 17 | - name: Harden Runner 18 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 19 | with: 20 | egress-policy: block 21 | allowed-endpoints: > 22 | api.deps.dev:443 23 | api.github.com:443 24 | api.securityscorecards.dev:443 25 | github.com:443 26 | 27 | - name: Check out the source code 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | 30 | - name: Review dependencies 31 | uses: actions/dependency-review-action@ce3cf9537a52e8119d91fd484ab5b8a807627bf8 # v4.6.0 32 | with: 33 | comment-summary-in-pr: true 34 | -------------------------------------------------------------------------------- /.github/workflows/package-audit.yml: -------------------------------------------------------------------------------- 1 | name: Package Audit 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | paths: 8 | - package.json 9 | - package-lock.json 10 | - .github/workflows/package-audit.yml 11 | workflow_dispatch: 12 | 13 | permissions: 14 | contents: read 15 | 16 | env: 17 | NO_UPDATE_NOTIFIER: 'true' 18 | 19 | jobs: 20 | audit-npm: 21 | name: NPM Audit 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Harden Runner 25 | uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0 26 | with: 27 | disable-sudo: true 28 | allowed-endpoints: 29 | api.github.com:443 30 | github.com:443 31 | objects.githubusercontent.com:443 32 | nodejs.org:443 33 | registry.npmjs.org:443 34 | 35 | - name: Check out the source code 36 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 37 | 38 | - name: Setup Node.js environment 39 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 40 | with: 41 | node-version-file: package.json 42 | cache: npm 43 | 44 | - name: Run audit 45 | run: npm audit --omit=dev 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | # Ignore built ts files 98 | __tests__/runner/* 99 | lib/**/* 100 | 101 | /test-report.xml 102 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | sign-git-tag=true 2 | message="chore: release %s" 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | package-lock.json 3 | yarn.lock 4 | dist 5 | lib 6 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "printWidth": 120, 6 | "tabWidth": 4 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Volodymyr Kolesnykov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # setup-wordpress-test-library 2 | 3 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sjinks_setup-wptl-action&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=sjinks_setup-wptl-action) 4 | [![Build and Test](https://github.com/sjinks/setup-wptl-action/actions/workflows/ci.yml/badge.svg)](https://github.com/sjinks/setup-wptl-action/actions/workflows/ci.yml) 5 | [![CodeQL Analysis](https://github.com/sjinks/setup-wptl-action/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/sjinks/setup-wptl-action/actions/workflows/codeql-analysis.yml) 6 | 7 | This action sets up WordPress and WordPress Test Library. WordPress plugins can make use of this action to run unit tests. 8 | 9 | ## Inputs 10 | 11 | * `version`: WordPress version to use. Can be `trunk` or `nightly` for the latest nightly build, `latest` for the latest available WordPress release, an explicit version number (like `6.0`) to install the specific WordPress version, or a partial version (`5.9.x`) to install the latest available patch for the specific WordPress release. The default value is `latest`. 12 | * `dir`: target directory for WordPress and WordPress Test Library; the default value is `/tmp`. **Warning:** the system will delete `wordpress`, `wordpress-test-library`, and `wordpress.zip` from that directory if they exist. 13 | * `db_user`: database user for WordPress, `wordpress` by default; 14 | * `db_password`: database password for WordPress, `wordpress` by default; 15 | * `db_name`: database name for WordPress, `wordpress_test` by default. **Warning:** WordPress Test Library may delete all tables from that database; 16 | * `db_host`: database host (`127.0.0.1` by default) for WordPress. 17 | 18 | ## Outputs 19 | 20 | * `wp_version`: the actual WordPress version. 21 | 22 | ## Environment Variables 23 | 24 | Upon success, the action sets the `WP_TESTS_DIR` environment variable; its value is the absolute path to the WordPress Test library 25 | 26 | ## Example usage 27 | 28 | ```yaml 29 | name: CI 30 | 31 | on: 32 | push: 33 | 34 | permissions: 35 | contents: read 36 | 37 | jobs: 38 | testing: 39 | name: Run tests 40 | runs-on: ubuntu-latest 41 | services: 42 | mysql: 43 | image: mariadb:latest 44 | ports: 45 | - '3306:3306' 46 | env: 47 | MYSQL_ROOT_PASSWORD: wordpress 48 | MARIADB_INITDB_SKIP_TZINFO: 1 49 | MYSQL_USER: wordpress 50 | MYSQL_PASSWORD: wordpress 51 | MYSQL_DATABASE: wordpress_test 52 | steps: 53 | - name: Check out the source code 54 | uses: actions/checkout@v3 55 | 56 | - name: Set up PHP 57 | uses: shivammathur/setup-php@v2 58 | with: 59 | coverage: none 60 | php-version: "8.2" 61 | 62 | - name: Install PHP Dependencies 63 | uses: ramsey/composer-install@v3 64 | 65 | - name: Set up WordPress and WordPress Test Library 66 | uses: sjinks/setup-wordpress-test-library@master 67 | with: 68 | version: latest 69 | 70 | - name: Verify MariaDB connection 71 | run: | 72 | while ! mysqladmin ping -h 127.0.0.1 -P ${{ job.services.mysql.ports[3306] }} --silent; do 73 | sleep 1 74 | done 75 | timeout-minutes: 1 76 | 77 | - name: Run tests 78 | run: vendor/bin/phpunit 79 | ``` 80 | 81 | See the [Integration Testing](.github/workflows/ci-integration.yml) workflow for a real-world example. 82 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting Security Issues 4 | 5 | We take security seriously. We appreciate your efforts to disclose your findings responsibly and will make every effort to acknowledge your contributions. 6 | 7 | To report a security vulnerability, please email us at [volodymyr@wildwolf.name](mailto:volodymyr@wildwolf.name). Please do not create public GitHub issues for security vulnerabilities. 8 | 9 | We will acknowledge receipt of your vulnerability report within 24 hours and will strive to provide regular updates about our progress in addressing the vulnerability. 10 | 11 | Please provide the following information when reporting a security vulnerability: 12 | - Description of the vulnerability 13 | - Steps to reproduce the vulnerability 14 | - Versions affected 15 | - Any additional information that might be useful 16 | 17 | ## Response Time 18 | 19 | We will acknowledge receipt of your vulnerability report within 24 hours, excluding weekends and holidays. We will then work diligently to assess and address the vulnerability promptly. 20 | 21 | We prioritize the handling of security vulnerabilities and strive to provide updates and fixes promptly. 22 | 23 | ## Confidentiality 24 | 25 | We request that you only disclose the details of the vulnerability or related correspondence once we have had an opportunity to address the issue. Once the vulnerability has been resolved, we will coordinate with you on an appropriate timeline for public disclosure. 26 | 27 | ## Scope 28 | 29 | This security policy applies to vulnerabilities in this project. If you discover a vulnerability in a dependency, please report it directly to the maintainer of that project. 30 | 31 | ## Bug Bounty 32 | 33 | We do not currently offer a bug bounty program, but we sincerely appreciate and acknowledge the contributions of security researchers who responsibly disclose vulnerabilities to us. 34 | 35 | Thank you for helping to keep this project secure! 36 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Set up WordPress Test Library' 2 | description: 'Sets up WordPress and WordPress test library' 3 | author: 'Volodymyr Kolesnykov' 4 | inputs: 5 | version: 6 | description: 'WordPress version' 7 | required: false 8 | default: 'latest' 9 | cache_prefix: 10 | description: 'Custom cache prefix' 11 | required: false 12 | default: '' 13 | dir: 14 | description: 'Directory to install WordPress and WordPress Test Library' 15 | required: false 16 | default: '/tmp' 17 | db_user: 18 | description: 'Database user' 19 | required: false 20 | default: 'wordpress' 21 | db_password: 22 | description: 'Database password' 23 | required: false 24 | default: 'wordpress' 25 | db_name: 26 | description: 'Database name' 27 | required: false 28 | default: 'wordpress_test' 29 | db_host: 30 | description: 'Database host' 31 | required: false 32 | default: '127.0.0.1' 33 | 34 | outputs: 35 | wp_version: 36 | description: 'Actual WordPress version' 37 | 38 | runs: 39 | using: 'node20' 40 | main: 'dist/setup/index.js' 41 | post: 'dist/post/index.js' 42 | 43 | branding: 44 | color: blue 45 | icon: target 46 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import MyrotvoretsConfig from '@myrotvorets/eslint-config-myrotvorets-ts'; 2 | 3 | /** @type {import('eslint').Linter.Config[]} */ 4 | export default [ 5 | { 6 | ignores: ['**/*.js', '**/*.d.ts', 'dist/**', 'lib/**'], 7 | }, 8 | ...MyrotvoretsConfig, 9 | ]; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "setup-wptl-action", 3 | "version": "2.1.4", 4 | "description": "Set up WordPress Test Library", 5 | "scripts": { 6 | "build": "tsc", 7 | "lint": "eslint .", 8 | "lint:fix": "eslint . --fix", 9 | "package": "ncc build -o dist/setup --minify --transpile-only src/main.ts && ncc build -o dist/post --minify --transpile-only src/post.ts", 10 | "test": "node --require=ts-node/register/transpile-only --test --test-reporter=node-reporter-gha --test-reporter-destination=stdout --test-reporter=spec --test-reporter-destination=stdout test/*.spec.ts", 11 | "all": "npm run build && npm run lint:fix && npm run package && npm test" 12 | }, 13 | "keywords": [], 14 | "author": "Volodymyr Kolesnykov (https://wildwolf.name/)", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "@actions/cache": "^4.0.0", 18 | "@actions/core": "^1.10.1", 19 | "@actions/http-client": "^2.2.3", 20 | "@actions/io": "^1.1.3", 21 | "@actions/tool-cache": "^2.0.1", 22 | "@myrotvorets/eslint-config-myrotvorets-ts": "^3.0.0", 23 | "@taiyosen/easy-svn": "^1.0.29", 24 | "@types/node": ">=22", 25 | "@types/semver": "^7.5.8", 26 | "@vercel/ncc": "^0.38.1", 27 | "node-reporter-gha": "^2.0.4", 28 | "semver": "^7.6.3", 29 | "ts-node": "^10.9.2", 30 | "typescript": "^5.5.4" 31 | }, 32 | "engines": { 33 | "node": "20" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { tmpdir } from 'node:os'; 2 | import { join, resolve } from 'node:path'; 3 | import { readFile, symlink, writeFile } from 'node:fs/promises'; 4 | import { type InputOptions, exportVariable, getInput, info, saveState, setFailed, setOutput } from '@actions/core'; 5 | import { isFeatureAvailable as isCacheAvailable, restoreCache } from '@actions/cache'; 6 | import { cacheDir, downloadTool, extractZip, find as findTool } from '@actions/tool-cache'; 7 | import { mkdirP, rmRF } from '@actions/io'; 8 | import { coerce } from 'semver'; 9 | import { SVNClient } from '@taiyosen/easy-svn'; 10 | import { downloadAsText, isDir, isGHES } from './utils'; 11 | import { getWordPressDownloadUrl, getWordPressTestLibraryBaseUrl, resolveWordPressVersion } from './wputils'; 12 | 13 | interface Inputs { 14 | version: string; 15 | dir: string; 16 | cache_prefix: string; 17 | db_user: string; 18 | db_password: string; 19 | db_name: string; 20 | db_host: string; 21 | has_cache: boolean; 22 | has_toolcache: boolean; 23 | semver: string | undefined; 24 | } 25 | 26 | /** 27 | * Get the inputs from the GitHub Actions environment. 28 | * 29 | * @returns {Inputs} The inputs for the script. 30 | */ 31 | function getInputs(): Inputs { 32 | const options: InputOptions = { 33 | required: false, 34 | trimWhitespace: true, 35 | }; 36 | 37 | return { 38 | version: getInput('version', options) || 'latest', 39 | cache_prefix: getInput('cache_prefix', options) || '', 40 | dir: resolve(getInput('dir', options) || tmpdir()), 41 | db_user: getInput('db_user', options) || 'wordpress', 42 | db_password: getInput('db_password', options) || 'wordpress', 43 | db_name: getInput('db_name', options) || 'wordpress_test', 44 | db_host: getInput('db_host', options) || '127.0.0.1', 45 | has_cache: isCacheAvailable() && !isGHES(), 46 | has_toolcache: process.env.RUNNER_TOOL_CACHE !== undefined, 47 | semver: undefined, 48 | }; 49 | } 50 | 51 | /** 52 | * Resolve the semantic version from the given version string. 53 | * 54 | * @param {string} version The version string to resolve. 55 | * @param {Inputs} inputs The inputs object to update. 56 | */ 57 | function resolveSemVer(version: string, inputs: Inputs): void { 58 | inputs.semver = coerce(version)?.format(); 59 | if (!inputs.semver) { 60 | inputs.has_cache = false; 61 | inputs.has_toolcache = false; 62 | } 63 | } 64 | 65 | async function cacheTool(path: string, name: string, inputs: Inputs): Promise { 66 | if (inputs.has_toolcache) { 67 | info(`📦 Caching ${path} as ${name} ${inputs.semver}…`); 68 | const dir = await cacheDir(path, name, inputs.semver!); 69 | info(`ℹ️ Saved cache to ${dir}`); 70 | } 71 | } 72 | 73 | /** 74 | * Find the cached version of the given tool. 75 | * 76 | * @async 77 | * @param {string} name The name of the tool. 78 | * @param {string} tool The tool to find. 79 | * @param {Inputs} inputs The inputs for the script. 80 | * @returns {Promise} True if the tool was found in the cache, false otherwise. 81 | */ 82 | async function findCached(name: string, tool: string, inputs: Inputs): Promise { 83 | if (inputs.has_toolcache && inputs.semver) { 84 | info(`ℹ️ Checking tool cache for ${tool} ${inputs.semver}…`); 85 | const cachePath = findTool(tool, inputs.semver); 86 | if (cachePath) { 87 | const resolvedPath = resolve(cachePath); 88 | 89 | info(`🚀 Using cached ${name} from ${resolvedPath}`); 90 | await symlink(resolvedPath, `${inputs.dir}/${tool}`); 91 | return true; 92 | } 93 | 94 | info(`😔 ${tool} ${inputs.semver} was not found in the tool cache`); 95 | } 96 | 97 | if (inputs.has_cache) { 98 | const key = `2:${inputs.cache_prefix}:${tool}:${inputs.semver}`; 99 | 100 | info(`ℹ️ Checking cache key ${key} for ${tool}…`); 101 | const result = await restoreCache([tool], key); 102 | 103 | if (result) { 104 | info(`🚀 Using cached ${name}, key is ${key}`); 105 | await cacheTool(join(inputs.dir, tool), tool, inputs); 106 | return true; 107 | } 108 | 109 | saveState(`dir_${tool}`, inputs.dir); 110 | saveState(`cache_key_${tool}`, key); 111 | } 112 | 113 | return false; 114 | } 115 | 116 | /** 117 | * Download WordPress and extract it to the given directory. 118 | * 119 | * @async 120 | * @param {string} url The URL to download WordPress from. 121 | * @param {Inputs} inputs The inputs for the script. 122 | */ 123 | async function downloadWordPress(url: string, inputs: Inputs): Promise { 124 | const dest = join(inputs.dir, 'wordpress.zip'); 125 | try { 126 | if (await findCached('WordPress', 'wordpress', inputs)) { 127 | return; 128 | } 129 | 130 | info(`📥 Downloading WordPress…`); 131 | const file = await downloadTool(url, dest); 132 | const targetDir = await extractZip(file, inputs.dir); 133 | 134 | await cacheTool(`${targetDir}/wordpress`, 'wordpress', inputs); 135 | } finally { 136 | await rmRF(dest); 137 | } 138 | } 139 | 140 | /** 141 | * Download the WordPress Test Library and extract it to the given directory. 142 | * 143 | * @async 144 | * @param {string} url The URL to download the WordPress Test Library from. 145 | * @param {Inputs} inputs The inputs for the script. 146 | */ 147 | async function downloadTestLibrary(url: string, inputs: Inputs): Promise { 148 | if (await findCached('WordPress Test Library', 'wordpress-tests-lib', inputs)) { 149 | return; 150 | } 151 | 152 | info(`📥 Downloading WordPress Test Library…`); 153 | await mkdirP(join(inputs.dir, 'wordpress-tests-lib')); 154 | const client = new SVNClient(); 155 | client.setConfig({ silent: true }); 156 | const [, , config] = await Promise.all([ 157 | client.checkout(`${url}/tests/phpunit/includes/`, `${inputs.dir}/wordpress-tests-lib/includes`), 158 | client.checkout(`${url}/tests/phpunit/data/`, `${inputs.dir}/wordpress-tests-lib/data`), 159 | downloadAsText(`${url}/wp-tests-config-sample.php`), 160 | ]); 161 | 162 | await Promise.all([ 163 | rmRF(`${inputs.dir}/wordpress-tests-lib/includes/.svn`), 164 | rmRF(`${inputs.dir}/wordpress-tests-lib/data/.svn`), 165 | writeFile(join(inputs.dir, 'wordpress-tests-lib', 'wp-tests-config-sample.php'), config), 166 | ]); 167 | 168 | await cacheTool(`${inputs.dir}/wordpress-tests-lib`, 'wordpress-tests-lib', inputs); 169 | } 170 | 171 | /** 172 | * Configure WordPress with the given inputs. 173 | * 174 | * @async 175 | * @param {Inputs} inputs The inputs for the script. 176 | */ 177 | async function configureWordPress(inputs: Inputs): Promise { 178 | const dir = join(inputs.dir, 'wordpress-tests-lib'); 179 | const config = (await readFile(join(dir, 'wp-tests-config-sample.php'), 'utf8')) 180 | .replace('youremptytestdbnamehere', inputs.db_name) 181 | .replace('yourusernamehere', inputs.db_user) 182 | .replace('yourpasswordhere', inputs.db_password) 183 | .replace('localhost', inputs.db_host) 184 | .replace("dirname( __FILE__ ) . '/src/'", `'${inputs.dir}/wordpress/'`); 185 | return writeFile(join(inputs.dir, 'wordpress-tests-lib', 'wp-tests-config.php'), config); 186 | } 187 | 188 | async function run(): Promise { 189 | try { 190 | const inputs = getInputs(); 191 | 192 | if (!(await isDir(inputs.dir))) { 193 | throw new Error(`Directory ${inputs.dir} does not exist`); 194 | } 195 | 196 | info('🤔 Determining WordPress version…'); 197 | const wpVersion = await resolveWordPressVersion(inputs.version); 198 | info(`ℹ️ WordPress version: ${wpVersion}`); 199 | setOutput('wp_version', wpVersion); 200 | 201 | resolveSemVer(wpVersion, inputs); 202 | 203 | await Promise.all([ 204 | rmRF(join(inputs.dir, 'wordpress')), 205 | rmRF(join(inputs.dir, 'wordpress-tests-lib')), 206 | rmRF(join(inputs.dir, 'wordpress.zip')), 207 | ]); 208 | 209 | info(`ℹ️ Cache is available: ${inputs.has_cache ? 'yes' : 'no'}`); 210 | info(`ℹ️ Tool cache is available: ${inputs.has_toolcache ? 'yes' : 'no'}`); 211 | 212 | const wpUrl = getWordPressDownloadUrl(wpVersion); 213 | const wptlUrl = getWordPressTestLibraryBaseUrl(wpVersion); 214 | const workspace = process.env.GITHUB_WORKSPACE; 215 | try { 216 | process.env.GITHUB_WORKSPACE = inputs.dir; 217 | await Promise.all([downloadWordPress(wpUrl, inputs), downloadTestLibrary(wptlUrl, inputs)]); 218 | } finally { 219 | process.env.GITHUB_WORKSPACE = workspace; 220 | } 221 | 222 | info('⚙️ Configuring WordPress…'); 223 | await configureWordPress(inputs); 224 | 225 | exportVariable('WP_TESTS_DIR', join(inputs.dir, 'wordpress-tests-lib')); 226 | setOutput('wp_directory', join(inputs.dir, 'wordpress')); 227 | setOutput('wptl_directory', join(inputs.dir, 'wordpress-tests-lib')); 228 | saveState('ok_to_save_cache', 'yes'); 229 | info('✅ Success'); 230 | } catch (error) { 231 | const err = error instanceof Error ? error : new Error('An unknown error occurred', { cause: error }); 232 | setFailed(`❌ ${err.message}`); 233 | } 234 | } 235 | 236 | void run(); 237 | -------------------------------------------------------------------------------- /src/post.ts: -------------------------------------------------------------------------------- 1 | import { getState, info, warning } from '@actions/core'; 2 | import { saveCache } from '@actions/cache'; 3 | 4 | const tools = ['wordpress', 'wordpress-tests-lib']; 5 | 6 | async function run(): Promise { 7 | const ok = getState('ok_to_save_cache'); 8 | if (ok !== 'yes') { 9 | warning(`⚠️ Something went wrong, not saving cache`); 10 | return; 11 | } 12 | 13 | for (const tool of tools) { 14 | const dir = getState(`dir_${tool}`); 15 | const key = getState(`cache_key_${tool}`); 16 | 17 | if (dir && key) { 18 | info(`ℹ️ Saving ${tool} cache with the key of ${key}`); 19 | try { 20 | process.env.GITHUB_WORKSPACE = dir; 21 | process.chdir(dir); 22 | // eslint-disable-next-line no-await-in-loop 23 | await saveCache([tool], key); 24 | } catch (e) { 25 | warning(`⚠️ Failed to save cache for ${tool}: ${(e as Error).message}`); 26 | } 27 | } 28 | } 29 | } 30 | 31 | void run(); 32 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { stat } from 'node:fs/promises'; 2 | import { HttpClient } from '@actions/http-client'; 3 | 4 | /** 5 | * Sort an array of version strings in descending order. 6 | * 7 | * @param {string[]} versions -The array of version strings to sort. 8 | * @returns {string[]} The sorted array of version strings. 9 | */ 10 | export function sortVersions(versions: string[]): string[] { 11 | return versions.sort((a, b) => { 12 | const aSplit = a.split('.'); 13 | const bSplit = b.split('.'); 14 | for (let i = 0; i < Math.max(aSplit.length, bSplit.length); ++i) { 15 | const aPart = Number(aSplit[i] || '0'); 16 | const bPart = Number(bSplit[i] || '0'); 17 | if (aPart !== bPart) { 18 | return bPart - aPart; 19 | } 20 | } 21 | 22 | return 0; 23 | }); 24 | } 25 | 26 | /** 27 | * Check if a given path is a directory. 28 | * 29 | * @async 30 | * @param {string} path The path to check. 31 | * @returns {Promise} A promise that resolves to true if the path is a directory, false otherwise. 32 | */ 33 | export async function isDir(path: string): Promise { 34 | try { 35 | const stats = await stat(path); 36 | return stats.isDirectory(); 37 | } catch { 38 | return false; 39 | } 40 | } 41 | 42 | /** 43 | * Download the content of a URL as a text string. 44 | * 45 | * @async 46 | * @param {string} url The URL to download from. 47 | * @returns {Promise} A promise that resolves to the downloaded text. 48 | * @throws {Error} If the status code of the response is not 200. 49 | */ 50 | export async function downloadAsText(url: string): Promise { 51 | const client = new HttpClient('setup-wptl-action', undefined, { allowRetries: true, maxRetries: 3 }); 52 | const response = await client.get(url); 53 | if (response.message.statusCode === 200) { 54 | return response.readBody(); 55 | } 56 | 57 | throw new Error(`Failed to download ${url}: error ${response.message.statusCode}`); 58 | } 59 | 60 | /** 61 | * Check if the GitHub server URL is not 'github.com', indicating it's a GitHub Enterprise Server (GHES). 62 | * 63 | * @returns {boolean} True if the GitHub server URL is not 'github.com', false otherwise. 64 | */ 65 | export function isGHES(): boolean { 66 | const url = process.env.GITHUB_SERVER_URL; 67 | if (!url) { 68 | return false; 69 | } 70 | 71 | const ghUrl = new URL(url); 72 | return ghUrl.hostname.toLowerCase() !== 'github.com'; 73 | } 74 | -------------------------------------------------------------------------------- /src/wpapi.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@actions/http-client'; 2 | import { sortVersions } from './utils'; 3 | 4 | interface Package { 5 | full: string; 6 | no_content: string; 7 | new_bundled: string; 8 | partial: boolean; 9 | rollback: boolean; 10 | } 11 | 12 | interface Offer { 13 | response: string; 14 | download: string; 15 | locale: string; 16 | packages: Package; 17 | current: string; 18 | version: string; 19 | php_version: string; 20 | mysql_version: string; 21 | new_bundled: string; 22 | partial_version: boolean; 23 | new_files?: boolean; 24 | } 25 | 26 | interface ApiResponse { 27 | offers: Offer[]; 28 | translations: unknown[]; 29 | } 30 | 31 | /** 32 | * Get the latest WordPress version. 33 | * 34 | * @async 35 | * @returns {Promise} The latest WordPress version. 36 | */ 37 | export async function getLatestVersion(): Promise { 38 | const client = new HttpClient(); 39 | // eslint-disable-next-line sonarjs/no-clear-text-protocols -- http:// endpoint returns different results 40 | const json = await client.getJson('http://api.wordpress.org/core/version-check/1.7/'); 41 | if (json.statusCode === 200 && json.result) { 42 | return json.result.offers[0].version; 43 | } 44 | 45 | throw new Error(`Failed to fetch WordPress versions: error ${json.statusCode}`); 46 | } 47 | 48 | /** 49 | * Get the latest version of a branch. 50 | * 51 | * @async 52 | * @param {string} prefix The branch prefix. 53 | * @returns {Promise} The latest version of the branch. 54 | */ 55 | export async function getLatestBranchVersion(prefix: string): Promise { 56 | const client = new HttpClient(); 57 | const json = await client.getJson('https://api.wordpress.org/core/version-check/1.7/'); 58 | 59 | if (json.statusCode === 200 && json.result) { 60 | const candidates = json.result.offers 61 | .filter((offer) => offer.version.startsWith(prefix)) 62 | .map((offer) => offer.version); 63 | const sorted = sortVersions(candidates); 64 | return sorted[0]; 65 | } 66 | 67 | throw new Error(`Failed to fetch WordPress versions: error ${json.statusCode}`); 68 | } 69 | -------------------------------------------------------------------------------- /src/wputils.ts: -------------------------------------------------------------------------------- 1 | import { getLatestBranchVersion, getLatestVersion } from './wpapi'; 2 | 3 | const NIGHTLY_BUILD_URL = 'https://wordpress.org/nightly-builds/wordpress-latest.zip'; 4 | const WORDPRESS_URL = 'https://wordpress.org/wordpress-'; 5 | const SVN_URL = 'https://develop.svn.wordpress.org/'; 6 | 7 | /** 8 | * Resolve the WordPress version. 9 | * 10 | * @async 11 | * @param {string} version The version to resolve. 12 | * @returns {Promise} The resolved version. 13 | */ 14 | export function resolveWordPressVersion(version: string): Promise { 15 | if (version === 'nightly' || version === 'trunk') { 16 | return Promise.resolve('nightly'); 17 | } 18 | 19 | if (version === 'latest') { 20 | return getLatestVersion(); 21 | } 22 | 23 | if (version.endsWith('.x')) { 24 | return getLatestBranchVersion(version.slice(0, -2)); 25 | } 26 | 27 | return Promise.resolve(version); 28 | } 29 | 30 | /** 31 | * Get the WordPress download URL. 32 | * 33 | * @param {string} version The version to get the download URL for. 34 | * @returns {string} The download URL. 35 | */ 36 | export function getWordPressDownloadUrl(version: string): string { 37 | if (version === 'nightly') { 38 | return NIGHTLY_BUILD_URL; 39 | } 40 | 41 | return `${WORDPRESS_URL}${version}.zip`; 42 | } 43 | 44 | /** 45 | * Get the WordPress test library base URL. 46 | * 47 | * @param {string} version The version to get the test library base URL for. 48 | * @returns {string} The test library base URL. 49 | */ 50 | export function getWordPressTestLibraryBaseUrl(version: string): string { 51 | const tag = version === 'nightly' ? 'trunk' : `tags/${version}`; 52 | return `${SVN_URL}${tag}`; 53 | } 54 | -------------------------------------------------------------------------------- /test/mocks/wpapi.ts: -------------------------------------------------------------------------------- 1 | import '../../src/wpapi'; 2 | 3 | require.cache[require.resolve('../../src/wpapi')]!.exports = { 4 | getLatestVersion: (): Promise => Promise.resolve('9.9.9'), 5 | getLatestBranchVersion: (version: string): Promise => { 6 | switch (version) { 7 | case '5': 8 | return Promise.resolve('5.9.9'); 9 | case '5.5': 10 | return Promise.resolve('5.5.9'); 11 | default: 12 | return Promise.reject(new Error('This should not happen')); 13 | } 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /test/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'node:test'; 2 | import { deepEqual } from 'node:assert/strict'; 3 | import { sortVersions } from '../src/utils'; 4 | 5 | void describe('sortVersions', async () => { 6 | await it('should sort versions correctly', () => { 7 | const input = ['5.9.3', '5', '5.8', '5.9', '5.9.10', '5.9.2', '6']; 8 | const expected = ['6', '5.9.10', '5.9.3', '5.9.2', '5.9', '5.8', '5']; 9 | const actual = sortVersions(input); 10 | deepEqual(actual, expected); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /test/wputils.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | import './mocks/wpapi'; 3 | 4 | import { describe, it } from 'node:test'; 5 | import { equal } from 'node:assert/strict'; 6 | import { resolveWordPressVersion } from '../src/wputils'; 7 | 8 | void describe('resolveWordPressVersion', async () => { 9 | for (const [version, expected] of [ 10 | ['latest', '9.9.9'], 11 | ['5.x', '5.9.9'], 12 | ['5.5.x', '5.5.9'], 13 | ['5.9.9', '5.9.9'], 14 | ]) { 15 | await it(`should resolve ${version} to ${expected}`, async () => { 16 | const actual = await resolveWordPressVersion(version); 17 | equal(actual, expected); 18 | }); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "noEmitOnError": true, 7 | "outDir": "./lib", 8 | "sourceMap": false, 9 | "declaration": false, 10 | "removeComments": true, 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": false, 14 | "noFallthroughCasesInSwitch": true, 15 | "esModuleInterop": true, 16 | "resolveJsonModule": true 17 | }, 18 | "compileOnSave": true, 19 | "include": ["src/**.ts", "test/**.ts"] 20 | } 21 | -------------------------------------------------------------------------------- /wptest/.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.phpunit.result.cache 3 | -------------------------------------------------------------------------------- /wptest/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require-dev": { 3 | "yoast/phpunit-polyfills": "^4.0" 4 | }, 5 | "config": { 6 | "sort-packages": true, 7 | "platform": { 8 | "php": "8.0.27" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /wptest/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "42565525e16aa4ca2b40eefa66a28123", 8 | "packages": [], 9 | "packages-dev": [ 10 | { 11 | "name": "doctrine/instantiator", 12 | "version": "1.5.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/doctrine/instantiator.git", 16 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", 21 | "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": "^7.1 || ^8.0" 26 | }, 27 | "require-dev": { 28 | "doctrine/coding-standard": "^9 || ^11", 29 | "ext-pdo": "*", 30 | "ext-phar": "*", 31 | "phpbench/phpbench": "^0.16 || ^1", 32 | "phpstan/phpstan": "^1.4", 33 | "phpstan/phpstan-phpunit": "^1", 34 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", 35 | "vimeo/psalm": "^4.30 || ^5.4" 36 | }, 37 | "type": "library", 38 | "autoload": { 39 | "psr-4": { 40 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 41 | } 42 | }, 43 | "notification-url": "https://packagist.org/downloads/", 44 | "license": [ 45 | "MIT" 46 | ], 47 | "authors": [ 48 | { 49 | "name": "Marco Pivetta", 50 | "email": "ocramius@gmail.com", 51 | "homepage": "https://ocramius.github.io/" 52 | } 53 | ], 54 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 55 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 56 | "keywords": [ 57 | "constructor", 58 | "instantiate" 59 | ], 60 | "support": { 61 | "issues": "https://github.com/doctrine/instantiator/issues", 62 | "source": "https://github.com/doctrine/instantiator/tree/1.5.0" 63 | }, 64 | "funding": [ 65 | { 66 | "url": "https://www.doctrine-project.org/sponsorship.html", 67 | "type": "custom" 68 | }, 69 | { 70 | "url": "https://www.patreon.com/phpdoctrine", 71 | "type": "patreon" 72 | }, 73 | { 74 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 75 | "type": "tidelift" 76 | } 77 | ], 78 | "time": "2022-12-30T00:15:36+00:00" 79 | }, 80 | { 81 | "name": "myclabs/deep-copy", 82 | "version": "1.13.0", 83 | "source": { 84 | "type": "git", 85 | "url": "https://github.com/myclabs/DeepCopy.git", 86 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414" 87 | }, 88 | "dist": { 89 | "type": "zip", 90 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", 91 | "reference": "024473a478be9df5fdaca2c793f2232fe788e414", 92 | "shasum": "" 93 | }, 94 | "require": { 95 | "php": "^7.1 || ^8.0" 96 | }, 97 | "conflict": { 98 | "doctrine/collections": "<1.6.8", 99 | "doctrine/common": "<2.13.3 || >=3 <3.2.2" 100 | }, 101 | "require-dev": { 102 | "doctrine/collections": "^1.6.8", 103 | "doctrine/common": "^2.13.3 || ^3.2.2", 104 | "phpspec/prophecy": "^1.10", 105 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" 106 | }, 107 | "type": "library", 108 | "autoload": { 109 | "files": [ 110 | "src/DeepCopy/deep_copy.php" 111 | ], 112 | "psr-4": { 113 | "DeepCopy\\": "src/DeepCopy/" 114 | } 115 | }, 116 | "notification-url": "https://packagist.org/downloads/", 117 | "license": [ 118 | "MIT" 119 | ], 120 | "description": "Create deep copies (clones) of your objects", 121 | "keywords": [ 122 | "clone", 123 | "copy", 124 | "duplicate", 125 | "object", 126 | "object graph" 127 | ], 128 | "support": { 129 | "issues": "https://github.com/myclabs/DeepCopy/issues", 130 | "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" 131 | }, 132 | "funding": [ 133 | { 134 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", 135 | "type": "tidelift" 136 | } 137 | ], 138 | "time": "2025-02-12T12:17:51+00:00" 139 | }, 140 | { 141 | "name": "nikic/php-parser", 142 | "version": "v5.4.0", 143 | "source": { 144 | "type": "git", 145 | "url": "https://github.com/nikic/PHP-Parser.git", 146 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494" 147 | }, 148 | "dist": { 149 | "type": "zip", 150 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", 151 | "reference": "447a020a1f875a434d62f2a401f53b82a396e494", 152 | "shasum": "" 153 | }, 154 | "require": { 155 | "ext-ctype": "*", 156 | "ext-json": "*", 157 | "ext-tokenizer": "*", 158 | "php": ">=7.4" 159 | }, 160 | "require-dev": { 161 | "ircmaxell/php-yacc": "^0.0.7", 162 | "phpunit/phpunit": "^9.0" 163 | }, 164 | "bin": [ 165 | "bin/php-parse" 166 | ], 167 | "type": "library", 168 | "extra": { 169 | "branch-alias": { 170 | "dev-master": "5.0-dev" 171 | } 172 | }, 173 | "autoload": { 174 | "psr-4": { 175 | "PhpParser\\": "lib/PhpParser" 176 | } 177 | }, 178 | "notification-url": "https://packagist.org/downloads/", 179 | "license": [ 180 | "BSD-3-Clause" 181 | ], 182 | "authors": [ 183 | { 184 | "name": "Nikita Popov" 185 | } 186 | ], 187 | "description": "A PHP parser written in PHP", 188 | "keywords": [ 189 | "parser", 190 | "php" 191 | ], 192 | "support": { 193 | "issues": "https://github.com/nikic/PHP-Parser/issues", 194 | "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" 195 | }, 196 | "time": "2024-12-30T11:07:19+00:00" 197 | }, 198 | { 199 | "name": "phar-io/manifest", 200 | "version": "2.0.4", 201 | "source": { 202 | "type": "git", 203 | "url": "https://github.com/phar-io/manifest.git", 204 | "reference": "54750ef60c58e43759730615a392c31c80e23176" 205 | }, 206 | "dist": { 207 | "type": "zip", 208 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", 209 | "reference": "54750ef60c58e43759730615a392c31c80e23176", 210 | "shasum": "" 211 | }, 212 | "require": { 213 | "ext-dom": "*", 214 | "ext-libxml": "*", 215 | "ext-phar": "*", 216 | "ext-xmlwriter": "*", 217 | "phar-io/version": "^3.0.1", 218 | "php": "^7.2 || ^8.0" 219 | }, 220 | "type": "library", 221 | "extra": { 222 | "branch-alias": { 223 | "dev-master": "2.0.x-dev" 224 | } 225 | }, 226 | "autoload": { 227 | "classmap": [ 228 | "src/" 229 | ] 230 | }, 231 | "notification-url": "https://packagist.org/downloads/", 232 | "license": [ 233 | "BSD-3-Clause" 234 | ], 235 | "authors": [ 236 | { 237 | "name": "Arne Blankerts", 238 | "email": "arne@blankerts.de", 239 | "role": "Developer" 240 | }, 241 | { 242 | "name": "Sebastian Heuer", 243 | "email": "sebastian@phpeople.de", 244 | "role": "Developer" 245 | }, 246 | { 247 | "name": "Sebastian Bergmann", 248 | "email": "sebastian@phpunit.de", 249 | "role": "Developer" 250 | } 251 | ], 252 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", 253 | "support": { 254 | "issues": "https://github.com/phar-io/manifest/issues", 255 | "source": "https://github.com/phar-io/manifest/tree/2.0.4" 256 | }, 257 | "funding": [ 258 | { 259 | "url": "https://github.com/theseer", 260 | "type": "github" 261 | } 262 | ], 263 | "time": "2024-03-03T12:33:53+00:00" 264 | }, 265 | { 266 | "name": "phar-io/version", 267 | "version": "3.2.1", 268 | "source": { 269 | "type": "git", 270 | "url": "https://github.com/phar-io/version.git", 271 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" 272 | }, 273 | "dist": { 274 | "type": "zip", 275 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 276 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", 277 | "shasum": "" 278 | }, 279 | "require": { 280 | "php": "^7.2 || ^8.0" 281 | }, 282 | "type": "library", 283 | "autoload": { 284 | "classmap": [ 285 | "src/" 286 | ] 287 | }, 288 | "notification-url": "https://packagist.org/downloads/", 289 | "license": [ 290 | "BSD-3-Clause" 291 | ], 292 | "authors": [ 293 | { 294 | "name": "Arne Blankerts", 295 | "email": "arne@blankerts.de", 296 | "role": "Developer" 297 | }, 298 | { 299 | "name": "Sebastian Heuer", 300 | "email": "sebastian@phpeople.de", 301 | "role": "Developer" 302 | }, 303 | { 304 | "name": "Sebastian Bergmann", 305 | "email": "sebastian@phpunit.de", 306 | "role": "Developer" 307 | } 308 | ], 309 | "description": "Library for handling version information and constraints", 310 | "support": { 311 | "issues": "https://github.com/phar-io/version/issues", 312 | "source": "https://github.com/phar-io/version/tree/3.2.1" 313 | }, 314 | "time": "2022-02-21T01:04:05+00:00" 315 | }, 316 | { 317 | "name": "phpunit/php-code-coverage", 318 | "version": "9.2.32", 319 | "source": { 320 | "type": "git", 321 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 322 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" 323 | }, 324 | "dist": { 325 | "type": "zip", 326 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", 327 | "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", 328 | "shasum": "" 329 | }, 330 | "require": { 331 | "ext-dom": "*", 332 | "ext-libxml": "*", 333 | "ext-xmlwriter": "*", 334 | "nikic/php-parser": "^4.19.1 || ^5.1.0", 335 | "php": ">=7.3", 336 | "phpunit/php-file-iterator": "^3.0.6", 337 | "phpunit/php-text-template": "^2.0.4", 338 | "sebastian/code-unit-reverse-lookup": "^2.0.3", 339 | "sebastian/complexity": "^2.0.3", 340 | "sebastian/environment": "^5.1.5", 341 | "sebastian/lines-of-code": "^1.0.4", 342 | "sebastian/version": "^3.0.2", 343 | "theseer/tokenizer": "^1.2.3" 344 | }, 345 | "require-dev": { 346 | "phpunit/phpunit": "^9.6" 347 | }, 348 | "suggest": { 349 | "ext-pcov": "PHP extension that provides line coverage", 350 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 351 | }, 352 | "type": "library", 353 | "extra": { 354 | "branch-alias": { 355 | "dev-main": "9.2.x-dev" 356 | } 357 | }, 358 | "autoload": { 359 | "classmap": [ 360 | "src/" 361 | ] 362 | }, 363 | "notification-url": "https://packagist.org/downloads/", 364 | "license": [ 365 | "BSD-3-Clause" 366 | ], 367 | "authors": [ 368 | { 369 | "name": "Sebastian Bergmann", 370 | "email": "sebastian@phpunit.de", 371 | "role": "lead" 372 | } 373 | ], 374 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 375 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 376 | "keywords": [ 377 | "coverage", 378 | "testing", 379 | "xunit" 380 | ], 381 | "support": { 382 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", 383 | "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", 384 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" 385 | }, 386 | "funding": [ 387 | { 388 | "url": "https://github.com/sebastianbergmann", 389 | "type": "github" 390 | } 391 | ], 392 | "time": "2024-08-22T04:23:01+00:00" 393 | }, 394 | { 395 | "name": "phpunit/php-file-iterator", 396 | "version": "3.0.6", 397 | "source": { 398 | "type": "git", 399 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 400 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" 401 | }, 402 | "dist": { 403 | "type": "zip", 404 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 405 | "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", 406 | "shasum": "" 407 | }, 408 | "require": { 409 | "php": ">=7.3" 410 | }, 411 | "require-dev": { 412 | "phpunit/phpunit": "^9.3" 413 | }, 414 | "type": "library", 415 | "extra": { 416 | "branch-alias": { 417 | "dev-master": "3.0-dev" 418 | } 419 | }, 420 | "autoload": { 421 | "classmap": [ 422 | "src/" 423 | ] 424 | }, 425 | "notification-url": "https://packagist.org/downloads/", 426 | "license": [ 427 | "BSD-3-Clause" 428 | ], 429 | "authors": [ 430 | { 431 | "name": "Sebastian Bergmann", 432 | "email": "sebastian@phpunit.de", 433 | "role": "lead" 434 | } 435 | ], 436 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 437 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 438 | "keywords": [ 439 | "filesystem", 440 | "iterator" 441 | ], 442 | "support": { 443 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", 444 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" 445 | }, 446 | "funding": [ 447 | { 448 | "url": "https://github.com/sebastianbergmann", 449 | "type": "github" 450 | } 451 | ], 452 | "time": "2021-12-02T12:48:52+00:00" 453 | }, 454 | { 455 | "name": "phpunit/php-invoker", 456 | "version": "3.1.1", 457 | "source": { 458 | "type": "git", 459 | "url": "https://github.com/sebastianbergmann/php-invoker.git", 460 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" 461 | }, 462 | "dist": { 463 | "type": "zip", 464 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 465 | "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", 466 | "shasum": "" 467 | }, 468 | "require": { 469 | "php": ">=7.3" 470 | }, 471 | "require-dev": { 472 | "ext-pcntl": "*", 473 | "phpunit/phpunit": "^9.3" 474 | }, 475 | "suggest": { 476 | "ext-pcntl": "*" 477 | }, 478 | "type": "library", 479 | "extra": { 480 | "branch-alias": { 481 | "dev-master": "3.1-dev" 482 | } 483 | }, 484 | "autoload": { 485 | "classmap": [ 486 | "src/" 487 | ] 488 | }, 489 | "notification-url": "https://packagist.org/downloads/", 490 | "license": [ 491 | "BSD-3-Clause" 492 | ], 493 | "authors": [ 494 | { 495 | "name": "Sebastian Bergmann", 496 | "email": "sebastian@phpunit.de", 497 | "role": "lead" 498 | } 499 | ], 500 | "description": "Invoke callables with a timeout", 501 | "homepage": "https://github.com/sebastianbergmann/php-invoker/", 502 | "keywords": [ 503 | "process" 504 | ], 505 | "support": { 506 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues", 507 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" 508 | }, 509 | "funding": [ 510 | { 511 | "url": "https://github.com/sebastianbergmann", 512 | "type": "github" 513 | } 514 | ], 515 | "time": "2020-09-28T05:58:55+00:00" 516 | }, 517 | { 518 | "name": "phpunit/php-text-template", 519 | "version": "2.0.4", 520 | "source": { 521 | "type": "git", 522 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 523 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" 524 | }, 525 | "dist": { 526 | "type": "zip", 527 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 528 | "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", 529 | "shasum": "" 530 | }, 531 | "require": { 532 | "php": ">=7.3" 533 | }, 534 | "require-dev": { 535 | "phpunit/phpunit": "^9.3" 536 | }, 537 | "type": "library", 538 | "extra": { 539 | "branch-alias": { 540 | "dev-master": "2.0-dev" 541 | } 542 | }, 543 | "autoload": { 544 | "classmap": [ 545 | "src/" 546 | ] 547 | }, 548 | "notification-url": "https://packagist.org/downloads/", 549 | "license": [ 550 | "BSD-3-Clause" 551 | ], 552 | "authors": [ 553 | { 554 | "name": "Sebastian Bergmann", 555 | "email": "sebastian@phpunit.de", 556 | "role": "lead" 557 | } 558 | ], 559 | "description": "Simple template engine.", 560 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 561 | "keywords": [ 562 | "template" 563 | ], 564 | "support": { 565 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues", 566 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" 567 | }, 568 | "funding": [ 569 | { 570 | "url": "https://github.com/sebastianbergmann", 571 | "type": "github" 572 | } 573 | ], 574 | "time": "2020-10-26T05:33:50+00:00" 575 | }, 576 | { 577 | "name": "phpunit/php-timer", 578 | "version": "5.0.3", 579 | "source": { 580 | "type": "git", 581 | "url": "https://github.com/sebastianbergmann/php-timer.git", 582 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" 583 | }, 584 | "dist": { 585 | "type": "zip", 586 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 587 | "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", 588 | "shasum": "" 589 | }, 590 | "require": { 591 | "php": ">=7.3" 592 | }, 593 | "require-dev": { 594 | "phpunit/phpunit": "^9.3" 595 | }, 596 | "type": "library", 597 | "extra": { 598 | "branch-alias": { 599 | "dev-master": "5.0-dev" 600 | } 601 | }, 602 | "autoload": { 603 | "classmap": [ 604 | "src/" 605 | ] 606 | }, 607 | "notification-url": "https://packagist.org/downloads/", 608 | "license": [ 609 | "BSD-3-Clause" 610 | ], 611 | "authors": [ 612 | { 613 | "name": "Sebastian Bergmann", 614 | "email": "sebastian@phpunit.de", 615 | "role": "lead" 616 | } 617 | ], 618 | "description": "Utility class for timing", 619 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 620 | "keywords": [ 621 | "timer" 622 | ], 623 | "support": { 624 | "issues": "https://github.com/sebastianbergmann/php-timer/issues", 625 | "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" 626 | }, 627 | "funding": [ 628 | { 629 | "url": "https://github.com/sebastianbergmann", 630 | "type": "github" 631 | } 632 | ], 633 | "time": "2020-10-26T13:16:10+00:00" 634 | }, 635 | { 636 | "name": "phpunit/phpunit", 637 | "version": "9.6.22", 638 | "source": { 639 | "type": "git", 640 | "url": "https://github.com/sebastianbergmann/phpunit.git", 641 | "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" 642 | }, 643 | "dist": { 644 | "type": "zip", 645 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", 646 | "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", 647 | "shasum": "" 648 | }, 649 | "require": { 650 | "doctrine/instantiator": "^1.5.0 || ^2", 651 | "ext-dom": "*", 652 | "ext-json": "*", 653 | "ext-libxml": "*", 654 | "ext-mbstring": "*", 655 | "ext-xml": "*", 656 | "ext-xmlwriter": "*", 657 | "myclabs/deep-copy": "^1.12.1", 658 | "phar-io/manifest": "^2.0.4", 659 | "phar-io/version": "^3.2.1", 660 | "php": ">=7.3", 661 | "phpunit/php-code-coverage": "^9.2.32", 662 | "phpunit/php-file-iterator": "^3.0.6", 663 | "phpunit/php-invoker": "^3.1.1", 664 | "phpunit/php-text-template": "^2.0.4", 665 | "phpunit/php-timer": "^5.0.3", 666 | "sebastian/cli-parser": "^1.0.2", 667 | "sebastian/code-unit": "^1.0.8", 668 | "sebastian/comparator": "^4.0.8", 669 | "sebastian/diff": "^4.0.6", 670 | "sebastian/environment": "^5.1.5", 671 | "sebastian/exporter": "^4.0.6", 672 | "sebastian/global-state": "^5.0.7", 673 | "sebastian/object-enumerator": "^4.0.4", 674 | "sebastian/resource-operations": "^3.0.4", 675 | "sebastian/type": "^3.2.1", 676 | "sebastian/version": "^3.0.2" 677 | }, 678 | "suggest": { 679 | "ext-soap": "To be able to generate mocks based on WSDL files", 680 | "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" 681 | }, 682 | "bin": [ 683 | "phpunit" 684 | ], 685 | "type": "library", 686 | "extra": { 687 | "branch-alias": { 688 | "dev-master": "9.6-dev" 689 | } 690 | }, 691 | "autoload": { 692 | "files": [ 693 | "src/Framework/Assert/Functions.php" 694 | ], 695 | "classmap": [ 696 | "src/" 697 | ] 698 | }, 699 | "notification-url": "https://packagist.org/downloads/", 700 | "license": [ 701 | "BSD-3-Clause" 702 | ], 703 | "authors": [ 704 | { 705 | "name": "Sebastian Bergmann", 706 | "email": "sebastian@phpunit.de", 707 | "role": "lead" 708 | } 709 | ], 710 | "description": "The PHP Unit Testing framework.", 711 | "homepage": "https://phpunit.de/", 712 | "keywords": [ 713 | "phpunit", 714 | "testing", 715 | "xunit" 716 | ], 717 | "support": { 718 | "issues": "https://github.com/sebastianbergmann/phpunit/issues", 719 | "security": "https://github.com/sebastianbergmann/phpunit/security/policy", 720 | "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22" 721 | }, 722 | "funding": [ 723 | { 724 | "url": "https://phpunit.de/sponsors.html", 725 | "type": "custom" 726 | }, 727 | { 728 | "url": "https://github.com/sebastianbergmann", 729 | "type": "github" 730 | }, 731 | { 732 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", 733 | "type": "tidelift" 734 | } 735 | ], 736 | "time": "2024-12-05T13:48:26+00:00" 737 | }, 738 | { 739 | "name": "sebastian/cli-parser", 740 | "version": "1.0.2", 741 | "source": { 742 | "type": "git", 743 | "url": "https://github.com/sebastianbergmann/cli-parser.git", 744 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" 745 | }, 746 | "dist": { 747 | "type": "zip", 748 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", 749 | "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", 750 | "shasum": "" 751 | }, 752 | "require": { 753 | "php": ">=7.3" 754 | }, 755 | "require-dev": { 756 | "phpunit/phpunit": "^9.3" 757 | }, 758 | "type": "library", 759 | "extra": { 760 | "branch-alias": { 761 | "dev-master": "1.0-dev" 762 | } 763 | }, 764 | "autoload": { 765 | "classmap": [ 766 | "src/" 767 | ] 768 | }, 769 | "notification-url": "https://packagist.org/downloads/", 770 | "license": [ 771 | "BSD-3-Clause" 772 | ], 773 | "authors": [ 774 | { 775 | "name": "Sebastian Bergmann", 776 | "email": "sebastian@phpunit.de", 777 | "role": "lead" 778 | } 779 | ], 780 | "description": "Library for parsing CLI options", 781 | "homepage": "https://github.com/sebastianbergmann/cli-parser", 782 | "support": { 783 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues", 784 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" 785 | }, 786 | "funding": [ 787 | { 788 | "url": "https://github.com/sebastianbergmann", 789 | "type": "github" 790 | } 791 | ], 792 | "time": "2024-03-02T06:27:43+00:00" 793 | }, 794 | { 795 | "name": "sebastian/code-unit", 796 | "version": "1.0.8", 797 | "source": { 798 | "type": "git", 799 | "url": "https://github.com/sebastianbergmann/code-unit.git", 800 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" 801 | }, 802 | "dist": { 803 | "type": "zip", 804 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", 805 | "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", 806 | "shasum": "" 807 | }, 808 | "require": { 809 | "php": ">=7.3" 810 | }, 811 | "require-dev": { 812 | "phpunit/phpunit": "^9.3" 813 | }, 814 | "type": "library", 815 | "extra": { 816 | "branch-alias": { 817 | "dev-master": "1.0-dev" 818 | } 819 | }, 820 | "autoload": { 821 | "classmap": [ 822 | "src/" 823 | ] 824 | }, 825 | "notification-url": "https://packagist.org/downloads/", 826 | "license": [ 827 | "BSD-3-Clause" 828 | ], 829 | "authors": [ 830 | { 831 | "name": "Sebastian Bergmann", 832 | "email": "sebastian@phpunit.de", 833 | "role": "lead" 834 | } 835 | ], 836 | "description": "Collection of value objects that represent the PHP code units", 837 | "homepage": "https://github.com/sebastianbergmann/code-unit", 838 | "support": { 839 | "issues": "https://github.com/sebastianbergmann/code-unit/issues", 840 | "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" 841 | }, 842 | "funding": [ 843 | { 844 | "url": "https://github.com/sebastianbergmann", 845 | "type": "github" 846 | } 847 | ], 848 | "time": "2020-10-26T13:08:54+00:00" 849 | }, 850 | { 851 | "name": "sebastian/code-unit-reverse-lookup", 852 | "version": "2.0.3", 853 | "source": { 854 | "type": "git", 855 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", 856 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" 857 | }, 858 | "dist": { 859 | "type": "zip", 860 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 861 | "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", 862 | "shasum": "" 863 | }, 864 | "require": { 865 | "php": ">=7.3" 866 | }, 867 | "require-dev": { 868 | "phpunit/phpunit": "^9.3" 869 | }, 870 | "type": "library", 871 | "extra": { 872 | "branch-alias": { 873 | "dev-master": "2.0-dev" 874 | } 875 | }, 876 | "autoload": { 877 | "classmap": [ 878 | "src/" 879 | ] 880 | }, 881 | "notification-url": "https://packagist.org/downloads/", 882 | "license": [ 883 | "BSD-3-Clause" 884 | ], 885 | "authors": [ 886 | { 887 | "name": "Sebastian Bergmann", 888 | "email": "sebastian@phpunit.de" 889 | } 890 | ], 891 | "description": "Looks up which function or method a line of code belongs to", 892 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", 893 | "support": { 894 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", 895 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" 896 | }, 897 | "funding": [ 898 | { 899 | "url": "https://github.com/sebastianbergmann", 900 | "type": "github" 901 | } 902 | ], 903 | "time": "2020-09-28T05:30:19+00:00" 904 | }, 905 | { 906 | "name": "sebastian/comparator", 907 | "version": "4.0.8", 908 | "source": { 909 | "type": "git", 910 | "url": "https://github.com/sebastianbergmann/comparator.git", 911 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a" 912 | }, 913 | "dist": { 914 | "type": "zip", 915 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", 916 | "reference": "fa0f136dd2334583309d32b62544682ee972b51a", 917 | "shasum": "" 918 | }, 919 | "require": { 920 | "php": ">=7.3", 921 | "sebastian/diff": "^4.0", 922 | "sebastian/exporter": "^4.0" 923 | }, 924 | "require-dev": { 925 | "phpunit/phpunit": "^9.3" 926 | }, 927 | "type": "library", 928 | "extra": { 929 | "branch-alias": { 930 | "dev-master": "4.0-dev" 931 | } 932 | }, 933 | "autoload": { 934 | "classmap": [ 935 | "src/" 936 | ] 937 | }, 938 | "notification-url": "https://packagist.org/downloads/", 939 | "license": [ 940 | "BSD-3-Clause" 941 | ], 942 | "authors": [ 943 | { 944 | "name": "Sebastian Bergmann", 945 | "email": "sebastian@phpunit.de" 946 | }, 947 | { 948 | "name": "Jeff Welch", 949 | "email": "whatthejeff@gmail.com" 950 | }, 951 | { 952 | "name": "Volker Dusch", 953 | "email": "github@wallbash.com" 954 | }, 955 | { 956 | "name": "Bernhard Schussek", 957 | "email": "bschussek@2bepublished.at" 958 | } 959 | ], 960 | "description": "Provides the functionality to compare PHP values for equality", 961 | "homepage": "https://github.com/sebastianbergmann/comparator", 962 | "keywords": [ 963 | "comparator", 964 | "compare", 965 | "equality" 966 | ], 967 | "support": { 968 | "issues": "https://github.com/sebastianbergmann/comparator/issues", 969 | "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" 970 | }, 971 | "funding": [ 972 | { 973 | "url": "https://github.com/sebastianbergmann", 974 | "type": "github" 975 | } 976 | ], 977 | "time": "2022-09-14T12:41:17+00:00" 978 | }, 979 | { 980 | "name": "sebastian/complexity", 981 | "version": "2.0.3", 982 | "source": { 983 | "type": "git", 984 | "url": "https://github.com/sebastianbergmann/complexity.git", 985 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" 986 | }, 987 | "dist": { 988 | "type": "zip", 989 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", 990 | "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", 991 | "shasum": "" 992 | }, 993 | "require": { 994 | "nikic/php-parser": "^4.18 || ^5.0", 995 | "php": ">=7.3" 996 | }, 997 | "require-dev": { 998 | "phpunit/phpunit": "^9.3" 999 | }, 1000 | "type": "library", 1001 | "extra": { 1002 | "branch-alias": { 1003 | "dev-master": "2.0-dev" 1004 | } 1005 | }, 1006 | "autoload": { 1007 | "classmap": [ 1008 | "src/" 1009 | ] 1010 | }, 1011 | "notification-url": "https://packagist.org/downloads/", 1012 | "license": [ 1013 | "BSD-3-Clause" 1014 | ], 1015 | "authors": [ 1016 | { 1017 | "name": "Sebastian Bergmann", 1018 | "email": "sebastian@phpunit.de", 1019 | "role": "lead" 1020 | } 1021 | ], 1022 | "description": "Library for calculating the complexity of PHP code units", 1023 | "homepage": "https://github.com/sebastianbergmann/complexity", 1024 | "support": { 1025 | "issues": "https://github.com/sebastianbergmann/complexity/issues", 1026 | "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" 1027 | }, 1028 | "funding": [ 1029 | { 1030 | "url": "https://github.com/sebastianbergmann", 1031 | "type": "github" 1032 | } 1033 | ], 1034 | "time": "2023-12-22T06:19:30+00:00" 1035 | }, 1036 | { 1037 | "name": "sebastian/diff", 1038 | "version": "4.0.6", 1039 | "source": { 1040 | "type": "git", 1041 | "url": "https://github.com/sebastianbergmann/diff.git", 1042 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" 1043 | }, 1044 | "dist": { 1045 | "type": "zip", 1046 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", 1047 | "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", 1048 | "shasum": "" 1049 | }, 1050 | "require": { 1051 | "php": ">=7.3" 1052 | }, 1053 | "require-dev": { 1054 | "phpunit/phpunit": "^9.3", 1055 | "symfony/process": "^4.2 || ^5" 1056 | }, 1057 | "type": "library", 1058 | "extra": { 1059 | "branch-alias": { 1060 | "dev-master": "4.0-dev" 1061 | } 1062 | }, 1063 | "autoload": { 1064 | "classmap": [ 1065 | "src/" 1066 | ] 1067 | }, 1068 | "notification-url": "https://packagist.org/downloads/", 1069 | "license": [ 1070 | "BSD-3-Clause" 1071 | ], 1072 | "authors": [ 1073 | { 1074 | "name": "Sebastian Bergmann", 1075 | "email": "sebastian@phpunit.de" 1076 | }, 1077 | { 1078 | "name": "Kore Nordmann", 1079 | "email": "mail@kore-nordmann.de" 1080 | } 1081 | ], 1082 | "description": "Diff implementation", 1083 | "homepage": "https://github.com/sebastianbergmann/diff", 1084 | "keywords": [ 1085 | "diff", 1086 | "udiff", 1087 | "unidiff", 1088 | "unified diff" 1089 | ], 1090 | "support": { 1091 | "issues": "https://github.com/sebastianbergmann/diff/issues", 1092 | "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" 1093 | }, 1094 | "funding": [ 1095 | { 1096 | "url": "https://github.com/sebastianbergmann", 1097 | "type": "github" 1098 | } 1099 | ], 1100 | "time": "2024-03-02T06:30:58+00:00" 1101 | }, 1102 | { 1103 | "name": "sebastian/environment", 1104 | "version": "5.1.5", 1105 | "source": { 1106 | "type": "git", 1107 | "url": "https://github.com/sebastianbergmann/environment.git", 1108 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" 1109 | }, 1110 | "dist": { 1111 | "type": "zip", 1112 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 1113 | "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", 1114 | "shasum": "" 1115 | }, 1116 | "require": { 1117 | "php": ">=7.3" 1118 | }, 1119 | "require-dev": { 1120 | "phpunit/phpunit": "^9.3" 1121 | }, 1122 | "suggest": { 1123 | "ext-posix": "*" 1124 | }, 1125 | "type": "library", 1126 | "extra": { 1127 | "branch-alias": { 1128 | "dev-master": "5.1-dev" 1129 | } 1130 | }, 1131 | "autoload": { 1132 | "classmap": [ 1133 | "src/" 1134 | ] 1135 | }, 1136 | "notification-url": "https://packagist.org/downloads/", 1137 | "license": [ 1138 | "BSD-3-Clause" 1139 | ], 1140 | "authors": [ 1141 | { 1142 | "name": "Sebastian Bergmann", 1143 | "email": "sebastian@phpunit.de" 1144 | } 1145 | ], 1146 | "description": "Provides functionality to handle HHVM/PHP environments", 1147 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1148 | "keywords": [ 1149 | "Xdebug", 1150 | "environment", 1151 | "hhvm" 1152 | ], 1153 | "support": { 1154 | "issues": "https://github.com/sebastianbergmann/environment/issues", 1155 | "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" 1156 | }, 1157 | "funding": [ 1158 | { 1159 | "url": "https://github.com/sebastianbergmann", 1160 | "type": "github" 1161 | } 1162 | ], 1163 | "time": "2023-02-03T06:03:51+00:00" 1164 | }, 1165 | { 1166 | "name": "sebastian/exporter", 1167 | "version": "4.0.6", 1168 | "source": { 1169 | "type": "git", 1170 | "url": "https://github.com/sebastianbergmann/exporter.git", 1171 | "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" 1172 | }, 1173 | "dist": { 1174 | "type": "zip", 1175 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", 1176 | "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", 1177 | "shasum": "" 1178 | }, 1179 | "require": { 1180 | "php": ">=7.3", 1181 | "sebastian/recursion-context": "^4.0" 1182 | }, 1183 | "require-dev": { 1184 | "ext-mbstring": "*", 1185 | "phpunit/phpunit": "^9.3" 1186 | }, 1187 | "type": "library", 1188 | "extra": { 1189 | "branch-alias": { 1190 | "dev-master": "4.0-dev" 1191 | } 1192 | }, 1193 | "autoload": { 1194 | "classmap": [ 1195 | "src/" 1196 | ] 1197 | }, 1198 | "notification-url": "https://packagist.org/downloads/", 1199 | "license": [ 1200 | "BSD-3-Clause" 1201 | ], 1202 | "authors": [ 1203 | { 1204 | "name": "Sebastian Bergmann", 1205 | "email": "sebastian@phpunit.de" 1206 | }, 1207 | { 1208 | "name": "Jeff Welch", 1209 | "email": "whatthejeff@gmail.com" 1210 | }, 1211 | { 1212 | "name": "Volker Dusch", 1213 | "email": "github@wallbash.com" 1214 | }, 1215 | { 1216 | "name": "Adam Harvey", 1217 | "email": "aharvey@php.net" 1218 | }, 1219 | { 1220 | "name": "Bernhard Schussek", 1221 | "email": "bschussek@gmail.com" 1222 | } 1223 | ], 1224 | "description": "Provides the functionality to export PHP variables for visualization", 1225 | "homepage": "https://www.github.com/sebastianbergmann/exporter", 1226 | "keywords": [ 1227 | "export", 1228 | "exporter" 1229 | ], 1230 | "support": { 1231 | "issues": "https://github.com/sebastianbergmann/exporter/issues", 1232 | "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" 1233 | }, 1234 | "funding": [ 1235 | { 1236 | "url": "https://github.com/sebastianbergmann", 1237 | "type": "github" 1238 | } 1239 | ], 1240 | "time": "2024-03-02T06:33:00+00:00" 1241 | }, 1242 | { 1243 | "name": "sebastian/global-state", 1244 | "version": "5.0.7", 1245 | "source": { 1246 | "type": "git", 1247 | "url": "https://github.com/sebastianbergmann/global-state.git", 1248 | "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" 1249 | }, 1250 | "dist": { 1251 | "type": "zip", 1252 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", 1253 | "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", 1254 | "shasum": "" 1255 | }, 1256 | "require": { 1257 | "php": ">=7.3", 1258 | "sebastian/object-reflector": "^2.0", 1259 | "sebastian/recursion-context": "^4.0" 1260 | }, 1261 | "require-dev": { 1262 | "ext-dom": "*", 1263 | "phpunit/phpunit": "^9.3" 1264 | }, 1265 | "suggest": { 1266 | "ext-uopz": "*" 1267 | }, 1268 | "type": "library", 1269 | "extra": { 1270 | "branch-alias": { 1271 | "dev-master": "5.0-dev" 1272 | } 1273 | }, 1274 | "autoload": { 1275 | "classmap": [ 1276 | "src/" 1277 | ] 1278 | }, 1279 | "notification-url": "https://packagist.org/downloads/", 1280 | "license": [ 1281 | "BSD-3-Clause" 1282 | ], 1283 | "authors": [ 1284 | { 1285 | "name": "Sebastian Bergmann", 1286 | "email": "sebastian@phpunit.de" 1287 | } 1288 | ], 1289 | "description": "Snapshotting of global state", 1290 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1291 | "keywords": [ 1292 | "global state" 1293 | ], 1294 | "support": { 1295 | "issues": "https://github.com/sebastianbergmann/global-state/issues", 1296 | "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" 1297 | }, 1298 | "funding": [ 1299 | { 1300 | "url": "https://github.com/sebastianbergmann", 1301 | "type": "github" 1302 | } 1303 | ], 1304 | "time": "2024-03-02T06:35:11+00:00" 1305 | }, 1306 | { 1307 | "name": "sebastian/lines-of-code", 1308 | "version": "1.0.4", 1309 | "source": { 1310 | "type": "git", 1311 | "url": "https://github.com/sebastianbergmann/lines-of-code.git", 1312 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" 1313 | }, 1314 | "dist": { 1315 | "type": "zip", 1316 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", 1317 | "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", 1318 | "shasum": "" 1319 | }, 1320 | "require": { 1321 | "nikic/php-parser": "^4.18 || ^5.0", 1322 | "php": ">=7.3" 1323 | }, 1324 | "require-dev": { 1325 | "phpunit/phpunit": "^9.3" 1326 | }, 1327 | "type": "library", 1328 | "extra": { 1329 | "branch-alias": { 1330 | "dev-master": "1.0-dev" 1331 | } 1332 | }, 1333 | "autoload": { 1334 | "classmap": [ 1335 | "src/" 1336 | ] 1337 | }, 1338 | "notification-url": "https://packagist.org/downloads/", 1339 | "license": [ 1340 | "BSD-3-Clause" 1341 | ], 1342 | "authors": [ 1343 | { 1344 | "name": "Sebastian Bergmann", 1345 | "email": "sebastian@phpunit.de", 1346 | "role": "lead" 1347 | } 1348 | ], 1349 | "description": "Library for counting the lines of code in PHP source code", 1350 | "homepage": "https://github.com/sebastianbergmann/lines-of-code", 1351 | "support": { 1352 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", 1353 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" 1354 | }, 1355 | "funding": [ 1356 | { 1357 | "url": "https://github.com/sebastianbergmann", 1358 | "type": "github" 1359 | } 1360 | ], 1361 | "time": "2023-12-22T06:20:34+00:00" 1362 | }, 1363 | { 1364 | "name": "sebastian/object-enumerator", 1365 | "version": "4.0.4", 1366 | "source": { 1367 | "type": "git", 1368 | "url": "https://github.com/sebastianbergmann/object-enumerator.git", 1369 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" 1370 | }, 1371 | "dist": { 1372 | "type": "zip", 1373 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", 1374 | "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", 1375 | "shasum": "" 1376 | }, 1377 | "require": { 1378 | "php": ">=7.3", 1379 | "sebastian/object-reflector": "^2.0", 1380 | "sebastian/recursion-context": "^4.0" 1381 | }, 1382 | "require-dev": { 1383 | "phpunit/phpunit": "^9.3" 1384 | }, 1385 | "type": "library", 1386 | "extra": { 1387 | "branch-alias": { 1388 | "dev-master": "4.0-dev" 1389 | } 1390 | }, 1391 | "autoload": { 1392 | "classmap": [ 1393 | "src/" 1394 | ] 1395 | }, 1396 | "notification-url": "https://packagist.org/downloads/", 1397 | "license": [ 1398 | "BSD-3-Clause" 1399 | ], 1400 | "authors": [ 1401 | { 1402 | "name": "Sebastian Bergmann", 1403 | "email": "sebastian@phpunit.de" 1404 | } 1405 | ], 1406 | "description": "Traverses array structures and object graphs to enumerate all referenced objects", 1407 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/", 1408 | "support": { 1409 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", 1410 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" 1411 | }, 1412 | "funding": [ 1413 | { 1414 | "url": "https://github.com/sebastianbergmann", 1415 | "type": "github" 1416 | } 1417 | ], 1418 | "time": "2020-10-26T13:12:34+00:00" 1419 | }, 1420 | { 1421 | "name": "sebastian/object-reflector", 1422 | "version": "2.0.4", 1423 | "source": { 1424 | "type": "git", 1425 | "url": "https://github.com/sebastianbergmann/object-reflector.git", 1426 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" 1427 | }, 1428 | "dist": { 1429 | "type": "zip", 1430 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1431 | "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", 1432 | "shasum": "" 1433 | }, 1434 | "require": { 1435 | "php": ">=7.3" 1436 | }, 1437 | "require-dev": { 1438 | "phpunit/phpunit": "^9.3" 1439 | }, 1440 | "type": "library", 1441 | "extra": { 1442 | "branch-alias": { 1443 | "dev-master": "2.0-dev" 1444 | } 1445 | }, 1446 | "autoload": { 1447 | "classmap": [ 1448 | "src/" 1449 | ] 1450 | }, 1451 | "notification-url": "https://packagist.org/downloads/", 1452 | "license": [ 1453 | "BSD-3-Clause" 1454 | ], 1455 | "authors": [ 1456 | { 1457 | "name": "Sebastian Bergmann", 1458 | "email": "sebastian@phpunit.de" 1459 | } 1460 | ], 1461 | "description": "Allows reflection of object attributes, including inherited and non-public ones", 1462 | "homepage": "https://github.com/sebastianbergmann/object-reflector/", 1463 | "support": { 1464 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues", 1465 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" 1466 | }, 1467 | "funding": [ 1468 | { 1469 | "url": "https://github.com/sebastianbergmann", 1470 | "type": "github" 1471 | } 1472 | ], 1473 | "time": "2020-10-26T13:14:26+00:00" 1474 | }, 1475 | { 1476 | "name": "sebastian/recursion-context", 1477 | "version": "4.0.5", 1478 | "source": { 1479 | "type": "git", 1480 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1481 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" 1482 | }, 1483 | "dist": { 1484 | "type": "zip", 1485 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 1486 | "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", 1487 | "shasum": "" 1488 | }, 1489 | "require": { 1490 | "php": ">=7.3" 1491 | }, 1492 | "require-dev": { 1493 | "phpunit/phpunit": "^9.3" 1494 | }, 1495 | "type": "library", 1496 | "extra": { 1497 | "branch-alias": { 1498 | "dev-master": "4.0-dev" 1499 | } 1500 | }, 1501 | "autoload": { 1502 | "classmap": [ 1503 | "src/" 1504 | ] 1505 | }, 1506 | "notification-url": "https://packagist.org/downloads/", 1507 | "license": [ 1508 | "BSD-3-Clause" 1509 | ], 1510 | "authors": [ 1511 | { 1512 | "name": "Sebastian Bergmann", 1513 | "email": "sebastian@phpunit.de" 1514 | }, 1515 | { 1516 | "name": "Jeff Welch", 1517 | "email": "whatthejeff@gmail.com" 1518 | }, 1519 | { 1520 | "name": "Adam Harvey", 1521 | "email": "aharvey@php.net" 1522 | } 1523 | ], 1524 | "description": "Provides functionality to recursively process PHP variables", 1525 | "homepage": "https://github.com/sebastianbergmann/recursion-context", 1526 | "support": { 1527 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues", 1528 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" 1529 | }, 1530 | "funding": [ 1531 | { 1532 | "url": "https://github.com/sebastianbergmann", 1533 | "type": "github" 1534 | } 1535 | ], 1536 | "time": "2023-02-03T06:07:39+00:00" 1537 | }, 1538 | { 1539 | "name": "sebastian/resource-operations", 1540 | "version": "3.0.4", 1541 | "source": { 1542 | "type": "git", 1543 | "url": "https://github.com/sebastianbergmann/resource-operations.git", 1544 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" 1545 | }, 1546 | "dist": { 1547 | "type": "zip", 1548 | "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", 1549 | "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", 1550 | "shasum": "" 1551 | }, 1552 | "require": { 1553 | "php": ">=7.3" 1554 | }, 1555 | "require-dev": { 1556 | "phpunit/phpunit": "^9.0" 1557 | }, 1558 | "type": "library", 1559 | "extra": { 1560 | "branch-alias": { 1561 | "dev-main": "3.0-dev" 1562 | } 1563 | }, 1564 | "autoload": { 1565 | "classmap": [ 1566 | "src/" 1567 | ] 1568 | }, 1569 | "notification-url": "https://packagist.org/downloads/", 1570 | "license": [ 1571 | "BSD-3-Clause" 1572 | ], 1573 | "authors": [ 1574 | { 1575 | "name": "Sebastian Bergmann", 1576 | "email": "sebastian@phpunit.de" 1577 | } 1578 | ], 1579 | "description": "Provides a list of PHP built-in functions that operate on resources", 1580 | "homepage": "https://www.github.com/sebastianbergmann/resource-operations", 1581 | "support": { 1582 | "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" 1583 | }, 1584 | "funding": [ 1585 | { 1586 | "url": "https://github.com/sebastianbergmann", 1587 | "type": "github" 1588 | } 1589 | ], 1590 | "time": "2024-03-14T16:00:52+00:00" 1591 | }, 1592 | { 1593 | "name": "sebastian/type", 1594 | "version": "3.2.1", 1595 | "source": { 1596 | "type": "git", 1597 | "url": "https://github.com/sebastianbergmann/type.git", 1598 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" 1599 | }, 1600 | "dist": { 1601 | "type": "zip", 1602 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 1603 | "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", 1604 | "shasum": "" 1605 | }, 1606 | "require": { 1607 | "php": ">=7.3" 1608 | }, 1609 | "require-dev": { 1610 | "phpunit/phpunit": "^9.5" 1611 | }, 1612 | "type": "library", 1613 | "extra": { 1614 | "branch-alias": { 1615 | "dev-master": "3.2-dev" 1616 | } 1617 | }, 1618 | "autoload": { 1619 | "classmap": [ 1620 | "src/" 1621 | ] 1622 | }, 1623 | "notification-url": "https://packagist.org/downloads/", 1624 | "license": [ 1625 | "BSD-3-Clause" 1626 | ], 1627 | "authors": [ 1628 | { 1629 | "name": "Sebastian Bergmann", 1630 | "email": "sebastian@phpunit.de", 1631 | "role": "lead" 1632 | } 1633 | ], 1634 | "description": "Collection of value objects that represent the types of the PHP type system", 1635 | "homepage": "https://github.com/sebastianbergmann/type", 1636 | "support": { 1637 | "issues": "https://github.com/sebastianbergmann/type/issues", 1638 | "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" 1639 | }, 1640 | "funding": [ 1641 | { 1642 | "url": "https://github.com/sebastianbergmann", 1643 | "type": "github" 1644 | } 1645 | ], 1646 | "time": "2023-02-03T06:13:03+00:00" 1647 | }, 1648 | { 1649 | "name": "sebastian/version", 1650 | "version": "3.0.2", 1651 | "source": { 1652 | "type": "git", 1653 | "url": "https://github.com/sebastianbergmann/version.git", 1654 | "reference": "c6c1022351a901512170118436c764e473f6de8c" 1655 | }, 1656 | "dist": { 1657 | "type": "zip", 1658 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", 1659 | "reference": "c6c1022351a901512170118436c764e473f6de8c", 1660 | "shasum": "" 1661 | }, 1662 | "require": { 1663 | "php": ">=7.3" 1664 | }, 1665 | "type": "library", 1666 | "extra": { 1667 | "branch-alias": { 1668 | "dev-master": "3.0-dev" 1669 | } 1670 | }, 1671 | "autoload": { 1672 | "classmap": [ 1673 | "src/" 1674 | ] 1675 | }, 1676 | "notification-url": "https://packagist.org/downloads/", 1677 | "license": [ 1678 | "BSD-3-Clause" 1679 | ], 1680 | "authors": [ 1681 | { 1682 | "name": "Sebastian Bergmann", 1683 | "email": "sebastian@phpunit.de", 1684 | "role": "lead" 1685 | } 1686 | ], 1687 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1688 | "homepage": "https://github.com/sebastianbergmann/version", 1689 | "support": { 1690 | "issues": "https://github.com/sebastianbergmann/version/issues", 1691 | "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" 1692 | }, 1693 | "funding": [ 1694 | { 1695 | "url": "https://github.com/sebastianbergmann", 1696 | "type": "github" 1697 | } 1698 | ], 1699 | "time": "2020-09-28T06:39:44+00:00" 1700 | }, 1701 | { 1702 | "name": "theseer/tokenizer", 1703 | "version": "1.2.3", 1704 | "source": { 1705 | "type": "git", 1706 | "url": "https://github.com/theseer/tokenizer.git", 1707 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" 1708 | }, 1709 | "dist": { 1710 | "type": "zip", 1711 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", 1712 | "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", 1713 | "shasum": "" 1714 | }, 1715 | "require": { 1716 | "ext-dom": "*", 1717 | "ext-tokenizer": "*", 1718 | "ext-xmlwriter": "*", 1719 | "php": "^7.2 || ^8.0" 1720 | }, 1721 | "type": "library", 1722 | "autoload": { 1723 | "classmap": [ 1724 | "src/" 1725 | ] 1726 | }, 1727 | "notification-url": "https://packagist.org/downloads/", 1728 | "license": [ 1729 | "BSD-3-Clause" 1730 | ], 1731 | "authors": [ 1732 | { 1733 | "name": "Arne Blankerts", 1734 | "email": "arne@blankerts.de", 1735 | "role": "Developer" 1736 | } 1737 | ], 1738 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", 1739 | "support": { 1740 | "issues": "https://github.com/theseer/tokenizer/issues", 1741 | "source": "https://github.com/theseer/tokenizer/tree/1.2.3" 1742 | }, 1743 | "funding": [ 1744 | { 1745 | "url": "https://github.com/theseer", 1746 | "type": "github" 1747 | } 1748 | ], 1749 | "time": "2024-03-03T12:36:25+00:00" 1750 | }, 1751 | { 1752 | "name": "yoast/phpunit-polyfills", 1753 | "version": "4.0.0", 1754 | "source": { 1755 | "type": "git", 1756 | "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", 1757 | "reference": "134921bfca9b02d8f374c48381451da1d98402f9" 1758 | }, 1759 | "dist": { 1760 | "type": "zip", 1761 | "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/134921bfca9b02d8f374c48381451da1d98402f9", 1762 | "reference": "134921bfca9b02d8f374c48381451da1d98402f9", 1763 | "shasum": "" 1764 | }, 1765 | "require": { 1766 | "php": ">=7.1", 1767 | "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0 || ^11.0 || ^12.0" 1768 | }, 1769 | "require-dev": { 1770 | "php-parallel-lint/php-console-highlighter": "^1.0.0", 1771 | "php-parallel-lint/php-parallel-lint": "^1.4.0", 1772 | "yoast/yoastcs": "^3.1.0" 1773 | }, 1774 | "type": "library", 1775 | "extra": { 1776 | "branch-alias": { 1777 | "dev-main": "4.x-dev" 1778 | } 1779 | }, 1780 | "autoload": { 1781 | "files": [ 1782 | "phpunitpolyfills-autoload.php" 1783 | ] 1784 | }, 1785 | "notification-url": "https://packagist.org/downloads/", 1786 | "license": [ 1787 | "BSD-3-Clause" 1788 | ], 1789 | "authors": [ 1790 | { 1791 | "name": "Team Yoast", 1792 | "email": "support@yoast.com", 1793 | "homepage": "https://yoast.com" 1794 | }, 1795 | { 1796 | "name": "Contributors", 1797 | "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" 1798 | } 1799 | ], 1800 | "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", 1801 | "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", 1802 | "keywords": [ 1803 | "phpunit", 1804 | "polyfill", 1805 | "testing" 1806 | ], 1807 | "support": { 1808 | "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", 1809 | "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", 1810 | "source": "https://github.com/Yoast/PHPUnit-Polyfills" 1811 | }, 1812 | "time": "2025-02-09T18:58:54+00:00" 1813 | } 1814 | ], 1815 | "aliases": [], 1816 | "minimum-stability": "stable", 1817 | "stability-flags": {}, 1818 | "prefer-stable": false, 1819 | "prefer-lowest": false, 1820 | "platform": {}, 1821 | "platform-dev": {}, 1822 | "platform-overrides": { 1823 | "php": "8.0.27" 1824 | }, 1825 | "plugin-api-version": "2.6.0" 1826 | } 1827 | -------------------------------------------------------------------------------- /wptest/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./tests/ 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /wptest/plugin.php: -------------------------------------------------------------------------------- 1 |