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
8 changes: 8 additions & 0 deletions .github/workflows/deploy-containers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,17 @@ jobs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Compute image prefix
id: meta
run: echo "prefix=${REGISTRY}/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"

- name: Compute dashboard version
id: dashboard_version
run: echo "dashboard_version=$(git describe --tags --always)" >> "$GITHUB_OUTPUT"

- name: Log in to GHCR
uses: docker/login-action@v3
with:
Expand All @@ -79,6 +85,8 @@ jobs:
context: .
file: ./dashboard/Dockerfile
push: true
build-args: |
DASHBOARD_VERSION=${{ steps.dashboard_version.outputs.dashboard_version }}
tags: |
${{ steps.meta.outputs.prefix }}/dashboard-frontend:latest
${{ steps.meta.outputs.prefix }}/dashboard-frontend:${{ github.sha }}
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/deploy-staging.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ jobs:
outputs:
has_new_migrations: ${{ steps.check.outputs.has_new_migrations }}
migration_list: ${{ steps.check.outputs.migration_list }}
dashboard_version: ${{ steps.dashboard_version.outputs.dashboard_version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Compute dashboard version
id: dashboard_version
run: echo "dashboard_version=$(git describe --tags --always)" >> "$GITHUB_OUTPUT"

- name: Check for new Django migrations
id: check
run: |
Expand Down Expand Up @@ -68,6 +73,7 @@ jobs:
cp ~/.env-staging dashboard-staging/.env &&
cd dashboard-staging &&
git checkout ${GITHUB_SHA} &&
export DASHBOARD_VERSION=${DASHBOARD_VERSION} &&
docker compose pull --ignore-buildable --policy=always &&
docker compose build --no-cache &&
docker compose up -d --remove-orphans
Expand All @@ -76,6 +82,7 @@ jobs:
SSH_USER: ${{ secrets.STAGING_USER }}
SSH_HOST: ${{ secrets.STAGING_HOST }}
SSH_KEY: ${{ secrets.STAGING_KEY }}
DASHBOARD_VERSION: ${{ needs.check-migrations.outputs.dashboard_version }}

cleanup:
needs: deploy-staging
Expand Down
22 changes: 22 additions & 0 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,28 @@ docker compose -f docker-compose-next.yml pull
docker compose -f docker-compose-next.yml up -d
```

### Tagging a release

Every production deployment must be preceded by a release tag.
The dashboard displays its version (`git describe --tags`) at the bottom of the
side menu, so an untagged deployment shows only a commit hash, making it hard to

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically, it will show release/<old release>-N-g<sha>, not only a commit sha

tell which release is live.

1. Tag the `main` commit being released, following the `release/YYYYMMDD.N`
convention (`N` starts at `0` and increments for further releases on the same day):

```bash
git fetch --tags
git tag release/20260729.0 <commit>
git push origin release/20260729.0
```

2. Manually trigger the `Publish GHCR Images` workflow. Images built by the
earlier push to `main` were baked before the tag existed, so they still carry the
previous version string.
3. Trigger the `Deploy production Dashboard` workflow with the new tag.
4. Confirm the version shown in the side menu matches the tag.

---

## 3. Staging
Expand Down
3 changes: 3 additions & 0 deletions dashboard/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ RUN npm install -g pnpm@10.33.3 && pnpm install --frozen-lockfile

COPY dashboard/. ./

ARG DASHBOARD_VERSION
ENV VITE_DASHBOARD_VERSION=$DASHBOARD_VERSION

RUN pnpm build

# Stage 2: Copy the static files from the builder stage
Expand Down
26 changes: 26 additions & 0 deletions dashboard/src/components/SideMenu/SideMenuContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/Tooltip';

import { ExternalLinkIcon } from '@/components/Icons/ExternalLink';

import { REPO_URL } from '@/utils/constants/general';

import SendFeedback from './SendFeedback';
import NavLink from './NavLink';
import {
Expand All @@ -25,6 +27,17 @@ import {
type RouteMenuItems,
} from './menuItems';

const dashboardVersion: string = import.meta.env.VITE_DASHBOARD_VERSION;

const versionRepoUrl = (version: string): string => {
if (version.endsWith('-dirty')) {
return REPO_URL;
}

const commitAfterTag = version.match(/-g([0-9a-f]+)$/)?.[1];
return `${REPO_URL}/tree/${commitAfterTag ?? version}`;
};

type SideMenuItemProps = {
item: RouteMenuItems;
};
Expand Down Expand Up @@ -124,6 +137,19 @@ const SideMenuContent = ({
<div className="flex w-full flex-col space-y-0">
{dashboardElements}
</div>
{dashboardVersion && (
<>
<Separator className="bg-on-secondary-10 my-4" />
<a
href={versionRepoUrl(dashboardVersion)}
target="_blank"
rel="noreferrer"
className="block w-full px-4 text-xs break-words text-white/40 hover:text-white/70"
>
{dashboardVersion}
</a>
</>
)}
</NavigationMenuList>
</NavigationMenu>
);
Expand Down
15 changes: 15 additions & 0 deletions dashboard/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import path from 'path';
import { execSync } from 'node:child_process';

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import tailwindcss from '@tailwindcss/vite';

import { TanStackRouterVite } from '@tanstack/router-plugin/vite';

const dashboardVersion =
process.env.VITE_DASHBOARD_VERSION ||
((): string => {
try {
return execSync('git describe --tags --always --dirty').toString().trim();
} catch {
return '';
}
})();

// https://vitejs.dev/config/
export default defineConfig({
plugins: [tailwindcss(), tsconfigPaths(), react(), TanStackRouterVite()],
define: {
'import.meta.env.VITE_DASHBOARD_VERSION': JSON.stringify(dashboardVersion),
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ services:
build:
context: .
dockerfile: ./dashboard/Dockerfile
args:
DASHBOARD_VERSION: ${DASHBOARD_VERSION:-}
image: ${IMAGE_REGISTRY:-ghcr.io}/${IMAGE_REPOSITORY:-local}/dashboard-frontend:${IMAGE_TAG:-latest}
volumes:
- static-data:/data/static
Expand Down
Loading