aboutsummaryrefslogtreecommitdiff
path: root/worker/scripts/coolify_webhook.ts
diff options
context:
space:
mode:
Diffstat (limited to 'worker/scripts/coolify_webhook.ts')
-rw-r--r--worker/scripts/coolify_webhook.ts83
1 files changed, 83 insertions, 0 deletions
diff --git a/worker/scripts/coolify_webhook.ts b/worker/scripts/coolify_webhook.ts
new file mode 100644
index 0000000..454bc56
--- /dev/null
+++ b/worker/scripts/coolify_webhook.ts
@@ -0,0 +1,83 @@
+#!/usr/bin/env node
+
+import {
+ Either,
+ getRequiredEnvVars,
+ LogTraceable,
+ LogMetricTraceable,
+ Metric,
+ TraceUtil,
+} from '@emprespresso/pengueno';
+import { Infisical, type SecureNote } from '@emprespresso/ci_worker';
+import { CoolifyWebhookJob } from '@emprespresso/ci_model';
+
+const eitherJob = getRequiredEnvVars(['webhookUrl']).mapRight(
+ (baseArgs) =>
+ <CoolifyWebhookJob>{
+ type: 'coolify_webhook.js',
+ arguments: baseArgs,
+ },
+);
+
+const eitherVault = Infisical.getConfigFromEnvironment().mapRight((config) => new Infisical(config));
+
+const webhookMetric = Metric.fromName('coolify_webhook.trigger').asResult();
+const _logJob = LogTraceable.of(eitherJob).flatMap(TraceUtil.withTrace('coolify_webhook'));
+await LogMetricTraceable.ofLogTraceable(_logJob)
+ .flatMap(TraceUtil.withMetricTrace(webhookMetric))
+ .peek((tEitherJob) => tEitherJob.trace.trace('starting coolify webhook trigger! (⑅˘꒳˘)'))
+ .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, 'coolify')
+ .then((e) => e.mapRight(({ notes }) => ({ job, webhookSecret: notes })))
+ .finally(() => vault.lock(tEitherJobVault, key)),
+ ),
+ )
+ .map(async (tEitherJobAndSecret) => {
+ const eitherJobAndSecret = await tEitherJobAndSecret.get();
+ return eitherJobAndSecret.flatMapAsync(async ({ job, webhookSecret }) => {
+ tEitherJobAndSecret.trace.trace(`triggering webhook at ${job.arguments.webhookUrl} (◕ᴗ◕✿)`);
+
+ return Either.fromFailableAsync<Error, string>(() =>
+ fetch(job.arguments.webhookUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${webhookSecret}`,
+ },
+ body: JSON.stringify({}),
+ }).then(async (response) => {
+ if (!response.ok) {
+ throw new Error(
+ `webhook request failed with status ${response.status}: ${await response.text()}`,
+ );
+ }
+ return response.text();
+ }),
+ ).then((e) => {
+ e.mapRight((responseText) =>
+ tEitherJobAndSecret.trace.trace(`webhook response: ${responseText}`),
+ );
+ return e;
+ });
+ });
+ })
+ .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(webhookMetric)))
+ .map(async (tEitherJob) => {
+ const eitherJob = await tEitherJob.get();
+ return eitherJob.fold(
+ (e) => Promise.reject(e),
+ () => Promise.resolve(0),
+ );
+ })
+ .get();