diff options
-rw-r--r-- | u/process/env.ts | 42 | ||||
-rw-r--r-- | u/types/fn/either.ts | 21 | ||||
-rwxr-xr-x | worker/scripts/checkout_ci.ts | 51 |
3 files changed, 65 insertions, 49 deletions
diff --git a/u/process/env.ts b/u/process/env.ts index 76961c9..88fb490 100644 --- a/u/process/env.ts +++ b/u/process/env.ts @@ -1,33 +1,27 @@ import { IOptional, Either, Optional, type IEither } from '@emprespresso/pengueno'; -export const getEnv = <V extends string>(name: string): IOptional<V> => - Optional.from(<V>process.env[name]).filter((val) => val.trim() !== ''); +export const getEnv = <V extends string>(name: string): IOptional<V> => Optional.from(<V>process.env[name]); export const getRequiredEnv = <V extends string>(name: string): IEither<Error, V> => - getEnv<V>(name) - .map((envVal) => Either.right<Error, V>(<V>envVal)) - .orSome(() => Either.left<Error, V>(new Error(`environment variable "${name}" is required D:`))) - .get(); + Either.fromFailable(() => getEnv<V>(name).get()).mapLeft( + () => new Error(`environment variable "${name}" is required D:`), + ); type ObjectFromList<T extends ReadonlyArray<string>, V = string> = { [K in T extends ReadonlyArray<infer U> ? U : never]: V; }; -export const getRequiredEnvVars = <V extends string>(vars: ReadonlyArray<V>) => - vars - .map((envVar) => [envVar, getRequiredEnv(envVar)] as [V, IEither<Error, V>]) - .reduce( - (acc: IEither<Error, ObjectFromList<typeof vars>>, x: [V, IEither<Error, V>]) => { - const [envVar, eitherVal] = x; - return acc.flatMap((args) => { - return eitherVal.mapRight( - (envValue) => - ({ - ...args, - [envVar]: envValue, - }) as ObjectFromList<typeof vars>, - ); - }); - }, - Either.right({} as ObjectFromList<typeof vars>), - ); +export const getRequiredEnvVars = <V extends string>(vars: Array<V>) => { + type Environment = ObjectFromList<typeof vars>; + const emptyEnvironment = Either.right<Error, Environment>(<Environment>{}); + const addTo = (env: Environment, key: V) => (val: string) => + <Environment>{ + ...env, + [key]: val, + }; + return Either.joinRight<V, Error, Environment>( + vars, + (envVar: V, environment: Environment) => getRequiredEnv(envVar).mapRight(addTo(environment, envVar)), + emptyEnvironment, + ); +}; diff --git a/u/types/fn/either.ts b/u/types/fn/either.ts index 6140ada..aa67d41 100644 --- a/u/types/fn/either.ts +++ b/u/types/fn/either.ts @@ -1,4 +1,4 @@ -import { IOptional, type Mapper, Optional, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno'; +import { BiMapper, IOptional, type Mapper, Optional, type Supplier, Tagged, isTagged } from '@emprespresso/pengueno'; export const IEitherTag = 'IEither' as const; export type IEitherTag = typeof IEitherTag; @@ -82,6 +82,25 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> { return Optional.none(); } + static joinRight<K, E, T>( + arr: Array<K>, + mapper: BiMapper<K, T, IEither<E, T>>, + init: IEither<E, T>, + ): IEither<E, T> { + return arr.reduce((acc: IEither<E, T>, x: K) => acc.flatMap((t) => mapper(x, t)), init); + } + + static joinRightAsync<K, E, T>( + arr: Array<K>, + mapper: BiMapper<K, T, Promise<IEither<E, T>>>, + init: IEither<E, T>, + ): Promise<IEither<E, T>> { + return arr.reduce( + (acc: Promise<IEither<E, T>>, x: K) => acc.then((res) => res.flatMapAsync((t) => mapper(x, t))), + Promise.resolve(init), + ); + } + static left<E, T>(e: E): IEither<E, T> { return new Either({ err: e, _tag: ELeftTag }); } diff --git a/worker/scripts/checkout_ci.ts b/worker/scripts/checkout_ci.ts index f1627c9..1892be8 100755 --- a/worker/scripts/checkout_ci.ts +++ b/worker/scripts/checkout_ci.ts @@ -86,28 +86,31 @@ await LogMetricTraceable.ofLogTraceable(_logJob) return repoCiFileContents .flatMap((fileText) => Either.fromFailable<Error, unknown>(() => JSON.parse(fileText))) .flatMap((json) => { - return eitherCiJob.flatMap((ciJob): IEither<Error, { cmd: Command; job: CheckoutCiJob }> => { - if (!isCiWorkflow(json)) { - const e = new Error("couldn't find any valid ci configuration (。•́︿•̀。), that's okay~"); - return Either.left(e); - } - return Either.right({ - cmd: getPipelineGenerationCommand(ciJob, json.workflow), - job: ciJob, - }); - }); + return eitherCiJob.flatMap( + (ciJob): IEither<Error, { commands: Array<Command>; job: CheckoutCiJob }> => { + if (!isCiWorkflow(json)) { + const e = new Error("couldn't find any valid ci configuration (。•́︿•̀。), that's okay~"); + return Either.left(e); + } + return Either.right({ + commands: getPipelineGenerationCommand(ciJob, json.workflow), + job: ciJob, + }); + }, + ); }); }) .map(async (tEitherPipelineGenerationCommand) => { - tEitherPipelineGenerationCommand.move(getDockerLoginReadonlyCommand()); - }) - .map(async (tEitherPipelineGenerationCommand) => { const eitherJobCommand = await tEitherPipelineGenerationCommand.get(); - const eitherPipeline = await eitherJobCommand.flatMapAsync((jobCommand) => - tEitherPipelineGenerationCommand.move(jobCommand.cmd).map(getStdout).get(), - ); - return eitherPipeline - .flatMap(PipelineImpl.from) + const pipelineSerialized = await eitherJobCommand.flatMapAsync(({ commands }) => { + return Either.joinRightAsync( + commands, + (command) => tEitherPipelineGenerationCommand.move(command).map(getStdout).get(), + Either.right<Error, string>(''), + ); + }); + return pipelineSerialized + .flatMap((s) => PipelineImpl.from(s)) .flatMap((pipeline) => eitherJobCommand.mapRight(({ job }) => ({ job, pipeline }))); }) .peek( @@ -149,17 +152,17 @@ function getSrcDirectoryForCiJob(job: CheckoutCiJob) { return `${job.arguments.returnPath}/${job.arguments.run}/src`; } -function getDockerLoginReadonlyCommand(credentials = READONLY_CREDENTIALS, registry = OCI_REGISTRY): Command { - return `docker login --username ${credentials.username} --password ${credentials.password} ${registry}`.split(' '); -} - function getPipelineGenerationCommand( job: CheckoutCiJob, pipelineGeneratorPath: string, + credentials = READONLY_CREDENTIALS, + registry = OCI_REGISTRY, image = PIPELINE_IMAGE, runFlags = '--rm --network none --cap-drop ALL --security-opt no-new-privileges'.split(' '), -): Command { +): Array<Command> { return [ + `docker login --username ${credentials.username} --password ${credentials.password} ${registry}`.split(' '), + ].concat([ 'docker', 'run', ...runFlags, @@ -171,5 +174,5 @@ function getPipelineGenerationCommand( `${getSrcDirectoryForCiJob(job)}/${pipelineGeneratorPath}:/pipeline_generator`, image, '/pipeline_generator', - ]; + ]); } |