mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-10-21 20:25:57 +00:00
Cli setup command (#3384)
Co-authored-by: Robert Kaussow <xoxys@rknet.org>
This commit is contained in:
1
web/components.d.ts
vendored
1
web/components.d.ts
vendored
@@ -110,6 +110,7 @@ declare module 'vue' {
|
||||
Tabs: typeof import('./src/components/layout/scaffold/Tabs.vue')['default']
|
||||
TextField: typeof import('./src/components/form/TextField.vue')['default']
|
||||
UserAPITab: typeof import('./src/components/user/UserAPITab.vue')['default']
|
||||
UserCLIAndAPITab: typeof import('./src/components/user/UserCLIAndAPITab.vue')['default']
|
||||
UserGeneralTab: typeof import('./src/components/user/UserGeneralTab.vue')['default']
|
||||
UserSecretsTab: typeof import('./src/components/user/UserSecretsTab.vue')['default']
|
||||
Warning: typeof import('./src/components/atomic/Warning.vue')['default']
|
||||
|
@@ -486,15 +486,13 @@
|
||||
"pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
|
||||
}
|
||||
},
|
||||
"api": {
|
||||
"api": "API",
|
||||
"desc": "Personal Access Token and API usage",
|
||||
"cli_and_api": {
|
||||
"cli_and_api": "CLI & API",
|
||||
"desc": "Personal Access Token, CLI and API usage",
|
||||
"token": "Personal Access Token",
|
||||
"shell_setup": "Shell setup",
|
||||
"api_usage": "Example API Usage",
|
||||
"cli_usage": "Example CLI Usage",
|
||||
"dl_cli": "Download CLI",
|
||||
"shell_setup_before": "do shell setup steps before",
|
||||
"download_cli": "Download CLI",
|
||||
"reset_token": "Reset token",
|
||||
"swagger_ui": "Swagger UI"
|
||||
}
|
||||
@@ -508,5 +506,12 @@
|
||||
"running_version": "You are running Woodpecker {0}",
|
||||
"update_woodpecker": "Please update your Woodpecker instance to {0}",
|
||||
"global_level_secret": "global secret",
|
||||
"org_level_secret": "organization secret"
|
||||
"org_level_secret": "organization secret",
|
||||
"login_to_cli": "Login to CLI",
|
||||
"login_to_cli_description": "By continuing you will be logged in to the CLI.",
|
||||
"abort": "Abort",
|
||||
"cli_login_success": "Login to CLI successful",
|
||||
"cli_login_failed": "Login to CLI failed",
|
||||
"cli_login_denied": "Login to CLI denied",
|
||||
"return_to_cli": "You can now close this tab and return to the CLI."
|
||||
}
|
||||
|
@@ -1,43 +1,38 @@
|
||||
<template>
|
||||
<Settings :title="$t('user.settings.api.api')" :desc="$t('user.settings.api.desc')">
|
||||
<InputField :label="$t('user.settings.api.token')">
|
||||
<Settings :title="$t('user.settings.cli_and_api.cli_and_api')" :desc="$t('user.settings.cli_and_api.desc')">
|
||||
<InputField :label="$t('user.settings.cli_and_api.cli_usage')">
|
||||
<template #titleActions>
|
||||
<Button class="ml-auto" :text="$t('user.settings.api.reset_token')" @click="resetToken" />
|
||||
<a :href="cliDownload" target="_blank" class="ml-4 text-wp-link-100 hover:text-wp-link-200">{{
|
||||
$t('user.settings.cli_and_api.download_cli')
|
||||
}}</a>
|
||||
</template>
|
||||
<pre class="code-box">{{ usageWithCli }}</pre>
|
||||
</InputField>
|
||||
|
||||
<InputField :label="$t('user.settings.cli_and_api.token')">
|
||||
<template #titleActions>
|
||||
<Button class="ml-auto" :text="$t('user.settings.cli_and_api.reset_token')" @click="resetToken" />
|
||||
</template>
|
||||
<pre class="code-box">{{ token }}</pre>
|
||||
</InputField>
|
||||
|
||||
<InputField :label="$t('user.settings.api.shell_setup')">
|
||||
<pre class="code-box">{{ usageWithShell }}</pre>
|
||||
</InputField>
|
||||
|
||||
<InputField :label="$t('user.settings.api.api_usage')">
|
||||
<InputField :label="$t('user.settings.cli_and_api.api_usage')">
|
||||
<template #titleActions>
|
||||
<a
|
||||
v-if="enableSwagger"
|
||||
:href="`${address}/swagger/index.html`"
|
||||
target="_blank"
|
||||
class="ml-4 text-wp-link-100 hover:text-wp-link-200"
|
||||
>{{ $t('user.settings.api.swagger_ui') }}</a
|
||||
>{{ $t('user.settings.cli_and_api.swagger_ui') }}</a
|
||||
>
|
||||
</template>
|
||||
<pre class="code-box">{{ usageWithCurl }}</pre>
|
||||
</InputField>
|
||||
|
||||
<InputField :label="$t('user.settings.api.cli_usage')">
|
||||
<template #titleActions>
|
||||
<a :href="cliDownload" target="_blank" class="ml-4 text-wp-link-100 hover:text-wp-link-200">{{
|
||||
$t('user.settings.api.dl_cli')
|
||||
}}</a>
|
||||
</template>
|
||||
<pre class="code-box">{{ usageWithCli }}</pre>
|
||||
</InputField>
|
||||
</Settings>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import InputField from '~/components/form/InputField.vue';
|
||||
@@ -45,7 +40,6 @@ import Settings from '~/components/layout/Settings.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import useConfig from '~/compositions/useConfig';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { rootPath, enableSwagger } = useConfig();
|
||||
|
||||
const apiClient = useApiClient();
|
||||
@@ -57,17 +51,15 @@ onMounted(async () => {
|
||||
|
||||
const address = `${window.location.protocol}//${window.location.host}${rootPath}`; // port is included in location.host
|
||||
|
||||
const usageWithShell = computed(() => {
|
||||
const usageWithCurl = computed(() => {
|
||||
let usage = `export WOODPECKER_SERVER="${address}"\n`;
|
||||
usage += `export WOODPECKER_TOKEN="${token.value}"\n`;
|
||||
usage += `\n`;
|
||||
usage += `# curl -i \${WOODPECKER_SERVER}/api/user -H "Authorization: Bearer \${WOODPECKER_TOKEN}"`;
|
||||
return usage;
|
||||
});
|
||||
|
||||
const usageWithCurl = `# ${t(
|
||||
'user.settings.api.shell_setup_before',
|
||||
)}\ncurl -i \${WOODPECKER_SERVER}/api/user -H "Authorization: Bearer \${WOODPECKER_TOKEN}"`;
|
||||
|
||||
const usageWithCli = `# ${t('user.settings.api.shell_setup_before')}\nwoodpecker info`;
|
||||
const usageWithCli = `# woodpecker setup --server-url ${address}`;
|
||||
|
||||
const cliDownload = 'https://github.com/woodpecker-ci/woodpecker/releases';
|
||||
|
@@ -166,6 +166,11 @@ const routes: RouteRecordRaw[] = [
|
||||
meta: { blank: true },
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: `${rootPath}/cli/auth`,
|
||||
component: () => import('~/views/cli/Auth.vue'),
|
||||
meta: { authentication: 'required' },
|
||||
},
|
||||
|
||||
// TODO: deprecated routes => remove after some time
|
||||
{
|
||||
|
@@ -8,8 +8,8 @@
|
||||
<Tab id="secrets" :title="$t('user.settings.secrets.secrets')">
|
||||
<UserSecretsTab />
|
||||
</Tab>
|
||||
<Tab id="api" :title="$t('user.settings.api.api')">
|
||||
<UserAPITab />
|
||||
<Tab id="cli-and-api" :title="$t('user.settings.cli_and_api.cli_and_api')">
|
||||
<UserCLIAndAPITab />
|
||||
</Tab>
|
||||
</Scaffold>
|
||||
</template>
|
||||
@@ -17,7 +17,7 @@
|
||||
<script lang="ts" setup>
|
||||
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
||||
import Tab from '~/components/layout/scaffold/Tab.vue';
|
||||
import UserAPITab from '~/components/user/UserAPITab.vue';
|
||||
import UserCLIAndAPITab from '~/components/user/UserCLIAndAPITab.vue';
|
||||
import UserGeneralTab from '~/components/user/UserGeneralTab.vue';
|
||||
import UserSecretsTab from '~/components/user/UserSecretsTab.vue';
|
||||
import useConfig from '~/compositions/useConfig';
|
||||
|
80
web/src/views/cli/Auth.vue
Normal file
80
web/src/views/cli/Auth.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4 m-auto">
|
||||
<div class="text-center text-wp-text-100">
|
||||
<img src="../../assets/logo.svg" alt="CLI" class="w-32 m-auto mb-8" />
|
||||
<template v-if="state === 'confirm'">
|
||||
<h1 class="text-4xl font-bold">{{ $t('login_to_cli') }}</h1>
|
||||
<p class="text-2xl">{{ $t('login_to_cli_description') }}</p>
|
||||
</template>
|
||||
<template v-else-if="state === 'success'">
|
||||
<h1 class="text-4xl font-bold">{{ $t('cli_login_success') }}</h1>
|
||||
<p class="text-2xl">{{ $t('return_to_cli') }}</p>
|
||||
</template>
|
||||
<template v-else-if="state === 'failed'">
|
||||
<h1 class="text-4xl font-bold mt-4">{{ $t('cli_login_failed') }}</h1>
|
||||
<p class="text-2xl">{{ $t('return_to_cli') }}</p>
|
||||
</template>
|
||||
<template v-else-if="state === 'denied'">
|
||||
<h1 class="text-4xl font-bold mt-4">{{ $t('cli_login_denied') }}</h1>
|
||||
<p class="text-2xl">{{ $t('return_to_cli') }}</p>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="state === 'confirm'" class="flex gap-4 justify-center">
|
||||
<Button :text="$t('login_to_cli')" color="green" @click="sendToken(false)" />
|
||||
<Button :text="$t('abort')" color="red" @click="abortLogin" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import Button from '~/components/atomic/Button.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
|
||||
const apiClient = useApiClient();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const state = ref<'confirm' | 'success' | 'failed' | 'denied'>('confirm');
|
||||
|
||||
async function sendToken(abort = false) {
|
||||
const port = route.query.port as string;
|
||||
if (!port) {
|
||||
throw new Error('Unexpected: port not found');
|
||||
}
|
||||
|
||||
const address = `http://localhost:${port}`;
|
||||
|
||||
const token = abort ? '' : await apiClient.getToken();
|
||||
|
||||
const resp = await fetch(`${address}/token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ token }),
|
||||
});
|
||||
|
||||
if (abort) {
|
||||
state.value = 'denied';
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
const data = (await resp.json()) as { ok: string };
|
||||
if (data.ok === 'true') {
|
||||
state.value = 'success';
|
||||
} else {
|
||||
state.value = 'failed';
|
||||
// eslint-disable-next-line no-alert
|
||||
alert(t('cli_login_failed'));
|
||||
}
|
||||
}
|
||||
|
||||
async function abortLogin() {
|
||||
await sendToken(true);
|
||||
}
|
||||
</script>
|
Reference in New Issue
Block a user