Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step logs removing API and Button #3451

Merged
merged 24 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fc0828f
Added API
zc-devs Feb 27, 2024
e1ea447
Added button
zc-devs Feb 27, 2024
cfe8947
Merge branch 'main' into 3444-step-logs-remove
zc-devs Feb 27, 2024
779412c
Changed permissions
zc-devs Mar 1, 2024
1ff5300
Merge branch 'main' into 3444-step-logs-remove
zc-devs Mar 1, 2024
bd2e141
Merge remote-tracking branch 'upstream/main' into 3444-step-logs-remove
zc-devs Mar 7, 2024
963f23b
Fixed PR note
zc-devs Mar 7, 2024
bb8d136
Merge branch 'main' into 3444-step-logs-remove
6543 Mar 7, 2024
483ad02
Merge remote-tracking branch 'upstream/main' into 3444-step-logs-remove
zc-devs Mar 8, 2024
4af02dc
linter
zc-devs Mar 8, 2024
09e1917
Merge branch 'main' into 3444-step-logs-remove
zc-devs Mar 20, 2024
0cd2140
Merge branch 'main' into 3444-step-logs-remove
qwerty287 Mar 22, 2024
06fdd58
Merge remote-tracking branch 'upstream/main' into 3444-step-logs-remove
zc-devs Mar 23, 2024
32e9c6a
PR notes
zc-devs Mar 23, 2024
ec27a76
Merge branch 'main' into 3444-step-logs-remove
6543 Mar 24, 2024
4c701bf
PR notes
zc-devs Mar 24, 2024
76cd0c6
Merge branch 'main' into 3444-step-logs-remove
zc-devs Mar 24, 2024
d2427cb
Suppressed ES linter
zc-devs Mar 28, 2024
78d9cf0
Merge remote-tracking branch 'upstream/main' into 3444-step-logs-remove
zc-devs Mar 28, 2024
ccc8c34
Update docs.go
qwerty287 Mar 28, 2024
26e39e7
Update docs.go
qwerty287 Mar 28, 2024
d029a1c
Update docs.go
qwerty287 Mar 28, 2024
b9fc970
Merge branch 'main' into 3444-step-logs-remove
qwerty287 Apr 9, 2024
de8e1d6
Merge branch 'main' into 3444-step-logs-remove
6543 Apr 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions server/api/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,66 @@ func GetStepLogs(c *gin.Context) {
c.JSON(http.StatusOK, logs)
}

// DeleteStepLogs
//
// @Summary Deletes step log
// @Router /repos/{repo_id}/logs/{number}/{stepId} [delete]
// @Produce plain
// @Success 204
// @Tags Pipeline logs
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
// @Param repo_id path int true "the repository id"
// @Param number path int true "the number of the pipeline"
// @Param stepId path int true "the step id"
func DeleteStepLogs(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)

pipelineNumber, err := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
if err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}

_pipeline, err := _store.GetPipelineNumber(repo, pipelineNumber)
if err != nil {
handleDBError(c, err)
return
}

stepID, err := strconv.ParseInt(c.Params.ByName("stepID"), 10, 64)
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err)
return
}

_step, err := _store.StepLoad(stepID)
if err != nil {
handleDBError(c, err)
return
}

if _step.PipelineID != _pipeline.ID {
// make sure we cannot read arbitrary logs by id
_ = c.AbortWithError(http.StatusBadRequest, fmt.Errorf("step with id %d is not part of repo %s", stepID, repo.FullName))
return
}

switch _step.State {
case model.StatusRunning, model.StatusPending:
c.String(http.StatusUnprocessableEntity, "Cannot delete logs for a pending or running step")
return
}

err = _store.LogDelete(_step)
if err != nil {
handleDBError(c, err)
return
}

c.Status(http.StatusNoContent)
}

