mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-10-22 02:12:19 +00:00
Add api for forges (#3733)
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
<i-simple-icons-gitea v-else-if="name === 'gitea'" class="h-8 w-8" />
|
||||
<i-simple-icons-forgejo v-else-if="name === 'forgejo'" class="h-8 w-8" />
|
||||
<i-ph-gitlab-logo-simple-fill v-else-if="name === 'gitlab'" class="h-8 w-8" />
|
||||
<i-mdi-bitbucket v-else-if="name === 'bitbucket' || name === 'bitbucket_dc'" class="h-8 w-8" />
|
||||
<i-mdi-bitbucket v-else-if="name === 'bitbucket' || name === 'bitbucket-dc'" class="h-8 w-8" />
|
||||
<i-vaadin-question-circle-o v-else-if="name === 'question'" class="h-6 w-6" />
|
||||
<i-ic-twotone-add v-else-if="name === 'plus'" class="h-6 w-6" />
|
||||
<i-mdi-format-list-bulleted v-else-if="name === 'list'" class="h-6 w-6" />
|
||||
@@ -86,7 +86,7 @@ export type IconNames =
|
||||
| 'gitea'
|
||||
| 'gitlab'
|
||||
| 'bitbucket'
|
||||
| 'bitbucket_dc'
|
||||
| 'bitbucket-dc'
|
||||
| 'forgejo'
|
||||
| 'question'
|
||||
| 'list'
|
||||
|
@@ -6,7 +6,6 @@ declare global {
|
||||
WOODPECKER_VERSION: string | undefined;
|
||||
WOODPECKER_SKIP_VERSION_CHECK: boolean | undefined;
|
||||
WOODPECKER_CSRF: string | undefined;
|
||||
WOODPECKER_FORGE: 'github' | 'gitlab' | 'gitea' | 'forgejo' | 'bitbucket' | 'bitbucket_dc' | undefined;
|
||||
WOODPECKER_ROOT_PATH: string | undefined;
|
||||
WOODPECKER_ENABLE_SWAGGER: boolean | undefined;
|
||||
}
|
||||
@@ -17,7 +16,6 @@ export default () => ({
|
||||
version: window.WOODPECKER_VERSION,
|
||||
skipVersionCheck: window.WOODPECKER_SKIP_VERSION_CHECK === true || false,
|
||||
csrf: window.WOODPECKER_CSRF ?? null,
|
||||
forge: window.WOODPECKER_FORGE ?? null,
|
||||
rootPath: window.WOODPECKER_ROOT_PATH ?? '',
|
||||
enableSwagger: window.WOODPECKER_ENABLE_SWAGGER === true || false,
|
||||
});
|
||||
|
30
web/src/compositions/useForgeStore.ts
Normal file
30
web/src/compositions/useForgeStore.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { computed, reactive, type Ref } from 'vue';
|
||||
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import type { Forge } from '~/lib/api/types';
|
||||
|
||||
export const useForgeStore = defineStore('forges', () => {
|
||||
const apiClient = useApiClient();
|
||||
|
||||
const forges = reactive<Map<number, Forge>>(new Map());
|
||||
|
||||
async function loadForge(forgeId: number): Promise<Forge> {
|
||||
const forge = await apiClient.getForge(forgeId);
|
||||
forges.set(forge.id, forge);
|
||||
return forge;
|
||||
}
|
||||
|
||||
async function getForge(forgeId: number): Promise<Ref<Forge | undefined>> {
|
||||
if (!forges.has(forgeId)) {
|
||||
await loadForge(forgeId);
|
||||
}
|
||||
|
||||
return computed(() => forges.get(forgeId));
|
||||
}
|
||||
|
||||
return {
|
||||
getForge,
|
||||
loadForge,
|
||||
};
|
||||
});
|
@@ -2,6 +2,7 @@ import ApiClient, { encodeQueryString } from './client';
|
||||
import type {
|
||||
Agent,
|
||||
Cron,
|
||||
Forge,
|
||||
Org,
|
||||
OrgPermissions,
|
||||
Pipeline,
|
||||
@@ -284,6 +285,27 @@ export default class WoodpeckerClient extends ApiClient {
|
||||
return this._delete(`/api/agents/${agent.id}`);
|
||||
}
|
||||
|
||||
getForges(opts?: PaginationOptions): Promise<Forge[] | null> {
|
||||
const query = encodeQueryString(opts);
|
||||
return this._get(`/api/forges?${query}`) as Promise<Forge[] | null>;
|
||||
}
|
||||
|
||||
getForge(forgeId: Forge['id']): Promise<Forge> {
|
||||
return this._get(`/api/forges/${forgeId}`) as Promise<Forge>;
|
||||
}
|
||||
|
||||
createForge(forge: Partial<Forge>): Promise<Forge> {
|
||||
return this._post('/api/forges', forge) as Promise<Forge>;
|
||||
}
|
||||
|
||||
updateForge(forge: Partial<Forge>): Promise<unknown> {
|
||||
return this._patch(`/api/forges/${forge.id}`, forge);
|
||||
}
|
||||
|
||||
deleteForge(forge: Forge): Promise<unknown> {
|
||||
return this._delete(`/api/forges/${forge.id}`);
|
||||
}
|
||||
|
||||
getQueueInfo(): Promise<QueueInfo> {
|
||||
return this._get('/api/queue/info') as Promise<QueueInfo>;
|
||||
}
|
||||
|
12
web/src/lib/api/types/forge.ts
Normal file
12
web/src/lib/api/types/forge.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export type ForgeType = 'github' | 'gitlab' | 'gitea' | 'bitbucket' | 'bitbucket-dc' | 'addon';
|
||||
|
||||
export interface Forge {
|
||||
id: number;
|
||||
type: ForgeType;
|
||||
url: string;
|
||||
client?: string;
|
||||
client_secret?: string;
|
||||
skip_verify?: boolean;
|
||||
oauth_host?: string;
|
||||
additional_options?: Record<string, unknown>;
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
export * from './agent';
|
||||
export * from './cron';
|
||||
export * from './forge';
|
||||
export * from './org';
|
||||
export * from './pipeline';
|
||||
export * from './pipelineConfig';
|
||||
|
@@ -9,6 +9,9 @@ export interface Repo {
|
||||
// The id of the repository on the source control management system.
|
||||
forge_remote_id: string;
|
||||
|
||||
// The id of the forge that the repository is on.
|
||||
forge_id: number;
|
||||
|
||||
// The source control management being used.
|
||||
// Currently, this is either 'git' or 'hg' (Mercurial).
|
||||
scm: string;
|
||||
|
@@ -17,7 +17,7 @@
|
||||
<a v-if="badgeUrl" :href="badgeUrl" target="_blank">
|
||||
<img :src="badgeUrl" />
|
||||
</a>
|
||||
<IconButton :href="repo.forge_url" :title="$t('repo.open_in_forge')" :icon="forge ?? 'repo'" class="forge" />
|
||||
<IconButton :href="repo.forge_url" :title="$t('repo.open_in_forge')" :icon="forgeIcon" class="forge" />
|
||||
<IconButton
|
||||
v-if="repoPermissions.admin"
|
||||
:to="{ name: 'repo-settings' }"
|
||||
@@ -49,6 +49,7 @@ import { computed, onMounted, provide, ref, toRef, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import type { IconNames } from '~/components/atomic/Icon.vue';
|
||||
import IconButton from '~/components/atomic/IconButton.vue';
|
||||
import ManualPipelinePopup from '~/components/layout/popups/ManualPipelinePopup.vue';
|
||||
import Scaffold from '~/components/layout/scaffold/Scaffold.vue';
|
||||
@@ -56,8 +57,9 @@ import Tab from '~/components/layout/scaffold/Tab.vue';
|
||||
import useApiClient from '~/compositions/useApiClient';
|
||||
import useAuthentication from '~/compositions/useAuthentication';
|
||||
import useConfig from '~/compositions/useConfig';
|
||||
import { useForgeStore } from '~/compositions/useForgeStore';
|
||||
import useNotifications from '~/compositions/useNotifications';
|
||||
import type { RepoPermissions } from '~/lib/api/types';
|
||||
import type { Forge, RepoPermissions } from '~/lib/api/types';
|
||||
import { usePipelineStore } from '~/store/pipelines';
|
||||
import { useRepoStore } from '~/store/repos';
|
||||
|
||||
@@ -76,14 +78,21 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const i18n = useI18n();
|
||||
const config = useConfig();
|
||||
const forgeStore = useForgeStore();
|
||||
|
||||
const { forge } = useConfig(); // TODO: remove this and use the forge type from the corresponding repo
|
||||
const repo = repoStore.getRepo(repositoryId);
|
||||
const repoPermissions = ref<RepoPermissions>();
|
||||
const pipelines = pipelineStore.getRepoPipelines(repositoryId);
|
||||
provide('repo', repo);
|
||||
provide('repo-permissions', repoPermissions);
|
||||
provide('pipelines', pipelines);
|
||||
const forge = ref<Forge>();
|
||||
const forgeIcon = computed<IconNames>(() => {
|
||||
if (forge.value && forge.value.type !== 'addon') {
|
||||
return forge.value.type;
|
||||
}
|
||||
return 'repo';
|
||||
});
|
||||
|
||||
const showManualPipelinePopup = ref(false);
|
||||
|
||||
@@ -102,6 +111,10 @@ async function loadRepo() {
|
||||
|
||||
await repoStore.loadRepo(repositoryId.value);
|
||||
await pipelineStore.loadRepoPipelines(repositoryId.value);
|
||||
|
||||
if (repo.value) {
|
||||
forge.value = (await forgeStore.getForge(repo.value?.forge_id)).value;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
Reference in New Issue
Block a user