Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 11 additions & 46 deletions .github/composite/build-image/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,23 @@ name: "Build & Upload Docker Image"
description: "Build & (optionally) upload Docker Image to Docker Registry"

inputs:
GPG_PRIVATE_KEY:
description: "GPG Private Key"
required: true
GPG_PASSPHRASE:
description: "GPG Passphrase"
required: true
DOCKER_UPLOAD:
description: "Boolean indicating whether the image should be uploaded to Docker registry or not."
required: false
default: true
TAG_PREFIX:
description: "Docker tags prefix"
required: false
SERVER_PROFILES:
description: "Profile(s) to apply to Codebloom instance."
required: false
default: prod
default: "true"
ENVIRONMENT:
description: "'staging' or 'production'"
required: true

outputs:
tag:
description: "Built Docker image tag (git SHA, with optional prefix)"
value: ${{ steps.build-image.outputs.tag }}

runs:
using: "composite"
steps:
- name: Setup CI
uses: ./.github/composite/setup-ci
with:
GPG_PRIVATE_KEY: ${{ inputs.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ inputs.GPG_PASSPHRASE }}

- name: Set up pnpm
uses: pnpm/action-setup@master
with:
version: 10.24.0
cache: true
cache_dependency_path: js/pnpm-lock.yaml
package_json_file: js/package.json

- name: Set up OpenJDK 25
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "25"

- name: Cache Maven packages
uses: actions/cache@v5
with:
path: |
~/.m2
~/repository
key: ${{ github.job }}-${{ hashFiles('**/pom.xml') }}

- name: Expose GitHub Runtime
uses: crazy-max/ghaction-github-runtime@v3

- name: Run script
id: build-image
shell: bash
run: bun run .github/scripts/build-image --tag-prefix=${{ inputs.TAG_PREFIX }} --docker-upload=${{ inputs.DOCKER_UPLOAD }} --server-profiles=${{ inputs.SERVER_PROFILES }}
run: bun run .github/scripts/build-image --environment "${{ inputs.ENVIRONMENT }}" --docker-upload=${{ inputs.DOCKER_UPLOAD }} --getGhaOutput=true
19 changes: 19 additions & 0 deletions .github/composite/deploy-web/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Deploy Web Service
description: Builds web image and deploys to k8s manifests

inputs:
ENVIRONMENT:
description: "'staging' or 'production'"
required: true

runs:
using: composite
steps:
- name: Build and push web image
id: build-image
shell: bash
run: bun run .github/scripts/build-image --environment "${{ inputs.ENVIRONMENT }}" --docker-upload=true --getGhaOutput=true

- name: Deploy web image tag
shell: bash
run: bun run .github/scripts/deploy --environment "${{ inputs.ENVIRONMENT }}" --newTagVersion "${{ steps.build-image.outputs.tag }}"
56 changes: 37 additions & 19 deletions .github/scripts/build-image/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { Environment } from "types";

import { $ } from "bun";
import { getEnvVariables } from "load-secrets/env/load";
import { backend } from "utils/run-backend-instance";
Expand All @@ -7,25 +9,33 @@ import { hideBin } from "yargs/helpers";

process.env.TZ = "America/New_York";

const { tagPrefix, dockerUpload, serverProfiles } = await yargs(
hideBin(process.argv),
)
.option("tagPrefix", {
type: "string",
demandOption: true,
})
.option("dockerUpload", {
type: "boolean",
default: false,
demandOption: true,
})
.option("serverProfiles", {
type: "string",
default: "prod",
demandOption: true,
})
.strict()
.parse();
const { environment, dockerUpload, getGhaOutput, githubOutputFile } =
await yargs(hideBin(process.argv))
.option("environment", {
choices: ["staging", "production"] satisfies Environment[],
describe: "Deployment environment (staging or production)",
demandOption: true,
})
.option("dockerUpload", {
type: "boolean",
default: false,
demandOption: true,
})
.option("getGhaOutput", {
type: "boolean",
describe: "Enable GitHub Actions output to receive latest built tag version",
default: false,
})
.option("githubOutputFile", {
type: "string",
describe: "Path to GITHUB_OUTPUT (passed in automatically in CI)",
default: process.env.GITHUB_OUTPUT,
})
.strict()
.parse();

const tagPrefix = environment === "staging" ? "staging-" : "";
const serverProfiles = environment === "staging" ? "stg" : "prod";

async function main() {
try {
Expand Down Expand Up @@ -103,6 +113,14 @@ async function main() {
.`;

console.log("Image pushed successfully.");

if (getGhaOutput && githubOutputFile) {
console.log("Outputting image tag...");
const w = Bun.file(githubOutputFile).writer();
await w.write(`tag<<EOF\n${tagPrefix}${gitSha}\nEOF\n`);
await w.flush();
await w.end();
}
} finally {
await backend.end();
await db.end();
Expand Down
6 changes: 5 additions & 1 deletion .github/scripts/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions .github/scripts/deploy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { Environment } from "types";

import { getEnvVariables } from "load-secrets/env/load";
import { updateK8sTagWithPR } from "utils/create-k8s-pr";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";

const { environment, newTagVersion } = await yargs(hideBin(process.argv))
.option("newTagVersion", {
type: "string",
demandOption: true,
})
.option("environment", {
choices: ["staging", "production"] satisfies Environment[],
describe: "Deployment environment (staging or production)",
demandOption: true,
})
.strict()
.parse();

async function main() {
const ciEnv = await getEnvVariables(["ci"]);
const { githubPat } = parseCiEnv(ciEnv);

await updateK8sTagWithPR({
githubPat,
kustomizationFilePath: `apps/${environment}/codebloom/kustomization.yaml`,
imageName: "docker.io/tahminator/codebloom",
newTag: newTagVersion,
environment,
});
}

function parseCiEnv(ciEnv: Record<string, string>) {
const githubPat = (() => {
const v = ciEnv["GITHUB_PAT"];
if (!v) {
throw new Error("Missing GITHUB_PAT from .env.ci");
}
return v;
})();

return { githubPat };
}

main()
.then(() => {
process.exit(0);
})
.catch((e) => {
console.error(e);
process.exit(1);
});
4 changes: 3 additions & 1 deletion .github/scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
"coolify": "https://github.com/tahminator/Coolify-TypeScript-SDK#8e19e18635ea2b095a9c39c574d22eefd938441f",
"discord.js": "^14.25.1",
"octokit": "^5.0.5",
"yargs": "^18.0.0"
"yaml": "^2.8.2",
"yargs": "^18.0.0",
"zod": "^4.3.6"
},
"devDependencies": {
"typescript": "^5.9.0",
Expand Down
2 changes: 2 additions & 0 deletions .github/scripts/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type Environment = "staging" | "production";

export type Location = "backend" | "frontend";

export type Type = "web" | "standup-bot";
Loading
Loading