Add version and update notes (#2722)

This commit is contained in:
Anbraten 2023-11-04 14:20:50 +01:00 committed by GitHub
parent 5f8e252fba
commit 33f9574dce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 147 additions and 25 deletions

View file

@ -1,4 +1,5 @@
when:
- event: tag
- event: pull_request
- event: push
path: &when_path
@ -59,7 +60,7 @@ steps:
secrets:
- BOT_PRIVATE_KEY
commands:
- apk add openssh-client git rsync
- apk add openssh-client git rsync jq
- mkdir -p $HOME/.ssh
- ssh-keyscan -t rsa github.com >> $HOME/.ssh/known_hosts
- echo "$BOT_PRIVATE_KEY" > $HOME/.ssh/id_rsa
@ -67,8 +68,11 @@ steps:
- git config --global user.email "woodpecker-bot@obermui.de"
- git config --global user.name "woodpecker-bot"
- git clone --depth 1 --single-branch git@github.com:woodpecker-ci/woodpecker-ci.github.io.git /repo
# update latest and next version
- if [ "$CI_PIPELINE_EVENT" == "tag" ] ; then jq '.latest = ${CI_COMMIT_TAG}' repo/version.json > repo/version.json.tmp && mv repo/version.json.tmp repo/version.json ; fi
- if [ "$CI_PIPELINE_EVENT" == "push" ] ; then jq "next-" '.next = ${CI_COMMIT_SHA:0:10}' repo/version.json > repo/version.json.tmp && mv repo/version.json.tmp repo/version.json ; fi
# copy all docs files and delete all old ones, but leave CNAME and index.yaml untouched
- rsync -r --exclude .git --exclude CNAME --exclude index.yaml --exclude README.md --delete docs/build/ /repo
- rsync -r --exclude .git --exclude CNAME --exclude index.yaml --exclude README.md --exclude version.json --delete docs/build/ /repo
- cd /repo
- git add .
# exit successfully if nothing changed
@ -76,5 +80,6 @@ steps:
- git commit -m "Deploy website - based on ${CI_COMMIT_SHA}"
- git push
when:
event: [push, cron]
path: *when_path
- event: [push, cron]
path: *when_path
- event: tag

2
web/components.d.ts vendored
View file

@ -10,6 +10,7 @@ declare module 'vue' {
ActionsTab: typeof import('./src/components/repo/settings/ActionsTab.vue')['default']
ActivePipelines: typeof import('./src/components/layout/header/ActivePipelines.vue')['default']
AdminAgentsTab: typeof import('./src/components/admin/settings/AdminAgentsTab.vue')['default']
AdminInfoTab: typeof import('./src/components/admin/settings/AdminInfoTab.vue')['default']
AdminOrgsTab: typeof import('./src/components/admin/settings/AdminOrgsTab.vue')['default']
AdminQueueStats: typeof import('./src/components/admin/settings/queue/AdminQueueStats.vue')['default']
AdminQueueTab: typeof import('./src/components/admin/settings/AdminQueueTab.vue')['default']
@ -22,6 +23,7 @@ declare module 'vue' {
Checkbox: typeof import('./src/components/form/Checkbox.vue')['default']
CheckboxesField: typeof import('./src/components/form/CheckboxesField.vue')['default']
Container: typeof import('./src/components/layout/Container.vue')['default']
copy: typeof import('./src/components/admin/settings/AdminAgentsTab copy.vue')['default']
CronTab: typeof import('./src/components/repo/settings/CronTab.vue')['default']
DeployPipelinePopup: typeof import('./src/components/layout/popups/DeployPipelinePopup.vue')['default']
DocsLink: typeof import('./src/components/atomic/DocsLink.vue')['default']

View file

@ -501,5 +501,8 @@
"internal_error": "Some internal error occurred",
"access_denied": "You are not allowed to login"
},
"default": "default"
"default": "default",
"info": "Info",
"running_version": "You are running woodpecker {0}",
"update_woodpecker": "Please update your Woodpecker instance to {0}"
}

View file

@ -0,0 +1,29 @@
<template>
<Settings :title="$t('info')">
<div class="flex flex-col items-center gap-4">
<WoodpeckerLogo class="w-48 h-48" />
<i18n-t keypath="running_version" tag="p" class="text-xl">
<span class="font-bold">{{ version?.current }}</span>
</i18n-t>
<i18n-t v-if="version?.needsUpdate" keypath="update_woodpecker" tag="span" class="text-int-wp-state-error-100">
<a
:href="`https://github.com/woodpecker-ci/woodpecker/releases/tag/${version.latest}`"
target="_blank"
rel="noopener noreferrer"
class="underline"
>{{ version.latest }}</a
>
</i18n-t>
</div>
</Settings>
</template>
<script lang="ts" setup>
import WoodpeckerLogo from '~/assets/logo.svg?component';
import Settings from '~/components/layout/Settings.vue';
import { useVersion } from '~/compositions/useVersion';
const version = useVersion();
</script>

View file

@ -1,47 +1,41 @@
<template>
<!-- Navbar -->
<nav
class="flex bg-wp-primary-200 dark:bg-wp-primary-300 text-neutral-content p-4 border-b border-wp-background-100 font-bold text-wp-primary-text-100"
>
<!-- Left Links Box -->
<div class="flex items-center space-x-2">
<!-- Logo -->
<router-link :to="{ name: 'home' }" class="flex flex-col -my-2 px-2">
<WoodpeckerLogo class="w-8 h-8" />
<span class="text-xs">{{ version }}</span>
<span class="text-xs" :title="version?.current">{{ version?.currentShort }}</span>
</router-link>
<!-- Repo Link -->
<router-link v-if="user" :to="{ name: 'repos' }" class="navbar-link navbar-clickable">
<span class="flex md:hidden">{{ $t('repos') }}</span>
<span class="hidden md:flex">{{ $t('repositories') }}</span>
</router-link>
<!-- Docs Link -->
<a href="https://woodpecker-ci.org/" target="_blank" class="navbar-link navbar-clickable hidden md:flex">{{
$t('docs')
}}</a>
<!-- API Link -->
<a v-if="enableSwagger" :href="apiUrl" target="_blank" class="navbar-link navbar-clickable hidden md:flex">{{
$t('api')
}}</a>
</div>
<!-- Right Icons Box -->
<div class="flex ml-auto -m-1.5 items-center space-x-2">
<!-- Admin Settings -->
<IconButton
v-if="user?.admin"
class="navbar-icon"
:title="$t('admin.settings.settings')"
:to="{ name: 'admin-settings' }"
icon="settings"
/>
<div v-if="user?.admin" class="relative">
<IconButton
class="navbar-icon"
:title="$t('admin.settings.settings')"
:to="{ name: 'admin-settings' }"
icon="settings"
/>
<div
v-if="version?.needsUpdate"
class="absolute top-2 right-2 bg-int-wp-state-error-100 rounded-full w-3 h-3"
/>
</div>
<!-- Active Pipelines Indicator -->
<ActivePipelines v-if="user" class="navbar-icon" />
<!-- User Avatar -->
<IconButton v-if="user" :to="{ name: 'user' }" :title="$t('user.settings.settings')" class="navbar-icon !p-1.5">
<img v-if="user && user.avatar_url" class="rounded-md" :src="`${user.avatar_url}`" />
</IconButton>
<!-- Login Button -->
<Button v-else :text="$t('login')" @click="doLogin" />
</div>
</nav>
@ -55,9 +49,11 @@ import Button from '~/components/atomic/Button.vue';
import IconButton from '~/components/atomic/IconButton.vue';
import useAuthentication from '~/compositions/useAuthentication';
import useConfig from '~/compositions/useConfig';
import { useVersion } from '~/compositions/useVersion';
import ActivePipelines from './ActivePipelines.vue';
const version = useVersion();
const config = useConfig();
const route = useRoute();
const authentication = useAuthentication();
@ -68,7 +64,6 @@ function doLogin() {
authentication.authenticate(route.fullPath);
}
const version = config.version?.startsWith('next') ? 'next' : config.version;
const { enableSwagger } = config;
</script>

View file

@ -0,0 +1,84 @@
import { onMounted, ref } from 'vue';
import useAuthentication from './useAuthentication';
import useConfig from './useConfig';
type VersionInfo = {
latest: string;
next: string;
};
const version = ref<{
latest: string | undefined;
current: string;
currentShort: string;
needsUpdate: boolean;
}>();
async function fetchVersion(): Promise<VersionInfo | undefined> {
try {
const resp = await fetch('https://woodpecker-ci.org/version.json');
const json = await resp.json();
return json;
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to fetch version info', error);
return undefined;
}
}
const isInitialised = ref(false);
export function useVersion() {
if (isInitialised.value) {
return version;
}
isInitialised.value = true;
const config = useConfig();
const current = config.version as string;
const usesNext = config.version?.startsWith('next');
const { user } = useAuthentication();
if (!user?.admin) {
version.value = {
latest: undefined,
current,
currentShort: usesNext ? 'next' : current,
needsUpdate: false,
};
return version;
}
if (current === 'dev') {
version.value = {
latest: undefined,
current,
currentShort: current,
needsUpdate: false,
};
return version;
}
onMounted(async () => {
const versionInfo = await fetchVersion();
let needsUpdate = false;
if (versionInfo) {
if (usesNext) {
needsUpdate = versionInfo.next !== current;
} else {
needsUpdate = versionInfo.latest !== current;
}
}
version.value = {
latest: usesNext ? versionInfo?.next : versionInfo?.latest,
current,
currentShort: usesNext ? 'next' : current,
needsUpdate,
};
});
return version;
}

View file

@ -3,6 +3,9 @@
<template #title>
{{ $t('repo.settings.settings') }}
</template>
<Tab id="info" :title="$t('info')">
<AdminInfoTab />
</Tab>
<Tab id="secrets" :title="$t('admin.settings.secrets.secrets')">
<AdminSecretsTab />
</Tab>
@ -30,6 +33,7 @@ import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import AdminAgentsTab from '~/components/admin/settings/AdminAgentsTab.vue';
import AdminInfoTab from '~/components/admin/settings/AdminInfoTab.vue';
import AdminOrgsTab from '~/components/admin/settings/AdminOrgsTab.vue';
import AdminQueueTab from '~/components/admin/settings/AdminQueueTab.vue';
import AdminReposTab from '~/components/admin/settings/AdminReposTab.vue';