@hexonet/semantic-release-whmcs 5.1.21 → 5.2.0
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/.github/workflows/test.yml +1 -0
- package/HISTORY.md +22 -0
- package/README.md +21 -4
- package/index.js +11 -0
- package/lib/prepare.js +110 -0
- package/lib/puppet-utils.js +1 -1
- package/lib/puppet.js +24 -7
- package/lib/resolve-config.js +1 -0
- package/package.json +8 -8
- package/pnpm-workspace.yaml +2 -0
- package/extensions/I-Still-Dont-Care-About-Cookies/_metadata/generated_indexed_rulesets/_ruleset1 +0 -0
package/HISTORY.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# [5.2.0](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/compare/v5.1.22...v5.2.0) (2026-01-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** bump puppeteer from 24.30.0 to 24.31.0 ([7d2ff8a](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/7d2ff8a2ead33c606f76e72303a92ed2fda05622))
|
|
7
|
+
* **deps:** bump puppeteer from 24.31.0 to 24.33.0 ([e05fd23](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/e05fd2336697239e1766f0617e08c8c62fc83040))
|
|
8
|
+
* **deps:** bump puppeteer from 24.33.0 to 24.33.1 ([cfbb3ad](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/cfbb3adb2310cbb04e9c4a48520e05f74cc996bf))
|
|
9
|
+
* **deps:** bump puppeteer from 24.33.1 to 24.34.0 ([aff5059](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/aff5059079c0c95cec7c513c2d12a0a79dd45c03))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* **index.js:** add prepare step to install Chromium/Chrome OS dependencies for Puppeteer ([7e61220](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/7e61220646f4e3bcf68d300370a47668955b990b))
|
|
15
|
+
|
|
16
|
+
## [5.1.22](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/compare/v5.1.21...v5.1.22) (2025-11-13)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **deps:** bump puppeteer from 24.29.1 to 24.30.0 ([86def84](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/86def849e2a6453057182b67d46c7c2b82922fce))
|
|
22
|
+
|
|
1
23
|
## [5.1.21](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/compare/v5.1.20...v5.1.21) (2025-11-07)
|
|
2
24
|
|
|
3
25
|
|
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
| Step | Description |
|
|
13
13
|
| ---- | ----------- |
|
|
14
|
+
| `prepare` | Install OS dependencies required by Puppeteer and Chromium/Chrome (Debian/Ubuntu only) if `osDepsCommand` is configured. |
|
|
14
15
|
| `verifyConditions` | Verify the presence and the validity of the authentication credentials (set via [environment variables](#environment-variables)) and the product id option configuration. |
|
|
15
16
|
| `publish` | Publish product/module version to [WHMCS Marketplace](https://marketplace.whmcs.com) including changelog notes. |
|
|
16
17
|
|
|
@@ -27,7 +28,7 @@ FYI: This module is ESM ready!
|
|
|
27
28
|
### Requirements
|
|
28
29
|
|
|
29
30
|
* Installed nodejs/npm. We suggest using [nvm](https://github.com/creationix/nvm).
|
|
30
|
-
*
|
|
31
|
+
* **OS Dependencies**: On Debian/Ubuntu systems, the `prepare` step can run a custom command (e.g. `puppeteer browsers install chrome --install-deps`) to install required packages on demand. This is configured via `osDepsCommand`.
|
|
31
32
|
* Using [semantic-release](https://github.com/semantic-release/semantic-release) in your CI/CD process
|
|
32
33
|
|
|
33
34
|
### Install
|
|
@@ -38,14 +39,27 @@ FYI: This module is ESM ready!
|
|
|
38
39
|
|
|
39
40
|
### Configuration
|
|
40
41
|
|
|
41
|
-
The plugin can be loaded in the [**semantic-release** configuration file](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration).
|
|
42
|
+
The plugin can be loaded in the [**semantic-release** configuration file](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration). The `prepare` step handles OS dependencies if `osDepsCommand` is provided (requires `sudo` access on Debian/Ubuntu for system packages).
|
|
42
43
|
|
|
43
44
|
```json
|
|
44
45
|
{
|
|
45
46
|
"plugins": [
|
|
46
47
|
"@semantic-release/commit-analyzer",
|
|
47
48
|
"@semantic-release/release-notes-generator",
|
|
48
|
-
|
|
49
|
+
[
|
|
50
|
+
"@hexonet/semantic-release-whmcs",
|
|
51
|
+
{
|
|
52
|
+
"osDepsCommand": [
|
|
53
|
+
"pnpm",
|
|
54
|
+
"dlx",
|
|
55
|
+
"puppeteer",
|
|
56
|
+
"browsers",
|
|
57
|
+
"install",
|
|
58
|
+
"chrome",
|
|
59
|
+
"--install-deps"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
49
63
|
]
|
|
50
64
|
}
|
|
51
65
|
```
|
|
@@ -81,7 +95,10 @@ That said, before you can use this module for publishing new product/module vers
|
|
|
81
95
|
|
|
82
96
|
### Options
|
|
83
97
|
|
|
84
|
-
|
|
98
|
+
| Option | Type | Description |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `skipOsDeps` | Boolean | **Optional.** Skip OS dependency installation in the prepare step. Default: `false`. Useful if you already have dependencies installed or prefer to manage them yourself. |
|
|
101
|
+
| `osDepsCommand` | string[] | **Optional.** Command to install dependencies (e.g. `["pnpm", "dlx", "puppeteer", "browsers", "install", "chrome", "--install-deps"]`). <br><br> **Note:** The command is automatically executed with `sudo` and the current `PATH` preserved (via `/bin/bash -c "sudo env PATH=$PATH ..."`), so you do not need to add `sudo` yourself. |
|
|
85
102
|
|
|
86
103
|
### Routines
|
|
87
104
|
|
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import verifyWHMCS from "./lib/verify.js";
|
|
2
|
+
import prepareWHMCS from "./lib/prepare.js";
|
|
2
3
|
import publishWHMCS from "./lib/publish.js";
|
|
3
4
|
import deleteVersion from "./lib/delete-marketplace-version.js";
|
|
4
5
|
import setCompatibleVersions from "./lib/set-compatible-versions.js";
|
|
@@ -8,6 +9,15 @@ import marketplaceVersions from "./lib/scrape-marketplace-versions.js";
|
|
|
8
9
|
let verified;
|
|
9
10
|
let whmcsPublishResult = null;
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Called by semantic-release during the prepare step
|
|
14
|
+
* @param {*} pluginConfig The semantic-release plugin config
|
|
15
|
+
* @param {*} context The context provided by semantic-release
|
|
16
|
+
*/
|
|
17
|
+
async function prepare(pluginConfig, context) {
|
|
18
|
+
await prepareWHMCS(pluginConfig, context);
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
/**
|
|
12
22
|
* Called by semantic-release during the verify step
|
|
13
23
|
* @param {*} pluginConfig The semantic-release plugin config
|
|
@@ -144,6 +154,7 @@ async function fail(pluginConfig, context) {
|
|
|
144
154
|
}
|
|
145
155
|
|
|
146
156
|
export default {
|
|
157
|
+
prepare,
|
|
147
158
|
verifyConditions,
|
|
148
159
|
publish,
|
|
149
160
|
//success,
|
package/lib/prepare.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import debugConfig from "debug";
|
|
3
|
+
|
|
4
|
+
const debug = debugConfig("semantic-release:whmcs");
|
|
5
|
+
|
|
6
|
+
// Exported for testing/debugging
|
|
7
|
+
export const DEBIAN_MARKER = "/etc/debian_version";
|
|
8
|
+
|
|
9
|
+
let spawnImplementation = spawn;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Test-only hook to override the child_process.spawn implementation.
|
|
13
|
+
* @param {(cmd: string, args?: string[], options?: object) => NodeJS.Process} implementation
|
|
14
|
+
*/
|
|
15
|
+
export function __setSpawnImplementation(implementation) {
|
|
16
|
+
spawnImplementation = implementation;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Test-only hook to reset spawn back to the native implementation.
|
|
21
|
+
*/
|
|
22
|
+
export function __resetSpawnImplementation() {
|
|
23
|
+
spawnImplementation = spawn;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Spawn a child process and return a promise
|
|
28
|
+
* @param {string} command The command to run
|
|
29
|
+
* @param {string[]} args The arguments to pass to the command
|
|
30
|
+
* @param {object} options Options to pass to spawn
|
|
31
|
+
* @returns {Promise<number>} The exit code of the process
|
|
32
|
+
*/
|
|
33
|
+
function spawnPromise(command, args, options = {}) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const child = spawnImplementation(command, args, { stdio: "inherit", ...options });
|
|
36
|
+
child.on("exit", (code) => {
|
|
37
|
+
if (code === 0) resolve(code);
|
|
38
|
+
else reject(new Error(`Process exited with code ${code}`));
|
|
39
|
+
});
|
|
40
|
+
child.on("error", reject);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if the system is Debian-like
|
|
46
|
+
* @returns {Promise<boolean>}
|
|
47
|
+
*/
|
|
48
|
+
async function isDebianLike() {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const child = spawnImplementation("test", ["-f", DEBIAN_MARKER], { stdio: "ignore" });
|
|
51
|
+
child.on("exit", (code) => resolve(code === 0));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Called by semantic-release during the prepare step
|
|
57
|
+
* @param {*} pluginConfig The semantic-release plugin config
|
|
58
|
+
* @param {*} context The context provided by semantic-release
|
|
59
|
+
*/
|
|
60
|
+
export default async (pluginConfig = {}, context = {}) => {
|
|
61
|
+
const { nextRelease, lastRelease } = context;
|
|
62
|
+
|
|
63
|
+
// Only run if there is a new version
|
|
64
|
+
if (lastRelease?.version && nextRelease?.version === lastRelease.version) {
|
|
65
|
+
debug("Skipping prepare step: No new version detected");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check if OS dependency installation is disabled
|
|
70
|
+
if (pluginConfig.skipOsDeps === true) {
|
|
71
|
+
debug("OS dependency installation skipped (skipOsDeps=true)");
|
|
72
|
+
console.log("ℹ️ Skipping OS dependency installation");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
debug("Installing Chromium/Chrome OS dependencies for puppeteer...");
|
|
78
|
+
if (await isDebianLike()) {
|
|
79
|
+
try {
|
|
80
|
+
debug("Detected Debian/Ubuntu system, installing google-chrome-stable via apt-get");
|
|
81
|
+
|
|
82
|
+
// Update package lists and install Google Chrome stable
|
|
83
|
+
await spawnPromise("sudo", ["apt-get", "update"]);
|
|
84
|
+
await spawnPromise("sudo", ["apt-get", "install", "-y", "google-chrome-stable"]);
|
|
85
|
+
debug("Chromium/Chrome dependencies installed successfully");
|
|
86
|
+
|
|
87
|
+
// Set Chrome executable path for Puppeteer if configured
|
|
88
|
+
const chromePath = "/usr/bin/google-chrome-stable";
|
|
89
|
+
if (!process.env.PUPPETEER_EXECUTABLE_PATH) {
|
|
90
|
+
process.env.PUPPETEER_EXECUTABLE_PATH = chromePath;
|
|
91
|
+
debug("Set PUPPETEER_EXECUTABLE_PATH to %s", chromePath);
|
|
92
|
+
} else {
|
|
93
|
+
debug("PUPPETEER_EXECUTABLE_PATH already set to %s", process.env.PUPPETEER_EXECUTABLE_PATH);
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
debug("Warning: Could not install google-chrome-stable via apt-get: %s", error.message);
|
|
97
|
+
console.warn(
|
|
98
|
+
`⚠️ Warning: Failed to install some OS dependencies: ${error.message}\n` +
|
|
99
|
+
"⚠️ Some dependencies may need to be installed manually or puppeteer may fall back to downloading Chromium"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
debug("Debian/Ubuntu system not detected, skipping OS dependency installation");
|
|
104
|
+
console.log("ℹ️ Running on non-Debian system. Puppeteer will download Chromium if needed.");
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
debug("Prepare step failed: %s", error.message);
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
};
|
package/lib/puppet-utils.js
CHANGED
|
@@ -32,7 +32,7 @@ export async function loginAndNavigate(puppet, context, urlBuilder, gotoOpts) {
|
|
|
32
32
|
}
|
|
33
33
|
const { page } = püppi.config;
|
|
34
34
|
const url = typeof urlBuilder === "function" ? urlBuilder(püppi) : urlBuilder;
|
|
35
|
-
const navOpts = gotoOpts || { waitUntil: ["load", "domcontentloaded"], timeout: 10000 };
|
|
35
|
+
const navOpts = gotoOpts || püppi.config.gotoOpts || { waitUntil: ["load", "domcontentloaded"], timeout: 10000 };
|
|
36
36
|
debug && debug(`Navigating to: ${url} with options: ${JSON.stringify(navOpts)}`);
|
|
37
37
|
await page.goto(url, navOpts);
|
|
38
38
|
debug && debug(`Navigation to ${url} complete.`);
|
package/lib/puppet.js
CHANGED
|
@@ -16,14 +16,14 @@ export default async (context) => {
|
|
|
16
16
|
// logger: logger,
|
|
17
17
|
gotoOpts: {
|
|
18
18
|
waitUntil: ["load", "domcontentloaded"],
|
|
19
|
-
timeout:
|
|
19
|
+
timeout: 30 * 1000, // increase to 30 seconds to handle slower loads
|
|
20
20
|
},
|
|
21
21
|
navOpts: {
|
|
22
22
|
waitUntil: ["networkidle0"],
|
|
23
|
-
timeout:
|
|
23
|
+
timeout: 30 * 1000, // increase to 30 seconds to handle slower navigation
|
|
24
24
|
},
|
|
25
25
|
selectorOpts: {
|
|
26
|
-
timeout:
|
|
26
|
+
timeout: 15 * 1000, // increase to 15 seconds for selector waits
|
|
27
27
|
},
|
|
28
28
|
logger: context.logger,
|
|
29
29
|
};
|
|
@@ -74,11 +74,13 @@ export default async (context) => {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
async function login() {
|
|
77
|
-
const { page, login, password, productid, gotoOpts, urlbase, selectorOpts } = config;
|
|
77
|
+
const { page, login, password, productid, gotoOpts, urlbase, selectorOpts, keepBrowserOpenOnError } = config;
|
|
78
78
|
const submitSelector = 'div.login-leftcol form button[type="submit"]';
|
|
79
79
|
try {
|
|
80
80
|
await page.goto(`${urlbase}/user/login`, gotoOpts);
|
|
81
81
|
debug("login form loaded at %s", `${urlbase}/user/login`);
|
|
82
|
+
// Give cookie banners/extensions a short window to run before interacting
|
|
83
|
+
await wait(2000);
|
|
82
84
|
// Wait for login form
|
|
83
85
|
await page.waitForSelector("#email", selectorOpts);
|
|
84
86
|
await page.waitForSelector("#password", selectorOpts);
|
|
@@ -103,7 +105,12 @@ export default async (context) => {
|
|
|
103
105
|
debug("Login failed: no navigation, no selector, and no error alert after submit");
|
|
104
106
|
}
|
|
105
107
|
// await page.screenshot({ path: `login-failed-no-redirect-or-selector.png` });
|
|
106
|
-
|
|
108
|
+
if (keepBrowserOpenOnError) {
|
|
109
|
+
debug("Keeping browser open for debugging after login failure.");
|
|
110
|
+
await wait(60 * 1000);
|
|
111
|
+
} else {
|
|
112
|
+
await safeClose(page);
|
|
113
|
+
}
|
|
107
114
|
return false;
|
|
108
115
|
}
|
|
109
116
|
debug("WHMCS Marketplace login succeeded (redirected: %s, selectorFound: %s)", redirected, selectorFound);
|
|
@@ -114,7 +121,12 @@ export default async (context) => {
|
|
|
114
121
|
} catch (e) {
|
|
115
122
|
debug("Screenshot failed", e.message);
|
|
116
123
|
}
|
|
117
|
-
|
|
124
|
+
if (keepBrowserOpenOnError) {
|
|
125
|
+
debug("Keeping browser open for debugging after login error.");
|
|
126
|
+
await wait(60 * 1000);
|
|
127
|
+
} else {
|
|
128
|
+
await safeClose(page);
|
|
129
|
+
}
|
|
118
130
|
return false;
|
|
119
131
|
}
|
|
120
132
|
|
|
@@ -122,7 +134,12 @@ export default async (context) => {
|
|
|
122
134
|
let tmp = productid;
|
|
123
135
|
if (!tmp || !/^[0-9]+$/.test(productid) || !parseInt(productid, 10)) {
|
|
124
136
|
debug("No or invalid WHMCS Marketplace Product ID provided.");
|
|
125
|
-
|
|
137
|
+
if (keepBrowserOpenOnError) {
|
|
138
|
+
debug("Keeping browser open for debugging due to invalid product id.");
|
|
139
|
+
await wait(60 * 1000);
|
|
140
|
+
} else {
|
|
141
|
+
await safeClose(page);
|
|
142
|
+
}
|
|
126
143
|
return false;
|
|
127
144
|
}
|
|
128
145
|
tmp = tmp.replace(/(.)/g, "$&\u200E");
|
package/lib/resolve-config.js
CHANGED
|
@@ -10,5 +10,6 @@ export default (context) => {
|
|
|
10
10
|
headless: env.PUPPETEER_HEADLESS || "1",
|
|
11
11
|
debug: (env.DEBUG && /^semantic-release:(\*|whmcs)$/.test(env.DEBUG)) || false,
|
|
12
12
|
useCookieExtension: env.USE_COOKIE_EXTENSION || true,
|
|
13
|
+
keepBrowserOpenOnError: env.PUPPETEER_KEEP_OPEN === "1" || env.PUPPETEER_KEEP_OPEN === "true" || false,
|
|
13
14
|
};
|
|
14
15
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hexonet/semantic-release-whmcs",
|
|
3
3
|
"description": "`semantic-release` plugin for auto-publishing on WHMCS marketplace",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
@@ -72,20 +72,20 @@
|
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@semantic-release/changelog": "^6.0.3",
|
|
75
|
-
"@semantic-release/exec": "^7.0
|
|
75
|
+
"@semantic-release/exec": "^7.1.0",
|
|
76
76
|
"@semantic-release/git": "^10.0.1",
|
|
77
77
|
"ava": "6.4.1",
|
|
78
|
-
"c8": "^10.
|
|
79
|
-
"prettier": "^3.
|
|
80
|
-
"semantic-release": "^25.0.
|
|
78
|
+
"c8": "^10.1.3",
|
|
79
|
+
"prettier": "^3.7.4",
|
|
80
|
+
"semantic-release": "^25.0.2",
|
|
81
81
|
"semantic-release-teams-notify-plugin": "github:centralnicgroup-opensource/rtldev-middleware-semantic-release-notify-plugin",
|
|
82
|
-
"stream-buffers": "^3.0.
|
|
82
|
+
"stream-buffers": "^3.0.3"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@octokit/rest": "^22.0.
|
|
85
|
+
"@octokit/rest": "^22.0.1",
|
|
86
86
|
"@semantic-release/error": "^4.0.0",
|
|
87
87
|
"aggregate-error": "^5.0.0",
|
|
88
|
-
"debug": "^4.3
|
|
88
|
+
"debug": "^4.4.3",
|
|
89
89
|
"puppeteer": ">=23.4.0",
|
|
90
90
|
"yargs": "^18.0.0"
|
|
91
91
|
}
|