diff --git a/models/project/workflows.go b/models/project/workflows.go index 48e88c6c56..49ce17c1ce 100644 --- a/models/project/workflows.go +++ b/models/project/workflows.go @@ -64,7 +64,7 @@ func (we WorkflowEvent) LangKey() string { } } -func (we WorkflowEvent) UUID() string { +func (we WorkflowEvent) EventID() string { switch we { case WorkflowEventItemOpened: return "item_opened" @@ -90,9 +90,9 @@ func (we WorkflowEvent) UUID() string { type WorkflowFilterType string const ( - WorkflowFilterTypeIssueType WorkflowFilterType = "issue_type" // issue, pull_request, etc. - WorkflowFilterTypeColumn WorkflowFilterType = "column" // target column for item_column_changed event - WorkflowFilterTypeLabels WorkflowFilterType = "labels" // filter by issue/PR labels + WorkflowFilterTypeIssueType WorkflowFilterType = "issue_type" // issue, pull_request, etc. + WorkflowFilterTypeColumn WorkflowFilterType = "target_column" // target column for item_column_changed event + WorkflowFilterTypeLabels WorkflowFilterType = "labels" // filter by issue/PR labels ) type WorkflowFilter struct { diff --git a/routers/web/projects/workflows.go b/routers/web/projects/workflows.go index a8bd0bda20..47e1b7d5e2 100644 --- a/routers/web/projects/workflows.go +++ b/routers/web/projects/workflows.go @@ -52,7 +52,7 @@ func getFilterSummary(ctx stdCtx.Context, filters []project_model.WorkflowFilter log.Error("GetColumn: %v", err) continue } - summary.WriteString(" (Column: " + col.Title + ")") + summary.WriteString(" (Target Column: " + col.Title + ")") case project_model.WorkflowFilterTypeLabels: labelID, _ := strconv.ParseInt(filter.Value, 10, 64) if labelID > 0 { @@ -243,7 +243,7 @@ func WorkflowsEvents(ctx *context.Context) { outputWorkflows = append(outputWorkflows, &WorkflowConfig{ ID: wf.ID, EventID: strconv.FormatInt(wf.ID, 10), - DisplayName: string(ctx.Tr(wf.WorkflowEvent.LangKey())) + filterSummary, + DisplayName: string(ctx.Tr(wf.WorkflowEvent.LangKey())), BaseEventType: string(wf.WorkflowEvent), WorkflowEvent: string(wf.WorkflowEvent), Capabilities: capabilities[event], @@ -258,7 +258,7 @@ func WorkflowsEvents(ctx *context.Context) { // Add placeholder for creating new workflow outputWorkflows = append(outputWorkflows, &WorkflowConfig{ ID: 0, - EventID: event.UUID(), + EventID: event.EventID(), DisplayName: string(ctx.Tr(event.LangKey())), BaseEventType: string(event), WorkflowEvent: string(event), @@ -514,7 +514,7 @@ func WorkflowsPost(ctx *context.Context) { "workflow": map[string]any{ "id": wf.ID, "event_id": strconv.FormatInt(wf.ID, 10), - "display_name": string(ctx.Tr(wf.WorkflowEvent.LangKey())) + filterSummary, + "display_name": string(ctx.Tr(wf.WorkflowEvent.LangKey())), "filters": wf.WorkflowFilters, "actions": wf.WorkflowActions, "filter_summary": filterSummary, diff --git a/services/projects/workflow_notifier.go b/services/projects/workflow_notifier.go index a48bb7e556..65ea72a8f8 100644 --- a/services/projects/workflow_notifier.go +++ b/services/projects/workflow_notifier.go @@ -55,7 +55,7 @@ func (m *workflowNotifier) NewIssue(ctx context.Context, issue *issues_model.Iss // Find workflows for the ItemOpened event for _, workflow := range workflows { if workflow.WorkflowEvent == project_model.WorkflowEventItemOpened { - fireIssueWorkflow(ctx, workflow, issue) + fireIssueWorkflow(ctx, workflow, issue, 0) } } } @@ -92,7 +92,7 @@ func (m *workflowNotifier) IssueChangeStatus(ctx context.Context, doer *user_mod // Find workflows for the specific event for _, workflow := range workflows { if workflow.WorkflowEvent == workflowEvent { - fireIssueWorkflow(ctx, workflow, issue) + fireIssueWorkflow(ctx, workflow, issue, 0) } } } @@ -124,7 +124,7 @@ func (*workflowNotifier) IssueChangeProjects(ctx context.Context, doer *user_mod // Find workflows for the ItemOpened event for _, workflow := range workflows { if workflow.WorkflowEvent == project_model.WorkflowEventItemAddedToProject { - fireIssueWorkflow(ctx, workflow, issue) + fireIssueWorkflow(ctx, workflow, issue, 0) } } } @@ -158,7 +158,7 @@ func (*workflowNotifier) IssueChangeProjectColumn(ctx context.Context, doer *use // Find workflows for the ItemColumnChanged event for _, workflow := range workflows { if workflow.WorkflowEvent == project_model.WorkflowEventItemColumnChanged { - fireIssueWorkflowWithColumn(ctx, workflow, issue, newColumnID) + fireIssueWorkflow(ctx, workflow, issue, newColumnID) } } } @@ -192,7 +192,7 @@ func (*workflowNotifier) MergePullRequest(ctx context.Context, doer *user_model. // Find workflows for the PullRequestMerged event for _, workflow := range workflows { if workflow.WorkflowEvent == project_model.WorkflowEventPullRequestMerged { - fireIssueWorkflow(ctx, workflow, issue) + fireIssueWorkflow(ctx, workflow, issue, 0) } } } @@ -231,14 +231,12 @@ func (*workflowNotifier) PullRequestReview(ctx context.Context, pr *issues_model for _, workflow := range workflows { if (workflow.WorkflowEvent == project_model.WorkflowEventCodeChangesRequested && review.Type == issues_model.ReviewTypeReject) || (workflow.WorkflowEvent == project_model.WorkflowEventCodeReviewApproved && review.Type == issues_model.ReviewTypeApprove) { - fireIssueWorkflow(ctx, workflow, issue) + fireIssueWorkflow(ctx, workflow, issue, 0) } } } -// fireIssueWorkflowWithColumn fires a workflow for an issue with a specific column ID -// This is used for ItemColumnChanged events where we need to check the target column -func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue, columnID int64) { +func fireIssueWorkflow(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue, columnID int64) { if !workflow.Enabled { return } @@ -249,6 +247,15 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo return } + if !matchWorkflowsFilters(workflow, issue, columnID) { + return + } + + executeWorkflowActions(ctx, workflow, issue) +} + +// matchWorkflowsFilters checks if the issue matches all filters of the workflow +func matchWorkflowsFilters(workflow *project_model.Workflow, issue *issues_model.Issue, columnID int64) bool { for _, filter := range workflow.WorkflowFilters { switch filter.Type { case project_model.WorkflowFilterTypeIssueType: @@ -258,10 +265,10 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo } // Filter value can be "issue" or "pull_request" if filter.Value == "issue" && issue.IsPull { - return + return false } if filter.Value == "pull_request" && !issue.IsPull { - return + return false } case project_model.WorkflowFilterTypeColumn: // If filter value is empty, match all columns @@ -271,18 +278,18 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo filterColumnID, _ := strconv.ParseInt(filter.Value, 10, 64) if filterColumnID == 0 { log.Error("Invalid column ID: %s", filter.Value) - return + return false } // For column changed event, check against the new column ID - if columnID != filterColumnID { - return + if columnID > 0 && columnID != filterColumnID { + return false } case project_model.WorkflowFilterTypeLabels: // Check if issue has the specified label labelID, _ := strconv.ParseInt(filter.Value, 10, 64) if labelID == 0 { log.Error("Invalid label ID: %s", filter.Value) - return + return false } // Check if issue has this label hasLabel := false @@ -293,85 +300,14 @@ func fireIssueWorkflowWithColumn(ctx context.Context, workflow *project_model.Wo } } if !hasLabel { - return + return false } default: log.Error("Unsupported filter type: %s", filter.Type) - return + return false } } - - executeWorkflowActions(ctx, workflow, issue) -} - -func fireIssueWorkflow(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue) { - if !workflow.Enabled { - return - } - - // Load issue labels for labels filter - if err := issue.LoadLabels(ctx); err != nil { - log.Error("LoadLabels: %v", err) - return - } - - for _, filter := range workflow.WorkflowFilters { - switch filter.Type { - case project_model.WorkflowFilterTypeIssueType: - // If filter value is empty, match all types - if filter.Value == "" { - continue - } - // Filter value can be "issue" or "pull_request" - if filter.Value == "issue" && issue.IsPull { - return - } - if filter.Value == "pull_request" && !issue.IsPull { - return - } - case project_model.WorkflowFilterTypeColumn: - // If filter value is empty, match all columns - if filter.Value == "" { - continue - } - columnID, _ := strconv.ParseInt(filter.Value, 10, 64) - if columnID == 0 { - log.Error("Invalid column ID: %s", filter.Value) - return - } - issueProjectColumnID, err := issue.ProjectColumnID(ctx) - if err != nil { - log.Error("Issue.ProjectColumnID: %v", err) - return - } - if issueProjectColumnID != columnID { - return - } - case project_model.WorkflowFilterTypeLabels: - // Check if issue has the specified label - labelID, _ := strconv.ParseInt(filter.Value, 10, 64) - if labelID == 0 { - log.Error("Invalid label ID: %s", filter.Value) - return - } - // Check if issue has this label - hasLabel := false - for _, label := range issue.Labels { - if label.ID == labelID { - hasLabel = true - break - } - } - if !hasLabel { - return - } - default: - log.Error("Unsupported filter type: %s", filter.Type) - return - } - } - - executeWorkflowActions(ctx, workflow, issue) + return true } func executeWorkflowActions(ctx context.Context, workflow *project_model.Workflow, issue *issues_model.Issue) { diff --git a/templates/repo/projects/workflows.tmpl b/templates/repo/projects/workflows.tmpl index 1752cd8c8a..2d5d0325f3 100644 --- a/templates/repo/projects/workflows.tmpl +++ b/templates/repo/projects/workflows.tmpl @@ -3,8 +3,8 @@ {{template "repo/header" .}}
{{template "projects/workflows" .}} diff --git a/web_src/js/components/projects/ProjectWorkflow.vue b/web_src/js/components/projects/ProjectWorkflow.vue index 306286e6d3..6668b8de9a 100644 --- a/web_src/js/components/projects/ProjectWorkflow.vue +++ b/web_src/js/components/projects/ProjectWorkflow.vue @@ -829,11 +829,11 @@ onUnmounted(() => { -