bitbucket-env-manager
Version:
Deploys Bitbucket Environment
198 lines (167 loc) • 5.67 kB
JavaScript
const { spinner, log, note } = require('@clack/prompts');
const color = require('picocolors');
const {
guarded_create_env,
guarded_create_var,
guarded_delete_env,
guarded_delete_var,
guarded_get_envs,
guarded_get_vars,
guarded_get_repo_vars,
guarded_create_repo_var,
guarded_delete_repo_var,
} = require('./guarded.api');
const { delay } = require('./helpers');
const { runConvert } = require('./convert');
const { apiSleepTime } = require('./config');
const run_repo_vars_setup = async (cfg) => {
const s = spinner();
try {
s.start(`Deploying repository variables for ${color.cyan(cfg.repo)}`);
const mainParams = {
repo_slug: cfg.repo,
workspace: cfg.workspace,
};
// Get existing repo variables
const repoVarsString = await guarded_get_repo_vars({ ...mainParams });
const repoVars = JSON.parse(repoVarsString).values;
const concurrency = 5;
// Delete existing variables
if (repoVars.length > 0) {
s.message(`Removing ${repoVars.length} existing variable(s)...`);
for (let i = 0; i < repoVars.length; i += concurrency) {
const batch = repoVars.slice(i, i + concurrency);
await Promise.all(
batch.map((v) => guarded_delete_repo_var({ ...mainParams, variable_uuid: v.uuid }))
);
await delay(apiSleepTime);
}
}
const varLen = cfg.vars.length;
// Upload new variables
for (let i = 0; i < varLen; i += concurrency) {
const batch = cfg.vars.slice(i, i + concurrency);
const end = Math.min(i + concurrency, varLen);
s.message(`Uploading ${color.dim(`(${i + 1}-${end}/${varLen})`)}`);
await Promise.all(
batch.map((v) =>
guarded_create_repo_var({
...mainParams,
var_key: v.key,
var_value: v.value.toString(),
var_secured: !!v.secured,
})
)
);
await delay(apiSleepTime);
}
s.stop(color.green(`Repository variables deployed for ${cfg.repo}`));
} catch (e) {
s.stop(color.red(`Failed to deploy repository variables for ${cfg.repo}`));
log.error(e.message);
}
};
const run_env_setup = async (cfg) => {
const s = spinner();
const envLabel = `${cfg.repo} -> ${cfg.env_name}`;
try {
s.start(`Deploying ${color.cyan(envLabel)}`);
const mainParams = {
repo_slug: cfg.repo,
workspace: cfg.workspace,
env_config: cfg.env_config,
};
const concurrency = 5;
// Get existing env details
const envsListString = await guarded_get_envs({ ...mainParams });
const envsList = JSON.parse(envsListString).values;
const existingEnv = envsList.find((env) => env.slug === cfg.env_name.toLowerCase());
const desiredRank = Math.max(Math.min(cfg.rank, 2), 0);
const rankMatches =
existingEnv && existingEnv.environment_type && existingEnv.environment_type.rank === desiredRank;
let targetEnv;
if (existingEnv && rankMatches) {
// Reuse existing env: clear its variables, keep the env itself
const existingVarsString = await guarded_get_vars({
...mainParams,
environment_uuid: existingEnv.uuid,
});
const existingVars = JSON.parse(existingVarsString).values || [];
if (existingVars.length > 0) {
s.message(`Clearing ${existingVars.length} existing variable(s)...`);
for (let i = 0; i < existingVars.length; i += concurrency) {
const batch = existingVars.slice(i, i + concurrency);
await Promise.all(
batch.map((v) =>
guarded_delete_var({
...mainParams,
environment_uuid: existingEnv.uuid,
variable_uuid: v.uuid,
})
)
);
await delay(apiSleepTime);
}
}
targetEnv = existingEnv;
} else {
// Name/rank changed (or env missing) — delete (if any) and recreate
if (existingEnv) {
s.message('Removing existing environment...');
await guarded_delete_env({ ...mainParams, environment_uuid: existingEnv.uuid });
}
s.message('Creating new environment...');
const newEnvString = await guarded_create_env({
...mainParams,
env_name: cfg.env_name,
env_rank: cfg.rank,
});
targetEnv = JSON.parse(newEnvString);
}
const varLen = cfg.vars.length;
// Upload variables
for (let i = 0; i < varLen; i += concurrency) {
const batch = cfg.vars.slice(i, i + concurrency);
const end = Math.min(i + concurrency, varLen);
s.message(`Uploading ${color.dim(`(${i + 1}-${end}/${varLen})`)}`);
await Promise.all(
batch.map((v) =>
guarded_create_var({
...mainParams,
environment_uuid: targetEnv.uuid,
var_key: v.key,
var_value: v.value.toString(),
var_secured: !!v.secured,
})
)
);
await delay(apiSleepTime);
}
s.stop(color.green(`Deployed ${envLabel}`));
} catch (e) {
s.stop(color.red(`Failed to deploy ${envLabel}`));
log.error(e.message);
}
};
const runDeploy = async () => {
try {
const cfgs = await runConvert({ multiple: true });
if (!cfgs || !cfgs.length) return;
note(`Deploying ${cfgs.length} configuration(s)`, 'Deploy');
for (const cfg of cfgs) {
if (cfg.is_repo) {
await run_repo_vars_setup(cfg);
} else {
await run_env_setup(cfg);
}
}
log.success('All deployments complete!');
} catch (e) {
log.error(e.message);
}
};
module.exports = {
runDeploy,
run_env_setup,
};