Add app version display in Footer and implement version API endpoint
Some checks failed
Code Analysis and Production Deploy / analyze (push) Successful in 2m49s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 1m54s
Code Analysis and Production Deploy / analyze (pull_request) Failing after 11s
Code Analysis and Production Deploy / deploy-production (pull_request) Has been skipped
Code Analysis and Production Deploy / deploy-test (pull_request) Has been skipped
Some checks failed
Code Analysis and Production Deploy / analyze (push) Successful in 2m49s
Code Analysis and Production Deploy / deploy-production (push) Has been skipped
Code Analysis and Production Deploy / deploy-test (push) Successful in 1m54s
Code Analysis and Production Deploy / analyze (pull_request) Failing after 11s
Code Analysis and Production Deploy / deploy-production (pull_request) Has been skipped
Code Analysis and Production Deploy / deploy-test (pull_request) Has been skipped
- Updated Footer.vue to show the application version for logged-in users. - Added a new API endpoint to return the application version from package.json. - Enhanced code-analysis.yml to require package version changes for main PRs.
This commit is contained in:
@@ -31,6 +31,10 @@ jobs:
|
||||
node -v
|
||||
npm -v
|
||||
|
||||
- name: Require package version change for main PRs
|
||||
if: github.event_name == 'pull_request' && github.base_ref == 'main'
|
||||
run: scripts/check-package-version-changed.sh origin/main
|
||||
|
||||
- name: gitleaks (Secrets Scanning)
|
||||
run: |
|
||||
# Try to get the latest release asset URL
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
© {{ currentYear }} Harheimer TC 1954 e.V.
|
||||
</p>
|
||||
<div class="flex items-center space-x-6 text-sm relative">
|
||||
<span
|
||||
v-if="isLoggedIn && appVersion"
|
||||
class="text-xs text-gray-600"
|
||||
title="Version"
|
||||
>
|
||||
v{{ appVersion }}
|
||||
</span>
|
||||
<NuxtLink
|
||||
to="/impressum"
|
||||
class="text-gray-400 hover:text-primary-400 transition-colors"
|
||||
@@ -89,7 +96,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { User, ChevronUp } from 'lucide-vue-next'
|
||||
|
||||
@@ -97,11 +104,26 @@ const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const currentYear = new Date().getFullYear()
|
||||
const isMemberMenuOpen = ref(false)
|
||||
const appVersion = ref('')
|
||||
|
||||
// Reactive auth state from store
|
||||
const isLoggedIn = computed(() => authStore.isLoggedIn)
|
||||
// const isAdmin = computed(() => authStore.isAdmin)
|
||||
|
||||
const loadAppVersion = async () => {
|
||||
if (!isLoggedIn.value) {
|
||||
appVersion.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await $fetch('/api/app/version')
|
||||
appVersion.value = response.version || ''
|
||||
} catch (_error) {
|
||||
appVersion.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const toggleMemberMenu = () => {
|
||||
isMemberMenuOpen.value = !isMemberMenuOpen.value
|
||||
}
|
||||
@@ -116,6 +138,10 @@ onMounted(() => {
|
||||
authStore.checkAuth()
|
||||
})
|
||||
|
||||
watch(isLoggedIn, () => {
|
||||
loadAppVersion()
|
||||
}, { immediate: true })
|
||||
|
||||
// Close menu when clicking outside
|
||||
const handleClickOutside = (event) => {
|
||||
if (!event.target.closest('.relative')) {
|
||||
|
||||
25
scripts/check-package-version-changed.sh
Executable file
25
scripts/check-package-version-changed.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BASE_REF="${1:-origin/main}"
|
||||
BASE_BRANCH="${BASE_REF#origin/}"
|
||||
|
||||
git fetch --no-tags --depth=1 origin "$BASE_BRANCH"
|
||||
|
||||
current_version="$(node -e 'const fs = require("fs"); const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); process.stdout.write(String(pkg.version || ""));')"
|
||||
base_version="$(git show "$BASE_REF:package.json" | node -e 'let input = ""; process.stdin.setEncoding("utf8"); process.stdin.on("data", chunk => input += chunk); process.stdin.on("end", () => { const pkg = JSON.parse(input); process.stdout.write(String(pkg.version || "")); });')"
|
||||
|
||||
if [ -z "$current_version" ]; then
|
||||
echo "ERROR: package.json enthält kein version-Feld."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$current_version" = "$base_version" ]; then
|
||||
echo "ERROR: package.json version wurde nicht geändert."
|
||||
echo "Base ($BASE_REF): $base_version"
|
||||
echo "Current: $current_version"
|
||||
echo "Bitte version in package.json erhöhen, bevor nach main gemerged wird."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "package.json version changed: $base_version -> $current_version"
|
||||
25
server/api/app/version.get.js
Normal file
25
server/api/app/version.get.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { getUserFromToken } from '../../utils/auth.js'
|
||||
|
||||
async function readPackageVersion() {
|
||||
const packageJsonPath = path.join(process.cwd(), 'package.json')
|
||||
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))
|
||||
return String(packageJson.version || '')
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const token = getCookie(event, 'auth_token')
|
||||
const user = token ? await getUserFromToken(token) : null
|
||||
|
||||
if (!user) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Nicht authentifiziert'
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
version: await readPackageVersion()
|
||||
}
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createEvent, mockSuccessReadBody } from './setup'
|
||||
import { readFileSync } from 'fs'
|
||||
|
||||
vi.mock('../server/utils/auth.js', () => {
|
||||
return {
|
||||
@@ -60,6 +61,7 @@ import logoutHandler from '../server/api/auth/logout.post.js'
|
||||
import registerHandler from '../server/api/auth/register.post.js'
|
||||
import resetPasswordHandler from '../server/api/auth/reset-password.post.js'
|
||||
import statusHandler from '../server/api/auth/status.get.js'
|
||||
import versionHandler from '../server/api/app/version.get.js'
|
||||
|
||||
describe('Auth API Endpoints', () => {
|
||||
afterEach(() => {
|
||||
@@ -241,4 +243,22 @@ describe('Auth API Endpoints', () => {
|
||||
expect(response.user).toMatchObject({ id: '1' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/app/version', () => {
|
||||
it('verlangt Login', async () => {
|
||||
const event = createEvent()
|
||||
|
||||
await expect(versionHandler(event)).rejects.toMatchObject({ statusCode: 401 })
|
||||
})
|
||||
|
||||
it('liefert eingeloggten Benutzern die package.json-Version', async () => {
|
||||
const event = createEvent({ cookies: { auth_token: 'token' } })
|
||||
authUtils.getUserFromToken.mockResolvedValue({ id: '1', email: 'user@example.com', roles: ['mitglied'] })
|
||||
const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
|
||||
|
||||
const response = await versionHandler(event)
|
||||
|
||||
expect(response.version).toBe(packageJson.version)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user