diff --git a/.github/workflows/secrets-scan.yml b/.github/workflows/secrets-scan.yml deleted file mode 100644 index 049c02f4..00000000 --- a/.github/workflows/secrets-scan.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Secrets Scan -on: - pull_request: - types: [opened, synchronize, reopened] -jobs: - security-secrets: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: '2' - ref: '${{ github.event.pull_request.head.ref }}' - - run: | - git reset --soft HEAD~1 - - name: Install Talisman - run: | - # Download Talisman - wget https://github.com/thoughtworks/talisman/releases/download/v1.37.0/talisman_linux_amd64 -O talisman - - # Checksum verification - checksum=$(sha256sum ./talisman | awk '{print $1}') - if [ "$checksum" != "8e0ae8bb7b160bf10c4fa1448beb04a32a35e63505b3dddff74a092bccaaa7e4" ]; then exit 1; fi - - # Make it executable - chmod +x talisman - - name: Run talisman - run: | - # Run Talisman with the pre-commit hook - ./talisman --githook pre-commit \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d146e3..2571992b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## [v1.25.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.25.0) (2025-09-03) + - Enhancement + - Added publish_all_localized param in bulk publish/unpublish + ## [v1.24.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.24.0) (2025-08-18) - Feat - Added Support for MFA diff --git a/CODEOWNERS b/CODEOWNERS index 1be7e0dc..0496bc6a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,11 @@ -* @contentstack/security-admin +* @contentstack/devex-pr-reviewers + +.github/workflows/sca-scan.yml @contentstack/security-admin + +.github/workflows/codeql-anaylsis.yml @contentstack/security-admin + +**/.snyk @contentstack/security-admin + +.github/workflows/policy-scan.yml @contentstack/security-admin + +.github/workflows/issues-jira.yml @contentstack/security-admin diff --git a/lib/stack/bulkOperation/index.js b/lib/stack/bulkOperation/index.js index dc7c72eb..18fa9778 100644 --- a/lib/stack/bulkOperation/index.js +++ b/lib/stack/bulkOperation/index.js @@ -187,7 +187,7 @@ export function BulkOperation (http, data = {}) { * */ // eslint-disable-next-line camelcase - this.publish = async ({ details, skip_workflow_stage = false, approvals = false, is_nested = false, api_version = '' }) => { + this.publish = async ({ details, skip_workflow_stage = false, approvals = false, is_nested = false, api_version = '', publishAllLocalized = false }) => { var httpBody = {} if (details) { httpBody = cloneDeep(details) @@ -212,6 +212,12 @@ export function BulkOperation (http, data = {}) { if (approvals) { headers.headers.approvals = approvals } + if (publishAllLocalized) { + if (!headers.params) { + headers.params = {} + } + headers.params.publish_all_localized = publishAllLocalized + } // eslint-disable-next-line camelcase if (api_version) headers.headers.api_version = api_version @@ -279,7 +285,7 @@ export function BulkOperation (http, data = {}) { * .then((response) => { console.log(response.notice) }) */ // eslint-disable-next-line camelcase - this.unpublish = async ({ details, skip_workflow_stage = false, approvals = false, is_nested = false, api_version = '' }) => { + this.unpublish = async ({ details, skip_workflow_stage = false, approvals = false, is_nested = false, api_version = '', unpublishAllLocalized = false }) => { var httpBody = {} if (details) { httpBody = cloneDeep(details) @@ -306,6 +312,13 @@ export function BulkOperation (http, data = {}) { } // eslint-disable-next-line camelcase if (api_version) headers.headers.api_version = api_version + + if (unpublishAllLocalized) { + if (!headers.params) { + headers.params = {} + } + headers.params.publish_all_localized = unpublishAllLocalized + } return publishUnpublish(http, '/bulk/unpublish', httpBody, headers) } diff --git a/package-lock.json b/package-lock.json index fe2ccde9..52af398b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@contentstack/management", - "version": "1.24.0", + "version": "1.25.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@contentstack/management", - "version": "1.24.0", + "version": "1.25.0", "license": "MIT", "dependencies": { "assert": "^2.1.0", diff --git a/package.json b/package.json index 4fcc7f9b..2e6cb22f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@contentstack/management", - "version": "1.24.0", + "version": "1.25.0", "description": "The Content Management API is used to manage the content of your Contentstack account", "main": "./dist/node/contentstack-management.js", "browser": "./dist/web/contentstack-management.js", diff --git a/test/sanity-check/api/bulkOperation-test.js b/test/sanity-check/api/bulkOperation-test.js index 8e33832d..4e1ccc02 100644 --- a/test/sanity-check/api/bulkOperation-test.js +++ b/test/sanity-check/api/bulkOperation-test.js @@ -16,6 +16,13 @@ let assetUid2 = '' let jobId1 = '' let jobId2 = '' let jobId3 = '' +let jobId4 = '' +let jobId5 = '' +let jobId6 = '' +let jobId7 = '' +let jobId8 = '' +let jobId9 = '' +let jobId10 = '' let tokenUidDev = '' let tokenUid = '' @@ -162,6 +169,228 @@ describe('BulkOperation api test', () => { .catch(done) }) + it('should publish entries with publishAllLocalized parameter set to true', done => { + const publishDetails = { + entries: [ + { + uid: entryUid1, + content_type: multiPageCT.content_type.uid, + locale: 'en-us' + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .publish({ + details: publishDetails, + api_version: '3.2', + publishAllLocalized: true + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId4 = response.job_id + done() + }) + .catch(done) + }) + + it('should publish entries with publishAllLocalized parameter set to false', done => { + const publishDetails = { + entries: [ + { + uid: entryUid2, + content_type: singlepageCT.content_type.uid, + locale: 'en-us' + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .publish({ + details: publishDetails, + api_version: '3.2', + publishAllLocalized: false + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId5 = response.job_id + done() + }) + .catch(done) + }) + + it('should publish assets with publishAllLocalized parameter', done => { + const publishDetails = { + assets: [ + { + uid: assetUid1 + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .publish({ + details: publishDetails, + api_version: '3.2', + publishAllLocalized: true + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId6 = response.job_id + done() + }) + .catch(done) + }) + + it('should unpublish entries with unpublishAllLocalized parameter set to true', done => { + const unpublishDetails = { + entries: [ + { + uid: entryUid1, + content_type: multiPageCT.content_type.uid, + locale: 'en-us' + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .unpublish({ + details: unpublishDetails, + api_version: '3.2', + unpublishAllLocalized: true + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId7 = response.job_id + done() + }) + .catch(done) + }) + + it('should unpublish entries with unpublishAllLocalized parameter set to false', done => { + const unpublishDetails = { + entries: [ + { + uid: entryUid2, + content_type: singlepageCT.content_type.uid, + locale: 'en-us' + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .unpublish({ + details: unpublishDetails, + api_version: '3.2', + unpublishAllLocalized: false + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId8 = response.job_id + done() + }) + .catch(done) + }) + + it('should unpublish assets with unpublishAllLocalized parameter', done => { + const unpublishDetails = { + assets: [ + { + uid: assetUid1 + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .unpublish({ + details: unpublishDetails, + api_version: '3.2', + unpublishAllLocalized: true + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId9 = response.job_id + done() + }) + .catch(done) + }) + + it('should publish entries with multiple parameters including publishAllLocalized', done => { + const publishDetails = { + entries: [ + { + uid: entryUid1, + content_type: multiPageCT.content_type.uid, + locale: 'en-us' + } + ], + locales: [ + 'en-us' + ], + environments: [ + 'development' + ] + } + doBulkOperation() + .publish({ + details: publishDetails, + api_version: '3.2', + publishAllLocalized: true, + skip_workflow_stage: true, + approvals: true + }) + .then((response) => { + expect(response.notice).to.not.equal(undefined) + expect(response.job_id).to.not.equal(undefined) + // Store job ID for later status check + jobId10 = response.job_id + done() + }) + .catch(done) + }) + it('should wait for all jobs to be processed before checking status', async () => { await delay(5000) // Wait 5 seconds for jobs to be processed }) @@ -216,6 +445,83 @@ describe('BulkOperation api test', () => { expect(response.body).to.not.equal(undefined) }) + it('should get job status for publishAllLocalized=true job', async () => { + const response = await waitForJobReady(jobId4) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + + it('should get job status for publishAllLocalized=false job', async () => { + const response = await waitForJobReady(jobId5) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + + it('should get job status for asset publishAllLocalized job', async () => { + const response = await waitForJobReady(jobId6) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + + it('should get job status for unpublishAllLocalized=true job', async () => { + const response = await waitForJobReady(jobId7) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + + it('should get job status for unpublishAllLocalized=false job', async () => { + const response = await waitForJobReady(jobId8) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + + it('should get job status for asset unpublishAllLocalized job', async () => { + const response = await waitForJobReady(jobId9) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + + it('should get job status for multiple parameters job', async () => { + const response = await waitForJobReady(jobId10) + + expect(response).to.not.equal(undefined) + expect(response.uid).to.not.equal(undefined) + expect(response.status).to.not.equal(undefined) + expect(response.action).to.not.equal(undefined) + expect(response.summary).to.not.equal(undefined) + expect(response.body).to.not.equal(undefined) + }) + it('should get job status with bulk_version parameter', async () => { await waitForJobReady(jobId1) diff --git a/types/stack/bulkOperation/index.d.ts b/types/stack/bulkOperation/index.d.ts index 268aa530..ba5c3731 100644 --- a/types/stack/bulkOperation/index.d.ts +++ b/types/stack/bulkOperation/index.d.ts @@ -17,6 +17,8 @@ export interface BulkOperationConfig { is_nested?: boolean api_version?: string bulk_version?: string + publishAllLocalized?: boolean + unpublishAllLocalized?: boolean } export interface PublishItems extends PublishDetails {