// GetPipelineConfig
//
// @Summary Pipeline configuration
Expand Down
1 change: 1 addition & 0 deletions server/router/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func apiRoutes(e *gin.RouterGroup) {
repo.POST("/pipelines/:number/decline", session.MustPush, api.PostDecline)

repo.GET("/logs/:number/:stepId", api.GetStepLogs)
repo.DELETE("/logs/:number/:stepId", session.MustPush, api.DeleteStepLogs)
6543 marked this conversation as resolved.
Show resolved Hide resolved

// requires push permissions
repo.DELETE("/logs/:number", session.MustPush, api.DeletePipelineLogs)
Expand Down
2 changes: 2 additions & 0 deletions web/src/assets/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
"pipeline": "Pipeline #{pipelineId}",
"log_title": "Step Logs",
"log_download_error": "There was an error while downloading the log file",
"log_delete_error": "There was an error while deleting the step logs",
"actions": {
"cancel": "Cancel",
"restart": "Restart",
Expand All @@ -249,6 +250,7 @@
"deploy": "Deploy",
"restart_success": "Pipeline restarted",
"log_download": "Download",
"log_delete": "Delete",
"log_auto_scroll": "Automatically scroll down",
"log_auto_scroll_off": "Turn off automatic scrolling"
},
Expand Down
23 changes: 22 additions & 1 deletion web/src/components/repo/pipeline/PipelineLog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
icon="download"
@click="download"
/>
<IconButton
v-if="step?.end_time !== undefined && hasLogs && isRepoAdmin"
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
:title="$t('repo.pipeline.actions.log_delete')"
class="!hover:bg-white !hover:bg-opacity-10"
zc-devs marked this conversation as resolved.
Show resolved Hide resolved
icon="trash"
@click="deleteLogs"
/>
<IconButton
v-if="step?.end_time === undefined"
:title="
Expand Down Expand Up @@ -111,7 +118,7 @@ import IconButton from '~/components/atomic/IconButton.vue';
import PipelineStatusIcon from '~/components/repo/pipeline/PipelineStatusIcon.vue';
import useApiClient from '~/compositions/useApiClient';
import useNotifications from '~/compositions/useNotifications';
import { Pipeline, Repo } from '~/lib/api/types';
import { Pipeline, Repo, RepoPermissions } from '~/lib/api/types';
import { findStep, isStepFinished, isStepRunning } from '~/utils/helpers';

type LogLine = {
Expand All @@ -136,6 +143,7 @@ const i18n = useI18n();
const pipeline = toRef(props, 'pipeline');
const stepId = toRef(props, 'stepId');
const repo = inject<Ref<Repo>>('repo');
const repoPermissions = inject<Ref<RepoPermissions>>('repo-permissions');
const apiClient = useApiClient();
const route = useRoute();

Expand All @@ -160,6 +168,7 @@ ansiUp.value.use_classes = true;
const logBuffer = ref<LogLine[]>([]);

const maxLineCount = 5000; // TODO(2653): set back to 500 and implement lazy-loading support
const isRepoAdmin = computed(() => repoPermissions?.value?.admin);

function isSelected(line: LogLine): boolean {
return route.hash === `#L${line.number}`;
Expand Down Expand Up @@ -297,6 +306,18 @@ async function loadLogs() {
}
}

async function deleteLogs() {
if (!repo?.value || !pipeline.value || !step.value) {
throw new Error('The repository, pipeline or step was undefined');
}

try {
await apiClient.deleteLogs(repo.value.id, pipeline.value.number, step.value.id);
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
} catch (e) {
notifications.notifyError(e, i18n.t('repo.pipeline.log_delete_error'));
}
}

onMounted(async () => {
await loadLogs();
});
Expand Down
4 changes: 4 additions & 0 deletions web/src/lib/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ export default class WoodpeckerClient extends ApiClient {
return this._get(`/api/repos/${repoId}/logs/${pipeline}/${step}`) as Promise<PipelineLog[]>;
}

deleteLogs(repoId: number, pipeline: number, step: number): Promise<unknown> {
return this._delete(`/api/repos/${repoId}/logs/${pipeline}/${step}`);
}

getSecretList(repoId: number, page: number): Promise<Secret[] | null> {
return this._get(`/api/repos/${repoId}/secrets?page=${page}`) as Promise<Secret[] | null>;
}
Expand Down