Skip to content

Commit

Permalink
feat: put the current version into docker image and display (#28) (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
holtgrewe authored Sep 1, 2023
1 parent 655e549 commit 586af7e
Show file tree
Hide file tree
Showing 22 changed files with 239 additions and 43 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
.coverage
coverage.lcov

# Version file
/VERSION

# Environment variables
.env

Expand Down
19 changes: 19 additions & 0 deletions backend/app/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import pathlib
import subprocess
import sys

import httpx
Expand All @@ -25,6 +26,14 @@
BACKEND_PREFIX_MEHARI = env.get("REEV_BACKEND_PREFIX_MEHARI", "http://mehari:8080")
#: Prefix for the backend of viguno service
BACKEND_PREFIX_VIGUNO = env.get("REEV_BACKEND_PREFIX_VIGUNO", "http://viguno:8080")
#: Path to REEV version file.
VERSION_FILE = env.get("REEV_VERSION_FILE", "/VERSION")
#: The REEV version from the file (``None`` if to load dynamically from git)
REEV_VERSION = None
# Try to obtain version from file, otherwise keep it at ``None``
if os.path.exists(VERSION_FILE):
with open(VERSION_FILE) as f:
REEV_VERSION = f.read().strip() or None


app = FastAPI()
Expand Down Expand Up @@ -82,6 +91,16 @@ async def reverse_proxy(request: Request) -> Response:
app.add_route("/proxy/{path:path}", reverse_proxy, methods=["GET", "POST"])


# Register app for returning REEV version.
@app.get("/version")
async def version():
if REEV_VERSION:
version = REEV_VERSION
else:
version = subprocess.check_output(["git", "describe", "--tags", "--dirty"]).strip()
return Response(content=version)


# Register route for favicon.
@app.get("/favicon.ico")
async def favicon():
Expand Down
14 changes: 10 additions & 4 deletions frontend/src/api/__tests__/common.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { describe, it, expect } from 'vitest'

import { API_BASE_PREFIX } from '../common'
import { API_BASE_PREFIX, API_PROXY_BASE_PREFIX } from '../common'

describe('API_BASE_PREFIX constant', () => {
it('returns the correct API base prefix in production mode', () => {
describe('constants', () => {
it('returns the correct proxy API base prefix in production mode', () => {
const originalMode = import.meta.env.MODE
expect(API_BASE_PREFIX).toBe('/proxy/annonars')
expect(API_BASE_PREFIX).toBe('/')
import.meta.env.MODE = originalMode
})

it('returns the correct proxy API base prefix in production mode', () => {
const originalMode = import.meta.env.MODE
expect(API_PROXY_BASE_PREFIX).toBe('/proxy/')
import.meta.env.MODE = originalMode
})
})
21 changes: 21 additions & 0 deletions frontend/src/api/__tests__/misc.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { beforeEach, describe, it, expect, vi } from 'vitest'
import createFetchMock from 'vitest-fetch-mock'

import { MiscClient } from '../misc'

const fetchMocker = createFetchMock(vi)

describe('Misc Client', () => {
beforeEach(() => {
fetchMocker.enableMocks()
fetchMocker.resetMocks()
})

it('fetches version info correctly', async () => {
fetchMocker.mockResponseOnce('v0.0.0')

const client = new MiscClient()
const result = await client.fetchVersion()
expect(result).toEqual('v0.0.0')
})
})
8 changes: 3 additions & 5 deletions frontend/src/api/annonars.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { API_BASE_PREFIX } from '@/api/common'

const API_BASE_URL = `${API_BASE_PREFIX}/`
import { API_PROXY_BASE_PREFIX } from '@/api/common'

export class AnnonarsClient {
private apiBaseUrl: string
private csrfToken: string | null

constructor(apiBaseUrl?: string, csrfToken?: string) {
this.apiBaseUrl = apiBaseUrl ?? API_BASE_URL
this.apiBaseUrl = apiBaseUrl ?? `${API_PROXY_BASE_PREFIX}annonars`
this.csrfToken = csrfToken ?? null
}

async fetchGeneInfo(hgncId: string): Promise<any> {
const response = await fetch(`${this.apiBaseUrl}genes/info?hgnc_id=${hgncId}`, {
const response = await fetch(`${this.apiBaseUrl}/genes/info?hgnc_id=${hgncId}`, {
method: 'GET'
})
return await response.json()
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/api/common.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const API_BASE_PREFIX =
import.meta.env.MODE == 'development' ? '//localhost:8080/proxy/annonars' : '/proxy/annonars'
export const API_BASE_PREFIX = import.meta.env.MODE == 'development' ? '//localhost:8080/' : '/'

export const API_PROXY_BASE_PREFIX = `${API_BASE_PREFIX}proxy/`
20 changes: 20 additions & 0 deletions frontend/src/api/misc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { API_BASE_PREFIX } from '@/api/common'

const API_BASE_URL = API_BASE_PREFIX

export class MiscClient {
private apiBaseUrl: string
private csrfToken: string | null

constructor(apiBaseUrl?: string, csrfToken?: string) {
this.apiBaseUrl = apiBaseUrl ?? API_BASE_URL
this.csrfToken = csrfToken ?? null
}

async fetchVersion(): Promise<any> {
const response = await fetch(`${this.apiBaseUrl}version`, {
method: 'GET'
})
return await response.text()
}
}
14 changes: 14 additions & 0 deletions frontend/src/components/HeaderDefault.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { useMiscStore } from '@/stores/misc'
const miscStore = useMiscStore()
onMounted(() => {
if (miscStore?.initialize) {
miscStore?.initialize()
}
})
</script>

<template>
<v-app-bar app class="top-bar">
<v-toolbar-title>
<router-link to="/">
<img src="@/assets/reev-logo.svg" id="logo" alt="logo" width="100" />
Explanation and Evaluation of Variants
<small>{{ miscStore?.appVersion }}</small>
</router-link>
</v-toolbar-title>
<v-spacer></v-spacer>
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/components/__tests__/HeaderDefault.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import { routes } from '@/router'
import { createTestingPinia } from '@pinia/testing'

import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
Expand All @@ -28,7 +29,18 @@ const makeWrapper = () => {
},
{
global: {
plugins: [vuetify, router],
plugins: [
vuetify,
router,
createTestingPinia({
createSpy: vi.fn(),
initialState: {
misc: {
appVersion: 'v0.0.0'
}
}
})
],
components: {
HeaderDefault
}
Expand All @@ -44,7 +56,7 @@ describe('HeaderDefault.vue', () => {
const logo = wrapper.find('#logo')
const title = wrapper.find('a[href="/"]')
expect(logo.exists()).toBe(true)
expect(title.text()).toBe('Explanation and Evaluation of Variants')
expect(title.text()).toBe('Explanation and Evaluation of Variants v0.0.0')
})

it('renders the navigation links', () => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/__tests__/HeaderDetailPage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'

import HeaderDetailPage from '../HeaderDetailPage.vue'
import { StoreState } from '@/stores/geneInfo'
import { StoreState } from '@/stores/misc'

const vuetify = createVuetify({
components,
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/stores/__tests__/geneInfo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import createFetchMock from 'vitest-fetch-mock'

import { setActivePinia, createPinia } from 'pinia'

import { useGeneInfoStore, StoreState } from '../geneInfo'
import { StoreState } from '../misc'
import { useGeneInfoStore } from '../geneInfo'

const fetchMocker = createFetchMock(vi)

Expand Down
33 changes: 33 additions & 0 deletions frontend/src/stores/__tests__/misc.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { beforeEach, describe, it, expect, vi } from 'vitest'
import createFetchMock from 'vitest-fetch-mock'

import { setActivePinia, createPinia } from 'pinia'

import { StoreState, useMiscStore } from '../misc'

const fetchMocker = createFetchMock(vi)

describe('miscInfo Store', () => {
beforeEach(() => {
setActivePinia(createPinia())
fetchMocker.enableMocks()
fetchMocker.resetMocks()
})

it('should have initial state', () => {
const store = useMiscStore()

expect(store.storeState).toBe(StoreState.Initial)
expect(store.appVersion).toBe(null)
})

it('should load data', async () => {
const store = useMiscStore()
fetchMocker.mockResponseOnce('v0.0.0')

await store.initialize()

expect(store.storeState).toBe(StoreState.Active)
expect(store.appVersion).toBe('v0.0.0')
})
})
8 changes: 1 addition & 7 deletions frontend/src/stores/geneInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,9 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'

import { StoreState } from '@/stores/misc'
import { AnnonarsClient } from '@/api/annonars'

export enum StoreState {
Initial = 'initial',
Loading = 'loading',
Active = 'active',
Error = 'error'
}

export const useGeneInfoStore = defineStore('geneInfo', () => {
// The current store state
const storeState = ref<StoreState>(StoreState.Initial)
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/stores/misc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Store for misc info such as the current version.
*/

import { defineStore } from 'pinia'
import { ref } from 'vue'

import { MiscClient } from '@/api/misc'

export enum StoreState {
Initial = 'initial',
Loading = 'loading',
Active = 'active',
Error = 'error'
}

export const useMiscStore = defineStore('misc', () => {
// The current store state
const storeState = ref<StoreState>(StoreState.Initial)

// The app version.
const appVersion = ref<string | null>(null)

// Initialize store, load version.
const initialize = async () => {
storeState.value = StoreState.Loading
try {
const client = new MiscClient()
appVersion.value = await client.fetchVersion()

storeState.value = StoreState.Active
} catch (e) {
console.error('There was an error loading the app version.', e)
storeState.value = StoreState.Error
}
}

return {
storeState,
appVersion,
initialize
}
})
3 changes: 2 additions & 1 deletion frontend/src/views/GeneDetailView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import { watch, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { StoreState, useGeneInfoStore } from '@/stores/geneInfo'
import { StoreState } from '@/stores/misc'
import { useGeneInfoStore } from '@/stores/geneInfo'
import HeaderDetailPage from '@/components/HeaderDetailPage.vue'
import { roundIt } from '@/api/utils'
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/views/__tests__/AboutView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import { routes } from '@/router'
import { createTestingPinia } from '@pinia/testing'

import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
Expand All @@ -28,7 +29,18 @@ const makeWrapper = () => {
},
{
global: {
plugins: [vuetify, router],
plugins: [
vuetify,
router,
createTestingPinia({
createSpy: vi.fn(),
initialState: {
misc: {
appVersion: 'v0.0.0'
}
}
})
],
components: {
AboutView
}
Expand Down
14 changes: 13 additions & 1 deletion frontend/src/views/__tests__/ContactView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import { routes } from '@/router'
import { createTestingPinia } from '@pinia/testing'

import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
Expand All @@ -28,7 +29,18 @@ const makeWrapper = () => {
},
{
global: {
plugins: [vuetify, router],
plugins: [
vuetify,
router,
createTestingPinia({
createSpy: vi.fn(),
initialState: {
misc: {
appVersion: 'v0.0.0'
}
}
})
],
components: {
ContactView
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/__tests__/GeneDetailView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'

import GeneDetailView from '../GeneDetailView.vue'
import { StoreState } from '@/stores/geneInfo'
import { StoreState } from '@/stores/misc'
import * as BRCA1geneInfo from '@/assets/__tests__/BRCA1GeneInfo.json'

const vuetify = createVuetify({
Expand Down
Loading

0 comments on commit 586af7e

Please sign in to comment.