@hexonet/semantic-release-whmcs 5.2.8 → 5.2.10
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/.env.example +15 -0
- package/HISTORY.md +15 -0
- package/README.md +5 -3
- package/index.js +7 -0
- package/lib/prepare.js +58 -15
- package/lib/puppet.js +86 -2
- package/lib/resolve-config.js +2 -1
- package/package.json +10 -5
package/.env.example
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copy this file to .env and fill in real values.
|
|
2
|
+
# Never commit your .env (it is gitignored).
|
|
3
|
+
|
|
4
|
+
WHMCSMP_PRODUCTID=product id
|
|
5
|
+
WHMCSMP_LOGIN=your.email@example.com
|
|
6
|
+
WHMCSMP_PASSWORD=your-password
|
|
7
|
+
|
|
8
|
+
# Recommended for CI/headless environments
|
|
9
|
+
PUPPETEER_HEADLESS=1
|
|
10
|
+
|
|
11
|
+
# Optional: more logs
|
|
12
|
+
# DEBUG=semantic-release:whmcs
|
|
13
|
+
|
|
14
|
+
# Optional: stable cache/workdir in Docker
|
|
15
|
+
# PROJECT_WORKDIR=/usr/share/rtldev-middleware-whmcs-src
|
package/HISTORY.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [5.2.10](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/compare/v5.2.9...v5.2.10) (2026-02-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **deps:** bump puppeteer from 24.37.2 to 24.37.3 ([171b2e2](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/171b2e262aa53093347265249ddcbc893f606541))
|
|
7
|
+
|
|
8
|
+
## [5.2.9](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/compare/v5.2.8...v5.2.9) (2026-02-06)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **prepare.js:** update OS dependency installation process for Puppeteer on Debian/Ubuntu ([f52c709](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/f52c709a8ec1d7eff02009e83afd9235083a0509))
|
|
14
|
+
* **prepare/puppet:** enhance prepare.js and puppet.js for improved configuration handling ([450b0e0](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/commit/450b0e0a088afc45286c1cd6ed49b8d325d63c55))
|
|
15
|
+
|
|
1
16
|
## [5.2.8](https://github.com/centralnicgroup-opensource/rtldev-middleware-semantic-release-whmcs/compare/v5.2.7...v5.2.8) (2026-02-06)
|
|
2
17
|
|
|
3
18
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
| Step | Description |
|
|
13
13
|
| ---- | ----------- |
|
|
14
|
-
| `prepare` | Install OS dependencies required by Puppeteer and Chromium/Chrome (Debian/Ubuntu only)
|
|
14
|
+
| `prepare` | Install OS dependencies required by Puppeteer and Chromium/Chrome (Debian/Ubuntu only). Can be customized via `osDepsCommand`. |
|
|
15
15
|
| `verifyConditions` | Verify the presence and the validity of the authentication credentials (set via [environment variables](#environment-variables)) and the product id option configuration. |
|
|
16
16
|
| `publish` | Publish product/module version to [WHMCS Marketplace](https://marketplace.whmcs.com) including changelog notes. |
|
|
17
17
|
|
|
@@ -28,7 +28,7 @@ FYI: This module is ESM ready!
|
|
|
28
28
|
### Requirements
|
|
29
29
|
|
|
30
30
|
* Installed nodejs/npm. We suggest using [nvm](https://github.com/creationix/nvm).
|
|
31
|
-
* **OS Dependencies**: On Debian/Ubuntu systems, the `prepare` step
|
|
31
|
+
* **OS Dependencies**: On Debian/Ubuntu systems, the `prepare` step installs Chrome (for testing) + required OS packages using `pnpm dlx puppeteer browsers install chrome --install-deps` (falls back to `npx` if `pnpm` is unavailable). You can override the command via `osDepsCommand`.
|
|
32
32
|
* Using [semantic-release](https://github.com/semantic-release/semantic-release) in your CI/CD process
|
|
33
33
|
|
|
34
34
|
### Install
|
|
@@ -39,7 +39,7 @@ FYI: This module is ESM ready!
|
|
|
39
39
|
|
|
40
40
|
### Configuration
|
|
41
41
|
|
|
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
|
|
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 on Debian/Ubuntu (requires `sudo` access for system packages).
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
45
|
{
|
|
@@ -92,6 +92,8 @@ That said, before you can use this module for publishing new product/module vers
|
|
|
92
92
|
| `GH_TOKEN` | **Optional.** GitHub API authentication token to use for syncing versions. |
|
|
93
93
|
| `GH_REPO` | **Optional.** GitHub repository name (format: organization/repository) to use for syncing versions. |
|
|
94
94
|
| `useCookieExtension` | **Optional.** Use cookies extension when puppeteer is running to avoid cookie banner disruptions. |
|
|
95
|
+
| `WHMCS_OS_DEPS_ALWAYS` | **Optional.** Force OS dependency installation in `prepare` even if there is no new release version. Useful for CI experiments. Values: `1` / `true`. |
|
|
96
|
+
| `SKIP_OS_DEPS` | **Optional.** Skip OS dependency installation in `prepare`. Values: `1` / `true` (also supported: `skipOsDeps`). |
|
|
95
97
|
|
|
96
98
|
### Options
|
|
97
99
|
|
package/index.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// Set Puppeteer cache dir early, before any puppeteer imports
|
|
2
|
+
import path from "path";
|
|
3
|
+
const workDir = process.env.PROJECT_WORKDIR || process.cwd();
|
|
4
|
+
if (!process.env.PUPPETEER_CACHE_DIR) {
|
|
5
|
+
process.env.PUPPETEER_CACHE_DIR = path.join(workDir, ".cache", "puppeteer");
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
import verifyWHMCS from "./lib/verify.js";
|
|
2
9
|
import prepareWHMCS from "./lib/prepare.js";
|
|
3
10
|
import publishWHMCS from "./lib/publish.js";
|
package/lib/prepare.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
import debugConfig from "debug";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import resolveConfig from "./resolve-config.js";
|
|
3
6
|
|
|
4
7
|
const debug = debugConfig("semantic-release:whmcs");
|
|
5
8
|
|
|
@@ -23,6 +26,26 @@ export function __resetSpawnImplementation() {
|
|
|
23
26
|
spawnImplementation = spawn;
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
function resolveCacheDir(context) {
|
|
30
|
+
if (process.env.PUPPETEER_CACHE_DIR) return process.env.PUPPETEER_CACHE_DIR;
|
|
31
|
+
const workDir = process.env.PROJECT_WORKDIR || context?.cwd || process.cwd();
|
|
32
|
+
return path.join(workDir, ".cache", "puppeteer");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveInstalledChromeExecutable(cacheDir) {
|
|
36
|
+
try {
|
|
37
|
+
const chromeDir = path.join(cacheDir, "chrome");
|
|
38
|
+
if (!fs.existsSync(chromeDir)) return null;
|
|
39
|
+
const versions = fs.readdirSync(chromeDir).filter(Boolean).sort();
|
|
40
|
+
if (versions.length === 0) return null;
|
|
41
|
+
const latest = versions[versions.length - 1];
|
|
42
|
+
const candidate = path.join(chromeDir, latest, "chrome-linux64", "chrome");
|
|
43
|
+
return fs.existsSync(candidate) ? candidate : null;
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
26
49
|
/**
|
|
27
50
|
* Spawn a child process and return a promise
|
|
28
51
|
* @param {string} command The command to run
|
|
@@ -67,7 +90,8 @@ export default async (pluginConfig = {}, context = {}) => {
|
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
// Check if OS dependency installation is disabled
|
|
70
|
-
|
|
93
|
+
const cfg = resolveConfig(context);
|
|
94
|
+
if (pluginConfig.skipOsDeps === true || cfg.skipOsDeps) {
|
|
71
95
|
debug("OS dependency installation skipped (skipOsDeps=true)");
|
|
72
96
|
console.log("ℹ️ Skipping OS dependency installation");
|
|
73
97
|
return;
|
|
@@ -77,23 +101,42 @@ export default async (pluginConfig = {}, context = {}) => {
|
|
|
77
101
|
debug("Installing Chromium/Chrome OS dependencies for puppeteer...");
|
|
78
102
|
if (await isDebianLike()) {
|
|
79
103
|
try {
|
|
80
|
-
debug("Detected Debian/Ubuntu system, installing
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
debug("Set PUPPETEER_EXECUTABLE_PATH to %s", chromePath);
|
|
104
|
+
debug("Detected Debian/Ubuntu system, installing Chrome (for testing) + OS deps for Puppeteer");
|
|
105
|
+
|
|
106
|
+
const cacheDir = resolveCacheDir(context);
|
|
107
|
+
process.env.PUPPETEER_CACHE_DIR = cacheDir;
|
|
108
|
+
|
|
109
|
+
const envPath = process.env.PATH || "";
|
|
110
|
+
const home = process.env.HOME || "";
|
|
111
|
+
const envPrefix = ["env", `PATH=${envPath}`, `HOME=${home}`, `PUPPETEER_CACHE_DIR=${cacheDir}`];
|
|
112
|
+
|
|
113
|
+
if (Array.isArray(pluginConfig.osDepsCommand) && pluginConfig.osDepsCommand.length > 0) {
|
|
114
|
+
await spawnPromise("sudo", [...envPrefix, ...pluginConfig.osDepsCommand]);
|
|
92
115
|
} else {
|
|
93
|
-
|
|
116
|
+
// Straightforward: let Puppeteer's installer handle both Chrome + OS deps.
|
|
117
|
+
await spawnPromise("sudo", [
|
|
118
|
+
...envPrefix,
|
|
119
|
+
"pnpm",
|
|
120
|
+
"dlx",
|
|
121
|
+
"puppeteer",
|
|
122
|
+
"browsers",
|
|
123
|
+
"install",
|
|
124
|
+
"chrome",
|
|
125
|
+
"--install-deps",
|
|
126
|
+
]);
|
|
94
127
|
}
|
|
128
|
+
|
|
129
|
+
const execPath = resolveInstalledChromeExecutable(cacheDir);
|
|
130
|
+
if (execPath) {
|
|
131
|
+
process.env.PUPPETEER_EXECUTABLE_PATH = execPath;
|
|
132
|
+
debug("Resolved Chrome executable: %s", execPath);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
debug("PUPPETEER_CACHE_DIR: %s", process.env.PUPPETEER_CACHE_DIR);
|
|
136
|
+
debug("PUPPETEER_EXECUTABLE_PATH: %s", process.env.PUPPETEER_EXECUTABLE_PATH);
|
|
137
|
+
debug("Chrome/Chromium OS dependencies installed successfully");
|
|
95
138
|
} catch (error) {
|
|
96
|
-
debug("Warning: Could not install
|
|
139
|
+
debug("Warning: Could not install Chrome/Chromium OS dependencies: %s", error.message);
|
|
97
140
|
console.warn(
|
|
98
141
|
`⚠️ Warning: Failed to install some OS dependencies: ${error.message}\n` +
|
|
99
142
|
"⚠️ Some dependencies may need to be installed manually or puppeteer may fall back to downloading Chromium"
|
package/lib/puppet.js
CHANGED
|
@@ -1,14 +1,97 @@
|
|
|
1
|
-
import puppeteer from "puppeteer";
|
|
2
1
|
import resolveConfig from "./resolve-config.js";
|
|
3
2
|
import debugConfig from "debug";
|
|
4
3
|
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import os from "os";
|
|
5
6
|
import { fileURLToPath } from "url";
|
|
6
7
|
import { waitForNavigationOrSelector, robustType, wait, safeClose } from "./puppet-utils.js";
|
|
8
|
+
|
|
7
9
|
const debug = debugConfig("semantic-release:whmcs");
|
|
8
10
|
|
|
9
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
12
|
const __dirname = path.dirname(__filename);
|
|
11
13
|
export default async (context) => {
|
|
14
|
+
// Set PUPPETEER_CACHE_DIR BEFORE importing puppeteer
|
|
15
|
+
const workDir = process.env.PROJECT_WORKDIR || process.cwd();
|
|
16
|
+
if (!process.env.PUPPETEER_CACHE_DIR) {
|
|
17
|
+
process.env.PUPPETEER_CACHE_DIR = path.join(workDir, ".cache", "puppeteer");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
debug("PROJECT_WORKDIR: %s", process.env.PROJECT_WORKDIR);
|
|
21
|
+
debug("PUPPETEER_CACHE_DIR: %s", process.env.PUPPETEER_CACHE_DIR);
|
|
22
|
+
debug("PUPPETEER_EXECUTABLE_PATH: %s", process.env.PUPPETEER_EXECUTABLE_PATH);
|
|
23
|
+
|
|
24
|
+
// Check if cache dir exists and list contents
|
|
25
|
+
const cacheDir = process.env.PUPPETEER_CACHE_DIR;
|
|
26
|
+
if (fs.existsSync(cacheDir)) {
|
|
27
|
+
debug("Cache dir contents: %s", fs.readdirSync(cacheDir).join(", "));
|
|
28
|
+
const chromeDir = path.join(cacheDir, "chrome");
|
|
29
|
+
if (fs.existsSync(chromeDir)) {
|
|
30
|
+
debug("Chrome dir contents: %s", fs.readdirSync(chromeDir).join(", "));
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
debug("Cache dir does NOT exist: %s", cacheDir);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const puppeteer = (await import("puppeteer")).default;
|
|
37
|
+
|
|
38
|
+
// Get executable path - prefer env var, then puppeteer's default
|
|
39
|
+
let executablePath = process.env.PUPPETEER_EXECUTABLE_PATH;
|
|
40
|
+
if (!executablePath) {
|
|
41
|
+
executablePath = puppeteer.executablePath();
|
|
42
|
+
debug("Using puppeteer.executablePath(): %s", executablePath);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check if executable exists
|
|
46
|
+
if (!fs.existsSync(executablePath)) {
|
|
47
|
+
// Try to find Chrome in the configured cache dir
|
|
48
|
+
const chromeDir = path.join(cacheDir, "chrome");
|
|
49
|
+
let found = false;
|
|
50
|
+
if (fs.existsSync(chromeDir)) {
|
|
51
|
+
const versions = fs.readdirSync(chromeDir);
|
|
52
|
+
debug("Available Chrome versions: %s", versions.join(", "));
|
|
53
|
+
if (versions.length > 0) {
|
|
54
|
+
const latestVersion = versions.sort().pop();
|
|
55
|
+
const possiblePath = path.join(chromeDir, latestVersion, "chrome-linux64", "chrome");
|
|
56
|
+
if (fs.existsSync(possiblePath)) {
|
|
57
|
+
executablePath = possiblePath;
|
|
58
|
+
debug("Found Chrome at: %s", executablePath);
|
|
59
|
+
found = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!found) {
|
|
65
|
+
// Fallback: Check default cache locations (home dir)
|
|
66
|
+
// This handles cases where PROJECT_WORKDIR is set but prepare step didn't run or install to project cache
|
|
67
|
+
const homeCache = path.join(os.homedir(), ".cache", "puppeteer", "chrome");
|
|
68
|
+
if (fs.existsSync(homeCache)) {
|
|
69
|
+
debug("Checking fallback cache at: %s", homeCache);
|
|
70
|
+
const versions = fs.readdirSync(homeCache).filter((v) => v.startsWith("linux-") || v.startsWith("chrome-"));
|
|
71
|
+
if (versions.length > 0) {
|
|
72
|
+
const latestVersion = versions.sort().pop();
|
|
73
|
+
const possiblePath = path.join(homeCache, latestVersion, "chrome-linux64", "chrome");
|
|
74
|
+
if (fs.existsSync(possiblePath)) {
|
|
75
|
+
executablePath = possiblePath;
|
|
76
|
+
debug("Found Chrome in fallback location: %s", executablePath);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!fs.existsSync(executablePath)) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Chrome executable not found at: ${executablePath}\n` +
|
|
86
|
+
`PUPPETEER_CACHE_DIR: ${cacheDir} (exists: ${fs.existsSync(cacheDir)})\n` +
|
|
87
|
+
`PUPPETEER_EXECUTABLE_PATH: ${process.env.PUPPETEER_EXECUTABLE_PATH}\n` +
|
|
88
|
+
`PROJECT_WORKDIR: ${process.env.PROJECT_WORKDIR}\n` +
|
|
89
|
+
`process.cwd(): ${process.cwd()}`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
debug("Final Chrome executable: %s", executablePath);
|
|
94
|
+
|
|
12
95
|
let config;
|
|
13
96
|
const cfg = {
|
|
14
97
|
urlbase: "https://marketplace.whmcs.com",
|
|
@@ -51,9 +134,10 @@ export default async (context) => {
|
|
|
51
134
|
}
|
|
52
135
|
|
|
53
136
|
const browser = await puppeteer.launch({
|
|
54
|
-
headless: cfg.headless
|
|
137
|
+
headless: cfg.headless,
|
|
55
138
|
defaultViewport: null, // automatically full-sized
|
|
56
139
|
args: launchArgs,
|
|
140
|
+
executablePath,
|
|
57
141
|
});
|
|
58
142
|
const { logger } = cfg;
|
|
59
143
|
const [page] = await browser.pages();
|
package/lib/resolve-config.js
CHANGED
|
@@ -7,9 +7,10 @@ export default (context) => {
|
|
|
7
7
|
minversion: env.WHMCSMP_MINVERSION || "7.10",
|
|
8
8
|
ghtoken: env.GH_TOKEN || env.GITHUB_TOKEN || false,
|
|
9
9
|
ghrepo: env.GH_REPO || env.GITHUB_REPO || false,
|
|
10
|
-
headless: env.PUPPETEER_HEADLESS
|
|
10
|
+
headless: env.PUPPETEER_HEADLESS !== "0" && env.PUPPETEER_HEADLESS !== "false" && env.PUPPETEER_HEADLESS !== false,
|
|
11
11
|
debug: (env.DEBUG && /^semantic-release:(\*|whmcs)$/.test(env.DEBUG)) || false,
|
|
12
12
|
useCookieExtension: env.USE_COOKIE_EXTENSION || true,
|
|
13
13
|
keepBrowserOpenOnError: env.PUPPETEER_KEEP_OPEN === "1" || env.PUPPETEER_KEEP_OPEN === "true" || false,
|
|
14
|
+
skipOsDeps: env.SKIP_OS_DEPS === "1" || env.SKIP_OS_DEPS === "true" || false,
|
|
14
15
|
};
|
|
15
16
|
};
|
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.2.
|
|
4
|
+
"version": "5.2.10",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
"files": [
|
|
38
38
|
"test/**/*.test.js"
|
|
39
39
|
],
|
|
40
|
+
"require": [
|
|
41
|
+
"dotenv/config"
|
|
42
|
+
],
|
|
40
43
|
"nodeArguments": [
|
|
41
44
|
"--no-warnings"
|
|
42
45
|
],
|
|
@@ -68,7 +71,8 @@
|
|
|
68
71
|
"overrides": {
|
|
69
72
|
"http-cache-semantics": "^4.1.1",
|
|
70
73
|
"word-wrap": "npm:@aashutoshrathi/word-wrap@1.2.6",
|
|
71
|
-
"glob-parent": "^5.1.2"
|
|
74
|
+
"glob-parent": "^5.1.2",
|
|
75
|
+
"tar": "^7.5.7"
|
|
72
76
|
},
|
|
73
77
|
"devDependencies": {
|
|
74
78
|
"@semantic-release/changelog": "^6.0.3",
|
|
@@ -76,8 +80,9 @@
|
|
|
76
80
|
"@semantic-release/git": "^10.0.1",
|
|
77
81
|
"ava": "6.4.1",
|
|
78
82
|
"c8": "^10.1.3",
|
|
79
|
-
"
|
|
80
|
-
"
|
|
83
|
+
"dotenv": "^16.6.1",
|
|
84
|
+
"prettier": "^3.8.1",
|
|
85
|
+
"semantic-release": "^25.0.3",
|
|
81
86
|
"semantic-release-teams-notify-plugin": "github:centralnicgroup-opensource/rtldev-middleware-semantic-release-notify-plugin",
|
|
82
87
|
"stream-buffers": "^3.0.3"
|
|
83
88
|
},
|
|
@@ -86,7 +91,7 @@
|
|
|
86
91
|
"@semantic-release/error": "^4.0.0",
|
|
87
92
|
"aggregate-error": "^5.0.0",
|
|
88
93
|
"debug": "^4.4.3",
|
|
89
|
-
"puppeteer": "
|
|
94
|
+
"puppeteer": "^24.37.2",
|
|
90
95
|
"yargs": "^18.0.0"
|
|
91
96
|
}
|
|
92
97
|
}
|