cherry-pick #3664 to 0.14 (#3665)

* fix: replace number with databaseId in issue.id

* fix: deal 30/page for pr in github graphql

* fix: fix a wrong err check

Co-authored-by: linyh <yanghui@meri.co>
diff --git a/plugins/core/dal/dal.go b/plugins/core/dal/dal.go
index 3a31e1d..5e82082 100644
--- a/plugins/core/dal/dal.go
+++ b/plugins/core/dal/dal.go
@@ -62,11 +62,11 @@
 	Cursor(clauses ...Clause) (*sql.Rows, errors.Error)
 	// Fetch loads row data from `cursor` into `dst`
 	Fetch(cursor *sql.Rows, dst interface{}) errors.Error
-	// All loads matched rows from database to `dst`, USE IT WITH COUTIOUS!!
+	// All loads matched rows from database to `dst`, USE IT WITH CAUTIOUS!!
 	All(dst interface{}, clauses ...Clause) errors.Error
 	// First loads first matched row from database to `dst`, error will be returned if no records were found
 	First(dst interface{}, clauses ...Clause) errors.Error
-	// All loads matched rows from database to `dst`, USE IT WITH COUTIOUS!!
+	// Count matched rows from database
 	Count(clauses ...Clause) (int64, errors.Error)
 	// Pluck used to query single column
 	Pluck(column string, dest interface{}, clauses ...Clause) errors.Error
@@ -86,7 +86,7 @@
 	AllTables() ([]string, errors.Error)
 	// GetColumns returns table columns in database
 	GetColumns(dst schema.Tabler, filter func(columnMeta ColumnMeta) bool) (cms []ColumnMeta, err errors.Error)
-	// GetPrimarykeyFields get the PrimaryKey from `gorm` tag
+	// GetPrimaryKeyFields get the PrimaryKey from `gorm` tag
 	GetPrimaryKeyFields(t reflect.Type) []reflect.StructField
 	// Dialect returns the dialect of current database
 	Dialect() string
diff --git a/plugins/github_graphql/plugin_main.go b/plugins/github_graphql/plugin_main.go
index a2a8b84..85fc2aa 100644
--- a/plugins/github_graphql/plugin_main.go
+++ b/plugins/github_graphql/plugin_main.go
@@ -59,6 +59,10 @@
 func (plugin GithubGraphql) SubTaskMetas() []core.SubTaskMeta {
 	return []core.SubTaskMeta{
 		tasks.CollectRepoMeta,
+
+		githubTasks.CollectMilestonesMeta,
+		githubTasks.ExtractMilestonesMeta,
+
 		tasks.CollectIssueMeta,
 		tasks.CollectPrMeta,
 
@@ -66,8 +70,6 @@
 		githubTasks.ExtractApiCommentsMeta,
 		githubTasks.CollectApiEventsMeta,
 		githubTasks.ExtractApiEventsMeta,
-		githubTasks.CollectMilestonesMeta,
-		githubTasks.ExtractMilestonesMeta,
 		githubTasks.CollectApiPrReviewCommentsMeta,
 		githubTasks.ExtractApiPrReviewCommentsMeta,
 
diff --git a/plugins/github_graphql/tasks/issue_collector.go b/plugins/github_graphql/tasks/issue_collector.go
index 9ceb85a..7315ee8 100644
--- a/plugins/github_graphql/tasks/issue_collector.go
+++ b/plugins/github_graphql/tasks/issue_collector.go
@@ -21,6 +21,7 @@
 	"github.com/apache/incubator-devlake/errors"
 	"github.com/apache/incubator-devlake/models/domainlayer/ticket"
 	"github.com/apache/incubator-devlake/plugins/core"
+	"github.com/apache/incubator-devlake/plugins/core/dal"
 	"github.com/apache/incubator-devlake/plugins/github/models"
 	githubTasks "github.com/apache/incubator-devlake/plugins/github/tasks"
 	"github.com/apache/incubator-devlake/plugins/helper"
@@ -61,12 +62,12 @@
 		Assignees []GraphqlInlineAccountQuery `graphql:"nodes"`
 	} `graphql:"assignees(first: 1)"`
 	Milestone *struct {
-		Number int `json:"number"`
+		Number int
 	} `json:"milestone"`
 	Labels struct {
 		Nodes []struct {
-			Id   string `json:"id"`
-			Name string `json:"name"`
+			Id   string
+			Name string
 		}
 	} `graphql:"labels(first: 100)"`
 }
@@ -81,6 +82,7 @@
 var _ core.SubTaskEntryPoint = CollectIssue
 
 func CollectIssue(taskCtx core.SubTaskContext) errors.Error {
+	db := taskCtx.GetDal()
 	data := taskCtx.GetData().(*githubTasks.GithubTaskData)
 	config := data.Options.TransformationRules
 	issueRegexes, err := githubTasks.NewIssueRegexes(config)
@@ -88,13 +90,14 @@
 		return nil
 	}
 
