Skip to content

Commit c3f15d1

Browse files
authored
Merge pull request #16 from youenchene/fix-general-tab
fix-general-tab
2 parents 4801590 + 6a89dea commit c3f15d1

10 files changed

Lines changed: 546 additions & 121 deletions

File tree

command/calculate/calculate.go

Lines changed: 177 additions & 42 deletions
Large diffs are not rendered by default.

command/import/import.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,17 @@ func Run(args []string) error {
138138
}
139139
// timeline aggregation below
140140
report := IssueReport{
141-
Org: *org,
142-
Repo: r.Name,
143-
Number: is.Number,
144-
Title: is.Title,
145-
URL: is.HTMLURL,
146-
State: is.State,
147-
Creator: valueOrEmpty(is.User),
148-
Assignees: usersToLogins(is.Assignees),
149-
CreatedAt: is.CreatedAt,
150-
ClosedAt: is.ClosedAt,
141+
Org: *org,
142+
Repo: r.Name,
143+
Number: is.Number,
144+
Title: is.Title,
145+
URL: is.HTMLURL,
146+
State: is.State,
147+
Creator: valueOrEmpty(is.User),
148+
Assignees: usersToLogins(is.Assignees),
149+
CreatedAt: is.CreatedAt,
150+
ClosedAt: is.ClosedAt,
151+
ProjectCustomFields: is.ProjectCustomFields,
151152
}
152153
// Prefer GitHub IssueType when available; fallback to label heuristics. Also set IsBug.
153154
var typ string

