@johnbillion/plugin-infrastructure 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 John Blackbourn
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.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # Plugin Infrastructure
2
+
3
+ Reusable infrastructure relating to testing, building, linting, deploying, and verifying my WordPress plugins (see the "Used by" section below).
4
+
5
+ Provided without support, warranty, guarantee, backwards compatibility, fitness for purpose, resilience, safety, sanity, beauty, or support for any plugin that isn't one of mine.
6
+
7
+ ## Used by
8
+
9
+ * [Extended CPTs](https://github.com/johnbillion/extended-cpts)
10
+ * [Query Monitor](https://github.com/johnbillion/query-monitor)
11
+ * [User Switching](https://github.com/johnbillion/user-switching)
12
+ * [WP Crontrol](https://github.com/johnbillion/wp-crontrol)
13
+
14
+ ## Features
15
+
16
+ * Acceptance testing
17
+ * Integration testing
18
+ * Coding standards testing
19
+ * Static analysis
20
+ * Workflow file linting
21
+ * Deployment to WordPress.org
22
+ * Build provenance attestation
23
+ * SLSA v1.0 Build level 3 facilitation
24
+ * Ongoing supply chain assurance
25
+
26
+ Plugins that use this library all use a similar setup in their workflows:
27
+
28
+ ## Acceptance testing
29
+
30
+ * Push to a main branch or pull request, `acceptance-tests.yml` fires
31
+ * Constructs a matrix of supported PHP and WordPress versions
32
+ * Uses `reusable-acceptance-tests.yml`
33
+ * Installs PHP and WordPress
34
+ * Runs the build
35
+ * Runs acceptance testing with Playwright
36
+
37
+ ## Integration testing
38
+
39
+ * Push to a main branch or pull request, `integration-tests.yml` fires
40
+ * Constructs a matrix of supported PHP and WordPress versions
41
+ * Uses `reusable-integration-tests.yml`
42
+ * Installs PHP and WordPress
43
+ * Runs the build
44
+ * Runs integration testing with PHPUnit, once for:
45
+ * Single site
46
+ * Multisite
47
+
48
+ ## Coding standards testing
49
+
50
+ * Push to a main branch or pull request, `coding-standards.yml` fires
51
+ * Uses `reusable-coding-standards.yml`
52
+ * Installs PHP
53
+ * Checks coding standards with PHPCS
54
+
55
+ ## Static analysis
56
+
57
+ * Push to a main branch or pull request, `static-analysis.yml` fires
58
+ * Constructs a matrix of supported PHP versions
59
+ * Uses `reusable-static-analysis.yml`
60
+ * Installs PHP
61
+ * Runs static analysis with PHPStan
62
+
63
+ ## Workflow file linting
64
+
65
+ * Push to a main branch or pull request, `lint-workflows.yml` fires
66
+ * Uses `reusable-workflow-lint.yml`
67
+ * Lints all GitHub Actions workflow files for correctness and security using:
68
+ * ActionLint
69
+ * Octoscan
70
+ * Zizmor
71
+ * Poutine
72
+ * Uploads results to GitHub Code Scanning
73
+
74
+ ## Deployment
75
+
76
+ ### WordPress.org
77
+
78
+ * Push to the `release` branch, `build.yml` fires
79
+ * Uses `reusable-build.yml`
80
+ * Runs the build
81
+ * Reads version from `package.json`
82
+ * Commits built files
83
+ * Pushes to `release-$VERSION`
84
+ * Tags the new version and pushes
85
+ * Creates a draft release
86
+ * Publish the release, `deploy-tag.yml` fires
87
+ * Uses `reusable-deploy-tag.yml`
88
+ * Creates a changelog entry from the release notes
89
+ * Uses `10up/action-wordpress-plugin-deploy`
90
+ * Deploys the new version to WordPress.org
91
+ * Generates a zip file
92
+ * Uses `johnbillion/action-wordpress-plugin-attestation`
93
+ * Fetches the zip from WordPress.org
94
+ * Generates a build provenance attestation if the zip contents matches the build
95
+
96
+ ### Packagist
97
+
98
+ * Happens automatically with each release via the auto-update mechanism on Packagist.org.
99
+ * Always identical to the version deployed to WordPress.org
100
+
101
+ ### GitHub
102
+
103
+ * Automatically closes the completed milestone for each release
104
+ * Automatically creates the next major, minor, and patch release milestones after each release
105
+
106
+ ## Supply chain assurance
107
+
108
+ * Hourly scheduled workflow runs in `verify-distribution.yml`
109
+ * Uses `reusable-verify-distribution.yml`
110
+ * Verifies the provenance of the plugin on WordPress.org
111
+
112
+ ## Licence
113
+
114
+ MIT
@@ -0,0 +1,22 @@
1
+ export interface GlobalUtilsOptions {
2
+ baseURL: string;
3
+ pluginSlug: string;
4
+ }
5
+ export declare class GlobalUtils {
6
+ private baseURL;
7
+ private pluginSlug;
8
+ constructor(options: GlobalUtilsOptions);
9
+ /**
10
+ * Run a WP-CLI command
11
+ *
12
+ * @throws Error if the command fails
13
+ */
14
+ runWPCLICommand(command: string): string;
15
+ installWordPress(): void;
16
+ /**
17
+ * Check if current WordPress version meets minimum requirement
18
+ *
19
+ * @throws Error if unable to parse WordPress version
20
+ */
21
+ isWordPressVersionAtLeast(minVersion: number): boolean;
22
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GlobalUtils = void 0;
4
+ class GlobalUtils {
5
+ constructor(options) {
6
+ this.baseURL = options.baseURL;
7
+ this.pluginSlug = options.pluginSlug;
8
+ }
9
+ /**
10
+ * Run a WP-CLI command
11
+ *
12
+ * @throws Error if the command fails
13
+ */
14
+ runWPCLICommand(command) {
15
+ const { execSync } = require('child_process');
16
+ const fullCommand = `docker compose exec --user wp_php wpcli wp --url="${this.baseURL}" ${command}`;
17
+ try {
18
+ const stdout = execSync(fullCommand, { encoding: 'utf8', cwd: process.cwd() });
19
+ return stdout.trim();
20
+ }
21
+ catch (error) {
22
+ throw new Error(`WP-CLI command failed: ${error.message}`);
23
+ }
24
+ }
25
+ installWordPress() {
26
+ // Install WordPress:
27
+ this.runWPCLICommand('db reset --yes');
28
+ this.runWPCLICommand(`core install --title="${this.pluginSlug}" --admin_user="admin" --admin_password="password" --admin_email="admin@example.com" --skip-email`);
29
+ // Set a predictable permalink structure:
30
+ this.runWPCLICommand('rewrite structure "/%postname%/"');
31
+ // Activate the plugin under test:
32
+ this.runWPCLICommand(`plugin activate ${this.pluginSlug}`);
33
+ }
34
+ /**
35
+ * Check if current WordPress version meets minimum requirement
36
+ *
37
+ * @throws Error if unable to parse WordPress version
38
+ */
39
+ isWordPressVersionAtLeast(minVersion) {
40
+ const wpVersion = this.runWPCLICommand('core version');
41
+ // Extract major.minor version from WordPress version string
42
+ // Examples: "6.2.1" -> "6.2", "6.9-alpha-60684" -> "6.9"
43
+ const versionMatch = wpVersion.match(/^(\d+\.\d+)/);
44
+ if (!versionMatch) {
45
+ throw new Error(`Unable to parse WordPress version: ${wpVersion}`);
46
+ }
47
+ const currentVersion = parseFloat(versionMatch[1]);
48
+ return currentVersion >= minVersion;
49
+ }
50
+ }
51
+ exports.GlobalUtils = GlobalUtils;
@@ -0,0 +1 @@
1
+ export { GlobalUtils, GlobalUtilsOptions } from './global-utils';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GlobalUtils = void 0;
4
+ var global_utils_1 = require("./global-utils");
5
+ Object.defineProperty(exports, "GlobalUtils", { enumerable: true, get: function () { return global_utils_1.GlobalUtils; } });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@johnbillion/plugin-infrastructure",
3
+ "version": "2.0.0-beta.1",
4
+ "description": "Shared utilities for WordPress plugin development",
5
+ "license": "MIT",
6
+ "author": "John Blackbourn",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/johnbillion/plugin-infrastructure.git"
10
+ },
11
+ "homepage": "https://github.com/johnbillion/plugin-infrastructure",
12
+ "exports": {
13
+ "./acceptance": {
14
+ "require": "./dist/acceptance/index.js",
15
+ "types": "./dist/acceptance/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "engines": {
22
+ "node": ">=18"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^24.3.0",
30
+ "typescript": "^5.9.2"
31
+ }
32
+ }