add staging deployment + test to gitea workflow
All checks were successful
Build and push image for doorman-homeassistant / docker (push) Successful in 30s
Build and push Doorman UI / API / docker (push) Successful in 3m42s
Build and push image for doorman-homeassistant / deploy-gitainer (push) Successful in 5s

This commit is contained in:
Martin Dimitrov 2025-06-08 19:00:49 -07:00
parent cde7a1309e
commit 8f75081e6b
7 changed files with 78 additions and 12 deletions

View File

@ -18,8 +18,8 @@ jobs:
- name: install dependencies - name: install dependencies
run: bun install run: bun install
- name: run api integ test - name: run local integration test
run: bun integ-test-api run: bun integ-test:local
env: env:
ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }} ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }} AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }}
@ -28,6 +28,25 @@ jobs:
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }} DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
DISCORD_CLIENT_SECRET: ${{ secrets.DISCORD_CLIENT_SECRET }} DISCORD_CLIENT_SECRET: ${{ secrets.DISCORD_CLIENT_SECRET }}
- name: Deploy Doorman UI and API to staging
run: bun run deploy-serverless:staging
env:
ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }}
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
DISCORD_BOT_TOKEN: ${{ secrets.DISCORD_BOT_TOKEN }}
DISCORD_CLIENT_SECRET: ${{ secrets.DISCORD_CLIENT_SECRET }}
- name: Deploy Doorman Buzzer Client to staging
run: bun run deploy-buzzer-client:staging
env:
ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }}
AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }}
- name: run staging integration test
run: bun integ-test:staging
- name: Deploy Doorman UI and API - name: Deploy Doorman UI and API
run: bun run deploy-serverless run: bun run deploy-serverless
env: env:

View File

@ -7,12 +7,15 @@
"bun-types": "latest" "bun-types": "latest"
}, },
"scripts": { "scripts": {
"integ-test-api": "bun --filter 'doorman-api' integ-test", "integ-test:local": "bun --filter 'doorman-api' integ-test:local",
"integ-test:staging": "bun --filter 'doorman-api' integ-test:staging",
"prepare-ui": "bun --filter 'doorman-ui' build && rm -rf packages/doorman-api/assets/* && mkdir -p packages/doorman-api/assets/assets && cp -fr packages/doorman-ui/dist/* packages/doorman-api/assets/ && cp -f packages/doorman-api/assets/index.html packages/doorman-api/assets/assets/index.html", "prepare-ui": "bun --filter 'doorman-ui' build && rm -rf packages/doorman-api/assets/* && mkdir -p packages/doorman-api/assets/assets && cp -fr packages/doorman-ui/dist/* packages/doorman-api/assets/ && cp -f packages/doorman-api/assets/index.html packages/doorman-api/assets/assets/index.html",
"deploy-serverless": "bun run prepare-ui && bun run build-twilio-api && bun --filter 'doorman-api' deploy", "deploy-serverless": "bun run prepare-ui && bun run build-twilio-api && bun --filter 'doorman-api' deploy",
"deploy-serverless:staging": "bun run prepare-ui && bun run build-twilio-api && bun --filter 'doorman-api' deploy:staging",
"build-twilio-client": "bun --filter 'doorman-client' build", "build-twilio-client": "bun --filter 'doorman-client' build",
"build-twilio-api": "bun --filter 'doorman-api' build", "build-twilio-api": "bun --filter 'doorman-api' build",
"deploy-buzzer-client": "bun run build-twilio-client && bun --filter 'doorman-client' deploy" "deploy-buzzer-client": "bun run build-twilio-client && bun --filter 'doorman-client' deploy",
"deploy-buzzer-client:staging": "bun run build-twilio-client && bun --filter 'doorman-client' deploy:staging"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.0.0" "typescript": "^5.0.0"

View File

@ -3,12 +3,14 @@
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"integ-test": "bun run build && export $(grep -v '^#' .env.example | grep -v '=$' | xargs) && concurrently --success first --kill-others \"bun run start-twilio\" \"bun test --timeout 30000\"", "integ-test:local": "bun run build && export $(grep -v '^#' .env.example | grep -v '=$' | xargs) && concurrently --success first --kill-others \"bun run start-twilio\" \"bun test --timeout 30000 ./tst/integ-local.test.ts\"",
"integ-test:staging": "STAGE=staging bun test --timeout 30000 ./tst/integ-staging.test.ts",
"start-twilio": "twilio-run --load-local-env --live --port 8080", "start-twilio": "twilio-run --load-local-env --live --port 8080",
"watch-build": "bun run --watch src/index.ts", "watch-build": "bun run --watch src/index.ts",
"start": "concurrently \"bun run watch-build\" \"bun run start-twilio\"", "start": "concurrently \"bun run watch-build\" \"bun run start-twilio\"",
"build": "bun run src/index.ts", "build": "bun run src/index.ts",
"deploy": "twilio-run deploy --load-system-env --env .env.example --service-name doorman --environment=prod --override-existing-project" "deploy": "twilio-run deploy --load-system-env --env .env.example --service-name doorman --environment=prod --override-existing-project",
"deploy:staging": "twilio-run deploy --load-system-env --env .env.example --service-name doorman --environment=staging --override-existing-project"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-dynamodb": "^3.821.0", "@aws-sdk/client-dynamodb": "^3.821.0",

View File

@ -1,9 +1,14 @@
import { describe, test, expect, beforeAll } from "bun:test"; import { describe, test, expect, beforeAll } from "bun:test";
import { waitForService, baseUrl, doorName, buzzerNumber, key } from "./testCommon"; import { waitForService, baseUrl, doorName, buzzerNumber, key, buzzerUrl } from "./testCommon";
import { DoorStatus } from "../src/types/DoorStatus"; import { DoorStatus } from "../src/types/DoorStatus";
import { StatusResponse } from "../src/functions/api/door/status"; import { StatusResponse } from "../src/functions/api/door/status";
import { sleep } from "bun"; import { sleep } from "bun";
// these tests should only run locally
if (process.env.STAGE === 'staging') {
process.exit(0);
}
beforeAll(async () => { beforeAll(async () => {
await waitForService(baseUrl); await waitForService(baseUrl);
}); });
@ -70,5 +75,3 @@ describe("unlock path works", () => {
expect(infoClosed.status).toBe(DoorStatus.CLOSED); expect(infoClosed.status).toBe(DoorStatus.CLOSED);
}); });
}); });
// TODO: add tests for edit / onboard. Not sure how I can automated receive info needed for discord DMs