connectors/config/config.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import (
1414
// Only the fields currently needed by commands are modeled.
1515
type Config struct {
1616
GitHub struct {
17-
Org string `yaml:"org"`
18-
Projects []Project `yaml:"projects"`
17+
Org string `yaml:"org"`
18+
BugSource BugSource `yaml:"bug-source"`
19+
Projects []Project `yaml:"projects"`
1920
} `yaml:"github"`
2021
CloudSpending struct {
2122
// Flat list of services to include (legacy/simple mode)
@@ -41,6 +42,13 @@ type Config struct {
4142
} `yaml:"cloudspending"`
4243
}
4344

45+
type BugSource struct {
46+
CustomFieldName string `yaml:"custom-field-name"`
47+
CustomerFacingValue string `yaml:"customer-facing-value"`
48+
InternalValue string `yaml:"internal-value"`
49+
DevProcessValue string `yaml:"dev-process-value"`
50+
}
51+
4452
// DetailedServiceGroup defines a logical group name and the list of concrete services it aggregates.
4553
type DetailedServiceGroup struct {
4654
Name string `yaml:"name"`

connectors/csv/csv.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ func WriteAllCSVs(org string, repos []gh.Repo, reports []gh.IssueReport) error {
3131
if err := WriteIssueProjectCSV(filepath.Join(dir, "issue_project_event.csv"), reports); err != nil {
3232
return err
3333
}
34+
if err := WriteIssueProjectCustomFieldCSV(filepath.Join(dir, "issue_project_custom_field.csv"), reports); err != nil {
35+
return err
36+
}
3437
return nil
3538
}
3639

@@ -199,3 +202,34 @@ func WriteIssueProjectCSV(path string, reports []gh.IssueReport) error {
199202
}
200203
return w.Error()
201204
}
205+
206+
func WriteIssueProjectCustomFieldCSV(path string, reports []gh.IssueReport) error {
207+
f, err := os.Create(path)
208+
if err != nil {
209+
return err
210+
}
211+
defer f.Close()
212+
w := csv.NewWriter(f)
213+
defer w.Flush()
214+
headers := []string{"org", "repo", "number", "project_id", "project_name", "field_name", "field_value"}
215+
if err := w.Write(headers); err != nil {
216+
return err
217+
}
218+
for _, rep := range reports {
219+
for _, fv := range rep.ProjectCustomFields {
220+
row := []string{
221+
rep.Org,
222+
rep.Repo,
223+
strconv.Itoa(rep.Number),
224+
fv.ProjectID,
225+
fv.ProjectName,
226+
fv.FieldName,
227+
fv.FieldValue,
228+
}
229+
if err := w.Write(row); err != nil {
230+
return err
231+
}
232+
}
233+
}
234+
return w.Error()
235+
}

connectors/github/client.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,59 @@ func (hc *Client) ListAllIssues(ctx context.Context, owner, repo, since string,
437437
assignees(first:20){nodes{login}}
438438
labels(first:50){nodes{name}}
439439
issueType { name }
440+
projectItems(first:10) {
441+
nodes {
442+
project {
443+
fullDatabaseId
444+
title
445+
}
446+
fieldValues(first:20) {
447+
nodes {
448+
__typename
449+
... on ProjectV2ItemFieldTextValue {
450+
text
451+
field {
452+
... on ProjectV2FieldCommon {
453+
name
454+
}
455+
}
456+
}
457+
... on ProjectV2ItemFieldIterationValue {
458+
title
459+
field {
460+
... on ProjectV2FieldCommon {
461+
name
462+
}
463+
}
464+
}
465+
... on ProjectV2ItemFieldSingleSelectValue {
466+
name
467+
field {
468+
... on ProjectV2FieldCommon {
469+
name
470+
}
471+
}
472+
}
473+
... on ProjectV2ItemFieldDateValue {
474+
date
475+
field {
476+
... on ProjectV2FieldCommon {
477+
name
478+
}
479+
}
480+
}
481+
... on ProjectV2ItemFieldNumberValue {
482+
number
483+
field {
484+
... on ProjectV2FieldCommon {
485+
name
486+
}
487+
}
488+
}
489+
}
490+
}
491+
}
492+
}
440493
}
441494
}
442495
}
@@ -494,6 +547,27 @@ func (hc *Client) ListAllIssues(ctx context.Context, owner, repo, since string,
494547
IssueType *struct {
495548
Name string `json:"name"`
496549
} `json:"issueType"`
550+
ProjectItems struct {
551+
Nodes []struct {
552+
Project struct {
553+
FullDatabaseId string `json:"fullDatabaseId"`
554+
Title string `json:"title"`
555+
} `json:"project"`
556+
FieldValues struct {
557+
Nodes []struct {
558+
Typename string `json:"__typename"`
559+
Text string `json:"text,omitempty"`
560+
Title string `json:"title,omitempty"`
561+
Name string `json:"name,omitempty"`
562+
Date string `json:"date,omitempty"`
563+
Number float64 `json:"number,omitempty"`
564+
Field struct {
565+
Name string `json:"name"`
566+
} `json:"field"`
567+
} `json:"nodes"`
568+
} `json:"fieldValues"`
569+
} `json:"nodes"`
570+
} `json:"projectItems"`
497571
} `json:"nodes"`
498572
} `json:"issues"`
499573
} `json:"repository"`
@@ -538,6 +612,31 @@ func (hc *Client) ListAllIssues(ctx context.Context, owner, repo, since string,
538612
if n.IssueType != nil {
539613
iss.Type = strings.ToLower(strings.TrimSpace(n.IssueType.Name))
540614
}
615+
for _, pi := range n.ProjectItems.Nodes {
616+
for _, fv := range pi.FieldValues.Nodes {
617+
val := ""
618+
switch fv.Typename {
619+
case "ProjectV2ItemFieldTextValue":
620+
val = fv.Text
621+
case "ProjectV2ItemFieldIterationValue":
622+
val = fv.Title
623+
case "ProjectV2ItemFieldSingleSelectValue":
624+
val = fv.Name
625+
case "ProjectV2ItemFieldDateValue":
626+
val = fv.Date
627+
case "ProjectV2ItemFieldNumberValue":
628+
val = fmt.Sprintf("%v", fv.Number)
629+
}
630+
if val != "" {
631+
iss.ProjectCustomFields = append(iss.ProjectCustomFields, gh.ProjectCustomField{
632+
ProjectID: pi.Project.FullDatabaseId,
633+
ProjectName: pi.Project.Title,
634+
FieldName: fv.Field.Name,
635+
FieldValue: val,
636+
})
637+
}
638+
}
639+
}
541640
all = append(all, iss)
542641
}
543642
pi := out.Data.Repository.Issues.PageInfo

