Skip to content

Commit a42893a

Browse files
Merge branch 'main' into feat/linear-plugin
2 parents 232e9d1 + 144c2b7 commit a42893a

2 files changed

Lines changed: 97 additions & 7 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
Licensed to the Apache Software Foundation (ASF) under one or more
3+
contributor license agreements. See the NOTICE file distributed with
4+
this work for additional information regarding copyright ownership.
5+
The ASF licenses this file to You under the Apache License, Version 2.0
6+
(the "License"); you may not use this file except in compliance with
7+
the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package e2e
19+
20+
import (
21+
"reflect"
22+
"sort"
23+
"testing"
24+
25+
"github.com/apache/incubator-devlake/helpers/e2ehelper"
26+
"github.com/apache/incubator-devlake/helpers/pluginhelper/api"
27+
"github.com/apache/incubator-devlake/plugins/circleci/impl"
28+
"github.com/apache/incubator-devlake/plugins/circleci/models"
29+
"github.com/apache/incubator-devlake/plugins/circleci/tasks"
30+
"github.com/stretchr/testify/assert"
31+
)
32+
33+
// TestCircleciUnfinishedJobsInputIterator is a regression test for
34+
// https://github.com/apache/devlake/issues/8907. The "collect unfinished job
35+
// details" collector builds its URL from "/v2/workflow/{{ .Input.Id }}/job" while
36+
// scanning rows into a models.CircleciJob. Its input query must therefore expose the
37+
// workflow id in the row's Id field; a bare "DISTINCT workflow_id" left Id empty and
38+
// produced "/v2/workflow//job" (HTTP 500). This test runs the production query
39+
// (tasks.UnfinishedJobsInputClauses) through the real iterator and asserts each
40+
// yielded row's Id is the workflow id, that results are DISTINCT, and that the
41+
// status/connection filters hold.
42+
func TestCircleciUnfinishedJobsInputIterator(t *testing.T) {
43+
var circleci impl.Circleci
44+
dataflowTester := e2ehelper.NewDataFlowTester(t, "circleci", circleci)
45+
46+
const projectSlug = "github/test/repo"
47+
dataflowTester.FlushTabler(&models.CircleciJob{})
48+
49+
seed := []models.CircleciJob{
50+
{ConnectionId: 1, WorkflowId: "wf-onhold", Id: "job-1", ProjectSlug: projectSlug, Status: "on_hold"},
51+
{ConnectionId: 1, WorkflowId: "wf-onhold", Id: "job-2", ProjectSlug: projectSlug, Status: "running"}, // same workflow -> DISTINCT
52+
{ConnectionId: 1, WorkflowId: "wf-queued", Id: "job-3", ProjectSlug: projectSlug, Status: "queued"},
53+
{ConnectionId: 1, WorkflowId: "wf-success", Id: "job-4", ProjectSlug: projectSlug, Status: "success"}, // terminal -> excluded
54+
{ConnectionId: 2, WorkflowId: "wf-otherconn", Id: "job-5", ProjectSlug: projectSlug, Status: "on_hold"}, // other connection -> excluded
55+
}
56+
for i := range seed {
57+
assert.Nil(t, dataflowTester.Dal.Create(&seed[i]))
58+
}
59+
60+
cursor, err := dataflowTester.Dal.Cursor(tasks.UnfinishedJobsInputClauses(1, projectSlug)...)
61+
assert.Nil(t, err)
62+
iter, err := api.NewDalCursorIterator(dataflowTester.Dal, cursor, reflect.TypeOf(models.CircleciJob{}))
63+
assert.Nil(t, err)
64+
defer iter.Close()
65+
66+
var ids []string
67+
for iter.HasNext() {
68+
item, err := iter.Fetch()
69+
assert.Nil(t, err)
70+
job := item.(*models.CircleciJob)
71+
ids = append(ids, job.Id)
72+
}
73+
sort.Strings(ids)
74+
75+
// Distinct workflow ids for connection 1's non-terminal jobs, with Id populated
76+
// (the URL template reads .Input.Id). wf-success (terminal) and wf-otherconn
77+
// (connection 2) are excluded.
78+
assert.Equal(t, []string{"wf-onhold", "wf-queued"}, ids)
79+
for _, id := range ids {
80+
assert.NotEmpty(t, id, "Input.Id must be the workflow id, not empty (#8907)")
81+
}
82+
}

backend/plugins/circleci/tasks/job_collector.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,20 @@ var CollectJobsMeta = plugin.SubTaskMeta{
4141
DomainTypes: []string{plugin.DOMAIN_TYPE_CICD},
4242
}
4343

44+
// UnfinishedJobsInputClauses returns the DAL clauses that select the workflows whose
45+
// jobs are still in a non-terminal status and therefore need their job details
46+
// recollected by the CollectJobs "unfinished details" collector.
47+
func UnfinishedJobsInputClauses(connectionId uint64, projectSlug string) []dal.Clause {
48+
return []dal.Clause{
49+
dal.Select("DISTINCT workflow_id AS id"), // #8907: alias to id so {{ .Input.Id }} resolves when scanned into CircleciJob
50+
dal.From(&models.CircleciJob{}),
51+
dal.Where(
52+
"connection_id = ? AND project_slug = ? AND status IN ('running', 'not_running', 'queued', 'on_hold')",
53+
connectionId, projectSlug,
54+
),
55+
}
56+
}
57+
4458
func CollectJobs(taskCtx plugin.SubTaskContext) errors.Error {
4559
rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, RAW_JOB_TABLE)
4660
logger := taskCtx.GetLogger()
@@ -94,14 +108,8 @@ func CollectJobs(taskCtx plugin.SubTaskContext) errors.Error {
94108
AfterResponse: ignoreDeletedBuilds,
95109
},
96110
BuildInputIterator: func() (api.Iterator, errors.Error) {
97-
clauses := []dal.Clause{
98-
dal.Select("DISTINCT workflow_id"), // Only need to recollect jobs for a workflow once
99-
dal.From(&models.CircleciJob{}),
100-
dal.Where("connection_id = ? AND project_slug = ? AND status IN ('running', 'not_running', 'queued', 'on_hold')", data.Options.ConnectionId, data.Options.ProjectSlug),
101-
}
102-
103111
db := taskCtx.GetDal()
104-
cursor, err := db.Cursor(clauses...)
112+
cursor, err := db.Cursor(UnfinishedJobsInputClauses(data.Options.ConnectionId, data.Options.ProjectSlug)...)
105113
if err != nil {
106114
return nil, err
107115
}

0 commit comments

Comments
 (0)