summaryrefslogtreecommitdiff
path: root/worker/scripts/npm_publish.ts
diff options
context:
space:
mode:
Diffstat (limited to 'worker/scripts/npm_publish.ts')
-rw-r--r--worker/scripts/npm_publish.ts103
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;
+ }),
+ );
+}