diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 96762d9f..9a11e9ff 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -36,3 +36,8 @@ - **Ignore Files**: When creating new file types, directories, or build artifacts, ALWAYS check and update `.gitignore`, `.dockerignore`, and `.codecov.yml` to ensure they are properly excluded or included as required. - The root `Dockerfile` builds the Go binary and the React static assets (multi-stage build). - Branch from `feature/**` and target `development`. + +## CI/CD & Commit Conventions +- **Docker Builds**: The `docker-publish` workflow skips builds for commits starting with `chore:`. +- **Triggering Builds**: To ensure a new Docker image is built (e.g., for testing on VPS), use `feat:`, `fix:`, or `perf:` prefixes. +- **Beta Branch**: The `feature/beta-release` branch is configured to ALWAYS build, overriding the skip logic. diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 98111952..8fe49b77 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -43,6 +43,7 @@ jobs: ACTOR: ${{ github.actor }} EVENT: ${{ github.event_name }} HEAD_MSG: ${{ github.event.head_commit.message }} + REF: ${{ github.ref }} run: | should_skip=false pr_title="" @@ -54,6 +55,13 @@ jobs: if echo "$HEAD_MSG" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi if echo "$pr_title" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi if echo "$pr_title" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi + + # Always build on beta-release branch to ensure artifacts for testing + if [[ "$REF" == "refs/heads/feature/beta-release" ]]; then + should_skip=false + echo "Force building on beta-release branch" + fi + echo "skip_build=$should_skip" >> $GITHUB_OUTPUT - name: Set up QEMU diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7de498d..d395f246 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -125,10 +125,9 @@ jobs: artifacts/caddy-linux-arm64/caddy-linux-arm64 generate_release_notes: true prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }} - env: - GITHUB_TOKEN: ${{ secrets.PROJECT_TOKEN }} + token: ${{ secrets.PROJECT_TOKEN }} build-and-publish: needs: create-release - uses: ./.github/workflows/docker-publish.yml + uses: ./.github/workflows/docker-publish.yml # Reusable workflow present; path validated secrets: inherit diff --git a/backend/internal/api/handlers/remote_server_handler_test.go b/backend/internal/api/handlers/remote_server_handler_test.go index 9bf8bc52..49a54524 100644 --- a/backend/internal/api/handlers/remote_server_handler_test.go +++ b/backend/internal/api/handlers/remote_server_handler_test.go @@ -16,6 +16,7 @@ import ( ) func setupRemoteServerTest_New(t *testing.T) (*gin.Engine, *handlers.RemoteServerHandler) { + t.Helper() db := setupTestDB() // Ensure RemoteServer table exists db.AutoMigrate(&models.RemoteServer{}) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1a29c33f..2f104373 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,63 +1,69 @@ +import { Suspense, lazy } from 'react' import { BrowserRouter as Router, Routes, Route, Outlet } from 'react-router-dom' import Layout from './components/Layout' import { ToastContainer } from './components/Toast' import { SetupGuard } from './components/SetupGuard' +import { LoadingOverlay } from './components/LoadingStates' import RequireAuth from './components/RequireAuth' import { AuthProvider } from './context/AuthContext' -import Dashboard from './pages/Dashboard' -import ProxyHosts from './pages/ProxyHosts' -import RemoteServers from './pages/RemoteServers' -import ImportCaddy from './pages/ImportCaddy' -import Certificates from './pages/Certificates' -import SystemSettings from './pages/SystemSettings' -import Account from './pages/Account' -import Settings from './pages/Settings' -import Backups from './pages/Backups' -import Tasks from './pages/Tasks' -import Logs from './pages/Logs' -import Domains from './pages/Domains' -import Login from './pages/Login' -import Setup from './pages/Setup' + +// Lazy load pages for code splitting +const Dashboard = lazy(() => import('./pages/Dashboard')) +const ProxyHosts = lazy(() => import('./pages/ProxyHosts')) +const RemoteServers = lazy(() => import('./pages/RemoteServers')) +const ImportCaddy = lazy(() => import('./pages/ImportCaddy')) +const Certificates = lazy(() => import('./pages/Certificates')) +const SystemSettings = lazy(() => import('./pages/SystemSettings')) +const Account = lazy(() => import('./pages/Account')) +const Settings = lazy(() => import('./pages/Settings')) +const Backups = lazy(() => import('./pages/Backups')) +const Tasks = lazy(() => import('./pages/Tasks')) +const Logs = lazy(() => import('./pages/Logs')) +const Domains = lazy(() => import('./pages/Domains')) +const Login = lazy(() => import('./pages/Login')) +const Setup = lazy(() => import('./pages/Setup')) export default function App() { return ( - - } /> - } /> - - - - - - - - }> - } /> - } /> - } /> - } /> - } /> - } /> + }> + + } /> + } /> + + + + + + + + }> + } /> + } /> + } /> + } /> + } /> + } /> + + {/* Settings Routes */} + }> + } /> + } /> + } /> + + + {/* Tasks Routes */} + }> + } /> + } /> + } /> + - {/* Settings Routes */} - }> - } /> - } /> - } /> - - {/* Tasks Routes */} - }> - } /> - } /> - } /> - - - - + +