From 42c9c5358123429f13f96deaa6d328ada171300b Mon Sep 17 00:00:00 2001 From: Shane <6071159+smashedr@users.noreply.github.com> Date: Sat, 8 Nov 2025 22:53:58 -0800 Subject: [PATCH 1/2] Updates for v2 and node24 --- .github/workflows/check-build.yaml | 34 +--- .github/workflows/labeler.yaml | 6 +- .github/workflows/lint.yaml | 7 +- .github/workflows/mirror.yaml | 2 +- .github/workflows/pull.yaml | 8 +- .github/workflows/release.yaml | 9 +- .github/workflows/tags.yaml | 2 +- .github/workflows/test.yaml | 8 + .prettierignore | 1 + README.md | 5 +- action.yml | 4 +- dist/index.js | 294 ++++++++++++++--------------- package-lock.json | 2 + package.json | 2 +- src/index.js | 290 ++++++++++++++-------------- 15 files changed, 339 insertions(+), 335 deletions(-) diff --git a/.github/workflows/check-build.yaml b/.github/workflows/check-build.yaml index 510ad80..f835fca 100644 --- a/.github/workflows/check-build.yaml +++ b/.github/workflows/check-build.yaml @@ -1,7 +1,14 @@ name: "Check Build" on: + push: + branches: [master] pull_request_target: + paths: + - "dist/**" + - "src/**" + - "package*.json" + - "rollup.config.*" concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -24,24 +31,12 @@ jobs: GITHUB_CTX: ${{ toJSON(github) }} run: echo "$GITHUB_CTX" - - name: "Check Changed Files" - id: changed - uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47 - with: - files: | - dist/** - src/** - package*.json - rollup.config.* - - name: "Checkout Pull" - if: ${{ steps.changed.outputs.any_changed == 'true' }} uses: actions/checkout@v5 with: ref: ${{ github.event.pull_request.head.sha }} - name: "Debug" - if: ${{ steps.changed.outputs.any_changed == 'true' }} continue-on-error: true run: | echo "::group::ls" @@ -51,18 +46,5 @@ jobs: tree . echo "::endgroup::" - #- name: "Setup Node" - # if: ${{ steps.changed.outputs.any_changed == 'true' }} - # uses: actions/setup-node@v6 - # with: - # node-version: 24 - # - #- name: "Install" - # if: ${{ steps.changed.outputs.any_changed == 'true' }} - # id: install - # run: | - # npm ci - - name: "Check Build Action" - if: ${{ steps.changed.outputs.any_changed == 'true' }} - uses: cssnr/check-build-action@v1 + uses: cssnr/check-build-action@latest diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml index eb36453..2f3c44d 100644 --- a/.github/workflows/labeler.yaml +++ b/.github/workflows/labeler.yaml @@ -3,6 +3,10 @@ name: "PR Labeler" on: pull_request_target: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: labeler: name: "Labeler" @@ -37,7 +41,7 @@ jobs: - name: "Label Creator" continue-on-error: true - uses: cssnr/label-creator-action@v1 + uses: cssnr/label-creator-action@latest with: file: .configs/labels/labels.yaml diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 4792273..306a104 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,6 +13,7 @@ concurrency: jobs: lint: name: "Lint" + if: ${{ !contains(github.event.head_commit.message, '#nolint') }} runs-on: ubuntu-latest timeout-minutes: 5 @@ -75,11 +76,7 @@ jobs: run: | yq -e '.runs.main | test("^dist/")' action.yml - #- name: "Check Build Action" - # if: ${{ !cancelled() }} - # uses: cssnr/check-build-action@v1 - - name: "ESLint Annotate" if: ${{ !cancelled() && steps.eslint.outcome != 'success' }} continue-on-error: true - uses: ataylorme/eslint-annotate-action@v3 + uses: ataylorme/eslint-annotate-action@d57a1193d4c59cbfbf3f86c271f42612f9dbd9e9 # 3.0.0 diff --git a/.github/workflows/mirror.yaml b/.github/workflows/mirror.yaml index 00bdae6..db82412 100644 --- a/.github/workflows/mirror.yaml +++ b/.github/workflows/mirror.yaml @@ -23,7 +23,7 @@ jobs: fetch-depth: 0 - name: "Mirror to Codeberg" - uses: cssnr/mirror-repository-action@v1 + uses: cssnr/mirror-repository-action@latest with: host: https://codeberg.org create: true diff --git a/.github/workflows/pull.yaml b/.github/workflows/pull.yaml index da86b80..3fe1eec 100644 --- a/.github/workflows/pull.yaml +++ b/.github/workflows/pull.yaml @@ -41,4 +41,10 @@ jobs: - name: "NPM Outdated Check" continue-on-error: true - uses: cssnr/npm-outdated-action@master + uses: cssnr/npm-outdated-action@latest + + - name: "Actions Up" + continue-on-error: true + uses: cssnr/actions-up-action@latest + with: + exclude: "cssnr/.*,actions/.*" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c37a857..6177006 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,7 +16,9 @@ jobs: steps: - name: "Update Tags" id: tags - uses: cssnr/update-version-tags-action@v1 + uses: cssnr/update-version-tags-action@latest + with: + tags: "latest" - name: "Debug Tags" continue-on-error: true @@ -30,13 +32,14 @@ jobs: with: tags: ${{ steps.tags.outputs.tags }} location: tail + type: "actions" - name: "Package Changelog Action" continue-on-error: true - uses: cssnr/package-changelog-action@v1 + uses: cssnr/package-changelog-action@latest - name: "Send Failure Notification" if: ${{ failure() }} - uses: sarisia/actions-status-discord@v1 + uses: sarisia/actions-status-discord@b8381b25576cb341b2af39926ab42c5056cc44ed # v1.15.5 with: webhook: ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index 38b5c74..a2ee80c 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: "Update Tags" - uses: cssnr/update-version-tags-action@v1 + uses: cssnr/update-version-tags-action@latest with: tag: ${{ inputs.tag }} token: ${{ secrets.GH_PAT }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4f275e0..5ca23e2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,5 +1,7 @@ name: "Test" +# actions-up-ignore-file + on: workflow_dispatch: schedule: @@ -35,6 +37,12 @@ jobs: GITHUB_CTX: ${{ toJSON(github) }} run: echo "$GITHUB_CTX" + - name: "Debug Environment" + if: ${{ !github.event.act }} + continue-on-error: true + run: | + env + - name: "Write YAML" id: yaml-action uses: teunmooij/yaml@v1 diff --git a/.prettierignore b/.prettierignore index cd26c30..b01fca6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -14,4 +14,5 @@ node_modules/ .github/disabled/ # Files +.github/PULL_REQUEST_TEMPLATE/ .github/pull_request_template.md diff --git a/README.md b/README.md index cf879ac..5aa6724 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![GitHub Tag Minor](https://img.shields.io/github/v/tag/cssnr/portainer-stack-deploy-action?sort=semver&filter=!v*.*.*&logo=git&logoColor=white&labelColor=585858&label=%20)](https://github.com/cssnr/portainer-stack-deploy-action/releases) [![GitHub Release Version](https://img.shields.io/github/v/release/cssnr/portainer-stack-deploy-action?logo=git&logoColor=white&labelColor=585858&label=%20)](https://github.com/cssnr/portainer-stack-deploy-action/releases/latest) [![GitHub Dist Size](https://img.shields.io/github/size/cssnr/portainer-stack-deploy-action/dist%2Findex.js?logo=bookstack&logoColor=white&label=dist%20size)](https://github.com/cssnr/portainer-stack-deploy-action/blob/master/src) +[![Action Run Using](https://img.shields.io/badge/dynamic/yaml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fcssnr%2Fportainer-stack-deploy-action%2Frefs%2Fheads%2Fmaster%2Faction.yml&query=%24.runs.using&logo=githubactions&logoColor=white&label=runs)](https://github.com/cssnr/portainer-stack-deploy-action/blob/master/action.yml) [![Workflow Release](https://img.shields.io/github/actions/workflow/status/cssnr/portainer-stack-deploy-action/release.yaml?logo=cachet&label=release)](https://github.com/cssnr/portainer-stack-deploy-action/actions/workflows/release.yaml) [![Workflow Test](https://img.shields.io/github/actions/workflow/status/cssnr/portainer-stack-deploy-action/test.yaml?logo=cachet&label=test)](https://github.com/cssnr/portainer-stack-deploy-action/actions/workflows/test.yaml) [![Workflow Lint](https://img.shields.io/github/actions/workflow/status/cssnr/portainer-stack-deploy-action/lint.yaml?logo=cachet&label=lint)](https://github.com/cssnr/portainer-stack-deploy-action/actions/workflows/lint.yaml) @@ -720,9 +721,9 @@ These actions are not published on the Marketplace, but may be useful. These are basic action templates that I use for creating new actions. - [js-test-action](https://github.com/smashedr/js-test-action?tab=readme-ov-file#readme) - JavaScript -- [py-test-action](https://github.com/smashedr/py-test-action?tab=readme-ov-file#readme) - Python - [ts-test-action](https://github.com/smashedr/ts-test-action?tab=readme-ov-file#readme) - TypeScript -- [docker-test-action](https://github.com/smashedr/docker-test-action?tab=readme-ov-file#readme) - Docker Image +- [py-test-action](https://github.com/smashedr/py-test-action?tab=readme-ov-file#readme) - Python (Dockerfile) +- [docker-test-action](https://github.com/smashedr/docker-test-action?tab=readme-ov-file#readme) - Docker (Image) Note: The `docker-test-action` builds, runs and pushes images to [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry). diff --git a/action.yml b/action.yml index 66979f5..e70f8d9 100644 --- a/action.yml +++ b/action.yml @@ -56,7 +56,7 @@ inputs: password: description: "Repository Password" fs_path: - description: "Relative path volume in host (only available in Portainer BE)" + description: "Relative path volume in host (Portainer BE)" headers: description: "Custom Headers JSON" summary: @@ -72,5 +72,5 @@ outputs: description: "Endpoint ID" runs: - using: "node20" + using: "node24" main: "dist/index.js" diff --git a/dist/index.js b/dist/index.js index efc8440..7b2b69f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -42212,168 +42212,162 @@ const yaml = __nccwpck_require__(4281) const Portainer = __nccwpck_require__(1055) -;(async () => { - try { - core.info('🏳️ Portainer Stack Deploy Action') +async function main() /* NOSONAR */ { + core.info('🏳️ Portainer Stack Deploy Action') - // Parse Inputs - const inputs = getInputs() - core.startGroup('Parsed Inputs') - console.log('inputs:', inputs) - core.endGroup() // Inputs + // Parse Inputs + const inputs = getInputs() + core.startGroup('Parsed Inputs') + console.log('inputs:', inputs) + core.endGroup() // Inputs - if (!['repo', 'file'].includes(inputs.type)) { - core.setFailed(`Unknown type: ${inputs.type}. Values: [repo, file]`) - return - } + if (!['repo', 'file'].includes(inputs.type)) { + core.setFailed(`Unknown type: ${inputs.type}. Values: [repo, file]`) + return + } - // Check Portainer - const headers = parseData(inputs.headers) - // console.log('headers:', headers) - const portainer = new Portainer(inputs.url, inputs.token, headers) - const version = await portainer.getVersion() - const versionString = `${version.ServerVersion} ${version.VersionSupport} ${version.ServerEdition}` - core.startGroup(`Portainer Version: \u001b[34m${versionString}`) - delete version.Runtime - console.log(version) - core.endGroup() // Portainer Version - - if (inputs.fs_path) { - if (version.ServerEdition !== 'EE') { - core.setFailed('Relative path only supported in Portainer EE!') - return - } + // Check Portainer + const headers = parseData(inputs.headers) + // console.log('headers:', headers) + const portainer = new Portainer(inputs.url, inputs.token, headers) + const version = await portainer.getVersion() + const versionString = `${version.ServerVersion} ${version.VersionSupport} ${version.ServerEdition}` + core.startGroup(`Portainer Version: \u001b[34m${versionString}`) + delete version.Runtime + console.log(version) + core.endGroup() // Portainer Version + + if (inputs.fs_path) { + if (version.ServerEdition !== 'EE') { + core.setFailed('Relative path only supported in Portainer EE!') + return } + } - // Set Variables - let endpointID = Number.parseInt(inputs.endpoint) + // Set Variables + let endpointID = Number.parseInt(inputs.endpoint) + if (!endpointID) { + const endpoints = await portainer.getEndpoints() + // console.log('endpoints:', endpoints) + endpointID = endpoints[0]?.Id if (!endpointID) { - const endpoints = await portainer.getEndpoints() - // console.log('endpoints:', endpoints) - endpointID = endpoints[0]?.Id - if (!endpointID) { - return core.setFailed('No Endpoints Found!') - } + return core.setFailed('No Endpoints Found!') } - core.info(`endpointID: \u001b[36m${endpointID}`) + } + core.info(`endpointID: \u001b[36m${endpointID}`) - let swarmID = null - if (!inputs.standalone) { - const swarm = await portainer.getSwarm(endpointID) - // console.log('swarm:', swarm) - swarmID = swarm.ID - } - core.info(`swarmID: \u001b[36m${swarmID}`) + let swarmID = null + if (!inputs.standalone) { + const swarm = await portainer.getSwarm(endpointID) + // console.log('swarm:', swarm) + swarmID = swarm.ID + } + core.info(`swarmID: \u001b[36m${swarmID}`) - // Get Stack - const stacks = await portainer.getStacks() - // console.log('stacks:', stacks) - let stack = stacks.find( - (item) => item.Name === inputs.name && item.EndpointId === endpointID - ) - // console.log('stack:', stack) - let stackID = stack?.Id - core.info(`stackID: \u001b[36m${stackID}`) - - // Update Environment - const env = getEnv(inputs, stack) - - // Perform Deploy - if (inputs.type === 'repo') { - core.info('🌐 Performing Repository Deployment') - const repositoryAuthentication = !!(inputs.username || inputs.password) - if (stackID) { - core.info(`Stack Found - Updating Stack ID: ${stack.Id}`) - const body = { - env, - prune: inputs.prune, - pullImage: inputs.pull, - repositoryReferenceName: inputs.ref, - repositoryAuthentication, - repositoryPassword: inputs.password, - repositoryUsername: inputs.username, - } - // console.log('body:', body) - stack = await portainer.updateStackRepo(stackID, endpointID, body) - // console.log('stack:', stack) - core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) - } else { - core.info('Stack NOT Found - Deploying NEW Stack') - const body = { - name: inputs.name, - swarmID, - repositoryURL: inputs.repo, - composeFile: inputs.file, - env, - tlsskipVerify: inputs.tlsskip, - repositoryReferenceName: inputs.ref, - repositoryAuthentication, - repositoryPassword: inputs.password, - repositoryUsername: inputs.username, - ...(inputs.fs_path && { - supportRelativePath: true, - fileSystemPath: inputs.fs_path, - }), - } - // console.log('body:', body) - stack = await portainer.createStackRepo(endpointID, body) - // console.log('stack:', stack) - core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) + // Get Stack + const stacks = await portainer.getStacks() + // console.log('stacks:', stacks) + let stack = stacks.find( + (item) => item.Name === inputs.name && item.EndpointId === endpointID + ) + // console.log('stack:', stack) + let stackID = stack?.Id + core.info(`stackID: \u001b[36m${stackID}`) + + // Update Environment + const env = getEnv(inputs, stack) + + // Perform Deploy + if (inputs.type === 'repo') { + core.info('🌐 Performing Repository Deployment') + const repositoryAuthentication = !!(inputs.username || inputs.password) + if (stackID) { + core.info(`Stack Found - Updating Stack ID: ${stack.Id}`) + const body = { + env, + prune: inputs.prune, + pullImage: inputs.pull, + repositoryReferenceName: inputs.ref, + repositoryAuthentication, + repositoryPassword: inputs.password, + repositoryUsername: inputs.username, } - } else if (inputs.type === 'file') { - core.info('📄 Performing Stack File Deployment') - const stackFileContent = fs.readFileSync(inputs.file, 'utf-8') - if (stackID) { - core.info(`Stack Found - Updating Stack ID: ${stackID}`) - const body = { - env, - prune: inputs.prune, - pullImage: inputs.pull, - stackFileContent, - } - // console.log('body:', body) - stack = await portainer.updateStackString(stackID, endpointID, body) - // console.log('stack:', stack) - core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) - } else { - core.info('Stack NOT Found - Deploying NEW Stack') - const body = { - name: inputs.name, - swarmID, - stackFileContent, - env, - } - // console.log('body:', body) - stack = await portainer.createStackString(endpointID, body) - // console.log('stack:', stack) - core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) + // console.log('body:', body) + stack = await portainer.updateStackRepo(stackID, endpointID, body) + // console.log('stack:', stack) + core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) + } else { + core.info('Stack NOT Found - Deploying NEW Stack') + const body = { + name: inputs.name, + swarmID, + repositoryURL: inputs.repo, + composeFile: inputs.file, + env, + tlsskipVerify: inputs.tlsskip, + repositoryReferenceName: inputs.ref, + repositoryAuthentication, + repositoryPassword: inputs.password, + repositoryUsername: inputs.username, + ...(inputs.fs_path && { + supportRelativePath: true, + fileSystemPath: inputs.fs_path, + }), } + // console.log('body:', body) + stack = await portainer.createStackRepo(endpointID, body) + // console.log('stack:', stack) + core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) + } + } else if (inputs.type === 'file') { + core.info('📄 Performing Stack File Deployment') + const stackFileContent = fs.readFileSync(inputs.file, 'utf-8') + if (stackID) { + core.info(`Stack Found - Updating Stack ID: ${stackID}`) + const body = { + env, + prune: inputs.prune, + pullImage: inputs.pull, + stackFileContent, + } + // console.log('body:', body) + stack = await portainer.updateStackString(stackID, endpointID, body) + // console.log('stack:', stack) + core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) + } else { + core.info('Stack NOT Found - Deploying NEW Stack') + const body = { + name: inputs.name, + swarmID, + stackFileContent, + env, + } + // console.log('body:', body) + stack = await portainer.createStackString(endpointID, body) + // console.log('stack:', stack) + core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) } + } - // Set Outputs - core.info('📩 Setting Outputs') - core.setOutput('stackID', stack.Id) - core.setOutput('swarmID', swarmID) - core.setOutput('endpointID', endpointID) + // Set Outputs + core.info('📩 Setting Outputs') + core.setOutput('stackID', stack.Id) + core.setOutput('swarmID', swarmID) + core.setOutput('endpointID', endpointID) - // Summary - if (inputs.summary) { - core.info('📝 Writing Job Summary') - try { - await addSummary(inputs, stack) - } catch (e) { - console.log(e) - core.error(`Error writing Job Summary ${e.message}`) - } + // Summary + if (inputs.summary) { + core.info('📝 Writing Job Summary') + try { + await addSummary(inputs, stack) + } catch (e) { + console.log(e) + core.error(`Error writing Job Summary ${e.message}`) } - - core.info('✅ \u001b[32;1mFinished Success') - } catch (e) { - core.debug(e) - console.log('response:', e.response?.data) - core.setFailed(e.message) } -})() + + core.info('✅ \u001b[32;1mFinished Success') +} /** * @function getEnv @@ -42472,7 +42466,7 @@ async function addSummary(inputs, stack) { } /** - * Parse Data from Input + * Parse JSON/YAML Data from a String * @param {string} data * @return {object} */ @@ -42545,6 +42539,12 @@ function getInputs() { } } +main().catch((e) => { + core.debug(e) + core.info(e.message) + core.setFailed(e.message) +}) + module.exports = __webpack_exports__; /******/ })() ; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c2da72b..d425a6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -288,6 +288,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -597,6 +598,7 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", diff --git a/package.json b/package.json index 22e7842..9956787 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "main": "dist/index.js", "scripts": { - "build": "ncc build src/index.js", + "build": "npx ncc build src/index.js", "build:watch": "npm run build -- --watch", "lint": "npx eslint src", "lint:report": "npm run lint -- --output-file eslint_report.json --format json", diff --git a/src/index.js b/src/index.js index 20cd1cc..514cba4 100644 --- a/src/index.js +++ b/src/index.js @@ -3,170 +3,164 @@ const fs = require('node:fs') const dotenv = require('dotenv') const yaml = require('js-yaml') -const Portainer = require('./portainer') +const Portainer = require('./portainer.js') -;(async () => { - try { - core.info('🏳️ Portainer Stack Deploy Action') +async function main() /* NOSONAR */ { + core.info('🏳️ Portainer Stack Deploy Action') - // Parse Inputs - const inputs = getInputs() - core.startGroup('Parsed Inputs') - console.log('inputs:', inputs) - core.endGroup() // Inputs + // Parse Inputs + const inputs = getInputs() + core.startGroup('Parsed Inputs') + console.log('inputs:', inputs) + core.endGroup() // Inputs - if (!['repo', 'file'].includes(inputs.type)) { - core.setFailed(`Unknown type: ${inputs.type}. Values: [repo, file]`) - return - } + if (!['repo', 'file'].includes(inputs.type)) { + core.setFailed(`Unknown type: ${inputs.type}. Values: [repo, file]`) + return + } - // Check Portainer - const headers = parseData(inputs.headers) - // console.log('headers:', headers) - const portainer = new Portainer(inputs.url, inputs.token, headers) - const version = await portainer.getVersion() - const versionString = `${version.ServerVersion} ${version.VersionSupport} ${version.ServerEdition}` - core.startGroup(`Portainer Version: \u001b[34m${versionString}`) - delete version.Runtime - console.log(version) - core.endGroup() // Portainer Version + // Check Portainer + const headers = parseData(inputs.headers) + // console.log('headers:', headers) + const portainer = new Portainer(inputs.url, inputs.token, headers) + const version = await portainer.getVersion() + const versionString = `${version.ServerVersion} ${version.VersionSupport} ${version.ServerEdition}` + core.startGroup(`Portainer Version: \u001b[34m${versionString}`) + delete version.Runtime + console.log(version) + core.endGroup() // Portainer Version - if (inputs.fs_path) { - if (version.ServerEdition !== 'EE') { - core.setFailed('Relative path only supported in Portainer EE!') - return - } + if (inputs.fs_path) { + if (version.ServerEdition !== 'EE') { + core.setFailed('Relative path only supported in Portainer EE!') + return } + } - // Set Variables - let endpointID = Number.parseInt(inputs.endpoint) + // Set Variables + let endpointID = Number.parseInt(inputs.endpoint) + if (!endpointID) { + const endpoints = await portainer.getEndpoints() + // console.log('endpoints:', endpoints) + endpointID = endpoints[0]?.Id if (!endpointID) { - const endpoints = await portainer.getEndpoints() - // console.log('endpoints:', endpoints) - endpointID = endpoints[0]?.Id - if (!endpointID) { - return core.setFailed('No Endpoints Found!') - } + return core.setFailed('No Endpoints Found!') } - core.info(`endpointID: \u001b[36m${endpointID}`) + } + core.info(`endpointID: \u001b[36m${endpointID}`) - let swarmID = null - if (!inputs.standalone) { - const swarm = await portainer.getSwarm(endpointID) - // console.log('swarm:', swarm) - swarmID = swarm.ID - } - core.info(`swarmID: \u001b[36m${swarmID}`) + let swarmID = null + if (!inputs.standalone) { + const swarm = await portainer.getSwarm(endpointID) + // console.log('swarm:', swarm) + swarmID = swarm.ID + } + core.info(`swarmID: \u001b[36m${swarmID}`) - // Get Stack - const stacks = await portainer.getStacks() - // console.log('stacks:', stacks) - let stack = stacks.find( - (item) => item.Name === inputs.name && item.EndpointId === endpointID - ) - // console.log('stack:', stack) - let stackID = stack?.Id - core.info(`stackID: \u001b[36m${stackID}`) + // Get Stack + const stacks = await portainer.getStacks() + // console.log('stacks:', stacks) + let stack = stacks.find( + (item) => item.Name === inputs.name && item.EndpointId === endpointID + ) + // console.log('stack:', stack) + let stackID = stack?.Id + core.info(`stackID: \u001b[36m${stackID}`) - // Update Environment - const env = getEnv(inputs, stack) + // Update Environment + const env = getEnv(inputs, stack) - // Perform Deploy - if (inputs.type === 'repo') { - core.info('🌐 Performing Repository Deployment') - const repositoryAuthentication = !!(inputs.username || inputs.password) - if (stackID) { - core.info(`Stack Found - Updating Stack ID: ${stack.Id}`) - const body = { - env, - prune: inputs.prune, - pullImage: inputs.pull, - repositoryReferenceName: inputs.ref, - repositoryAuthentication, - repositoryPassword: inputs.password, - repositoryUsername: inputs.username, - } - // console.log('body:', body) - stack = await portainer.updateStackRepo(stackID, endpointID, body) - // console.log('stack:', stack) - core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) - } else { - core.info('Stack NOT Found - Deploying NEW Stack') - const body = { - name: inputs.name, - swarmID, - repositoryURL: inputs.repo, - composeFile: inputs.file, - env, - tlsskipVerify: inputs.tlsskip, - repositoryReferenceName: inputs.ref, - repositoryAuthentication, - repositoryPassword: inputs.password, - repositoryUsername: inputs.username, - ...(inputs.fs_path && { - supportRelativePath: true, - fileSystemPath: inputs.fs_path, - }), - } - // console.log('body:', body) - stack = await portainer.createStackRepo(endpointID, body) - // console.log('stack:', stack) - core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) + // Perform Deploy + if (inputs.type === 'repo') { + core.info('🌐 Performing Repository Deployment') + const repositoryAuthentication = !!(inputs.username || inputs.password) + if (stackID) { + core.info(`Stack Found - Updating Stack ID: ${stack.Id}`) + const body = { + env, + prune: inputs.prune, + pullImage: inputs.pull, + repositoryReferenceName: inputs.ref, + repositoryAuthentication, + repositoryPassword: inputs.password, + repositoryUsername: inputs.username, } - } else if (inputs.type === 'file') { - core.info('📄 Performing Stack File Deployment') - const stackFileContent = fs.readFileSync(inputs.file, 'utf-8') - if (stackID) { - core.info(`Stack Found - Updating Stack ID: ${stackID}`) - const body = { - env, - prune: inputs.prune, - pullImage: inputs.pull, - stackFileContent, - } - // console.log('body:', body) - stack = await portainer.updateStackString(stackID, endpointID, body) - // console.log('stack:', stack) - core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) - } else { - core.info('Stack NOT Found - Deploying NEW Stack') - const body = { - name: inputs.name, - swarmID, - stackFileContent, - env, - } - // console.log('body:', body) - stack = await portainer.createStackString(endpointID, body) - // console.log('stack:', stack) - core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) + // console.log('body:', body) + stack = await portainer.updateStackRepo(stackID, endpointID, body) + // console.log('stack:', stack) + core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) + } else { + core.info('Stack NOT Found - Deploying NEW Stack') + const body = { + name: inputs.name, + swarmID, + repositoryURL: inputs.repo, + composeFile: inputs.file, + env, + tlsskipVerify: inputs.tlsskip, + repositoryReferenceName: inputs.ref, + repositoryAuthentication, + repositoryPassword: inputs.password, + repositoryUsername: inputs.username, + ...(inputs.fs_path && { + supportRelativePath: true, + fileSystemPath: inputs.fs_path, + }), } + // console.log('body:', body) + stack = await portainer.createStackRepo(endpointID, body) + // console.log('stack:', stack) + core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) } - - // Set Outputs - core.info('📩 Setting Outputs') - core.setOutput('stackID', stack.Id) - core.setOutput('swarmID', swarmID) - core.setOutput('endpointID', endpointID) - - // Summary - if (inputs.summary) { - core.info('📝 Writing Job Summary') - try { - await addSummary(inputs, stack) - } catch (e) { - console.log(e) - core.error(`Error writing Job Summary ${e.message}`) + } else if (inputs.type === 'file') { + core.info('📄 Performing Stack File Deployment') + const stackFileContent = fs.readFileSync(inputs.file, 'utf-8') + if (stackID) { + core.info(`Stack Found - Updating Stack ID: ${stackID}`) + const body = { + env, + prune: inputs.prune, + pullImage: inputs.pull, + stackFileContent, } + // console.log('body:', body) + stack = await portainer.updateStackString(stackID, endpointID, body) + // console.log('stack:', stack) + core.info(`Updated Stack ${stack.Id}: ${stack.Name}`) + } else { + core.info('Stack NOT Found - Deploying NEW Stack') + const body = { + name: inputs.name, + swarmID, + stackFileContent, + env, + } + // console.log('body:', body) + stack = await portainer.createStackString(endpointID, body) + // console.log('stack:', stack) + core.info(`Deployed Stack: ${stack.Id}: ${stack.Name}`) } + } - core.info('✅ \u001b[32;1mFinished Success') - } catch (e) { - core.debug(e) - console.log('response:', e.response?.data) - core.setFailed(e.message) + // Set Outputs + core.info('📩 Setting Outputs') + core.setOutput('stackID', stack.Id) + core.setOutput('swarmID', swarmID) + core.setOutput('endpointID', endpointID) + + // Summary + if (inputs.summary) { + core.info('📝 Writing Job Summary') + try { + await addSummary(inputs, stack) + } catch (e) { + console.log(e) + core.error(`Error writing Job Summary ${e.message}`) + } } -})() + + core.info('✅ \u001b[32;1mFinished Success') +} /** * @function getEnv @@ -265,7 +259,7 @@ async function addSummary(inputs, stack) { } /** - * Parse Data from Input + * Parse JSON/YAML Data from a String * @param {string} data * @return {object} */ @@ -337,3 +331,9 @@ function getInputs() { summary: core.getBooleanInput('summary'), } } + +main().catch((e) => { + core.debug(e) + core.info(e.message) + core.setFailed(e.message) +}) From 8fb36780a6a0882b51c2dc18da5188cf9cfa4587 Mon Sep 17 00:00:00 2001 From: Shane <6071159+smashedr@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:24:37 -0800 Subject: [PATCH 2/2] Updates --- .github/workflows/check-build.yaml | 2 +- .github/workflows/labeler.yaml | 2 +- .github/workflows/lint.yaml | 14 +++--- .github/workflows/mirror.yaml | 2 +- .github/workflows/pull.yaml | 2 +- .github/workflows/release.yaml | 1 + .github/workflows/test.yaml | 3 +- README.md | 70 ++++++++++++++++-------------- action.yml | 1 + dist/index.js | 30 ++++++++----- package-lock.json | 16 +++---- package.json | 4 +- 12 files changed, 81 insertions(+), 66 deletions(-) diff --git a/.github/workflows/check-build.yaml b/.github/workflows/check-build.yaml index f835fca..4f47f08 100644 --- a/.github/workflows/check-build.yaml +++ b/.github/workflows/check-build.yaml @@ -32,7 +32,7 @@ jobs: run: echo "$GITHUB_CTX" - name: "Checkout Pull" - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml index 2f3c44d..6f280f5 100644 --- a/.github/workflows/labeler.yaml +++ b/.github/workflows/labeler.yaml @@ -19,7 +19,7 @@ jobs: steps: - name: "Checkout Configs" - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: cssnr/configs ref: master diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 306a104..2f37923 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -19,10 +19,12 @@ jobs: permissions: pull-requests: write + statuses: write + checks: write steps: - name: "Checkout" - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: "Setup Node 24" uses: actions/setup-node@v6 @@ -38,7 +40,7 @@ jobs: id: eslint if: ${{ !cancelled() }} run: | - npm run lint:report + npm run lint - name: "Prettier" if: ${{ !cancelled() }} @@ -76,7 +78,7 @@ jobs: run: | yq -e '.runs.main | test("^dist/")' action.yml - - name: "ESLint Annotate" - if: ${{ !cancelled() && steps.eslint.outcome != 'success' }} - continue-on-error: true - uses: ataylorme/eslint-annotate-action@d57a1193d4c59cbfbf3f86c271f42612f9dbd9e9 # 3.0.0 + #- name: "ESLint Annotate" + # if: ${{ !cancelled() && steps.eslint.outcome != 'success' }} + # continue-on-error: true + # uses: ataylorme/eslint-annotate-action@d57a1193d4c59cbfbf3f86c271f42612f9dbd9e9 # 3.0.0 diff --git a/.github/workflows/mirror.yaml b/.github/workflows/mirror.yaml index db82412..6e90954 100644 --- a/.github/workflows/mirror.yaml +++ b/.github/workflows/mirror.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: "Checkout" - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 diff --git a/.github/workflows/pull.yaml b/.github/workflows/pull.yaml index 3fe1eec..5722a77 100644 --- a/.github/workflows/pull.yaml +++ b/.github/workflows/pull.yaml @@ -25,7 +25,7 @@ jobs: run: echo "$GITHUB_CTX" - name: "Checkout Pull" - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6177006..26a168c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -43,3 +43,4 @@ jobs: uses: sarisia/actions-status-discord@b8381b25576cb341b2af39926ab42c5056cc44ed # v1.15.5 with: webhook: ${{ secrets.DISCORD_WEBHOOK }} + description: ${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5ca23e2..c441cf4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -28,7 +28,7 @@ jobs: steps: - name: "Checkout" - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: "Debug CTX github" if: ${{ !github.event.act }} @@ -93,3 +93,4 @@ jobs: uses: sarisia/actions-status-discord@v1 with: webhook: ${{ secrets.DISCORD_WEBHOOK }} + description: ${{ github.event.repository.html_url }}/actions/runs/${{ github.run_id }} diff --git a/README.md b/README.md index 5aa6724..9f5eb31 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ [![GitHub Last Commit](https://img.shields.io/github/last-commit/cssnr/portainer-stack-deploy-action?logo=github&label=updated)](https://github.com/cssnr/portainer-stack-deploy-action/pulse) [![Codeberg Last Commit](https://img.shields.io/gitea/last-commit/cssnr/portainer-stack-deploy-action/master?gitea_url=https%3A%2F%2Fcodeberg.org%2F&logo=codeberg&logoColor=white&label=updated)](https://codeberg.org/cssnr/portainer-stack-deploy-action) [![Docs Last Commit](https://img.shields.io/github/last-commit/cssnr/portainer-stack-deploy-docs?logo=vitepress&logoColor=white&label=docs)](https://portainer-deploy.cssnr.com/) -[![GitHub Contributors](https://img.shields.io/github/contributors-anon/cssnr/portainer-stack-deploy-action?logo=github)](https://github.com/cssnr/portainer-stack-deploy-action/graphs/contributors) [![GitHub Repo Size](https://img.shields.io/github/repo-size/cssnr/portainer-stack-deploy-action?logo=bookstack&logoColor=white&label=repo%20size)](https://github.com/cssnr/portainer-stack-deploy-action?tab=readme-ov-file#readme) [![GitHub Top Language](https://img.shields.io/github/languages/top/cssnr/portainer-stack-deploy-action?logo=htmx)](https://github.com/cssnr/portainer-stack-deploy-action/blob/master/src) +[![GitHub Contributors](https://img.shields.io/github/contributors-anon/cssnr/portainer-stack-deploy-action?logo=github)](https://github.com/cssnr/portainer-stack-deploy-action/graphs/contributors) [![GitHub Discussions](https://img.shields.io/github/discussions/cssnr/portainer-stack-deploy-action?logo=github)](https://github.com/cssnr/portainer-stack-deploy-action/discussions) [![GitHub Forks](https://img.shields.io/github/forks/cssnr/portainer-stack-deploy-action?style=flat&logo=github)](https://github.com/cssnr/portainer-stack-deploy-action/forks) [![GitHub Repo Stars](https://img.shields.io/github/stars/cssnr/portainer-stack-deploy-action?style=flat&logo=github)](https://github.com/cssnr/portainer-stack-deploy-action/stargazers) @@ -22,6 +22,9 @@ # Portainer Stack Deploy Action + +Portainer Stack Deploy + - [Features](#Features) - [Inputs](#Inputs) - [Outputs](#Outputs) @@ -31,10 +34,6 @@ - [Support](#Support) - [Contributing](#Contributing) -

-Portainer Stack Deploy -

- Deploy, Update or Create a Portainer Stack from a Repository or Compose File. Supports both Swarm and Standalone Docker deployments for Portainer Community and Business Enterprise Edition. Includes most [features](#features) including file or repo deploy, deploy from other repo, custom headers, and much more... @@ -80,29 +79,29 @@ You can [get started here](https://portainer-deploy.cssnr.com/guides/get-started > [!IMPORTANT] > Visit the [Documentation Site](https://portainer-deploy.cssnr.com/) for comprehensive, up-to-date documentation. -| Input | Default Value | Description of the Input | -| :------------- | :-------------------- | :------------------------------------------ | -| **name** | _Required_ | Stack Name [⤵️](#name) | -| **url** | _Required_ | Portainer URL [⤵️](#url) | -| **token** | _Required_ | Portainer Token [⤵️](#token) | -| **file** | `docker-compose.yaml` | Compose File [⤵️](#file) | -| **endpoint** | `endpoints[0].Id` | Portainer Endpoint [⤵️](#endpoint) | -| **ref** | `current reference` | Repository Ref [⤵️](#ref) | -| **repo** | `current repository` | Repository URL [⤵️](#repo) | -| **tlsskip** | `false` | Skip Repo TLS Verify | -| **prune** | `true` | Prune Services | -| **pull** | `true` | Pull Images | -| **type** | `repo` | Type [`repo`, `file`] [⤵️](#type) | -| **standalone** | `false` | Deploy Standalone Stack | -| **env_data** | - | Env JSON/YAML Data [⤵️](#env_data) | -| **env_json** | **DEPRECATED** | This has changed to [env_data](#env_data) | -| **env_file** | - | Dotenv File Path [⤵️](#env_file) | -| **merge_env** | `false` | Merge Env Vars [⤵️](#merge_env) | -| **username** | - | Repository Username [⤵️](#usernamepassword) | -| **password** | - | Repository Password [⤵️](#usernamepassword) | -| **fs_path** | - | Relative Path (BE) [⤵️](#fs_path) | -| **headers** | - | Custom Headers JSON/YAML [⤵️](#headers) | -| **summary** | `true` | Add Summary to Job [⤵️](#summary) | +| Input | Default Value | Description of the Input | +| :--------- | :-------------------- | :------------------------------------------ | +| name | _Required_ | Stack Name [⤵️](#name) | +| url | _Required_ | Portainer URL [⤵️](#url) | +| token | _Required_ | Portainer Token [⤵️](#token) | +| file | `docker-compose.yaml` | Compose File [⤵️](#file) | +| endpoint | `endpoints[0].Id` | Portainer Endpoint [⤵️](#endpoint) | +| ref | `current reference` | Repository Ref [⤵️](#ref) | +| repo | `current repository` | Repository URL [⤵️](#repo) | +| tlsskip | `false` | Skip Repo TLS Verify | +| prune | `true` | Prune Services | +| pull | `true` | Pull Images | +| type | `repo` | Type [`repo`, `file`] [⤵️](#type) | +| standalone | `false` | Deploy Standalone Stack | +| env_data | - | Env JSON/YAML Data [⤵️](#env_data) | +| env_json | **DEPRECATED** | This has changed to [env_data](#env_data) | +| env_file | - | Dotenv File Path [⤵️](#env_file) | +| merge_env | `false` | Merge Env Vars [⤵️](#merge_env) | +| username | - | Repository Username [⤵️](#usernamepassword) | +| password | - | Repository Password [⤵️](#usernamepassword) | +| fs_path | - | Relative Path (BE) [⤵️](#fs_path) | +| headers | - | Custom Headers JSON/YAML [⤵️](#headers) | +| summary | `true` | Add Summary to Job [⤵️](#summary) | > For more details, see the [Inputs Documentation](https://portainer-deploy.cssnr.com/docs/inputs) > and [Portainer API Documentation](https://app.swaggerhub.com/apis/portainer/portainer-ce/). @@ -677,16 +676,20 @@ and [additional](https://cssnr.com/) open source projects. [![Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/cssnr) -Additionally, you can support other GitHub Actions I have published: +[![Actions Tools](https://raw.githubusercontent.com/smashedr/repo-images/refs/heads/master/actions/actions-tools.png)](https://actions-tools.cssnr.com/) + +Additionally, you can support other [GitHub Actions](https://actions.cssnr.com/) 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) +- [Zensical Action](https://github.com/cssnr/zensical-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) - [Docker Tags Action](https://github.com/cssnr/docker-tags-action?tab=readme-ov-file#readme) +- [TOML Action](https://github.com/cssnr/toml-action?tab=readme-ov-file#readme) - [Update JSON Value Action](https://github.com/cssnr/update-json-value-action?tab=readme-ov-file#readme) - [JSON Key Value Check Action](https://github.com/cssnr/json-key-value-check-action?tab=readme-ov-file#readme) - [Parse Issue Form Action](https://github.com/cssnr/parse-issue-form-action?tab=readme-ov-file#readme) @@ -720,10 +723,11 @@ These actions are not published on the Marketplace, but may be useful. These are basic action templates that I use for creating new actions. -- [js-test-action](https://github.com/smashedr/js-test-action?tab=readme-ov-file#readme) - JavaScript -- [ts-test-action](https://github.com/smashedr/ts-test-action?tab=readme-ov-file#readme) - TypeScript -- [py-test-action](https://github.com/smashedr/py-test-action?tab=readme-ov-file#readme) - Python (Dockerfile) -- [docker-test-action](https://github.com/smashedr/docker-test-action?tab=readme-ov-file#readme) - Docker (Image) +- [javascript-action](https://github.com/smashedr/javascript-action?tab=readme-ov-file#readme) - JavaScript +- [typescript-action](https://github.com/smashedr/typescript-action?tab=readme-ov-file#readme) - TypeScript +- [py-test-action](https://github.com/smashedr/py-test-action?tab=readme-ov-file#readme) - Dockerfile Python +- [test-action-uv](https://github.com/smashedr/test-action-uv?tab=readme-ov-file#readme) - Dockerfile Python UV +- [docker-test-action](https://github.com/smashedr/docker-test-action?tab=readme-ov-file#readme) - Docker Image Python Note: The `docker-test-action` builds, runs and pushes images to [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry). diff --git a/action.yml b/action.yml index e70f8d9..f97601a 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,7 @@ name: "Portainer Stack Deploy Action" description: "Deploy, Update or Create a Portainer Swarm or Standalone Stack from a Repository or Compose File" author: "Shane" + branding: icon: "layers" color: "blue" diff --git a/dist/index.js b/dist/index.js index 7b2b69f..08e56fe 100644 --- a/dist/index.js +++ b/dist/index.js @@ -8776,6 +8776,22 @@ function charFromCodepoint(c) { ); } +// set a property of a literal object, while protecting against prototype pollution, +// see https://github.com/nodeca/js-yaml/issues/164 for more details +function setProperty(object, key, value) { + // used for this specific key only because Object.defineProperty is slow + if (key === '__proto__') { + Object.defineProperty(object, key, { + configurable: true, + enumerable: true, + writable: true, + value: value + }); + } else { + object[key] = value; + } +} + var simpleEscapeCheck = new Array(256); // integer, for fast access var simpleEscapeMap = new Array(256); for (var i = 0; i < 256; i++) { @@ -8954,7 +8970,7 @@ function mergeMappings(state, destination, source, overridableKeys) { key = sourceKeys[index]; if (!_hasOwnProperty.call(destination, key)) { - destination[key] = source[key]; + setProperty(destination, key, source[key]); overridableKeys[key] = true; } } @@ -9014,17 +9030,7 @@ function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valu throwError(state, 'duplicated mapping key'); } - // used for this specific key only because Object.defineProperty is slow - if (keyNode === '__proto__') { - Object.defineProperty(_result, keyNode, { - configurable: true, - enumerable: true, - writable: true, - value: valueNode - }); - } else { - _result[keyNode] = valueNode; - } + setProperty(_result, keyNode, valueNode); delete overridableKeys[keyNode]; } diff --git a/package-lock.json b/package-lock.json index d425a6b..b2ba82e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,13 @@ "@actions/core": "^1.11.1", "axios": "^1.13.2", "dotenv": "^17.2.3", - "js-yaml": "^4.1.0" + "js-yaml": "^4.1.1" }, "devDependencies": { "@eslint/js": "^9.39.1", "@vercel/ncc": "^0.38.4", "eslint": "^9.39.1", - "prettier": "^3.6.2" + "prettier": "^3.7.1" } }, "node_modules/@actions/core": { @@ -1056,9 +1056,9 @@ "license": "ISC" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -1286,9 +1286,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.1.tgz", + "integrity": "sha512-RWKXE4qB3u5Z6yz7omJkjWwmTfLdcbv44jUVHC5NpfXwFGzvpQM798FGv/6WNK879tc+Cn0AAyherCl1KjbyZQ==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 9956787..ed94680 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,12 @@ "@actions/core": "^1.11.1", "axios": "^1.13.2", "dotenv": "^17.2.3", - "js-yaml": "^4.1.0" + "js-yaml": "^4.1.1" }, "devDependencies": { "@eslint/js": "^9.39.1", "@vercel/ncc": "^0.38.4", "eslint": "^9.39.1", - "prettier": "^3.6.2" + "prettier": "^3.7.1" } }