/ opencodehub / src / lib / iac-hooks.ts
Swadhin Biswas feat(api): add runner, analytics, packages, and security services · 3/6/2026
28f7954
104 lines · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import { and, eq } from "drizzle-orm";
import { getDatabase, schema } from "@/db";
import { logger } from "@/lib/logger";
import type { CloudConfig } from "@/lib/cloud-integrations";
import { terraformApply, terraformPlan } from "@/lib/cloud-integrations";

export interface IaCHookRunResult {
  provider: string;
  configId: string;
  action: "plan" | "apply";
  success: boolean;
  runId?: string;
  status?: string;
  message?: string;
}

export function detectIaCFiles(changedFiles: string[]): string[] {
  const patterns = [
    /\.tf$/i,
    /\.tfvars(\.json)?$/i,
    /terraform\//i,
    /terragrunt\.hcl$/i,
    /pulumi\.(ya?ml|json|ts|js|py|go)$/i,
    /cloudformation\/.*\.(ya?ml|json)$/i,
    /k8s\/.*\.(ya?ml|json)$/i,
    /helm\/.*\.(ya?ml|tpl)$/i,
  ];
  return changedFiles.filter((file) => patterns.some((pattern) => pattern.test(file)));
}

export async function triggerIaCHooks(options: {
  repositoryId: string;
  action: "plan" | "apply";
  runId?: string;
  message?: string;
  configId?: string;
}): Promise<IaCHookRunResult[]> {
  const db = getDatabase() as NodePgDatabase<typeof schema>;
  const configs =
    (await db.query.cloudConfigs?.findMany({
      where: and(
        eq(schema.cloudConfigs.repositoryId, options.repositoryId),
        eq(schema.cloudConfigs.provider, "terraform"),
        eq(schema.cloudConfigs.isEnabled, true)
      ),
    })) || [];

  const targets = options.configId
    ? configs.filter((config) => config.id === options.configId)
    : configs;

  const results: IaCHookRunResult[] = [];
  for (const config of targets) {
    if (options.action === "plan") {
      const plan = await terraformPlan({
        config: config as CloudConfig,
        message: options.message,
      });
      results.push({
        provider: config.provider,
        configId: config.id,
        action: "plan",
        success: !!plan,
        runId: plan?.runId,
        status: plan?.status,
        message: plan ? "Terraform plan triggered" : "Terraform plan failed",
      });
      continue;
    }

    if (!options.runId) {
      results.push({
        provider: config.provider,
        configId: config.id,
        action: "apply",
        success: false,
        message: "runId is required for apply",
      });
      continue;
    }

    const ok = await terraformApply({
      config: config as CloudConfig,
      runId: options.runId,
      comment: options.message,
    });
    results.push({
      provider: config.provider,
      configId: config.id,
      action: "apply",
      success: ok,
      runId: options.runId,
      message: ok ? "Terraform apply triggered" : "Terraform apply failed",
    });
  }

  logger.info(
    { repositoryId: options.repositoryId, action: options.action, targets: targets.length },
    "IaC hooks executed"
  );
  return results;
}