diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8ee3a8a..3cab51d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,5 +6,5 @@ - [ ] Verify the Required Checks are Passing - [ ] Update the [README.md](../blob/master/README.md) _if applicable_ -- -- [ ] Update the [documentation](https://github.com/cssnr/portainer-stack-deploy-docs) _if applicable_ + + \ No newline at end of file diff --git a/README.md b/README.md index 977e015..cf879ac 100644 --- a/README.md +++ b/README.md @@ -681,6 +681,7 @@ Additionally, you can support other GitHub Actions I have published: - [Stack Deploy Action](https://github.com/cssnr/stack-deploy-action?tab=readme-ov-file#readme) - [Portainer Stack Deploy Action](https://github.com/cssnr/portainer-stack-deploy-action?tab=readme-ov-file#readme) - [Docker Context Action](https://github.com/cssnr/docker-context-action?tab=readme-ov-file#readme) +- [Actions Up Action](https://github.com/cssnr/actions-up-action?tab=readme-ov-file#readme) - [VirusTotal Action](https://github.com/cssnr/virustotal-action?tab=readme-ov-file#readme) - [Mirror Repository Action](https://github.com/cssnr/mirror-repository-action?tab=readme-ov-file#readme) - [Update Version Tags Action](https://github.com/cssnr/update-version-tags-action?tab=readme-ov-file#readme) @@ -703,6 +704,7 @@ Additionally, you can support other GitHub Actions I have published: These actions are not published on the Marketplace, but may be useful. +- [cssnr/create-files-action](https://github.com/cssnr/create-files-action?tab=readme-ov-file#readme) - Create various files from templates. - [cssnr/draft-release-action](https://github.com/cssnr/draft-release-action?tab=readme-ov-file#readme) - Keep a draft release ready to publish. - [cssnr/env-json-action](https://github.com/cssnr/env-json-action?tab=readme-ov-file#readme) - Convert env file to json or vice versa. - [cssnr/push-artifacts-action](https://github.com/cssnr/push-artifacts-action?tab=readme-ov-file#readme) - Sync files to a remote host with rsync. diff --git a/dist/index.js b/dist/index.js index ef896c9..efc8440 100644 --- a/dist/index.js +++ b/dist/index.js @@ -34804,7 +34804,7 @@ const https = __nccwpck_require__(4708) class Portainer { /** - * Portainer API + * Portainer API - https://app.swaggerhub.com/apis/portainer/portainer-ce/ * @param {string} url * @param {string} token * @param {object} [headers] @@ -34816,6 +34816,7 @@ class Portainer { const agent = new https.Agent({ rejectUnauthorized: false, }) + // noinspection JSCheckFunctionSignatures this.client = axios.create({ baseURL: url, headers: { 'X-API-Key': token, ...headers }, @@ -34828,7 +34829,17 @@ class Portainer { /** * Get Version - * @return {Promise} + * @typedef {object} Version - https://app.swaggerhub.com/apis/portainer/portainer-ce/#/system.versionResponse + * @property {boolean} UpdateAvailable + * @property {string} LatestVersion + * @property {string} ServerVersion + * @property {string} VersionSupport + * @property {string} ServerEdition + * @property {string} DatabaseVersion + * @property {object} Build + * @property {object} Dependencies + * @property {object} Runtime + * @return {Promise} */ async getVersion() { const response = await this.client.get('/system/version') @@ -34847,7 +34858,19 @@ class Portainer { /** * Get Swarm * @param {string|number} endpointId - * @return {Promise} + * @typedef {object} Swarm + * @property {string} CreatedAt + * @property {number} DataPathPort + * @property {string[]} DefaultAddrPool + * @property {string} ID + * @property {object} JoinTokens + * @property {boolean} RootRotationInProgress + * @property {object} Spec + * @property {number} SubnetSize + * @property {object} TLSInfo + * @property {string} UpdatedAt + * @property {object} Version + * @return {Promise} */ async getSwarm(endpointId) { const response = await this.client.get(`/endpoints/${endpointId}/docker/swarm`) @@ -34856,7 +34879,33 @@ class Portainer { /** * Get Stacks - * @return {Promise} + * @typedef {object} Stack - https://app.swaggerhub.com/apis/portainer/portainer-ce/#/portainer.Stack + * @property {number} Id + * @property {string} Name + * @property {number} Type + * @property {number} EndpointId + * @property {string} SwarmId + * @property {string} EntryPoint + * @property {Env[]} Env + * @property {object} ResourceControl + * @property {number} Status + * @property {string} ProjectPath + * @property {number} CreationDate + * @property {string} CreatedBy + * @property {number} UpdateDate + * @property {string} UpdatedBy + * @property {object} AdditionalFiles + * @property {object} AutoUpdate + * @property {object} Option + * @property {object} GitConfig + * @property {boolean} FromAppTemplate + * @property {string} Namespace + * + * @typedef {object} Env + * @property {string} name + * @property {string} value + * + * @return {Promise} */ async getStacks() { const response = await this.client.get('/stacks') @@ -34865,10 +34914,10 @@ class Portainer { /** * Update Stack Repository - * @param {string} stackID + * @param {string|number} stackID * @param {string|number} endpointId * @param {object} body - * @return {Promise} + * @return {Promise} */ async updateStackRepo(stackID, endpointId, body) { const response = await this.client.put(`/stacks/${stackID}/git/redeploy`, body, { @@ -34882,7 +34931,7 @@ class Portainer { * @param {string|number} endpointId * @param {object} body * @param {string} [url] - * @return {Promise} + * @return {Promise} */ async createStackRepo(endpointId, body, url) { if (body.swarmID) { @@ -34898,10 +34947,10 @@ class Portainer { /** * Update Stack String - * @param {string} stackID + * @param {string|number} stackID * @param {string|number} endpointId * @param {object} body - * @return {Promise} + * @return {Promise} */ async updateStackString(stackID, endpointId, body) { const response = await this.client.put(`/stacks/${stackID}`, body, { @@ -34915,7 +34964,7 @@ class Portainer { * @param {string|number} endpointId * @param {object} body * @param {string} [url] - * @return {Promise} + * @return {Promise} */ async createStackString(endpointId, body, url) { if (body.swarmID) { @@ -36855,16 +36904,16 @@ module.exports = parseParams /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; -/*! Axios v1.13.1 Copyright (c) 2025 Matt Zabriskie and contributors */ +/*! Axios v1.13.2 Copyright (c) 2025 Matt Zabriskie and contributors */ const FormData$1 = __nccwpck_require__(6454); const crypto = __nccwpck_require__(6982); const url = __nccwpck_require__(7016); -const http2 = __nccwpck_require__(5675); const proxyFromEnv = __nccwpck_require__(7777); const http = __nccwpck_require__(8611); const https = __nccwpck_require__(5692); +const http2 = __nccwpck_require__(5675); const util = __nccwpck_require__(9023); const followRedirects = __nccwpck_require__(1573); const zlib = __nccwpck_require__(3106); @@ -36879,6 +36928,7 @@ const url__default = /*#__PURE__*/_interopDefaultLegacy(url); const proxyFromEnv__default = /*#__PURE__*/_interopDefaultLegacy(proxyFromEnv); const http__default = /*#__PURE__*/_interopDefaultLegacy(http); const https__default = /*#__PURE__*/_interopDefaultLegacy(https); +const http2__default = /*#__PURE__*/_interopDefaultLegacy(http2); const util__default = /*#__PURE__*/_interopDefaultLegacy(util); const followRedirects__default = /*#__PURE__*/_interopDefaultLegacy(followRedirects); const zlib__default = /*#__PURE__*/_interopDefaultLegacy(zlib); @@ -39015,7 +39065,7 @@ function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) { return requestedURL; } -const VERSION = "1.13.1"; +const VERSION = "1.13.2"; function parseProtocol(url) { const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url); @@ -39592,13 +39642,6 @@ const brotliOptions = { finishFlush: zlib__default["default"].constants.BROTLI_OPERATION_FLUSH }; -const { - HTTP2_HEADER_SCHEME, - HTTP2_HEADER_METHOD, - HTTP2_HEADER_PATH, - HTTP2_HEADER_STATUS -} = http2.constants; - const isBrotliSupported = utils$1.isFunction(zlib__default["default"].createBrotliDecompress); const {http: httpFollow, https: httpsFollow} = followRedirects__default["default"]; @@ -39628,9 +39671,9 @@ class Http2Sessions { sessionTimeout: 1000 }, options); - let authoritySessions; + let authoritySessions = this.sessions[authority]; - if ((authoritySessions = this.sessions[authority])) { + if (authoritySessions) { let len = authoritySessions.length; for (let i = 0; i < len; i++) { @@ -39641,7 +39684,7 @@ class Http2Sessions { } } - const session = http2.connect(authority, options); + const session = http2__default["default"].connect(authority, options); let removed; @@ -39656,11 +39699,12 @@ class Http2Sessions { while (i--) { if (entries[i][0] === session) { - entries.splice(i, 1); if (len === 1) { delete this.sessions[authority]; - return; + } else { + entries.splice(i, 1); } + return; } } }; @@ -39699,12 +39743,12 @@ class Http2Sessions { session.once('close', removeSession); - let entries = this.sessions[authority], entry = [ - session, - options - ]; + let entry = [ + session, + options + ]; - entries ? this.sessions[authority].push(entry) : authoritySessions = this.sessions[authority] = [entry]; + authoritySessions ? authoritySessions.push(entry) : authoritySessions = this.sessions[authority] = [entry]; return session; } @@ -39832,6 +39876,13 @@ const http2Transport = { const session = http2Sessions.getSession(authority, http2Options); + const { + HTTP2_HEADER_SCHEME, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_HEADER_STATUS + } = http2__default["default"].constants; + const http2Headers = { [HTTP2_HEADER_SCHEME]: options.protocol.replace(':', ''), [HTTP2_HEADER_METHOD]: options.method, @@ -40411,6 +40462,9 @@ const httpAdapter = isHttpAdapterSupported && function httpAdapter(config) { req )); }); + } else { + // explicitly reset the socket timeout value for a possible `keep-alive` request + req.setTimeout(0); } @@ -42282,7 +42336,7 @@ const Portainer = __nccwpck_require__(1055) // console.log('stack:', stack) core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) } else { - core.info(' Stack NOT Found - Deploying NEW Stack') + core.info('Stack NOT Found - Deploying NEW Stack') const body = { name: inputs.name, swarmID, @@ -42325,7 +42379,7 @@ const Portainer = __nccwpck_require__(1055) * @function getEnv * @param {Inputs} inputs * @param {object} stack - * @return {object[]} Portainer formatted environment + * @return {Env[]} */ function getEnv(inputs, stack) { if (!inputs.env_data && !inputs.env_file) { diff --git a/package-lock.json b/package-lock.json index 9c29db2..c2da72b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,14 +7,14 @@ "name": "portainer-stack-deploy-action", "dependencies": { "@actions/core": "^1.11.1", - "axios": "^1.13.1", + "axios": "^1.13.2", "dotenv": "^17.2.3", "js-yaml": "^4.1.0" }, "devDependencies": { - "@eslint/js": "^9.39.0", + "@eslint/js": "^9.39.1", "@vercel/ncc": "^0.38.4", - "eslint": "^9.39.0", + "eslint": "^9.39.1", "prettier": "^3.6.2" } }, @@ -161,9 +161,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.0.tgz", - "integrity": "sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { @@ -351,9 +351,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.1.tgz", - "integrity": "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -592,9 +592,9 @@ } }, "node_modules/eslint": { - "version": "9.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.0.tgz", - "integrity": "sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", "dependencies": { @@ -604,7 +604,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.0", + "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/package.json b/package.json index a73af67..22e7842 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,14 @@ }, "dependencies": { "@actions/core": "^1.11.1", - "axios": "^1.13.1", + "axios": "^1.13.2", "dotenv": "^17.2.3", "js-yaml": "^4.1.0" }, "devDependencies": { - "@eslint/js": "^9.39.0", + "@eslint/js": "^9.39.1", "@vercel/ncc": "^0.38.4", - "eslint": "^9.39.0", + "eslint": "^9.39.1", "prettier": "^3.6.2" } } diff --git a/src/index.js b/src/index.js index 4613352..20cd1cc 100644 --- a/src/index.js +++ b/src/index.js @@ -129,7 +129,7 @@ const Portainer = require('./portainer') // console.log('stack:', stack) core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) } else { - core.info(' Stack NOT Found - Deploying NEW Stack') + core.info('Stack NOT Found - Deploying NEW Stack') const body = { name: inputs.name, swarmID, @@ -172,7 +172,7 @@ const Portainer = require('./portainer') * @function getEnv * @param {Inputs} inputs * @param {object} stack - * @return {object[]} Portainer formatted environment + * @return {Env[]} */ function getEnv(inputs, stack) { if (!inputs.env_data && !inputs.env_file) { diff --git a/src/portainer.js b/src/portainer.js index 64bce62..facb61f 100644 --- a/src/portainer.js +++ b/src/portainer.js @@ -3,7 +3,7 @@ const https = require('node:https') class Portainer { /** - * Portainer API + * Portainer API - https://app.swaggerhub.com/apis/portainer/portainer-ce/ * @param {string} url * @param {string} token * @param {object} [headers] @@ -15,6 +15,7 @@ class Portainer { const agent = new https.Agent({ rejectUnauthorized: false, }) + // noinspection JSCheckFunctionSignatures this.client = axios.create({ baseURL: url, headers: { 'X-API-Key': token, ...headers }, @@ -27,7 +28,17 @@ class Portainer { /** * Get Version - * @return {Promise} + * @typedef {object} Version - https://app.swaggerhub.com/apis/portainer/portainer-ce/#/system.versionResponse + * @property {boolean} UpdateAvailable + * @property {string} LatestVersion + * @property {string} ServerVersion + * @property {string} VersionSupport + * @property {string} ServerEdition + * @property {string} DatabaseVersion + * @property {object} Build + * @property {object} Dependencies + * @property {object} Runtime + * @return {Promise} */ async getVersion() { const response = await this.client.get('/system/version') @@ -46,7 +57,19 @@ class Portainer { /** * Get Swarm * @param {string|number} endpointId - * @return {Promise} + * @typedef {object} Swarm + * @property {string} CreatedAt + * @property {number} DataPathPort + * @property {string[]} DefaultAddrPool + * @property {string} ID + * @property {object} JoinTokens + * @property {boolean} RootRotationInProgress + * @property {object} Spec + * @property {number} SubnetSize + * @property {object} TLSInfo + * @property {string} UpdatedAt + * @property {object} Version + * @return {Promise} */ async getSwarm(endpointId) { const response = await this.client.get(`/endpoints/${endpointId}/docker/swarm`) @@ -55,7 +78,33 @@ class Portainer { /** * Get Stacks - * @return {Promise} + * @typedef {object} Stack - https://app.swaggerhub.com/apis/portainer/portainer-ce/#/portainer.Stack + * @property {number} Id + * @property {string} Name + * @property {number} Type + * @property {number} EndpointId + * @property {string} SwarmId + * @property {string} EntryPoint + * @property {Env[]} Env + * @property {object} ResourceControl + * @property {number} Status + * @property {string} ProjectPath + * @property {number} CreationDate + * @property {string} CreatedBy + * @property {number} UpdateDate + * @property {string} UpdatedBy + * @property {object} AdditionalFiles + * @property {object} AutoUpdate + * @property {object} Option + * @property {object} GitConfig + * @property {boolean} FromAppTemplate + * @property {string} Namespace + * + * @typedef {object} Env + * @property {string} name + * @property {string} value + * + * @return {Promise} */ async getStacks() { const response = await this.client.get('/stacks') @@ -64,10 +113,10 @@ class Portainer { /** * Update Stack Repository - * @param {string} stackID + * @param {string|number} stackID * @param {string|number} endpointId * @param {object} body - * @return {Promise} + * @return {Promise} */ async updateStackRepo(stackID, endpointId, body) { const response = await this.client.put(`/stacks/${stackID}/git/redeploy`, body, { @@ -81,7 +130,7 @@ class Portainer { * @param {string|number} endpointId * @param {object} body * @param {string} [url] - * @return {Promise} + * @return {Promise} */ async createStackRepo(endpointId, body, url) { if (body.swarmID) { @@ -97,10 +146,10 @@ class Portainer { /** * Update Stack String - * @param {string} stackID + * @param {string|number} stackID * @param {string|number} endpointId * @param {object} body - * @return {Promise} + * @return {Promise} */ async updateStackString(stackID, endpointId, body) { const response = await this.client.put(`/stacks/${stackID}`, body, { @@ -114,7 +163,7 @@ class Portainer { * @param {string|number} endpointId * @param {object} body * @param {string} [url] - * @return {Promise} + * @return {Promise} */ async createStackString(endpointId, body, url) { if (body.swarmID) {