You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by kl...@apache.org on 2022/06/16 09:58:17 UTC
[incubator-devlake] branch main updated: github issue task refactor (#2202)
This is an automated email from the ASF dual-hosted git repository.
klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new ea6542a0 github issue task refactor (#2202)
ea6542a0 is described below
commit ea6542a02ff1fa63aa08ffd52423a90ace7c174c
Author: likyh <l...@likyh.com>
AuthorDate: Thu Jun 16 17:58:14 2022 +0800
github issue task refactor (#2202)
* fix repo
* append ConnectionId for repo in github
* add repo raw table
* add csv
* update csv for connectionId
* update csv for connectionId 2
* add issue extract and some old e2e test
* update connection id for issue in github
* append
* fix for err check
Co-authored-by: linyh <ya...@meri.co>
---
helpers/e2ehelper/data_flow_tester.go | 17 ++-
plugins/github/e2e/issue_test.go | 160 +++++++++++++++++++++
.../e2e/raw_tables/_raw_github_api_issues.csv | 42 ++++++
.../snapshot_tables/_tool_github_issue_labels.csv | 12 ++
.../e2e/snapshot_tables/_tool_github_issues.csv | 27 ++++
.../github/e2e/snapshot_tables/board_issues.csv | 27 ++++
.../github/e2e/snapshot_tables/issue_labels.csv | 12 ++
plugins/github/e2e/snapshot_tables/issues.csv | 27 ++++
plugins/github/models/issue.go | 1 +
plugins/github/models/issue_label.go | 5 +-
.../models/migrationscripts/archived/issue.go | 1 +
.../migrationscripts/archived/issue_label.go | 5 +-
..._schema_20220610.go => init_schema_20220611.go} | 4 +-
plugins/github/tasks/issue_collector.go | 17 ++-
plugins/github/tasks/issue_convertor.go | 18 ++-
plugins/github/tasks/issue_extractor.go | 19 +--
plugins/github/tasks/issue_label_convertor.go | 21 +--
17 files changed, 376 insertions(+), 39 deletions(-)
diff --git a/helpers/e2ehelper/data_flow_tester.go b/helpers/e2ehelper/data_flow_tester.go
index 4f30f681..53bc83c9 100644
--- a/helpers/e2ehelper/data_flow_tester.go
+++ b/helpers/e2ehelper/data_flow_tester.go
@@ -226,7 +226,7 @@ func (t *DataFlowTester) VerifyTable(dst schema.Tabler, csvRelPath string, pkfie
location, _ := time.LoadLocation(`UTC`)
defer csvIter.Close()
- var expectedTotal int64
+ expectedTotal := int64(0)
for csvIter.HasNext() {
expected := csvIter.Fetch()
pkvalues := make([]interface{}, 0, len(pkfields))
@@ -238,7 +238,18 @@ func (t *DataFlowTester) VerifyTable(dst schema.Tabler, csvRelPath string, pkfie
for _, field := range pkfields {
where = append(where, fmt.Sprintf(" %s = ?", field))
}
- err := t.Db.Table(dst.TableName()).Where(strings.Join(where, ` AND `), pkvalues...).Find(actual).Error
+
+ var actualCount int64
+ err := t.Db.Table(dst.TableName()).Where(strings.Join(where, ` AND `), pkvalues...).Count(&actualCount).Error
+ if err != nil {
+ panic(err)
+ }
+ assert.Equal(t.T, int64(1), actualCount, fmt.Sprintf(`%s found not eq 1 but %d (with params from csv %s)`, dst.TableName(), actualCount, pkvalues))
+ if actualCount != 1 {
+ continue
+ }
+
+ err = t.Db.Table(dst.TableName()).Where(strings.Join(where, ` AND `), pkvalues...).Find(actual).Error
if err != nil {
panic(err)
}
@@ -260,7 +271,7 @@ func (t *DataFlowTester) VerifyTable(dst schema.Tabler, csvRelPath string, pkfie
actualValue = fmt.Sprint(actual[field])
}
}
- assert.Equal(t.T, expected[field], actualValue, fmt.Sprintf(`%s.%s not match`, dst.TableName(), field))
+ assert.Equal(t.T, expected[field], actualValue, fmt.Sprintf(`%s.%s not match (with params from csv %s)`, dst.TableName(), field, pkvalues))
}
expectedTotal++
}
diff --git a/plugins/github/e2e/issue_test.go b/plugins/github/e2e/issue_test.go
new file mode 100644
index 00000000..068d1128
--- /dev/null
+++ b/plugins/github/e2e/issue_test.go
@@ -0,0 +1,160 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package e2e
+
+import (
+ "fmt"
+ "github.com/apache/incubator-devlake/models/domainlayer/ticket"
+ "github.com/apache/incubator-devlake/plugins/github/models"
+ "testing"
+
+ "github.com/apache/incubator-devlake/helpers/e2ehelper"
+ "github.com/apache/incubator-devlake/plugins/github/impl"
+ "github.com/apache/incubator-devlake/plugins/github/tasks"
+)
+
+func TestIssueDataFlow(t *testing.T) {
+ var plugin impl.Github
+ dataflowTester := e2ehelper.NewDataFlowTester(t, "gitlab", plugin)
+
+ githubRepository := &models.GithubRepo{
+ GithubId: 134018330,
+ }
+ taskData := &tasks.GithubTaskData{
+ Options: &tasks.GithubOptions{
+ ConnectionId: 1,
+ Owner: "panjf2000",
+ Repo: "ants",
+ Config: models.Config{
+ PrType: "type/(.*)$",
+ PrComponent: "component/(.*)$",
+ PrBodyClosePattern: "(?mi)(fix|close|resolve|fixes|closes|resolves|fixed|closed|resolved)[\\s]*.*(((and )?(#|https:\\/\\/github.com\\/%s\\/%s\\/issues\\/)\\d+[ ]*)+)",
+ IssueSeverity: "severity/(.*)$",
+ IssuePriority: "^(highest|high|medium|low)$",
+ IssueComponent: "component/(.*)$",
+ IssueTypeBug: "^(bug|failure|error)$",
+ IssueTypeIncident: "",
+ IssueTypeRequirement: "^(feat|feature|proposal|requirement)$",
+ },
+ },
+ Repo: githubRepository,
+ }
+
+ // import raw data table
+ dataflowTester.ImportCsvIntoRawTable("./raw_tables/_raw_github_api_issues.csv", "_raw_github_api_issues")
+
+ // verify extraction
+ dataflowTester.FlushTabler(&models.GithubIssue{})
+ dataflowTester.FlushTabler(&models.GithubIssueLabel{})
+ dataflowTester.Subtask(tasks.ExtractApiIssuesMeta, taskData)
+ dataflowTester.VerifyTable(
+ models.GithubIssue{},
+ fmt.Sprintf("./snapshot_tables/%s.csv", models.GithubIssue{}.TableName()),
+ []string{"connection_id", "github_id", "repo_id"},
+ []string{
+ "number",
+ "state",
+ "title",
+ "body",
+ "priority",
+ "type",
+ "status",
+ "author_id",
+ "author_name",
+ "assignee_id",
+ "assignee_name",
+ "lead_time_minutes",
+ "url",
+ "closed_at",
+ "github_created_at",
+ "github_updated_at",
+ "severity",
+ "component",
+ "_raw_data_params",
+ "_raw_data_table",
+ "_raw_data_id",
+ "_raw_data_remark",
+ },
+ )
+
+ // verify extraction
+ dataflowTester.VerifyTable(
+ models.GithubIssueLabel{},
+ fmt.Sprintf("./snapshot_tables/%s.csv", models.GithubIssueLabel{}.TableName()),
+ []string{"connection_id", "issue_id", "label_name"},
+ []string{
+ "_raw_data_params",
+ "_raw_data_table",
+ "_raw_data_id",
+ "_raw_data_remark",
+ },
+ )
+
+ // verify extraction
+ dataflowTester.FlushTabler(&ticket.Issue{})
+ dataflowTester.FlushTabler(&ticket.BoardIssue{})
+ dataflowTester.Subtask(tasks.ConvertIssuesMeta, taskData)
+ dataflowTester.VerifyTable(
+ ticket.Issue{},
+ fmt.Sprintf("./snapshot_tables/%s.csv", ticket.Issue{}.TableName()),
+ []string{"id"},
+ []string{
+ "url",
+ "icon_url",
+ "issue_key",
+ "title",
+ "description",
+ "epic_key",
+ "type",
+ "status",
+ "original_status",
+ "story_point",
+ "resolution_date",
+ "created_date",
+ "updated_date",
+ "lead_time_minutes",
+ "parent_issue_id",
+ "priority",
+ "original_estimate_minutes",
+ "time_spent_minutes",
+ "time_remaining_minutes",
+ "creator_id",
+ "creator_name",
+ "assignee_id",
+ "assignee_name",
+ "severity",
+ "component",
+ },
+ )
+ dataflowTester.VerifyTable(
+ ticket.BoardIssue{},
+ fmt.Sprintf("./snapshot_tables/%s.csv", ticket.BoardIssue{}.TableName()),
+ []string{"board_id", "issue_id"},
+ []string{},
+ )
+
+ // verify extraction
+ dataflowTester.FlushTabler(&ticket.IssueLabel{})
+ dataflowTester.Subtask(tasks.ConvertIssueLabelsMeta, taskData)
+ dataflowTester.VerifyTable(
+ ticket.IssueLabel{},
+ fmt.Sprintf("./snapshot_tables/%s.csv", ticket.IssueLabel{}.TableName()),
+ []string{"issue_id", "label_name"},
+ []string{},
+ )
+}
diff --git a/plugins/github/e2e/raw_tables/_raw_github_api_issues.csv b/plugins/github/e2e/raw_tables/_raw_github_api_issues.csv
new file mode 100644
index 00000000..bbce55ef
--- /dev/null
+++ b/plugins/github/e2e/raw_tables/_raw_github_api_issues.csv
@@ -0,0 +1,42 @@
+id,params,data,url,input,created_at
+10,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/4"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/4/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/4/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/4/events"",""html_url"":""https://github.com/panjf200 [...]
+11,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/5"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/5/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/5/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/5/events"",""html_url"":""https://github.com/panjf200 [...]
+12,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/6"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/6/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/6/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/6/events"",""html_url"":""https://github.com/panjf200 [...]
+13,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/7"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/7/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/7/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/7/events"",""html_url"":""https://github.com/panjf200 [...]
+14,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/8"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/8/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/8/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/8/events"",""html_url"":""https://github.com/panjf200 [...]
+15,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/9"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/9/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/9/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/9/events"",""html_url"":""https://github.com/panjf200 [...]
+16,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/10"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/10/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/10/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/10/events"",""html_url"":""https://github.com/panj [...]
+17,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/11"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/11/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/11/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/11/events"",""html_url"":""https://github.com/panj [...]
+18,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/12"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/12/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/12/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/12/events"",""html_url"":""https://github.com/panj [...]
+19,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/13"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/13/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/13/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/13/events"",""html_url"":""https://github.com/panj [...]
+20,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/14"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/14/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/14/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/14/events"",""html_url"":""https://github.com/panj [...]
+21,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/15"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/15/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/15/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/15/events"",""html_url"":""https://github.com/panj [...]
+22,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/16"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/16/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/16/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/16/events"",""html_url"":""https://github.com/panj [...]
+23,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/17"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/17/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/17/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/17/events"",""html_url"":""https://github.com/panj [...]
+24,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/18"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/18/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/18/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/18/events"",""html_url"":""https://github.com/panj [...]
+25,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/19"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/19/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/19/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/19/events"",""html_url"":""https://github.com/panj [...]
+26,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/20"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/20/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/20/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/20/events"",""html_url"":""https://github.com/panj [...]
+27,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/21"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/21/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/21/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/21/events"",""html_url"":""https://github.com/panj [...]
+28,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/22"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/22/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/22/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/22/events"",""html_url"":""https://github.com/panj [...]
+29,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/23"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/23/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/23/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/23/events"",""html_url"":""https://github.com/panj [...]
+30,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/24"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/24/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/24/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/24/events"",""html_url"":""https://github.com/panj [...]
+31,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/25"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/25/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/25/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/25/events"",""html_url"":""https://github.com/panj [...]
+32,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/26"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/26/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/26/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/26/events"",""html_url"":""https://github.com/panj [...]
+33,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/27"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/27/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/27/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/27/events"",""html_url"":""https://github.com/panj [...]
+34,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/28"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/28/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/28/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/28/events"",""html_url"":""https://github.com/panj [...]
+35,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/29"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/29/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/29/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/29/events"",""html_url"":""https://github.com/panj [...]
+36,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/30"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/30/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/30/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/30/events"",""html_url"":""https://github.com/panj [...]
+37,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/31"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/31/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/31/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/31/events"",""html_url"":""https://github.com/panj [...]
+38,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/32"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/32/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/32/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/32/events"",""html_url"":""https://github.com/panj [...]
+39,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/33"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/33/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/33/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/33/events"",""html_url"":""https://github.com/panj [...]
+40,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/34"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/34/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/34/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/34/events"",""html_url"":""https://github.com/panj [...]
+41,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/35"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/35/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/35/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/35/events"",""html_url"":""https://github.com/panj [...]
+42,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/36"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/36/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/36/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/36/events"",""html_url"":""https://github.com/panj [...]
+43,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/37"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/37/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/37/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/37/events"",""html_url"":""https://github.com/panj [...]
+44,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/38"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/38/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/38/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/38/events"",""html_url"":""https://github.com/panj [...]
+45,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/39"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/39/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/39/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/39/events"",""html_url"":""https://github.com/panj [...]
+46,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/40"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/40/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/40/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/40/events"",""html_url"":""https://github.com/panj [...]
+47,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/41"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/41/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/41/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/41/events"",""html_url"":""https://github.com/panj [...]
+48,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/42"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/42/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/42/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/42/events"",""html_url"":""https://github.com/panj [...]
+49,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/43"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/43/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/43/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/43/events"",""html_url"":""https://github.com/panj [...]
+50,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}","{""url"":""https://api.github.com/repos/panjf2000/ants/issues/44"",""repository_url"":""https://api.github.com/repos/panjf2000/ants"",""labels_url"":""https://api.github.com/repos/panjf2000/ants/issues/44/labels{/name}"",""comments_url"":""https://api.github.com/repos/panjf2000/ants/issues/44/comments"",""events_url"":""https://api.github.com/repos/panjf2000/ants/issues/44/events"",""html_url"":""https://github.com/panj [...]
diff --git a/plugins/github/e2e/snapshot_tables/_tool_github_issue_labels.csv b/plugins/github/e2e/snapshot_tables/_tool_github_issue_labels.csv
new file mode 100644
index 00000000..44b54924
--- /dev/null
+++ b/plugins/github/e2e/snapshot_tables/_tool_github_issue_labels.csv
@@ -0,0 +1,12 @@
+connection_id,issue_id,label_name,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+1,346842831,question,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,11,
+1,347255859,bug,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,12,
+1,348630179,bug,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,13,
+1,356703393,question,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,16,
+1,381941219,enhancement,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,23,
+1,382039050,question,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,24,
+1,382574800,enhancement,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,26,
+1,401277739,enhancement,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,28,
+1,402513849,enhancement,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,30,
+1,433564955,enhancement,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,38,
+1,434069015,enhancement,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,39,
diff --git a/plugins/github/e2e/snapshot_tables/_tool_github_issues.csv b/plugins/github/e2e/snapshot_tables/_tool_github_issues.csv
new file mode 100644
index 00000000..801fc2dd
--- /dev/null
+++ b/plugins/github/e2e/snapshot_tables/_tool_github_issues.csv
@@ -0,0 +1,27 @@
+connection_id,github_id,repo_id,number,state,title,body,priority,type,status,author_id,author_name,assignee_id,assignee_name,lead_time_minutes,url,closed_at,github_created_at,github_updated_at,severity,component,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+1,346842831,134018330,5,closed,关于 <-p.freeSignal 的疑惑,"""Hi,\r\n 我阅读了源码,对 `<-p.freeSignal` 这句代码有疑惑。 这句代码出现在了多个地方,freeSignal 的作用英文注释我是理解的,并且知道在 `putWorker` 中才进行 `p.freeSignal <- sig{}`\r\n\r\n对于下面的代码\r\n```\r\nfunc (p *Pool) getWorker() *Worker {\r\n\tvar w *Worker\r\n\twaiting := false\r\n\r\n\tp.lock.Lock()\r\n\tidleWorkers := p.workers\r\n\tn := len(idleWorkers) - 1\r\n\tif n < 0 { // 说明 pool中没有worker了\r\n\t\twaiting = p.Running() >= p.Cap()\r\n\t} else { // 说明pool中有worker\r\n\t\t<-p [...]
+1,347255859,134018330,6,closed,死锁bug,"""func (p *Pool) getWorker() *Worker 这个函数的 199行 \r\n必须先解锁在加锁, 要不然会产生死锁\r\n\r\n\tp.lock.Unlock()\r\n\t\t<-p.freeSignal\r\n\t\tp.lock.Lock()""",,BUG,,13118848,lovelly,0,,1786,https://github.com/panjf2000/ants/issues/6,2018-08-04T10:18:41.000+00:00,2018-08-03T04:32:28.000+00:00,2018-08-04T10:18:41.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,12,
+1,348630179,134018330,7,closed,清理过期协程报错,"""你好,非常感谢提供这么好用的工具包。我在使用ants时,发现报异常。结果见下图\r\n![image](https://user-images.githubusercontent.com/4555057/43823431-98384444-9b21-11e8-880c-7458b931734a.png)\r\n日志是我在periodicallyPurge里加的调试信息\r\n![image](https://user-images.githubusercontent.com/4555057/43823534-e3c624a8-9b21-11e8-96c6-512e3e08db22.png)\r\n\r\n### 原因分析\r\n\r\n我认为可能原因是没有处理n==0的情况\r\n```\r\nif n > 0 {\r\n\tn++\r\n\tp.workers = idleWorkers[n:]\r\n}\r\n```\r\n\r\n\r\n### 测试代码\r\n```\r\npa [...]
+1,356703393,134018330,10,closed,高并发下设定较小的worker数量问题,"""会存在cpu飚升的问题吧?""",,,,11763614,Moonlight-Zhao,0,,36198,https://github.com/panjf2000/ants/issues/10,2018-09-29T11:45:00.000+00:00,2018-09-04T08:26:55.000+00:00,2018-09-29T11:45:00.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,16,
+1,364361014,134018330,12,closed,潘少,更新下tag吧,"""鄙人现在在弄dep依赖管理,有用到你写的ants项目,可是你好像忘记打最新的tag了。最新的tag 3.6是指向ed55924这个提交,git上的最新代码是af376f1b这次提交,两次提交都隔了快5个月了,看到的话,麻烦打一个最新的tag吧。(手动可怜)""",,,,29452204,edcismybrother,0,,1293,https://github.com/panjf2000/ants/issues/12,2018-09-28T06:05:58.000+00:00,2018-09-27T08:32:25.000+00:00,2019-04-21T08:19:58.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,18,
+1,381941219,134018330,17,closed,关于优雅退出的问题,"""关于这个package优雅退出的问题,我看了一下Release的代码:\r\n\r\n`\r\n\t// Release Closed this pool.\r\n\tfunc (p *PoolWithFunc) Release() error {\r\n\t\tp.once.Do(func() {\r\n\t\t\tp.release <- sig{}\r\n\t\t\tp.lock.Lock()\r\n\t\t\tidleWorkers := p.workers\r\n\t\t\tfor i, w := range idleWorkers {\r\n\t\t\t\tw.args <- nil\r\n\t\t\t\tidleWorkers[i] = nil\r\n\t\t\t}\r\n\t\t\tp.workers = nil\r\n\t\t\tp.lock.Unlock()\r\n\t\t})\r\n\t\treturn nil\r\n\t}\r\n`\r\n\r\nrelea [...]
+1,382039050,134018330,18,closed,go协程的理解,"""你好楼主,向您请教一个协程和线程的问题,协程基于go进程调度,线程基于系统内核调度,调度协程的过程是先调度线程后获得资源再去调度协程。\""官方解释: GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously。限制cpu数,本质上是什么,限制并行数?,并行数即同时执行数量?,执行单元即线程?,即限制最大并行线程数量?\""""",,,,13944100,LinuxForYQH,0,,20213,https://github.com/panjf2000/ants/issues/18,2018-12-03T03:53:50.000+00:00,2018-11-19T02:59:53.000+00:00,2018-12-03T03:53:50.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""} [...]
+1,382574800,134018330,20,closed,是否考虑任务支持回调函数处理失败的逻辑和任务依赖,"""#""",,,,5668717,kklinan,0,,95398,https://github.com/panjf2000/ants/issues/20,2019-01-25T15:34:03.000+00:00,2018-11-20T09:36:02.000+00:00,2019-01-25T15:34:03.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,26,
+1,388907811,134018330,21,closed,Benchmark 下直接使用 Semaphore 似乎更快呢?,"""简单跑了一下 benchmark,Semaphore 更快且很简单\r\n\r\n```bash\r\n$ go test -bench .\r\ngoos: darwin\r\ngoarch: amd64\r\npkg: github.com/panjf2000/ants\r\nBenchmarkGoroutineWithFunc-4 \t 1\t3445631705 ns/op\r\nBenchmarkSemaphoreWithFunc-4 \t 1\t1037219073 ns/op\r\nBenchmarkAntsPoolWithFunc-4 \t 1\t1138053222 ns/op\r\nBenchmarkGoroutine-4 \t 2\t 731850771 ns/op\r\nBenchmarkSemaphore-4 [...]
+1,401277739,134018330,22,closed,是否考虑 worker 中添加 PanicHandler ?,"""比方说在创建 Pool 的时候传入一个 PanicHandler,然后在每个 worker 创建的时候 recover 之后传给 PanicHandler 处理。否则池子里如果发生 panic 会直接挂掉整个进程。""",,,,8923413,choleraehyq,0,,1174,https://github.com/panjf2000/ants/issues/22,2019-01-22T05:41:34.000+00:00,2019-01-21T10:06:56.000+00:00,2019-01-22T05:41:34.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,28,
+1,402513849,134018330,24,closed,提交任务不阻塞,"""`Pool.Submit`和`PoolWithFunc.Server`提交任务,如果没有空的worker,会一直阻塞。建议增加不阻塞的接口,当前失败时直接返回错误。""",,,,5044825,tenfyzhong,0,,300032,https://github.com/panjf2000/ants/issues/24,2019-08-20T10:56:30.000+00:00,2019-01-24T02:24:13.000+00:00,2019-08-20T10:56:30.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,30,
+1,405951301,134018330,25,closed,use example errors,"""./antstest.go:37:14: cannot use syncCalculateSum (type func()) as type ants.f in argument to ants.Submit\r\n./antstest.go:45:35: cannot use func literal (type func(interface {})) as type ants.pf in argument to ants.NewPoolWithFunc\r\n""",,,,5244267,jiashiwen,0,,3088,https://github.com/panjf2000/ants/issues/25,2019-02-04T09:11:52.000+00:00,2019-02-02T05:43:38.000+00:00,2019-02-04T09:11:52.000+00:00,,,"{""ConnectionId"":1,""Owner"":""pa [...]
+1,413968505,134018330,26,closed,running可能大于cap的问题,"""running与cap的比较判断与incRuning分开执行的, 可能会出现running大于cap的问题?\r\n`func (p *Pool) retrieveWorker() *Worker {\r\n\tvar w *Worker\r\n\r\n\tp.lock.Lock()\r\n\tidleWorkers := p.workers\r\n\tn := len(idleWorkers) - 1\r\n\tif n >= 0 {\r\n\t\tw = idleWorkers[n]\r\n\t\tidleWorkers[n] = nil\r\n\t\tp.workers = idleWorkers[:n]\r\n\t\tp.lock.Unlock()\r\n\t} else if p.Running() < p.Cap() {\r\n\t\tp.lock.Unlock()\r\n\t\tif cacheWorker := p.workerCache.Get() [...]
+1,419183961,134018330,27,closed,为何goroutine一直上不去,用户量也打不上去,"""为何goroutine一直上不去,用户量也打不上去\r\n是我用的有问题吗?\r\n\r\nwebsocket server\r\nhttps://github.com/im-ai/pushm/blob/master/learn/goroutine/goroutinepoolwebsocket.go\r\n\r\nwebsocket cient\r\nhttps://github.com/im-ai/pushm/blob/master/learn/goroutine/goroutinepoolwebsocketclient.go\r\n""",,,,38367404,liliang8858,0,,37496,https://github.com/panjf2000/ants/issues/27,2019-04-05T14:05:20.000+00:00,2019-03-10T13:08:52.000+00:00,2019-04-05T14:05:20 [...]
+1,419268851,134018330,28,closed,cap 和 running 比较的问题,"""这是我在 Playground 上面的代码 https://play.golang.org/p/D94YUU3FnX6\r\natomic 只能保证自增自减时的原子操作,在比较过程中,其他线程对变量进行了操作 比较过程并无感知,所以这个比较结果 不是完全正确的,想要实现 比较的数量完全正确,只能在修改和比较两个值的地方加锁\r\n像 #26 说的是对的""",,,,29243953,naiba,0,,237002,https://github.com/panjf2000/ants/issues/28,2019-08-22T16:27:37.000+00:00,2019-03-11T02:24:41.000+00:00,2019-08-22T16:27:37.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,34,
+1,424634533,134018330,29,closed,任务传参,"""你好,你的项目太酷了👍\r\n\r\nhttps://github.com/panjf2000/ants/blob/master/pool.go#L124 貌似不支持带参数的任务, 请问传参是用闭包的方式吗?\r\n""",,,,8509898,prprprus,0,,999,https://github.com/panjf2000/ants/issues/29,2019-03-25T09:32:11.000+00:00,2019-03-24T16:52:21.000+00:00,2019-03-25T09:45:05.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,35,
+1,429972115,134018330,31,closed,Add go.mod,"""""",,,,48135919,tsatke,0,,3474,https://github.com/panjf2000/ants/issues/31,2019-04-08T09:45:31.000+00:00,2019-04-05T23:50:36.000+00:00,2019-10-17T03:12:19.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,37,
+1,433564955,134018330,32,closed,关于版本问题,我发现小版本(0.0.x)这种更新就会不向下兼容?,"""如题,我感觉这样不好。\r\n\r\n功能版本号不向下兼容能理解\r\n\r\n修复问题的版本号也不向下兼容,难以理解。""",,,,7931755,zplzpl,0,,7440,https://github.com/panjf2000/ants/issues/32,2019-04-21T07:16:26.000+00:00,2019-04-16T03:16:02.000+00:00,2019-04-21T07:16:26.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,38,
+1,434069015,134018330,33,closed,support semantic versioning.,"""建议将发布的tag兼容为semantic versioning,vX.Y.Z。go modules对此支持比较良好。\r\nhttps://semver.org/\r\nhttps://research.swtch.com/vgo-import""",,,,1284892,jjeffcaii,0,,6090,https://github.com/panjf2000/ants/issues/33,2019-04-21T08:25:20.000+00:00,2019-04-17T02:55:11.000+00:00,2019-04-21T08:25:20.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,39,
+1,435486645,134018330,34,closed,Important announcement about <ants> from author !!!,"""**Dear users of `ants`:**\r\nI am apologetically telling you that I have to dump all tags which already presents in `ants` repository.\r\n\r\nThe reason why I'm doing so is to standardize the version management with `Semantic Versioning`, which will make a formal and clear dependency management in go, for go modules, godep, or glide, etc. So I decide to start over the tag sequence, you could find more [...]
+1,461280653,134018330,35,closed,worker exit on panic,"""个人认为PanicHandler设计不妥。\r\n1.无PanicHandler时,抛出给外面的不是panic,外层感受不到。\r\n2.无论有没有PanicHandler,都会导致worker退出,最终pool阻塞住全部任务。""",,,,38849208,king526,0,,74481,https://github.com/panjf2000/ants/issues/35,2019-08-17T20:33:10.000+00:00,2019-06-27T03:11:49.000+00:00,2019-08-17T20:33:10.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,41,
+1,462631417,134018330,37,closed,请不要再随意变更版本号了。。。,"""之前用的是 3.9.9,结果今天构建出了问题,一看发现这个版本没了,变成 1.0.0。这种变更完全不考虑现有用户的情况。希望以后不要随意变更了""",,,,8923413,choleraehyq,0,,140,https://github.com/panjf2000/ants/issues/37,2019-07-01T12:37:55.000+00:00,2019-07-01T10:17:15.000+00:00,2019-07-02T10:17:31.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,43,
+1,472125082,134018330,38,closed,retrieveWorker与revertWorker之间会导致死锁,"""func (p *Pool) retrieveWorker() *Worker {\r\n\tvar w *Worker\r\n\r\n\t**p.lock.Lock()**\r\n\tidleWorkers := p.workers\r\n\tn := len(idleWorkers) - 1\r\n\tif n >= 0 {\r\n\t\tw = idleWorkers[n]\r\n\t\tidleWorkers[n] = nil\r\n\t\tp.workers = idleWorkers[:n]\r\n\t\tp.lock.Unlock()\r\n\t} else if p.Running() < p.Cap() {\r\n\t\tp.lock.Unlock()\r\n\t\tif cacheWorker := p.workerCache.Get(); cacheWorker != nil {\r\n\t\t\tw = ca [...]
+1,483164833,134018330,42,closed,带选项的初始化函数,我觉得用 functional options 更好一点,"""以下是示意代码\r\n如果用 functional options,原来的写法是\r\n```\r\nants.NewPool(10)\r\n```\r\n新的写法,如果不加 option,写法是不变的,因为 options 是作为可变参数传进去的。如果要加 option,只需要改成\r\n```\r\nants.NewPool(10, ants.WithNonblocking(true))\r\n```\r\n这样。\r\n\r\n现在是直接传一个 Option 结构体进去,所有的地方都要改,感觉很不优雅。\r\n具体 functional options 的设计可以看 rob pike 的一篇博客 https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html""",,,,8923413,choleraehyq,0 [...]
+1,483736247,134018330,43,closed,1.3.0 是不兼容更新,"""Pool 里那些暴露出来的字段(PanicHandler 之类的)都没了,这是一个不兼容更新,根据语义化版本的要求要发大版本。""",,,,8923413,choleraehyq,0,,652,https://github.com/panjf2000/ants/issues/43,2019-08-22T13:22:10.000+00:00,2019-08-22T02:29:34.000+00:00,2019-08-22T13:22:10.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,49,
+1,484311063,134018330,44,closed,1.1.1 -> 1.2.0 也是不兼容更新,"""Pool.Release 的返回值没了""",,,,8923413,choleraehyq,0,,3068,https://github.com/panjf2000/ants/issues/44,2019-08-25T06:36:14.000+00:00,2019-08-23T03:27:38.000+00:00,2019-08-25T06:36:14.000+00:00,,,"{""ConnectionId"":1,""Owner"":""panjf2000"",""Repo"":""ants""}",_raw_github_api_issues,50,
diff --git a/plugins/github/e2e/snapshot_tables/board_issues.csv b/plugins/github/e2e/snapshot_tables/board_issues.csv
new file mode 100644
index 00000000..9b2423b7
--- /dev/null
+++ b/plugins/github/e2e/snapshot_tables/board_issues.csv
@@ -0,0 +1,27 @@
+board_id,issue_id
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:346842831
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:347255859
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:348630179
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:356703393
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:364361014
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:381941219
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:382039050
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:382574800
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:388907811
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:401277739
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:402513849
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:405951301
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:413968505
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:419183961
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:419268851
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:424634533
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:429972115
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:433564955
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:434069015
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:435486645
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:461280653
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:462631417
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:472125082
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:483164833
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:483736247
+gitlab:GithubRepo:1:134018330,gitlab:GithubIssue:1:484311063
diff --git a/plugins/github/e2e/snapshot_tables/issue_labels.csv b/plugins/github/e2e/snapshot_tables/issue_labels.csv
new file mode 100644
index 00000000..c324c08c
--- /dev/null
+++ b/plugins/github/e2e/snapshot_tables/issue_labels.csv
@@ -0,0 +1,12 @@
+issue_id,label_name
+gitlab:GithubIssue:1:346842831,question
+gitlab:GithubIssue:1:347255859,bug
+gitlab:GithubIssue:1:348630179,bug
+gitlab:GithubIssue:1:356703393,question
+gitlab:GithubIssue:1:381941219,enhancement
+gitlab:GithubIssue:1:382039050,question
+gitlab:GithubIssue:1:382574800,enhancement
+gitlab:GithubIssue:1:401277739,enhancement
+gitlab:GithubIssue:1:402513849,enhancement
+gitlab:GithubIssue:1:433564955,enhancement
+gitlab:GithubIssue:1:434069015,enhancement
diff --git a/plugins/github/e2e/snapshot_tables/issues.csv b/plugins/github/e2e/snapshot_tables/issues.csv
new file mode 100644
index 00000000..477c87e7
--- /dev/null
+++ b/plugins/github/e2e/snapshot_tables/issues.csv
@@ -0,0 +1,27 @@
+id,url,icon_url,issue_key,title,description,epic_key,type,status,original_status,story_point,resolution_date,created_date,updated_date,lead_time_minutes,parent_issue_id,priority,original_estimate_minutes,time_spent_minutes,time_remaining_minutes,creator_id,creator_name,assignee_id,assignee_name,severity,component
+gitlab:GithubIssue:1:346842831,https://github.com/panjf2000/ants/issues/5,,5,关于 <-p.freeSignal 的疑惑,"""Hi,\r\n 我阅读了源码,对 `<-p.freeSignal` 这句代码有疑惑。 这句代码出现在了多个地方,freeSignal 的作用英文注释我是理解的,并且知道在 `putWorker` 中才进行 `p.freeSignal <- sig{}`\r\n\r\n对于下面的代码\r\n```\r\nfunc (p *Pool) getWorker() *Worker {\r\n\tvar w *Worker\r\n\twaiting := false\r\n\r\n\tp.lock.Lock()\r\n\tidleWorkers := p.workers\r\n\tn := len(idleWorkers) - 1\r\n\tif n < 0 { // 说明 pool中没有worker了\r\n\t\twaiting = p.Running() >= p.Ca [...]
+gitlab:GithubIssue:1:347255859,https://github.com/panjf2000/ants/issues/6,,6,死锁bug,"""func (p *Pool) getWorker() *Worker 这个函数的 199行 \r\n必须先解锁在加锁, 要不然会产生死锁\r\n\r\n\tp.lock.Unlock()\r\n\t\t<-p.freeSignal\r\n\t\tp.lock.Lock()""",,BUG,DONE,,0,2018-08-04T10:18:41.000+00:00,2018-08-03T04:32:28.000+00:00,2018-08-04T10:18:41.000+00:00,1786,,,0,0,0,gitlab:GithubUser:13118848,lovelly,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:348630179,https://github.com/panjf2000/ants/issues/7,,7,清理过期协程报错,"""你好,非常感谢提供这么好用的工具包。我在使用ants时,发现报异常。结果见下图\r\n![image](https://user-images.githubusercontent.com/4555057/43823431-98384444-9b21-11e8-880c-7458b931734a.png)\r\n日志是我在periodicallyPurge里加的调试信息\r\n![image](https://user-images.githubusercontent.com/4555057/43823534-e3c624a8-9b21-11e8-96c6-512e3e08db22.png)\r\n\r\n### 原因分析\r\n\r\n我认为可能原因是没有处理n==0的情况\r\n```\r\nif n > 0 {\r\n\tn++\r\n\tp.workers = idleWorkers[n: [...]
+gitlab:GithubIssue:1:356703393,https://github.com/panjf2000/ants/issues/10,,10,高并发下设定较小的worker数量问题,"""会存在cpu飚升的问题吧?""",,,DONE,,0,2018-09-29T11:45:00.000+00:00,2018-09-04T08:26:55.000+00:00,2018-09-29T11:45:00.000+00:00,36198,,,0,0,0,gitlab:GithubUser:11763614,Moonlight-Zhao,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:364361014,https://github.com/panjf2000/ants/issues/12,,12,潘少,更新下tag吧,"""鄙人现在在弄dep依赖管理,有用到你写的ants项目,可是你好像忘记打最新的tag了。最新的tag 3.6是指向ed55924这个提交,git上的最新代码是af376f1b这次提交,两次提交都隔了快5个月了,看到的话,麻烦打一个最新的tag吧。(手动可怜)""",,,DONE,,0,2018-09-28T06:05:58.000+00:00,2018-09-27T08:32:25.000+00:00,2019-04-21T08:19:58.000+00:00,1293,,,0,0,0,gitlab:GithubUser:29452204,edcismybrother,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:381941219,https://github.com/panjf2000/ants/issues/17,,17,关于优雅退出的问题,"""关于这个package优雅退出的问题,我看了一下Release的代码:\r\n\r\n`\r\n\t// Release Closed this pool.\r\n\tfunc (p *PoolWithFunc) Release() error {\r\n\t\tp.once.Do(func() {\r\n\t\t\tp.release <- sig{}\r\n\t\t\tp.lock.Lock()\r\n\t\t\tidleWorkers := p.workers\r\n\t\t\tfor i, w := range idleWorkers {\r\n\t\t\t\tw.args <- nil\r\n\t\t\t\tidleWorkers[i] = nil\r\n\t\t\t}\r\n\t\t\tp.workers = nil\r\n\t\t\tp.lock.Unlock()\r\n\t [...]
+gitlab:GithubIssue:1:382039050,https://github.com/panjf2000/ants/issues/18,,18,go协程的理解,"""你好楼主,向您请教一个协程和线程的问题,协程基于go进程调度,线程基于系统内核调度,调度协程的过程是先调度线程后获得资源再去调度协程。\""官方解释: GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously。限制cpu数,本质上是什么,限制并行数?,并行数即同时执行数量?,执行单元即线程?,即限制最大并行线程数量?\""""",,,DONE,,0,2018-12-03T03:53:50.000+00:00,2018-11-19T02:59:53.000+00:00,2018-12-03T03:53:50.000+00:00,20213,,,0,0,0,gitlab:GithubUser:13944100,LinuxForYQH,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:382574800,https://github.com/panjf2000/ants/issues/20,,20,是否考虑任务支持回调函数处理失败的逻辑和任务依赖,"""#""",,,DONE,,0,2019-01-25T15:34:03.000+00:00,2018-11-20T09:36:02.000+00:00,2019-01-25T15:34:03.000+00:00,95398,,,0,0,0,gitlab:GithubUser:5668717,kklinan,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:388907811,https://github.com/panjf2000/ants/issues/21,,21,Benchmark 下直接使用 Semaphore 似乎更快呢?,"""简单跑了一下 benchmark,Semaphore 更快且很简单\r\n\r\n```bash\r\n$ go test -bench .\r\ngoos: darwin\r\ngoarch: amd64\r\npkg: github.com/panjf2000/ants\r\nBenchmarkGoroutineWithFunc-4 \t 1\t3445631705 ns/op\r\nBenchmarkSemaphoreWithFunc-4 \t 1\t1037219073 ns/op\r\nBenchmarkAntsPoolWithFunc-4 \t 1\t1138053222 ns/op\r\nBenchmarkGoroutine-4 \t 2\t 731 [...]
+gitlab:GithubIssue:1:401277739,https://github.com/panjf2000/ants/issues/22,,22,是否考虑 worker 中添加 PanicHandler ?,"""比方说在创建 Pool 的时候传入一个 PanicHandler,然后在每个 worker 创建的时候 recover 之后传给 PanicHandler 处理。否则池子里如果发生 panic 会直接挂掉整个进程。""",,,DONE,,0,2019-01-22T05:41:34.000+00:00,2019-01-21T10:06:56.000+00:00,2019-01-22T05:41:34.000+00:00,1174,,,0,0,0,gitlab:GithubUser:8923413,choleraehyq,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:402513849,https://github.com/panjf2000/ants/issues/24,,24,提交任务不阻塞,"""`Pool.Submit`和`PoolWithFunc.Server`提交任务,如果没有空的worker,会一直阻塞。建议增加不阻塞的接口,当前失败时直接返回错误。""",,,DONE,,0,2019-08-20T10:56:30.000+00:00,2019-01-24T02:24:13.000+00:00,2019-08-20T10:56:30.000+00:00,300032,,,0,0,0,gitlab:GithubUser:5044825,tenfyzhong,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:405951301,https://github.com/panjf2000/ants/issues/25,,25,use example errors,"""./antstest.go:37:14: cannot use syncCalculateSum (type func()) as type ants.f in argument to ants.Submit\r\n./antstest.go:45:35: cannot use func literal (type func(interface {})) as type ants.pf in argument to ants.NewPoolWithFunc\r\n""",,,DONE,,0,2019-02-04T09:11:52.000+00:00,2019-02-02T05:43:38.000+00:00,2019-02-04T09:11:52.000+00:00,3088,,,0,0,0,gitlab:GithubUser:5244267,jiashiwen,gitl [...]
+gitlab:GithubIssue:1:413968505,https://github.com/panjf2000/ants/issues/26,,26,running可能大于cap的问题,"""running与cap的比较判断与incRuning分开执行的, 可能会出现running大于cap的问题?\r\n`func (p *Pool) retrieveWorker() *Worker {\r\n\tvar w *Worker\r\n\r\n\tp.lock.Lock()\r\n\tidleWorkers := p.workers\r\n\tn := len(idleWorkers) - 1\r\n\tif n >= 0 {\r\n\t\tw = idleWorkers[n]\r\n\t\tidleWorkers[n] = nil\r\n\t\tp.workers = idleWorkers[:n]\r\n\t\tp.lock.Unlock()\r\n\t} else if p.Running() < p.Cap() {\r\n\t\tp.lock.Unlock [...]
+gitlab:GithubIssue:1:419183961,https://github.com/panjf2000/ants/issues/27,,27,为何goroutine一直上不去,用户量也打不上去,"""为何goroutine一直上不去,用户量也打不上去\r\n是我用的有问题吗?\r\n\r\nwebsocket server\r\nhttps://github.com/im-ai/pushm/blob/master/learn/goroutine/goroutinepoolwebsocket.go\r\n\r\nwebsocket cient\r\nhttps://github.com/im-ai/pushm/blob/master/learn/goroutine/goroutinepoolwebsocketclient.go\r\n""",,,DONE,,0,2019-04-05T14:05:20.000+00:00,2019-03-10T13:08:52.000+00:00,2019-04-05T14:05:20.000+00:00,37496,,,0 [...]
+gitlab:GithubIssue:1:419268851,https://github.com/panjf2000/ants/issues/28,,28,cap 和 running 比较的问题,"""这是我在 Playground 上面的代码 https://play.golang.org/p/D94YUU3FnX6\r\natomic 只能保证自增自减时的原子操作,在比较过程中,其他线程对变量进行了操作 比较过程并无感知,所以这个比较结果 不是完全正确的,想要实现 比较的数量完全正确,只能在修改和比较两个值的地方加锁\r\n像 #26 说的是对的""",,,DONE,,0,2019-08-22T16:27:37.000+00:00,2019-03-11T02:24:41.000+00:00,2019-08-22T16:27:37.000+00:00,237002,,,0,0,0,gitlab:GithubUser:29243953,naiba,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:424634533,https://github.com/panjf2000/ants/issues/29,,29,任务传参,"""你好,你的项目太酷了👍\r\n\r\nhttps://github.com/panjf2000/ants/blob/master/pool.go#L124 貌似不支持带参数的任务, 请问传参是用闭包的方式吗?\r\n""",,,DONE,,0,2019-03-25T09:32:11.000+00:00,2019-03-24T16:52:21.000+00:00,2019-03-25T09:45:05.000+00:00,999,,,0,0,0,gitlab:GithubUser:8509898,prprprus,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:429972115,https://github.com/panjf2000/ants/issues/31,,31,Add go.mod,"""""",,,DONE,,0,2019-04-08T09:45:31.000+00:00,2019-04-05T23:50:36.000+00:00,2019-10-17T03:12:19.000+00:00,3474,,,0,0,0,gitlab:GithubUser:48135919,tsatke,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:433564955,https://github.com/panjf2000/ants/issues/32,,32,关于版本问题,我发现小版本(0.0.x)这种更新就会不向下兼容?,"""如题,我感觉这样不好。\r\n\r\n功能版本号不向下兼容能理解\r\n\r\n修复问题的版本号也不向下兼容,难以理解。""",,,DONE,,0,2019-04-21T07:16:26.000+00:00,2019-04-16T03:16:02.000+00:00,2019-04-21T07:16:26.000+00:00,7440,,,0,0,0,gitlab:GithubUser:7931755,zplzpl,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:434069015,https://github.com/panjf2000/ants/issues/33,,33,support semantic versioning.,"""建议将发布的tag兼容为semantic versioning,vX.Y.Z。go modules对此支持比较良好。\r\nhttps://semver.org/\r\nhttps://research.swtch.com/vgo-import""",,,DONE,,0,2019-04-21T08:25:20.000+00:00,2019-04-17T02:55:11.000+00:00,2019-04-21T08:25:20.000+00:00,6090,,,0,0,0,gitlab:GithubUser:1284892,jjeffcaii,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:435486645,https://github.com/panjf2000/ants/issues/34,,34,Important announcement about <ants> from author !!!,"""**Dear users of `ants`:**\r\nI am apologetically telling you that I have to dump all tags which already presents in `ants` repository.\r\n\r\nThe reason why I'm doing so is to standardize the version management with `Semantic Versioning`, which will make a formal and clear dependency management in go, for go modules, godep, or glide, etc. So I decide to st [...]
+gitlab:GithubIssue:1:461280653,https://github.com/panjf2000/ants/issues/35,,35,worker exit on panic,"""个人认为PanicHandler设计不妥。\r\n1.无PanicHandler时,抛出给外面的不是panic,外层感受不到。\r\n2.无论有没有PanicHandler,都会导致worker退出,最终pool阻塞住全部任务。""",,,DONE,,0,2019-08-17T20:33:10.000+00:00,2019-06-27T03:11:49.000+00:00,2019-08-17T20:33:10.000+00:00,74481,,,0,0,0,gitlab:GithubUser:38849208,king526,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:462631417,https://github.com/panjf2000/ants/issues/37,,37,请不要再随意变更版本号了。。。,"""之前用的是 3.9.9,结果今天构建出了问题,一看发现这个版本没了,变成 1.0.0。这种变更完全不考虑现有用户的情况。希望以后不要随意变更了""",,,DONE,,0,2019-07-01T12:37:55.000+00:00,2019-07-01T10:17:15.000+00:00,2019-07-02T10:17:31.000+00:00,140,,,0,0,0,gitlab:GithubUser:8923413,choleraehyq,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:472125082,https://github.com/panjf2000/ants/issues/38,,38,retrieveWorker与revertWorker之间会导致死锁,"""func (p *Pool) retrieveWorker() *Worker {\r\n\tvar w *Worker\r\n\r\n\t**p.lock.Lock()**\r\n\tidleWorkers := p.workers\r\n\tn := len(idleWorkers) - 1\r\n\tif n >= 0 {\r\n\t\tw = idleWorkers[n]\r\n\t\tidleWorkers[n] = nil\r\n\t\tp.workers = idleWorkers[:n]\r\n\t\tp.lock.Unlock()\r\n\t} else if p.Running() < p.Cap() {\r\n\t\tp.lock.Unlock()\r\n\t\tif cacheWorker := p.workerCa [...]
+gitlab:GithubIssue:1:483164833,https://github.com/panjf2000/ants/issues/42,,42,带选项的初始化函数,我觉得用 functional options 更好一点,"""以下是示意代码\r\n如果用 functional options,原来的写法是\r\n```\r\nants.NewPool(10)\r\n```\r\n新的写法,如果不加 option,写法是不变的,因为 options 是作为可变参数传进去的。如果要加 option,只需要改成\r\n```\r\nants.NewPool(10, ants.WithNonblocking(true))\r\n```\r\n这样。\r\n\r\n现在是直接传一个 Option 结构体进去,所有的地方都要改,感觉很不优雅。\r\n具体 functional options 的设计可以看 rob pike 的一篇博客 https://commandcenter.blogspot.com/2014/01/self-referential-functi [...]
+gitlab:GithubIssue:1:483736247,https://github.com/panjf2000/ants/issues/43,,43,1.3.0 是不兼容更新,"""Pool 里那些暴露出来的字段(PanicHandler 之类的)都没了,这是一个不兼容更新,根据语义化版本的要求要发大版本。""",,,DONE,,0,2019-08-22T13:22:10.000+00:00,2019-08-22T02:29:34.000+00:00,2019-08-22T13:22:10.000+00:00,652,,,0,0,0,gitlab:GithubUser:8923413,choleraehyq,gitlab:GithubUser:0,,,
+gitlab:GithubIssue:1:484311063,https://github.com/panjf2000/ants/issues/44,,44,1.1.1 -> 1.2.0 也是不兼容更新,"""Pool.Release 的返回值没了""",,,DONE,,0,2019-08-25T06:36:14.000+00:00,2019-08-23T03:27:38.000+00:00,2019-08-25T06:36:14.000+00:00,3068,,,0,0,0,gitlab:GithubUser:8923413,choleraehyq,gitlab:GithubUser:0,,,
diff --git a/plugins/github/models/issue.go b/plugins/github/models/issue.go
index b99cfa46..b508e55d 100644
--- a/plugins/github/models/issue.go
+++ b/plugins/github/models/issue.go
@@ -23,6 +23,7 @@ import (
)
type GithubIssue struct {
+ ConnectionId uint64 `gorm:"primaryKey"`
GithubId int `gorm:"primaryKey"`
RepoId int `gorm:"index"`
Number int `gorm:"index;comment:Used in API requests ex. api/repo/1/issue/<THIS_NUMBER>"`
diff --git a/plugins/github/models/issue_label.go b/plugins/github/models/issue_label.go
index 6bd74a8c..5cc960d1 100644
--- a/plugins/github/models/issue_label.go
+++ b/plugins/github/models/issue_label.go
@@ -25,8 +25,9 @@ import (
// Pull Requests are considered Issues in GitHub.
type GithubIssueLabel struct {
- IssueId int `gorm:"primaryKey;autoIncrement:false"`
- LabelName string `gorm:"primaryKey;type:varchar(255)"`
+ ConnectionId uint64 `gorm:"primaryKey"`
+ IssueId int `gorm:"primaryKey;autoIncrement:false"`
+ LabelName string `gorm:"primaryKey;type:varchar(255)"`
common.NoPKModel
}
diff --git a/plugins/github/models/migrationscripts/archived/issue.go b/plugins/github/models/migrationscripts/archived/issue.go
index ff465b8b..09af0e6e 100644
--- a/plugins/github/models/migrationscripts/archived/issue.go
+++ b/plugins/github/models/migrationscripts/archived/issue.go
@@ -24,6 +24,7 @@ import (
)
type GithubIssue struct {
+ ConnectionId uint64 `gorm:"primaryKey"`
GithubId int `gorm:"primaryKey"`
RepoId int `gorm:"index"`
Number int `gorm:"index;comment:Used in API requests ex. api/repo/1/issue/<THIS_NUMBER>"`
diff --git a/plugins/github/models/migrationscripts/archived/issue_label.go b/plugins/github/models/migrationscripts/archived/issue_label.go
index e37b2b34..dc6bc7cd 100644
--- a/plugins/github/models/migrationscripts/archived/issue_label.go
+++ b/plugins/github/models/migrationscripts/archived/issue_label.go
@@ -23,8 +23,9 @@ import "github.com/apache/incubator-devlake/models/migrationscripts/archived"
// Pull Requests are considered Issues in GitHub.
type GithubIssueLabel struct {
- IssueId int `gorm:"primaryKey;autoIncrement:false"`
- LabelName string `gorm:"primaryKey;type:varchar(255)"`
+ ConnectionId uint64 `gorm:"primaryKey"`
+ IssueId int `gorm:"primaryKey;autoIncrement:false"`
+ LabelName string `gorm:"primaryKey;type:varchar(255)"`
archived.NoPKModel
}
diff --git a/plugins/github/models/migrationscripts/init_schema_20220610.go b/plugins/github/models/migrationscripts/init_schema_20220611.go
similarity index 98%
rename from plugins/github/models/migrationscripts/init_schema_20220610.go
rename to plugins/github/models/migrationscripts/init_schema_20220611.go
index d684f767..23acfce8 100644
--- a/plugins/github/models/migrationscripts/init_schema_20220610.go
+++ b/plugins/github/models/migrationscripts/init_schema_20220611.go
@@ -131,9 +131,9 @@ func (u *InitSchemas) Up(ctx context.Context, db *gorm.DB) error {
}
func (*InitSchemas) Version() uint64 {
- return 20220610000001
+ return 20220611000001
}
func (*InitSchemas) Name() string {
- return "Github init schemas 20220610"
+ return "Github init schemas 20220611"
}
diff --git a/plugins/github/tasks/issue_collector.go b/plugins/github/tasks/issue_collector.go
index 89f11cd0..fe378c0b 100644
--- a/plugins/github/tasks/issue_collector.go
+++ b/plugins/github/tasks/issue_collector.go
@@ -20,6 +20,7 @@ package tasks
import (
"encoding/json"
"fmt"
+ "github.com/apache/incubator-devlake/plugins/core/dal"
"net/http"
"net/url"
@@ -46,7 +47,7 @@ var CollectApiIssuesMeta = core.SubTaskMeta{
}
func CollectApiIssues(taskCtx core.SubTaskContext) error {
- db := taskCtx.GetDb()
+ db := taskCtx.GetDal()
data := taskCtx.GetData().(*GithubTaskData)
since := data.Since
@@ -54,9 +55,12 @@ func CollectApiIssues(taskCtx core.SubTaskContext) error {
// user didn't specify a time range to sync, try load from database
if since == nil {
var latestUpdated models.GithubIssue
- err := db.Model(&latestUpdated).
- Where("repo_id = ?", data.Repo.GithubId).
- Order("github_updated_at DESC").Limit(1).Find(&latestUpdated).Error
+ err := db.All(
+ &latestUpdated,
+ dal.Where("repo_id = ? and connection_id = ?", data.Repo.GithubId, data.Repo.ConnectionId),
+ dal.Orderby("github_updated_at DESC"),
+ dal.Limit(1),
+ )
if err != nil {
return fmt.Errorf("failed to get latest github issue record: %w", err)
}
@@ -74,8 +78,9 @@ func CollectApiIssues(taskCtx core.SubTaskContext) error {
set of data to be process, for example, we process JiraIssues by Board
*/
Params: GithubApiParams{
- Owner: data.Options.Owner,
- Repo: data.Options.Repo,
+ ConnectionId: data.Options.ConnectionId,
+ Owner: data.Options.Owner,
+ Repo: data.Options.Repo,
},
/*
Table store raw data
diff --git a/plugins/github/tasks/issue_convertor.go b/plugins/github/tasks/issue_convertor.go
index f7aa338d..477b3fa9 100644
--- a/plugins/github/tasks/issue_convertor.go
+++ b/plugins/github/tasks/issue_convertor.go
@@ -18,6 +18,7 @@ limitations under the License.
package tasks
import (
+ "github.com/apache/incubator-devlake/plugins/core/dal"
"reflect"
"strconv"
@@ -38,13 +39,15 @@ var ConvertIssuesMeta = core.SubTaskMeta{
}
func ConvertIssues(taskCtx core.SubTaskContext) error {
- db := taskCtx.GetDb()
+ db := taskCtx.GetDal()
data := taskCtx.GetData().(*GithubTaskData)
repoId := data.Repo.GithubId
issue := &githubModels.GithubIssue{}
- cursor, err := db.Model(issue).Where("repo_id = ?", repoId).Rows()
-
+ cursor, err := db.Cursor(
+ dal.From(issue),
+ dal.Where("repo_id = ? and connection_id=?", repoId, data.Options.ConnectionId),
+ )
if err != nil {
return err
}
@@ -58,8 +61,9 @@ func ConvertIssues(taskCtx core.SubTaskContext) error {
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Ctx: taskCtx,
Params: GithubApiParams{
- Owner: data.Options.Owner,
- Repo: data.Options.Repo,
+ ConnectionId: data.Options.ConnectionId,
+ Owner: data.Options.Owner,
+ Repo: data.Options.Repo,
},
Table: RAW_ISSUE_TABLE,
},
@@ -68,7 +72,7 @@ func ConvertIssues(taskCtx core.SubTaskContext) error {
Convert: func(inputRow interface{}) ([]interface{}, error) {
issue := inputRow.(*githubModels.GithubIssue)
domainIssue := &ticket.Issue{
- DomainEntity: domainlayer.DomainEntity{Id: issueIdGen.Generate(issue.GithubId)},
+ DomainEntity: domainlayer.DomainEntity{Id: issueIdGen.Generate(data.Options.ConnectionId, issue.GithubId)},
IssueKey: strconv.Itoa(issue.Number),
Title: issue.Title,
Description: issue.Body,
@@ -92,7 +96,7 @@ func ConvertIssues(taskCtx core.SubTaskContext) error {
domainIssue.Status = ticket.TODO
}
boardIssue := &ticket.BoardIssue{
- BoardId: boardIdGen.Generate(repoId),
+ BoardId: boardIdGen.Generate(data.Options.ConnectionId, repoId),
IssueId: domainIssue.Id,
}
return []interface{}{
diff --git a/plugins/github/tasks/issue_extractor.go b/plugins/github/tasks/issue_extractor.go
index 8581112f..6abbeffa 100644
--- a/plugins/github/tasks/issue_extractor.go
+++ b/plugins/github/tasks/issue_extractor.go
@@ -39,7 +39,7 @@ type IssuesResponse struct {
Number int
State string
Title string
- Body string
+ Body json.RawMessage
HtmlUrl string `json:"html_url"`
PullRequest struct {
Url string `json:"url"`
@@ -104,8 +104,9 @@ func ExtractApiIssues(taskCtx core.SubTaskContext) error {
set of data to be process, for example, we process JiraIssues by Board
*/
Params: GithubApiParams{
- Owner: data.Options.Owner,
- Repo: data.Options.Repo,
+ ConnectionId: data.Options.ConnectionId,
+ Owner: data.Options.Owner,
+ Repo: data.Options.Repo,
},
/*
Table store raw data
@@ -127,14 +128,15 @@ func ExtractApiIssues(taskCtx core.SubTaskContext) error {
return nil, nil
}
results := make([]interface{}, 0, 2)
- githubIssue, err := convertGithubIssue(body, data.Repo.GithubId)
+ githubIssue, err := convertGithubIssue(body, data.Options.ConnectionId, data.Repo.GithubId)
if err != nil {
return nil, err
}
for _, label := range body.Labels {
results = append(results, &models.GithubIssueLabel{
- IssueId: githubIssue.GithubId,
- LabelName: label.Name,
+ ConnectionId: data.Options.ConnectionId,
+ IssueId: githubIssue.GithubId,
+ LabelName: label.Name,
})
if issueSeverityRegex != nil {
groups := issueSeverityRegex.FindStringSubmatch(label.Name)
@@ -187,14 +189,15 @@ func ExtractApiIssues(taskCtx core.SubTaskContext) error {
return extractor.Execute()
}
-func convertGithubIssue(issue *IssuesResponse, repositoryId int) (*models.GithubIssue, error) {
+func convertGithubIssue(issue *IssuesResponse, connectionId uint64, repositoryId int) (*models.GithubIssue, error) {
githubIssue := &models.GithubIssue{
+ ConnectionId: connectionId,
GithubId: issue.GithubId,
RepoId: repositoryId,
Number: issue.Number,
State: issue.State,
Title: issue.Title,
- Body: issue.Body,
+ Body: string(issue.Body),
Url: issue.HtmlUrl,
ClosedAt: helper.Iso8601TimeToTime(issue.ClosedAt),
GithubCreatedAt: issue.GithubCreatedAt.ToTime(),
diff --git a/plugins/github/tasks/issue_label_convertor.go b/plugins/github/tasks/issue_label_convertor.go
index b2ece5dc..6ba44d77 100644
--- a/plugins/github/tasks/issue_label_convertor.go
+++ b/plugins/github/tasks/issue_label_convertor.go
@@ -18,6 +18,7 @@ limitations under the License.
package tasks
import (
+ "github.com/apache/incubator-devlake/plugins/core/dal"
"reflect"
"github.com/apache/incubator-devlake/models/domainlayer/didgen"
@@ -35,15 +36,16 @@ var ConvertIssueLabelsMeta = core.SubTaskMeta{
}
func ConvertIssueLabels(taskCtx core.SubTaskContext) error {
- db := taskCtx.GetDb()
+ db := taskCtx.GetDal()
data := taskCtx.GetData().(*GithubTaskData)
repoId := data.Repo.GithubId
- cursor, err := db.Model(&githubModels.GithubIssueLabel{}).
- Joins(`left join _tool_github_issues on _tool_github_issues.github_id = _tool_github_issue_labels.issue_id`).
- Where("_tool_github_issues.repo_id = ?", repoId).
- Order("issue_id ASC").
- Rows()
+ cursor, err := db.Cursor(
+ dal.From(&githubModels.GithubIssueLabel{}),
+ dal.Join(`left join _tool_github_issues on _tool_github_issues.github_id = _tool_github_issue_labels.issue_id`),
+ dal.Where("_tool_github_issues.repo_id = ? and _tool_github_issues.connection_id = ?", repoId, data.Options.ConnectionId),
+ dal.Orderby("issue_id ASC"),
+ )
if err != nil {
return err
}
@@ -54,8 +56,9 @@ func ConvertIssueLabels(taskCtx core.SubTaskContext) error {
RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
Ctx: taskCtx,
Params: GithubApiParams{
- Owner: data.Options.Owner,
- Repo: data.Options.Repo,
+ ConnectionId: data.Options.ConnectionId,
+ Owner: data.Options.Owner,
+ Repo: data.Options.Repo,
},
Table: RAW_ISSUE_TABLE,
},
@@ -64,7 +67,7 @@ func ConvertIssueLabels(taskCtx core.SubTaskContext) error {
Convert: func(inputRow interface{}) ([]interface{}, error) {
issueLabel := inputRow.(*githubModels.GithubIssueLabel)
domainIssueLabel := &ticket.IssueLabel{
- IssueId: issueIdGen.Generate(issueLabel.IssueId),
+ IssueId: issueIdGen.Generate(data.Options.ConnectionId, issueLabel.IssueId),
LabelName: issueLabel.LabelName,
}
return []interface{}{