mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-09-19 03:58:30 +02:00
Implemented Danswer versioning system. (#649)
* Web & API server versioning system. Displayed on UI. * Remove some debugging code. * Integrated backend version into GitHub Action & Docker build workflow using env variables. * Fixed web container environment variable name. * Revise Dockerfiles for GitHub Actions workflow. * Added system information page to admin panel with version info. Updated github workflows to include tagged version, and corresponding changes in the dockerfiles and codebases for web&backend to use env variables if present. Changed to 'dev' naming scheme if no env var is present to indicate local setup. Removed version from admin panel header. * Added missing systeminfo dir to remote repo.
This commit is contained in:
@@ -32,3 +32,5 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
danswer/danswer-backend:${{ github.ref_name }}
|
danswer/danswer-backend:${{ github.ref_name }}
|
||||||
danswer/danswer-backend:latest
|
danswer/danswer-backend:latest
|
||||||
|
build-args: |
|
||||||
|
DANSWER_VERSION: ${{ github.ref_name }}
|
||||||
|
@@ -32,3 +32,5 @@ jobs:
|
|||||||
tags: |
|
tags: |
|
||||||
danswer/danswer-web-server:${{ github.ref_name }}
|
danswer/danswer-web-server:${{ github.ref_name }}
|
||||||
danswer/danswer-web-server:latest
|
danswer/danswer-web-server:latest
|
||||||
|
build-args: |
|
||||||
|
DANSWER_VERSION: ${{ github.ref_name }}
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
FROM python:3.11.4-slim-bookworm
|
FROM python:3.11.4-slim-bookworm
|
||||||
|
|
||||||
|
# Default DANSWER_VERSION build argument set here.
|
||||||
|
# This can be overridden by passing in a build arg, typically from GitHub Actions.
|
||||||
|
ARG DANSWER_VERSION=0.1.0
|
||||||
|
# Then passed to the container environment.
|
||||||
|
ENV DANSWER_VERSION=${DANSWER_VERSION}
|
||||||
|
|
||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y git cmake pkg-config libprotobuf-c-dev protobuf-compiler \
|
apt-get install -y git cmake pkg-config libprotobuf-c-dev protobuf-compiler \
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
# Pulls the version from the environment variable DANSWER_VERSION, or defaults to 0.1.0dev.
|
||||||
|
__version__ = os.environ.get("DANSWER_VERSION", "") or "0.1.0dev"
|
@@ -46,6 +46,10 @@ class AuthTypeResponse(BaseModel):
|
|||||||
auth_type: AuthType
|
auth_type: AuthType
|
||||||
|
|
||||||
|
|
||||||
|
class VersionResponse(BaseModel):
|
||||||
|
backend_version: str
|
||||||
|
|
||||||
|
|
||||||
class DataRequest(BaseModel):
|
class DataRequest(BaseModel):
|
||||||
data: str
|
data: str
|
||||||
|
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from danswer import __version__
|
||||||
from danswer.configs.app_configs import AUTH_TYPE
|
from danswer.configs.app_configs import AUTH_TYPE
|
||||||
from danswer.server.models import AuthTypeResponse
|
from danswer.server.models import AuthTypeResponse
|
||||||
from danswer.server.models import StatusResponse
|
from danswer.server.models import StatusResponse
|
||||||
|
from danswer.server.models import VersionResponse
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@@ -16,3 +17,8 @@ def healthcheck() -> StatusResponse:
|
|||||||
@router.get("/auth/type")
|
@router.get("/auth/type")
|
||||||
def get_auth_type() -> AuthTypeResponse:
|
def get_auth_type() -> AuthTypeResponse:
|
||||||
return AuthTypeResponse(auth_type=AUTH_TYPE)
|
return AuthTypeResponse(auth_type=AUTH_TYPE)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/version")
|
||||||
|
def get_version() -> VersionResponse:
|
||||||
|
return VersionResponse(backend_version=__version__)
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
FROM node:20-alpine AS base
|
FROM node:20-alpine AS base
|
||||||
|
|
||||||
|
# Default DANSWER_VERSION build argument set here.
|
||||||
|
# This can be overridden by passing in a build arg, typically from GitHub Actions.
|
||||||
|
ARG DANSWER_VERSION=0.1.0
|
||||||
|
# Then passed to the container environment.
|
||||||
|
ENV DANSWER_VERSION=${DANSWER_VERSION}
|
||||||
|
|
||||||
# Step 1. Install dependencies only when needed
|
# Step 1. Install dependencies only when needed
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
|
@@ -1,3 +1,9 @@
|
|||||||
|
// Get Danswer Web Version
|
||||||
|
const { version: package_version } = require('./package.json'); // version from package.json
|
||||||
|
const env_version = process.env.DANSWER_VERSION; // version from env variable
|
||||||
|
// Use env version if set & valid, otherwise default to package version
|
||||||
|
const version = env_version || package_version;
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
@@ -33,6 +39,9 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
publicRuntimeConfig: {
|
||||||
|
version,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
4
web/package-lock.json
generated
4
web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "qa",
|
"name": "qa",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0dev",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "qa",
|
"name": "qa",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0dev",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@phosphor-icons/react": "^2.0.8",
|
"@phosphor-icons/react": "^2.0.8",
|
||||||
"@tremor/react": "^3.9.2",
|
"@tremor/react": "^3.9.2",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "qa",
|
"name": "qa",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0dev",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
40
web/src/app/admin/systeminfo/page.tsx
Normal file
40
web/src/app/admin/systeminfo/page.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { NotebookIcon } from "@/components/icons/icons";
|
||||||
|
import { getWebVersion, getBackendVersion } from "@/lib/version"
|
||||||
|
|
||||||
|
const Page = async () => {
|
||||||
|
|
||||||
|
let web_version: string | null = null;
|
||||||
|
let backend_version: string | null = null;
|
||||||
|
try {
|
||||||
|
[web_version, backend_version] = await Promise.all([
|
||||||
|
getWebVersion(),
|
||||||
|
getBackendVersion(),
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Version info fetch failed for system info page - ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="border-solid border-gray-600 border-b pb-2 mb-4 flex">
|
||||||
|
<NotebookIcon size={32} />
|
||||||
|
<h1 className="text-3xl font-bold pl-2">System Information</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="font-bold text-lg my-auto mb-2">Danswer MIT</p>
|
||||||
|
<div className="flex mb-2">
|
||||||
|
<p className="my-auto mr-1">Backend Version: </p>
|
||||||
|
<p className="text-base my-auto text-slate-400 italic">{backend_version}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex mb-2">
|
||||||
|
<p className="my-auto mr-1">Web Version: </p>
|
||||||
|
<p className="text-base my-auto text-slate-400 italic">{web_version}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
@@ -3,6 +3,8 @@ import { AuthType, OAUTH_NAME } from "@/lib/constants";
|
|||||||
import { User } from "@/lib/types";
|
import { User } from "@/lib/types";
|
||||||
import { getCurrentUserSS, getAuthUrlSS, getAuthTypeSS } from "@/lib/userSS";
|
import { getCurrentUserSS, getAuthUrlSS, getAuthTypeSS } from "@/lib/userSS";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
import { getWebVersion, getBackendVersion } from "@/lib/version"
|
||||||
|
|
||||||
|
|
||||||
const BUTTON_STYLE =
|
const BUTTON_STYLE =
|
||||||
"group relative w-64 flex justify-center " +
|
"group relative w-64 flex justify-center " +
|
||||||
@@ -25,6 +27,17 @@ const Page = async () => {
|
|||||||
console.log(`Some fetch failed for the login page - ${e}`);
|
console.log(`Some fetch failed for the login page - ${e}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let web_version: string | null = null;
|
||||||
|
let backend_version: string | null = null;
|
||||||
|
try {
|
||||||
|
[web_version, backend_version] = await Promise.all([
|
||||||
|
getWebVersion(),
|
||||||
|
getBackendVersion(),
|
||||||
|
]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Version info fetch failed for the login page - ${e}`);
|
||||||
|
}
|
||||||
|
|
||||||
// simply take the user to the home page if Auth is disabled
|
// simply take the user to the home page if Auth is disabled
|
||||||
if (authType === "disabled") {
|
if (authType === "disabled") {
|
||||||
return redirect("/");
|
return redirect("/");
|
||||||
@@ -80,6 +93,9 @@ const Page = async () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="fixed bottom-4 right-4 z-50 text-slate-400 p-2">
|
||||||
|
VERSION w{ web_version } b{ backend_version }
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
@@ -317,6 +317,20 @@ export async function Layout({ children }: { children: React.ReactNode }) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Info",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: (
|
||||||
|
<div className="flex">
|
||||||
|
<NotebookIcon size={18} />
|
||||||
|
<div className="ml-1">System Information</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
link: "/admin/systeminfo",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<div className="px-12 min-h-screen bg-gray-900 text-gray-100 w-full">
|
<div className="px-12 min-h-screen bg-gray-900 text-gray-100 w-full">
|
||||||
|
27
web/src/lib/version.ts
Normal file
27
web/src/lib/version.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { buildUrl } from "./utilsSS";
|
||||||
|
import getConfig from 'next/config';
|
||||||
|
|
||||||
|
const { publicRuntimeConfig } = getConfig();
|
||||||
|
const version = publicRuntimeConfig?.version;
|
||||||
|
|
||||||
|
// Maybe improve type-safety by creating a 'VersionType' instead of generic string
|
||||||
|
export const getBackendVersion = async (): Promise<string | null> => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(buildUrl("/version"));
|
||||||
|
if (!res.ok) {
|
||||||
|
//throw new Error("Failed to fetch data");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: { backend_version: string } = await res.json();
|
||||||
|
return data.backend_version as string;
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Error fetching backend version info: ${e}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Frontend?
|
||||||
|
export const getWebVersion = (): string | null => {
|
||||||
|
return version;
|
||||||
|
};
|
Reference in New Issue
Block a user