+	milestoneMap, err := getMilestoneMap(db, data.Repo.GithubId, data.Repo.ConnectionId)
+	if err != nil {
+		return nil
+	}
+
 	collector, err := helper.NewGraphqlCollector(helper.GraphqlCollectorArgs{
 		RawDataSubTaskArgs: helper.RawDataSubTaskArgs{
 			Ctx: taskCtx,
-			/*
-				This struct will be JSONEncoded and stored into database along with raw data itself, to identity minimal
-				set of data to be process, for example, we process JiraIssues by Board
-			*/
 			Params: githubTasks.GithubApiParams{
 				ConnectionId: data.Options.ConnectionId,
 				Owner:        data.Options.Owner,
@@ -104,9 +107,6 @@
 		},
 		GraphqlClient: data.GraphqlClient,
 		PageSize:      100,
-		/*
-			(Optional) Return query string for request, or you can plug them into UrlTemplate directly
-		*/
 		BuildQuery: func(reqData *helper.GraphqlRequestData) (interface{}, map[string]interface{}, error) {
 			query := &GraphqlQueryIssueWrapper{}
 			variables := map[string]interface{}{
@@ -127,7 +127,7 @@
 
 			results := make([]interface{}, 0, 1)
 			for _, issue := range issues {
-				githubIssue, err := convertGithubIssue(issue, data.Options.ConnectionId, data.Repo.GithubId)
+				githubIssue, err := convertGithubIssue(milestoneMap, issue, data.Options.ConnectionId, data.Repo.GithubId)
 				if err != nil {
 					return nil, err
 				}
@@ -163,7 +163,29 @@
 	return collector.Execute()
 }
 
-func convertGithubIssue(issue GraphqlQueryIssue, connectionId uint64, repositoryId int) (*models.GithubIssue, errors.Error) {
+// create a milestone map for numberId to databaseId
+func getMilestoneMap(db dal.Dal, repoId int, connectionId uint64) (map[int]int, errors.Error) {
+	milestoneMap := map[int]int{}
+	var milestones []struct {
+		MilestoneId int
+		RepoId      int
+		Number      int
+	}
+	err := db.All(
+		&milestones,
+		dal.From(&models.GithubMilestone{}),
+		dal.Where("repo_id = ? and connection_id = ?", repoId, connectionId),
+	)
+	if err != nil {
+		return nil, err
+	}
+	for _, milestone := range milestones {
+		milestoneMap[milestone.Number] = milestone.MilestoneId
+	}
+	return milestoneMap, nil
+}
+
+func convertGithubIssue(milestoneMap map[int]int, issue GraphqlQueryIssue, connectionId uint64, repositoryId int) (*models.GithubIssue, errors.Error) {
 	githubIssue := &models.GithubIssue{
 		ConnectionId:    connectionId,
 		GithubId:        issue.DatabaseId,
@@ -189,7 +211,9 @@
 		githubIssue.LeadTimeMinutes = uint(issue.ClosedAt.Sub(issue.CreatedAt).Minutes())
 	}
 	if issue.Milestone != nil {
-		githubIssue.MilestoneId = issue.Milestone.Number
+		if milestoneId, ok := milestoneMap[issue.Milestone.Number]; ok {
+			githubIssue.MilestoneId = milestoneId
+		}
 	}
 	return githubIssue, nil
 }
diff --git a/plugins/github_graphql/tasks/pr_collector.go b/plugins/github_graphql/tasks/pr_collector.go
index a56a33b..fc0be69 100644
--- a/plugins/github_graphql/tasks/pr_collector.go
+++ b/plugins/github_graphql/tasks/pr_collector.go
@@ -154,7 +154,7 @@
 			Table: RAW_PRS_TABLE,
 		},
 		GraphqlClient: data.GraphqlClient,
-		PageSize:      100,
+		PageSize:      30,
 		/*
 			(Optional) Return query string for request, or you can plug them into UrlTemplate directly
 		*/
diff --git a/plugins/helper/graphql_collector.go b/plugins/helper/graphql_collector.go
index 1091e19..c03a9ee 100644
--- a/plugins/helper/graphql_collector.go
+++ b/plugins/helper/graphql_collector.go
@@ -264,7 +264,9 @@
 	}
 	if len(dataErrors) > 0 {
 		if collector.args.ResponseParserWithDataErrors == nil {
-			collector.checkError(errors.Default.Wrap(err, `graphql query got error`))
+			for _, dataError := range dataErrors {
+				collector.checkError(errors.Default.Wrap(dataError, `graphql query got error`))
+			}
 			return
 		}
 		// else: error will deal by ResponseParserWithDataErrors