domain/github/github.go

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@ type Repo struct {
1313

1414
// Issue represents a GitHub issue (excluding PRs which have PullRequest != nil)
1515
type Issue struct {
16-
Number int `json:"number"`
17-
Title string `json:"title"`
18-
State string `json:"state"`
19-
HTMLURL string `json:"html_url"`
20-
CreatedAt time.Time `json:"created_at"`
21-
UpdatedAt time.Time `json:"updated_at"`
22-
ClosedAt *time.Time `json:"closed_at"`
23-
User *User `json:"user"`
24-
Assignees []User `json:"assignees"`
25-
Labels []Label `json:"labels"`
26-
Type string `json:"type"`
27-
PullRequest *struct{} `json:"pull_request"`
16+
Number int `json:"number"`
17+
Title string `json:"title"`
18+
State string `json:"state"`
19+
HTMLURL string `json:"html_url"`
20+
CreatedAt time.Time `json:"created_at"`
21+
UpdatedAt time.Time `json:"updated_at"`
22+
ClosedAt *time.Time `json:"closed_at"`
23+
User *User `json:"user"`
24+
Assignees []User `json:"assignees"`
25+
Labels []Label `json:"labels"`
26+
Type string `json:"type"`
27+
PullRequest *struct{} `json:"pull_request"`
28+
ProjectCustomFields []ProjectCustomField `json:"project_custom_fields,omitempty"`
2829
}
2930

3031
type User struct {
@@ -105,22 +106,30 @@ type ProjectMoveEvent struct {
105106

106107
// IssueReport is the final aggregated record for output
107108
type IssueReport struct {
108-
Org string `json:"org"`
109-
Repo string `json:"repo"`
110-
Number int `json:"number"`
111-
Title string `json:"title"`
112-
URL string `json:"url"`
113-
State string `json:"state"`
114-
Type string `json:"type,omitempty"`
115-
IsBug bool `json:"is_bug"`
116-
Creator string `json:"creator"`
117-
Assignees []string `json:"assignees"`
118-
CreatedAt time.Time `json:"created_at"`
119-
ClosedAt *time.Time `json:"closed_at,omitempty"`
120-
Committer string `json:"committer,omitempty"`
121-
StatusHistory []StatusEvent `json:"status_history"`
122-
ProjectHistory []ProjectMoveEvent `json:"project_history"`
123-
CurrentProjects []CurrentProject `json:"current_projects"`
109+
Org string `json:"org"`
110+
Repo string `json:"repo"`
111+
Number int `json:"number"`
112+
Title string `json:"title"`
113+
URL string `json:"url"`
114+
State string `json:"state"`
115+
Type string `json:"type,omitempty"`
116+
IsBug bool `json:"is_bug"`
117+
Creator string `json:"creator"`
118+
Assignees []string `json:"assignees"`
119+
CreatedAt time.Time `json:"created_at"`
120+
ClosedAt *time.Time `json:"closed_at,omitempty"`
121+
Committer string `json:"committer,omitempty"`
122+
StatusHistory []StatusEvent `json:"status_history"`
123+
ProjectHistory []ProjectMoveEvent `json:"project_history"`
124+
CurrentProjects []CurrentProject `json:"current_projects"`
125+
ProjectCustomFields []ProjectCustomField `json:"project_custom_fields,omitempty"`
126+
}
127+
128+
type ProjectCustomField struct {
129+
ProjectID string `json:"project_id"`
130+
ProjectName string `json:"project_name"`
131+
FieldName string `json:"field_name"`
132+
FieldValue string `json:"field_value"`
124133
}
125134

126135
type CurrentProject struct {

0 commit comments

Comments
 (0)