View File

@ -0,0 +1,35 @@
import { describe, test, expect } from "bun:test";
import { buzzerUrl, buzzerNumber, baseUrl, doorName, key } from "./testCommon";
import { DoorStatus } from "../src/types/DoorStatus";
import { InfoResponseUI } from "../src/functions/api/door/info";
if (process.env.STAGE !== 'staging') {
process.exit(0);
}
// currently these tests only run against STAGING env
describe("buzzer client works", () => {
test("unknown buzzer should reject", async () => {
const unknownBuzzResp = await fetch(buzzerUrl + `?From=1`).then(res => res.text());
expect(unknownBuzzResp).toContain("<Reject");
});
test("no auth, should dial fallback numbers", async () => {
const noAuthBuzzResp = await fetch(buzzerUrl + `?From=${buzzerNumber}`).then(res => res.text());
expect(noAuthBuzzResp).toContain("<Dial");
});
test("sample e2e happy path", async () => {
// unlock door
const authResp = await fetch(baseUrl + `/api/door/auth?door=${doorName}&key=${key}`);
expect(authResp.status).toBe(200);
// buzzer should return an unlock
const buzzerActivatedResp = await fetch(buzzerUrl + `?From=${buzzerNumber}`).then(res => res.text());
expect(buzzerActivatedResp).toContain("<Play");
// door should now be closed
const infoResp = await fetch(baseUrl + `/api/door/info?door=${doorName}`).then(res => res.json()) as InfoResponseUI;
expect(infoResp.status).toBe(DoorStatus.CLOSED);
});
});

View File

@ -1,8 +1,11 @@
export const baseUrl = "http://localhost:8080"; export const baseUrl = process.env.STAGE == "staging" ? "https://doorman-6741-staging.twil.io": "http://localhost:8080";
export const buzzerUrl = process.env.STAGE == "staging" ? "https://buzzer-2439-staging.twil.io/buzzer-activated": "http://localhost:4500/buzzer-activated";
export const doorName = "test"; export const doorName = "test";
export const buzzerNumber = "6133163433"; export const buzzerNumber = "6133163433";
export const key = "1234"; export const key = "1234";
console.log("using URL", baseUrl, buzzerUrl);
export const waitForService = async (url: string, timeout = 30000) => { export const waitForService = async (url: string, timeout = 30000) => {
const start = Date.now(); const start = Date.now();

View File

@ -8,7 +8,8 @@
"start-twilio": "twilio-run --live --port 4500", "start-twilio": "twilio-run --live --port 4500",
"start": "concurrently \"bun run watch-build\" \"bun run start-twilio\"", "start": "concurrently \"bun run watch-build\" \"bun run start-twilio\"",
"build": "bun run src/index.ts", "build": "bun run src/index.ts",
"deploy": "twilio-run deploy --load-system-env --env .env.example --service-name buzzer --environment=prod --override-existing-project" "deploy": "twilio-run deploy --load-system-env --env .env.example --service-name buzzer --environment=prod --override-existing-project",
"deploy:staging": "twilio-run deploy --load-system-env --env .env.example --service-name buzzer --environment=staging --override-existing-project"
}, },
"dependencies": { "dependencies": {
"@twilio-labs/serverless-runtime-types": "^4.0.1", "@twilio-labs/serverless-runtime-types": "^4.0.1",