You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	| @@ -180,6 +180,30 @@ func GetProcLogs(c *gin.Context) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func GetBuildConfig(c *gin.Context) { | ||||
| 	_store := store.FromContext(c) | ||||
| 	repo := session.Repo(c) | ||||
| 	num, err := strconv.ParseInt(c.Param("number"), 10, 64) | ||||
| 	if err != nil { | ||||
| 		_ = c.AbortWithError(http.StatusBadRequest, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	build, err := _store.GetBuildNumber(repo, num) | ||||
| 	if err != nil { | ||||
| 		_ = c.AbortWithError(http.StatusInternalServerError, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	configs, err := _store.ConfigsForBuild(build.ID) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusInternalServerError, err.Error()) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	c.JSON(http.StatusOK, configs) | ||||
| } | ||||
|  | ||||
| // DeleteBuild cancels a build | ||||
| func DeleteBuild(c *gin.Context) { | ||||
| 	_store := store.FromContext(c) | ||||
|   | ||||
| @@ -61,6 +61,7 @@ func apiRoutes(e *gin.Engine) { | ||||
|  | ||||
| 			repo.GET("/builds", api.GetBuilds) | ||||
| 			repo.GET("/builds/:number", api.GetBuild) | ||||
| 			repo.GET("/builds/:number/config", api.GetBuildConfig) | ||||
|  | ||||
| 			// requires push permissions | ||||
| 			repo.POST("/builds/:number", session.MustPush, api.PostBuild) | ||||
|   | ||||
| @@ -1,5 +1,16 @@ | ||||
| import ApiClient, { encodeQueryString } from './client'; | ||||
| import { Build, BuildFeed, BuildLog, BuildProc, Registry, Repo, RepoPermissions, RepoSettings, Secret } from './types'; | ||||
| import { | ||||
|   Build, | ||||
|   BuildConfig, | ||||
|   BuildFeed, | ||||
|   BuildLog, | ||||
|   BuildProc, | ||||
|   Registry, | ||||
|   Repo, | ||||
|   RepoPermissions, | ||||
|   RepoSettings, | ||||
|   Secret, | ||||
| } from './types'; | ||||
|  | ||||
| type RepoListOptions = { | ||||
|   all?: boolean; | ||||
| @@ -49,6 +60,10 @@ export default class WoodpeckerClient extends ApiClient { | ||||
|     return this._get(`/api/repos/${owner}/${repo}/builds/${number}`) as Promise<Build>; | ||||
|   } | ||||
|  | ||||
|   getBuildConfig(owner: string, repo: string, number: number): Promise<BuildConfig[]> { | ||||
|     return this._get(`/api/repos/${owner}/${repo}/builds/${number}/config`) as Promise<BuildConfig[]>; | ||||
|   } | ||||
|  | ||||
|   getBuildFeed(opts?: Record<string, string | number | boolean>): Promise<BuildFeed[]> { | ||||
|     const query = encodeQueryString(opts); | ||||
|     return this._get(`/api/user/feed?${query}`) as Promise<BuildFeed[]>; | ||||
|   | ||||
							
								
								
									
										6
									
								
								web/src/lib/api/types/buildConfig.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								web/src/lib/api/types/buildConfig.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| // A config for a build. | ||||
| export type BuildConfig = { | ||||
|   hash: string; | ||||
|   name: string; | ||||
|   data: string; | ||||
| }; | ||||
| @@ -1,4 +1,5 @@ | ||||
| export * from './build'; | ||||
| export * from './buildConfig'; | ||||
| export * from './registry'; | ||||
| export * from './repo'; | ||||
| export * from './secret'; | ||||
|   | ||||
| @@ -58,6 +58,12 @@ const routes: RouteRecordRaw[] = [ | ||||
|             component: (): Component => import('~/views/repo/build/Build.vue'), | ||||
|             props: true, | ||||
|           }, | ||||
|           { | ||||
|             path: 'config', | ||||
|             name: 'repo-build-config', | ||||
|             component: (): Component => import('~/views/repo/build/BuildConfig.vue'), | ||||
|             props: true, | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|   | ||||
							
								
								
									
										58
									
								
								web/src/views/repo/build/BuildConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								web/src/views/repo/build/BuildConfig.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| <template> | ||||
|   <FluidContainer v-if="buildConfigs" class="flex flex-col gap-y-6 text-gray-500 justify-between !py-0"> | ||||
|     <Panel v-for="buildConfig in buildConfigs" :key="buildConfig.hash" :title="buildConfig.name"> | ||||
|       <span class="font-mono whitespace-pre">{{ buildConfig.data }}</span> | ||||
|     </Panel> | ||||
|   </FluidContainer> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import { defineComponent, inject, onMounted, Ref, ref, watch } from 'vue'; | ||||
|  | ||||
| import FluidContainer from '~/components/layout/FluidContainer.vue'; | ||||
| import Panel from '~/components/layout/Panel.vue'; | ||||
| import useApiClient from '~/compositions/useApiClient'; | ||||
| import { Build, BuildConfig, Repo } from '~/lib/api/types'; | ||||
|  | ||||
| export default defineComponent({ | ||||
|   name: 'BuildConfig', | ||||
|  | ||||
|   components: { | ||||
|     FluidContainer, | ||||
|     Panel, | ||||
|   }, | ||||
|  | ||||
|   setup() { | ||||
|     const build = inject<Ref<Build>>('build'); | ||||
|     const apiClient = useApiClient(); | ||||
|     const repo = inject<Ref<Repo>>('repo'); | ||||
|     if (!repo || !build) { | ||||
|       throw new Error('Unexpected: "repo" & "build" should be provided at this place'); | ||||
|     } | ||||
|  | ||||
|     const buildConfigs = ref<BuildConfig[]>(); | ||||
|     async function loadBuildConfig() { | ||||
|       if (!repo || !build) { | ||||
|         throw new Error('Unexpected: "repo" & "build" should be provided at this place'); | ||||
|       } | ||||
|  | ||||
|       buildConfigs.value = (await apiClient.getBuildConfig(repo.value.owner, repo.value.name, build.value.number)).map( | ||||
|         (i) => ({ | ||||
|           ...i, | ||||
|           data: atob(i.data), | ||||
|         }), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     onMounted(() => { | ||||
|       loadBuildConfig(); | ||||
|     }); | ||||
|  | ||||
|     watch(build, () => { | ||||
|       loadBuildConfig(); | ||||
|     }); | ||||
|  | ||||
|     return { buildConfigs }; | ||||
|   }, | ||||
| }); | ||||
| </script> | ||||
| @@ -31,6 +31,7 @@ | ||||
|       <div class="flex flex-wrap gap-y-2 items-center justify-between"> | ||||
|         <Tabs v-model="activeTab" disable-hash-mode> | ||||
|           <Tab id="tasks" title="Tasks" /> | ||||
|           <Tab id="config" title="Config" /> | ||||
|         </Tabs> | ||||
|  | ||||
|         <div class="flex justify-between gap-x-4 text-gray-500 flex-shrink-0 ml-auto"> | ||||
| @@ -63,7 +64,7 @@ import { | ||||
|   toRef, | ||||
|   watch, | ||||
| } from 'vue'; | ||||
| import { useRouter } from 'vue-router'; | ||||
| import { useRoute, useRouter } from 'vue-router'; | ||||
|  | ||||
| import Button from '~/components/atomic/Button.vue'; | ||||
| import IconButton from '~/components/atomic/IconButton.vue'; | ||||
| @@ -122,6 +123,7 @@ export default defineComponent({ | ||||
|  | ||||
|   setup(props) { | ||||
|     const apiClient = useApiClient(); | ||||
|     const route = useRoute(); | ||||
|     const router = useRouter(); | ||||
|     const notifications = useNotifications(); | ||||
|     const favicon = useFavicon(); | ||||
| @@ -191,12 +193,20 @@ export default defineComponent({ | ||||
|  | ||||
|     const activeTab = computed({ | ||||
|       get() { | ||||
|         if (route.name === 'repo-build-config') { | ||||
|           return 'config'; | ||||
|         } | ||||
|  | ||||
|         return 'tasks'; | ||||
|       }, | ||||
|       set(tab: string) { | ||||
|         if (tab === 'tasks') { | ||||
|           router.replace({ name: 'repo-build' }); | ||||
|         } | ||||
|  | ||||
|         if (tab === 'config') { | ||||
|           router.replace({ name: 'repo-build-config' }); | ||||
|         } | ||||
|       }, | ||||
|     }); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user