From 2b2f4f46c03735991bae6337c0444de27511ce62 Mon Sep 17 00:00:00 2001 From: Ryan Kegel Date: Sun, 26 Apr 2026 14:33:51 -0400 Subject: [PATCH] feat: add workflow for promoting master to production with testing and deployment steps --- .gitea/workflows/promote-master.yaml | 2 +- frontend/e2e/.auth/user-cc.json | 12 ++++++------ frontend/e2e/.auth/user-delete.json | 12 ++++++------ frontend/e2e/.auth/user.json | 12 ++++++------ .../digest-action-approve-chore.spec.ts | 3 ++- .../digest-action-approve-reward.spec.ts | 3 ++- .../notifications/digest-action-deny-chore.spec.ts | 3 ++- .../digest-action-deny-reward.spec.ts | 3 ++- .../notifications/digest-action-errors.spec.ts | 3 ++- frontend/package-lock.json | 14 ++++++++++++++ frontend/package.json | 1 + frontend/vite.config.ts | 5 +++-- 12 files changed, 47 insertions(+), 26 deletions(-) diff --git a/.gitea/workflows/promote-master.yaml b/.gitea/workflows/promote-master.yaml index a1104dd..7ab54fc 100644 --- a/.gitea/workflows/promote-master.yaml +++ b/.gitea/workflows/promote-master.yaml @@ -155,7 +155,7 @@ jobs: working-directory: frontend env: CI: "true" - PLAYWRIGHT_BASE_URL: "http://localhost:5173" + PLAYWRIGHT_BASE_URL: "https://localhost:5173" deploy: runs-on: ubuntu-latest diff --git a/frontend/e2e/.auth/user-cc.json b/frontend/e2e/.auth/user-cc.json index bacbbf8..6d184a8 100644 --- a/frontend/e2e/.auth/user-cc.json +++ b/frontend/e2e/.auth/user-cc.json @@ -2,20 +2,20 @@ "cookies": [ { "name": "refresh_token", - "value": "oh4sQB_Q1Se4xydZHTIolU6FhvlKPIlDPsxfd_qe4wQ", + "value": "v-K0IrmQf50MVvYCdmQfnUor8Q8e9KURnPnyVPYRN8Q", "domain": "localhost", "path": "/api/auth", - "expires": 1784867824.852037, + "expires": 1785003958.597918, "httpOnly": true, "secure": true, "sameSite": "Strict" }, { "name": "access_token", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI4NGY1Y2I3NS05NWU1LTRjMTItOTExOS02MzdkYjJlMWY1MGYiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzcwOTI3MjR9.7-d4EvJEYtYSi_5ZFiU7tuxgc4ilVMBxhwzgAQZNTvY", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI0NDg5ZjZhNS1mZWEyLTQ0ZGEtYTczNy00MDQwNTQyMmU0YTEiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzcyMjg4NTh9.V7gsUwZ-mjcRqCIwI2ppFVrGD16R18JJDQ5wsv_ul1k", "domain": "localhost", "path": "/", - "expires": 1777092724.851439, + "expires": 1777228858.597862, "httpOnly": true, "secure": true, "sameSite": "Lax" @@ -27,11 +27,11 @@ "localStorage": [ { "name": "authSyncEvent", - "value": "{\"type\":\"logout\",\"at\":1777091824594}" + "value": "{\"type\":\"logout\",\"at\":1777227958453}" }, { "name": "parentAuth", - "value": "{\"expiresAt\":1777264625262}" + "value": "{\"expiresAt\":1777400758775}" } ] } diff --git a/frontend/e2e/.auth/user-delete.json b/frontend/e2e/.auth/user-delete.json index 7d597db..7b36770 100644 --- a/frontend/e2e/.auth/user-delete.json +++ b/frontend/e2e/.auth/user-delete.json @@ -2,20 +2,20 @@ "cookies": [ { "name": "refresh_token", - "value": "lIhurtvmo0oGcimN_8v59h9y3CrglEAloQO1QFw8RsQ", + "value": "s8cSiajWyuCcjv9zXjqsKrmEK8cRPp-VOWV74Cz_ueQ", "domain": "localhost", "path": "/api/auth", - "expires": 1784867824.995155, + "expires": 1785003958.599099, "httpOnly": true, "secure": true, "sameSite": "Strict" }, { "name": "access_token", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1kZWxldGVAdGVzdC5jb20iLCJ1c2VyX2lkIjoiOWYzYTljNWMtM2IwMy00YTZlLTliNmUtYjE0MTQzZWNhMzNkIiwidG9rZW5fdmVyc2lvbiI6MCwiZXhwIjoxNzc3MDkyNzI0fQ.UB5MCIZ2PHbn3UyohNzmFbOCb3TR-KHxJPWB9qkWwCQ", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1kZWxldGVAdGVzdC5jb20iLCJ1c2VyX2lkIjoiYmE3MDNmMWItMzg0Zi00MzBjLWJiNjYtN2Q0YWRhMWIwYjRiIiwidG9rZW5fdmVyc2lvbiI6MCwiZXhwIjoxNzc3MjI4ODU4fQ.FnEEIVv2wchkrJhDiRuNiDBF-lIPkyZUU2UwLmLZVHM", "domain": "localhost", "path": "/", - "expires": 1777092724.99406, + "expires": 1777228858.599061, "httpOnly": true, "secure": true, "sameSite": "Lax" @@ -27,11 +27,11 @@ "localStorage": [ { "name": "authSyncEvent", - "value": "{\"type\":\"logout\",\"at\":1777091824687}" + "value": "{\"type\":\"logout\",\"at\":1777227958453}" }, { "name": "parentAuth", - "value": "{\"expiresAt\":1777264625511}" + "value": "{\"expiresAt\":1777400758775}" } ] } diff --git a/frontend/e2e/.auth/user.json b/frontend/e2e/.auth/user.json index cd463e3..c5fb6cd 100644 --- a/frontend/e2e/.auth/user.json +++ b/frontend/e2e/.auth/user.json @@ -2,20 +2,20 @@ "cookies": [ { "name": "refresh_token", - "value": "uMExObHukEdFnlszorcDq2XlbRW0AeIV71x_vSovEF4", + "value": "caYfAayTk40YWkRvN82a9_mGQ_-wXy6JdBBaD_UhLcQ", "domain": "localhost", "path": "/api/auth", - "expires": 1784867821.107956, + "expires": 1785003956.884209, "httpOnly": true, "secure": true, "sameSite": "Strict" }, { "name": "access_token", - "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiI2ZWE5YWZmZC1jMGExLTRkMzUtOGJmYS1mZDBkOWY5NzFmOWQiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzcwOTI3MjF9.rb64zKqS6uXqkgX_4kke37Rc6om68elt4Qa24Fy9NPo", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiI3YjcxMGU0ZC02ZTExLTRjMjctODllNS1jZTcxNGZhOTgwZTIiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzcyMjg4NTZ9.wJCrQ9Y5nbVpqd6yCeCHcpcpGpg4YqavqlsHbU8kDPE", "domain": "localhost", "path": "/", - "expires": 1777092721.107403, + "expires": 1777228856.884169, "httpOnly": true, "secure": true, "sameSite": "Lax" @@ -27,11 +27,11 @@ "localStorage": [ { "name": "authSyncEvent", - "value": "{\"type\":\"logout\",\"at\":1777091820880}" + "value": "{\"type\":\"logout\",\"at\":1777227956772}" }, { "name": "parentAuth", - "value": "{\"expiresAt\":1777264621275}" + "value": "{\"expiresAt\":1777400757015}" } ] } diff --git a/frontend/e2e/mode_parent/notifications/digest-action-approve-chore.spec.ts b/frontend/e2e/mode_parent/notifications/digest-action-approve-chore.spec.ts index b0eea14..f1490a0 100644 --- a/frontend/e2e/mode_parent/notifications/digest-action-approve-chore.spec.ts +++ b/frontend/e2e/mode_parent/notifications/digest-action-approve-chore.spec.ts @@ -5,6 +5,7 @@ import { test, expect, type APIRequestContext } from '@playwright/test' const CHILD_NAME = 'DigestApproveChoreChild' const CHORE_NAME = 'DigestApproveChoreChore' const CHORE_POINTS = 8 +const DIGEST_ACTION_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173' async function createChild(request: APIRequestContext, name: string): Promise { const pre = await request.get('/api/child/list') @@ -81,7 +82,7 @@ test.describe('Digest Action Token — Approve Chore', () => { }) => { const unauthCtx = await playwright.request.newContext({ ignoreHTTPSErrors: true, - baseURL: 'https://localhost:5173', + baseURL: DIGEST_ACTION_BASE_URL, }) const res = await unauthCtx.get(`/api/digest-action/${approveToken}`, { maxRedirects: 0, diff --git a/frontend/e2e/mode_parent/notifications/digest-action-approve-reward.spec.ts b/frontend/e2e/mode_parent/notifications/digest-action-approve-reward.spec.ts index aa53acc..81233d0 100644 --- a/frontend/e2e/mode_parent/notifications/digest-action-approve-reward.spec.ts +++ b/frontend/e2e/mode_parent/notifications/digest-action-approve-reward.spec.ts @@ -6,6 +6,7 @@ const CHILD_NAME = 'DigestApproveRewardChild' const REWARD_NAME = 'DigestApproveRewardReward' const REWARD_COST = 15 const INITIAL_POINTS = 50 +const DIGEST_ACTION_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173' async function createChild( request: APIRequestContext, @@ -78,7 +79,7 @@ test.describe('Digest Action Token — Approve Reward', () => { }) => { const unauthCtx = await playwright.request.newContext({ ignoreHTTPSErrors: true, - baseURL: 'https://localhost:5173', + baseURL: DIGEST_ACTION_BASE_URL, }) const res = await unauthCtx.get(`/api/digest-action/${approveToken}`, { maxRedirects: 0, diff --git a/frontend/e2e/mode_parent/notifications/digest-action-deny-chore.spec.ts b/frontend/e2e/mode_parent/notifications/digest-action-deny-chore.spec.ts index 851c209..515bc87 100644 --- a/frontend/e2e/mode_parent/notifications/digest-action-deny-chore.spec.ts +++ b/frontend/e2e/mode_parent/notifications/digest-action-deny-chore.spec.ts @@ -5,6 +5,7 @@ import { test, expect, type APIRequestContext } from '@playwright/test' const CHILD_NAME = 'DigestDenyChoreChild' const CHORE_NAME = 'DigestDenyChoreChore' const CHORE_POINTS = 8 +const DIGEST_ACTION_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173' async function createChild(request: APIRequestContext, name: string): Promise { const pre = await request.get('/api/child/list') @@ -71,7 +72,7 @@ test.describe('Digest Action Token — Deny Chore', () => { }) => { const unauthCtx = await playwright.request.newContext({ ignoreHTTPSErrors: true, - baseURL: 'https://localhost:5173', + baseURL: DIGEST_ACTION_BASE_URL, }) const res = await unauthCtx.get(`/api/digest-action/${denyToken}`, { maxRedirects: 0, diff --git a/frontend/e2e/mode_parent/notifications/digest-action-deny-reward.spec.ts b/frontend/e2e/mode_parent/notifications/digest-action-deny-reward.spec.ts index 63867cf..59a8385 100644 --- a/frontend/e2e/mode_parent/notifications/digest-action-deny-reward.spec.ts +++ b/frontend/e2e/mode_parent/notifications/digest-action-deny-reward.spec.ts @@ -6,6 +6,7 @@ const CHILD_NAME = 'DigestDenyRewardChild' const REWARD_NAME = 'DigestDenyRewardReward' const REWARD_COST = 15 const INITIAL_POINTS = 50 +const DIGEST_ACTION_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173' async function createChild( request: APIRequestContext, @@ -78,7 +79,7 @@ test.describe('Digest Action Token — Deny Reward', () => { }) => { const unauthCtx = await playwright.request.newContext({ ignoreHTTPSErrors: true, - baseURL: 'https://localhost:5173', + baseURL: DIGEST_ACTION_BASE_URL, }) const res = await unauthCtx.get(`/api/digest-action/${denyToken}`, { maxRedirects: 0, diff --git a/frontend/e2e/mode_parent/notifications/digest-action-errors.spec.ts b/frontend/e2e/mode_parent/notifications/digest-action-errors.spec.ts index 8017b9b..6a9e844 100644 --- a/frontend/e2e/mode_parent/notifications/digest-action-errors.spec.ts +++ b/frontend/e2e/mode_parent/notifications/digest-action-errors.spec.ts @@ -5,6 +5,7 @@ import { test, expect, type APIRequestContext } from '@playwright/test' const CHILD_NAME = 'DigestErrorChild' const CHORE_NAME = 'DigestErrorChore' const CHORE_POINTS = 5 +const DIGEST_ACTION_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'https://localhost:5173' async function createChild(request: APIRequestContext, name: string): Promise { const pre = await request.get('/api/child/list') @@ -33,7 +34,7 @@ async function createTask( async function getUnauthContext(playwright: any) { return playwright.request.newContext({ ignoreHTTPSErrors: true, - baseURL: 'https://localhost:5173', + baseURL: DIGEST_ACTION_BASE_URL, }) } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5f16105..b0aee77 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,7 @@ "@tsconfig/node22": "^22.0.2", "@types/jsdom": "^27.0.0", "@types/node": "^22.18.11", + "@vitejs/plugin-basic-ssl": "^2.3.0", "@vitejs/plugin-vue": "^6.0.1", "@vitest/eslint-plugin": "^1.3.23", "@vue/eslint-config-prettier": "^10.2.0", @@ -2171,6 +2172,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.3.0.tgz", + "integrity": "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 756b55e..a87999f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@tsconfig/node22": "^22.0.2", "@types/jsdom": "^27.0.0", "@types/node": "^22.18.11", + "@vitejs/plugin-basic-ssl": "^2.3.0", "@vitejs/plugin-vue": "^6.0.1", "@vitest/eslint-plugin": "^1.3.23", "@vue/eslint-config-prettier": "^10.2.0", diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index aad5d09..92a7816 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,6 +1,7 @@ import { fileURLToPath, URL } from 'node:url' import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' +import basicSsl from '@vitejs/plugin-basic-ssl' import fs from 'fs' export default defineConfig(({ mode }) => { @@ -13,10 +14,10 @@ export default defineConfig(({ mode }) => { : undefined return { - plugins: [vue()], + plugins: [vue(), basicSsl()], server: { host: '0.0.0.0', - https: httpsConfig, + https: httpsConfig ?? true, proxy: { '/api': { target: `http://${backendHost}:5000`,