From ec1c65d3c16adf75e2311801d8bc91c304c718f6 Mon Sep 17 00:00:00 2001 From: Adrien Poupa Date: Thu, 1 Jun 2023 14:58:28 -0400 Subject: [PATCH 1/5] fix: npm link is removed in NPM9, use direct path --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b593867..926ed66 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ ], "scripts": { "lint": "$(npm bin)/eslint src", - "test": "NODE_ENV=test $(npm bin)/mocha --recursive --compilers js:babel-core/register test", - "test:coverage": "$(npm bin)/nyc --check-coverage --lines 90 --reporter=text --reporter=text-summary npm test", - "build": "rm -Rf bin && $(npm bin)/babel src --out-dir bin --source-maps inline", + "test": "NODE_ENV=test ./node_modules/.bin/mocha --recursive --compilers js:babel-core/register test", + "test:coverage": "./node_modules/.bin/nyc --check-coverage --lines 90 --reporter=text --reporter=text-summary npm test", + "build": "rm -Rf bin && ./node_modules/.bin/babel src --out-dir bin --source-maps inline", "deploy": "npm run build && npm link", "preversion": "npm run build && npm run lint && npm run test" }, From f2870f19525affc3c756018a048517990f597c61 Mon Sep 17 00:00:00 2001 From: Adrien Poupa Date: Thu, 1 Jun 2023 14:58:50 -0400 Subject: [PATCH 2/5] feat: remove .idea from Git tracking --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 23c40a2..c518981 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ bin gitlab.env.yml .nyc_output .gitlabrc +.idea From ac47c7899f2461f078b3756ce2d0616014a07055 Mon Sep 17 00:00:00 2001 From: Adrien Poupa Date: Thu, 1 Jun 2023 16:06:45 -0400 Subject: [PATCH 3/5] fix: make JS files executable after build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 926ed66..2bdb3dd 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "lint": "$(npm bin)/eslint src", "test": "NODE_ENV=test ./node_modules/.bin/mocha --recursive --compilers js:babel-core/register test", "test:coverage": "./node_modules/.bin/nyc --check-coverage --lines 90 --reporter=text --reporter=text-summary npm test", - "build": "rm -Rf bin && ./node_modules/.bin/babel src --out-dir bin --source-maps inline", + "build": "rm -Rf bin && ./node_modules/.bin/babel src --out-dir bin --source-maps inline && chmod +x ./bin/*.js", "deploy": "npm run build && npm link", "preversion": "npm run build && npm run lint && npm run test" }, From d55fdfe7134b935909036852cf3200478dc624f7 Mon Sep 17 00:00:00 2001 From: Adrien Poupa Date: Thu, 1 Jun 2023 16:06:50 -0400 Subject: [PATCH 4/5] feat: add new options (masked, protected, raw, scope) and handle HTTP errors --- src/glci-set.js | 25 ++++++++++++++--- src/glci-setAll.js | 23 +++++++++++++++- src/lib/gitlab-ci.js | 64 +++++++++++++++++++++++++++++++++----------- 3 files changed, 91 insertions(+), 21 deletions(-) diff --git a/src/glci-set.js b/src/glci-set.js index 5e0d4b4..40928f6 100644 --- a/src/glci-set.js +++ b/src/glci-set.js @@ -19,15 +19,20 @@ async function execute(cmd) { const keyExists = existingKeys.includes(conf.key); + const isProtected = Boolean(cmd.protected); + const masked = Boolean(cmd.masked); + const raw = Boolean(cmd.raw); + const scope = cmd.environmentScope !== undefined ? cmd.environmentScope : '*'; + if (keyExists && cmd.doNotForce) { console.log(`Skipping ${conf.key}, already set.`); return undefined; } if (keyExists) { - resp = await handler.updateVariable(conf.key, conf.value); + resp = await handler.updateVariable(conf.key, conf.value, isProtected, masked, raw, scope); } else { - resp = await handler.createVariable(conf.key, conf.value); + resp = await handler.createVariable(conf.key, conf.value, isProtected, masked, raw, scope); } console.log('Completed setting variable on Gitlab CI.'); @@ -53,8 +58,20 @@ program 'Your Gitlab CI value', ) .option( - '--do-not-force', - 'Ignore variable if it already exists on gitlab CI. By default variable is overridden', + '--protected', + 'Set the variable as protected. By default it is not protected', + ) + .option( + '--masked', + 'Set the variable as masked. By default it is not masked', + ) + .option( + '--raw', + 'Set the variable as raw. By default it is not raw', + ) + .option( + '--environment-scope ', + 'Set the environment scope. By default it is set to *', ) .parse(process.argv); diff --git a/src/glci-setAll.js b/src/glci-setAll.js index df4b019..16cca1c 100644 --- a/src/glci-setAll.js +++ b/src/glci-setAll.js @@ -8,8 +8,13 @@ async function execute(cmd) { const conf = await getConf(); const properties = getProperties(); + const forceUpdate = !cmd.doNotForce; + const isProtected = Boolean(cmd.protected); + const masked = Boolean(cmd.masked); + const raw = Boolean(cmd.raw); + const scope = cmd.environmentScope !== undefined ? cmd.environmentScope : '*'; const handler = gitlabCI(conf.url, conf.token); - const resp = await handler.setVariables(properties, !cmd.doNotForce); + const resp = await handler.setVariables(properties, forceUpdate, isProtected, masked, raw, scope); console.log('Completed setting variables on Gitlab CI.'); return resp; @@ -29,6 +34,22 @@ program '--do-not-force', 'Ignore variables if they already exist on gitlab CI. By default all variables are overridden', ) + .option( + '--protected', + 'Set the variable as protected. By default it is not protected', + ) + .option( + '--masked', + 'Set the variable as masked. By default it is not masked', + ) + .option( + '--raw', + 'Set the variable as raw. By default it is not raw', + ) + .option( + '--environment-scope ', + 'Set the environment scope. By default it is set to *', + ) .parse(process.argv); execute(program); diff --git a/src/lib/gitlab-ci.js b/src/lib/gitlab-ci.js index df9072e..4fba8c9 100644 --- a/src/lib/gitlab-ci.js +++ b/src/lib/gitlab-ci.js @@ -43,22 +43,36 @@ export default function gitlabCI(url, token) { * * @param key * @param value - * + * @param isProtected + * @param masked + * @param raw + * @param scope * @return {Promise} variable object */ - async function createVariable(key, value) { - const response = await axios({ + async function createVariable(key, value, isProtected, masked, raw, scope) { + await axios({ method: 'post', url: `${apiUrl}?${tokenQueryString}`, data: { key, value: serialiseValue(value), + protected: isProtected, + masked, + raw, + environment_scope: scope, }, - }); + }).then((response) => { + console.log(`Created new variable ${key} = ${JSON.stringify(value)}`); - console.log(`Created new variable ${key} = ${JSON.stringify(value)}`); + return response.data; + }).catch((error) => { + console.log(`Creation failed: ${error}`); - return response.data; + if (masked) { + console.log('Retrying unmasked...'); + createVariable(key, value, isProtected, false, raw, scope); + } + }); } /** @@ -66,22 +80,36 @@ export default function gitlabCI(url, token) { * * @param key * @param value - * + * @param isProtected + * @param masked + * @param raw + * @param scope * @return {Promise} variable object */ - async function updateVariable(key, value) { - const response = await axios({ + async function updateVariable(key, value, isProtected, masked, raw, scope) { + await axios({ method: 'put', url: `${apiUrl}/${key}?${tokenQueryString}`, data: { key, value: serialiseValue(value), + protected: isProtected, + masked, + raw, + environment_scope: scope, }, - }); + }).then((response) => { + console.log(`Updated variable ${key} = ${JSON.stringify(value)}`); - console.log(`Updated variable ${key} = ${JSON.stringify(value)}`); + return response.data; + }).catch((error) => { + console.log(`Update failed: ${error}`); - return response.data; + if (masked) { + console.log('Retrying unmasked...'); + updateVariable(key, value, isProtected, false, raw, scope); + } + }); } /** @@ -99,11 +127,15 @@ export default function gitlabCI(url, token) { * Set project variables * * @param {Object} properties - * @param forceUpdate if true, override existing values, otherwise ignore them + * @param forceUpdate + * @param isProtected + * @param masked + * @param raw + * @param scope * * @return {Promise} array of variable objects */ - async function setVariables(properties, forceUpdate) { + async function setVariables(properties, forceUpdate, isProtected, masked, raw, scope) { if (!properties) { return null; } @@ -123,10 +155,10 @@ export default function gitlabCI(url, token) { let variable; if (keyExists) { // Update variable - variable = await updateVariable(key, value); + variable = await updateVariable(key, value, isProtected, masked, raw, scope); } else { // Create variable - variable = await createVariable(key, value); + variable = await createVariable(key, value, isProtected, masked, raw, scope); } return variable; From 90dec9cbd51786efebd60e123139c1106d2b710c Mon Sep 17 00:00:00 2001 From: Adrien Poupa Date: Fri, 2 Jun 2023 13:58:32 -0400 Subject: [PATCH 5/5] fix: iterate through pages if there are > 100 variables --- src/lib/gitlab-ci.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/lib/gitlab-ci.js b/src/lib/gitlab-ci.js index 4fba8c9..6894156 100644 --- a/src/lib/gitlab-ci.js +++ b/src/lib/gitlab-ci.js @@ -118,9 +118,19 @@ export default function gitlabCI(url, token) { * @return {Promise} array of variable objects */ async function listVariables() { - const response = await axios.get(`${apiUrl}?${tokenQueryString}&${perPageQueryString}`); + let response = await axios.get(`${apiUrl}?${tokenQueryString}&${perPageQueryString}&page=1`); - return response.data; + const nbPages = response.headers['x-total-pages'] !== undefined ? response.headers['x-total-pages'] : 1; + + let data = response.data; + + for (let page = 2; page <= nbPages; page += 1) { + /* eslint-disable no-await-in-loop */ + response = await axios.get(`${apiUrl}?${tokenQueryString}&${perPageQueryString}&page=${page}`); + data = [...data, ...response.data]; + } + + return data; } /**