diff options
Diffstat (limited to 'worker/scripts/npm_publish.ts')
-rw-r--r-- | worker/scripts/npm_publish.ts | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/worker/scripts/npm_publish.ts b/worker/scripts/npm_publish.ts index e69de29..f97ee48 100644 --- a/worker/scripts/npm_publish.ts +++ b/worker/scripts/npm_publish.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env node + +import { + Either, + getRequiredEnvVars, + getStdout, + type IEither, + LogTraceable, + LogMetricTraceable, + Metric, + prependWith, + TraceUtil, +} from '@emprespresso/pengueno'; +import { Bitwarden, getPathOnHost, type SecureNote } from '@emprespresso/ci_worker'; +import { writeFile, mkdir } from 'fs/promises'; +import { join } from 'path'; +import { rmSync } from 'fs'; +import { NpmPublishJob } from '@emprespresso/ci_model'; + +const eitherJob = getRequiredEnvVars(['source', 'registry']).mapRight( + (baseArgs) => + <NpmPublishJob>{ + type: 'npm_publish.js', + arguments: baseArgs, + }, +); + +const eitherVault = Bitwarden.getConfigFromEnvironment().mapRight((config) => new Bitwarden(config)); + +const packPubMetric = Metric.fromName('npm_publish.packpub'); +const _logJob = LogTraceable.of(eitherJob).flatMap(TraceUtil.withTrace('npm_publish')); +await LogMetricTraceable.ofLogTraceable(_logJob) + .flatMap(TraceUtil.withMetricTrace(packPubMetric)) + .peek((tEitherJob) => tEitherJob.trace.trace('starting npm packpub job! (⑅˘꒳˘)')) + .map((tEitherJob) => + tEitherJob.get().flatMapAsync((job) => + eitherVault.flatMapAsync(async (vault) => { + const eitherKey = await vault.unlock(tEitherJob); + tEitherJob.trace.trace('unlocked vault :3'); + return eitherKey.mapRight((key) => ({ job, key, vault })); + }), + ), + ) + .map(async (tEitherJobVault) => + (await tEitherJobVault.get()).flatMapAsync(({ job, key, vault }) => + vault + .fetchSecret<SecureNote>(tEitherJobVault, key, 'npm_auth_token') + .then((e) => + e + .mapRight(({ notes }) => notes) + .mapRight((token) => [job.arguments.registry, `_authToken=${token.trim()}`].join(':')) + .flatMapAsync((npmRc) => saveToTempFile(npmRc)), + ) + .then((e) => e.mapRight((npmRc) => ({ npmRc, job }))) + .finally(() => vault.lock(tEitherJobVault, key)), + ), + ) + .map(async (tEitherJobNpmRc) => { + const jobNpmRc = await tEitherJobNpmRc.get(); + return jobNpmRc.flatMapAsync(async ({ job, npmRc }) => { + const [srcMount, npmRcMount] = await Promise.all( + [join(process.cwd(), job.arguments.source), npmRc].map((x) => + getPathOnHost(x).then((e) => e.right().get()), + ), + ); + const volumes = [`${srcMount}:/src`, `${npmRcMount}:/etc/npmrc`]; + const packPub = [ + 'docker', + 'run', + ...prependWith(volumes, '-v'), + 'oci.liz.coffee/emprespresso/ci_packpub_npm:release', + ]; + tEitherJobNpmRc.trace.trace(`running packpub magic~ (◕ᴗ◕✿) ${packPub}`); + return tEitherJobNpmRc + .move(packPub) + .map((c) => + getStdout(c, { streamTraceable: ['stdout', 'stderr'] }).then((e) => { + rmSync(npmRcMount!); + return e; + }), + ) + .get(); + }); + }) + .map(async (tEitherJob) => { + const eitherJob = await tEitherJob.get(); + return eitherJob.fold( + (e) => Promise.reject(e), + () => Promise.resolve(0), + ); + }) + .get(); + +async function saveToTempFile(text: string): Promise<IEither<Error, string>> { + const dir = join(process.cwd(), '.secrets', crypto.randomUUID()); + const file = join(dir, 'secret'); + return Either.fromFailableAsync(() => + mkdir(dir, { recursive: true }).then(async () => { + await writeFile(file, text, { encoding: 'utf-8' }); + return file; + }), + ); +} |