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 ce4015a76 chore: resolve conflits (#5295)
ce4015a76 is described below
commit ce4015a76d211b87a85afbac702d9c36bc05cec4
Author: Liang Zhang <[email protected]>
AuthorDate: Wed Jun 7 12:05:34 2023 +0800
chore: resolve conflits (#5295)
---
backend/plugins/github/api/init.go | 6 +
backend/plugins/github/api/remote.go | 285 +++++++++++++++++++++++++++++++++++
backend/plugins/github/impl/impl.go | 6 +
3 files changed, 297 insertions(+)
diff --git a/backend/plugins/github/api/init.go
b/backend/plugins/github/api/init.go
index 9657f5918..4201779c9 100644
--- a/backend/plugins/github/api/init.go
+++ b/backend/plugins/github/api/init.go
@@ -33,6 +33,7 @@ var connectionHelper *api.ConnectionApiHelper
var scopeHelper *api.ScopeApiHelper[models.GithubConnection,
models.GithubRepo, models.GithubScopeConfig]
var basicRes context.BasicRes
var scHelper *api.ScopeConfigHelper[models.GithubScopeConfig]
+var remoteHelper *api.RemoteApiHelper[models.GithubConnection,
models.GithubRepo, repo, org]
func Init(br context.BasicRes) {
basicRes = br
@@ -74,4 +75,9 @@ func Init(br context.BasicRes) {
basicRes,
vld,
)
+ remoteHelper = api.NewRemoteHelper[models.GithubConnection,
models.GithubRepo, repo, org](
+ basicRes,
+ vld,
+ connectionHelper,
+ )
}
diff --git a/backend/plugins/github/api/remote.go
b/backend/plugins/github/api/remote.go
new file mode 100644
index 000000000..64e3af44a
--- /dev/null
+++ b/backend/plugins/github/api/remote.go
@@ -0,0 +1,285 @@
+/*
+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 api
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "net/url"
+ "strconv"
+ "time"
+
+ context2 "github.com/apache/incubator-devlake/core/context"
+ "github.com/apache/incubator-devlake/core/errors"
+ "github.com/apache/incubator-devlake/core/plugin"
+ "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
+ "github.com/apache/incubator-devlake/plugins/github/models"
+)
+
+type org struct {
+ Login string `json:"login"`
+ ID int `json:"id"`
+ NodeID string `json:"node_id"`
+ URL string `json:"url"`
+ ReposURL string `json:"repos_url"`
+ EventsURL string `json:"events_url"`
+ HooksURL string `json:"hooks_url"`
+ IssuesURL string `json:"issues_url"`
+ MembersURL string `json:"members_url"`
+ PublicMembersURL string `json:"public_members_url"`
+ AvatarURL string `json:"avatar_url"`
+ Description string `json:"description"`
+}
+
+func (o org) GroupId() string {
+ return strconv.Itoa(o.ID)
+}
+
+func (o org) GroupName() string {
+ return o.Login
+}
+
+type repo struct {
+ ID int `json:"id"`
+ NodeID string `json:"node_id"`
+ Name string `json:"name"`
+ FullName string `json:"full_name"`
+ Owner struct {
+ Login string `json:"login"`
+ ID int `json:"id"`
+ NodeID string `json:"node_id"`
+ AvatarURL string `json:"avatar_url"`
+ GravatarID string `json:"gravatar_id"`
+ URL string `json:"url"`
+ HTMLURL string `json:"html_url"`
+ FollowersURL string `json:"followers_url"`
+ FollowingURL string `json:"following_url"`
+ GistsURL string `json:"gists_url"`
+ StarredURL string `json:"starred_url"`
+ SubscriptionsURL string `json:"subscriptions_url"`
+ OrganizationsURL string `json:"organizations_url"`
+ ReposURL string `json:"repos_url"`
+ EventsURL string `json:"events_url"`
+ ReceivedEventsURL string `json:"received_events_url"`
+ Type string `json:"type"`
+ SiteAdmin bool `json:"site_admin"`
+ } `json:"owner"`
+ Private bool `json:"private"`
+ HTMLURL string `json:"html_url"`
+ Description string `json:"description"`
+ Fork bool `json:"fork"`
+ URL string `json:"url"`
+ ArchiveURL string `json:"archive_url"`
+ AssigneesURL string `json:"assignees_url"`
+ BlobsURL string `json:"blobs_url"`
+ BranchesURL string `json:"branches_url"`
+ CollaboratorsURL string `json:"collaborators_url"`
+ CommentsURL string `json:"comments_url"`
+ CommitsURL string `json:"commits_url"`
+ CompareURL string `json:"compare_url"`
+ ContentsURL string `json:"contents_url"`
+ ContributorsURL string `json:"contributors_url"`
+ DeploymentsURL string `json:"deployments_url"`
+ DownloadsURL string `json:"downloads_url"`
+ EventsURL string `json:"events_url"`
+ ForksURL string `json:"forks_url"`
+ GitCommitsURL string `json:"git_commits_url"`
+ GitRefsURL string `json:"git_refs_url"`
+ GitTagsURL string `json:"git_tags_url"`
+ GitURL string `json:"git_url"`
+ IssueCommentURL string `json:"issue_comment_url"`
+ IssueEventsURL string `json:"issue_events_url"`
+ IssuesURL string `json:"issues_url"`
+ KeysURL string `json:"keys_url"`
+ LabelsURL string `json:"labels_url"`
+ LanguagesURL string `json:"languages_url"`
+ MergesURL string `json:"merges_url"`
+ MilestonesURL string `json:"milestones_url"`
+ NotificationsURL string `json:"notifications_url"`
+ PullsURL string `json:"pulls_url"`
+ ReleasesURL string `json:"releases_url"`
+ SSHURL string `json:"ssh_url"`
+ StargazersURL string `json:"stargazers_url"`
+ StatusesURL string `json:"statuses_url"`
+ SubscribersURL string `json:"subscribers_url"`
+ SubscriptionURL string `json:"subscription_url"`
+ TagsURL string `json:"tags_url"`
+ TeamsURL string `json:"teams_url"`
+ TreesURL string `json:"trees_url"`
+ CloneURL string `json:"clone_url"`
+ MirrorURL string `json:"mirror_url"`
+ HooksURL string `json:"hooks_url"`
+ SvnURL string `json:"svn_url"`
+ Homepage string `json:"homepage"`
+ ForksCount int `json:"forks_count"`
+ StargazersCount int `json:"stargazers_count"`
+ WatchersCount int `json:"watchers_count"`
+ Size int `json:"size"`
+ DefaultBranch string `json:"default_branch"`
+ OpenIssuesCount int `json:"open_issues_count"`
+ IsTemplate bool `json:"is_template"`
+ Topics []string `json:"topics"`
+ HasIssues bool `json:"has_issues"`
+ HasProjects bool `json:"has_projects"`
+ HasWiki bool `json:"has_wiki"`
+ HasPages bool `json:"has_pages"`
+ HasDownloads bool `json:"has_downloads"`
+ HasDiscussions bool `json:"has_discussions"`
+ Archived bool `json:"archived"`
+ Disabled bool `json:"disabled"`
+ Visibility string `json:"visibility"`
+ PushedAt *time.Time `json:"pushed_at"`
+ CreatedAt *time.Time `json:"created_at"`
+ UpdatedAt *time.Time `json:"updated_at"`
+ Permissions struct {
+ Admin bool `json:"admin"`
+ Push bool `json:"push"`
+ Pull bool `json:"pull"`
+ } `json:"permissions"`
+ SecurityAndAnalysis struct {
+ AdvancedSecurity struct {
+ Status string `json:"status"`
+ } `json:"advanced_security"`
+ SecretScanning struct {
+ Status string `json:"status"`
+ } `json:"secret_scanning"`
+ SecretScanningPushProtection struct {
+ Status string `json:"status"`
+ } `json:"secret_scanning_push_protection"`
+ } `json:"security_and_analysis"`
+}
+
+func (r repo) ConvertApiScope() plugin.ToolLayerScope {
+ githubRepository := &models.GithubRepo{
+ //ConnectionId: data.Options.ConnectionId,
+ GithubId: r.ID,
+ Name: r.Name,
+ HTMLUrl: r.HTMLURL,
+ Description: r.Description,
+ OwnerId: r.Owner.ID,
+ CreatedDate: r.CreatedAt,
+ UpdatedDate: r.UpdatedAt,
+ }
+
+ return githubRepository
+}
+
+// RemoteScopes list all available scope for users
+// @Summary list all available scope for users
+// @Description list all available scope for users
+// @Tags plugins/github
+// @Accept application/json
+// @Param connectionId path int true "connection ID"
+// @Param groupId query string false "organization"
+// @Success 200 {object} api.RemoteScopesOutput
+// @Failure 400 {object} shared.ApiBody "Bad Request"
+// @Failure 500 {object} shared.ApiBody "Internal Error"
+// @Router /plugins/github/connections/{connectionId}/remote-scopes [GET]
+func RemoteScopes(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
+ return remoteHelper.GetScopesFromRemote(input,
+ func(basicRes context2.BasicRes, gid string, queryData
*api.RemoteQueryData, connection models.GithubConnection) ([]org, errors.Error)
{
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ res, err := apiClient.Get("user/orgs", query, nil)
+ if err != nil {
+ return nil, err
+ }
+ var resBody []org
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody, err
+ },
+ func(basicRes context2.BasicRes, gid string, queryData
*api.RemoteQueryData, connection models.GithubConnection) ([]repo,
errors.Error) {
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ var res *http.Response
+ if gid == "" {
+ res, err = apiClient.Get("user/repos", query,
nil)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ res, err =
apiClient.Get(fmt.Sprintf("orgs/%s/repos", gid), query, nil)
+ if err != nil {
+ return nil, err
+ }
+ }
+ var resBody []repo
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody, err
+ })
+}
+
+// SearchRemoteScopes use the Search API and only return project
+// @Summary use the Search API and only return project
+// @Description use the Search API and only return project
+// @Tags plugins/github
+// @Accept application/json
+// @Param connectionId path int false "connection ID"
+// @Param search query string false "search"
+// @Param page query int false "page number"
+// @Param pageSize query int false "page size per page"
+// @Success 200 {object} api.SearchRemoteScopesOutput
+// @Failure 400 {object} shared.ApiBody "Bad Request"
+// @Failure 500 {object} shared.ApiBody "Internal Error"
+// @Router /plugins/github/connections/{connectionId}/search-remote-scopes
[GET]
+func SearchRemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ return remoteHelper.SearchRemoteScopes(input,
+ func(basicRes context2.BasicRes, queryData
*api.RemoteQueryData, connection models.GithubConnection) ([]repo,
errors.Error) {
+ apiClient, err :=
api.NewApiClientFromConnection(context.TODO(), basicRes, &connection)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed
to get create apiClient")
+ }
+ query := initialQuery(queryData)
+ if len(queryData.Search) == 0 {
+ return nil, errors.BadInput.New("empty search
query")
+ }
+ query.Set("q", queryData.Search[0])
+ res, err := apiClient.Get("search/repositories", query,
nil)
+ if err != nil {
+ return nil, err
+ }
+ var resBody struct {
+ Items []repo `json:"items"`
+ }
+ err = api.UnmarshalResponse(res, &resBody)
+ if err != nil {
+ return nil, err
+ }
+ return resBody.Items, err
+ })
+}
+
+func initialQuery(queryData *api.RemoteQueryData) url.Values {
+ query := url.Values{}
+ query.Set("page", fmt.Sprintf("%v", queryData.Page))
+ query.Set("per_page", fmt.Sprintf("%v", queryData.PerPage))
+ return query
+}
diff --git a/backend/plugins/github/impl/impl.go
b/backend/plugins/github/impl/impl.go
index 236cd9773..49b99a05a 100644
--- a/backend/plugins/github/impl/impl.go
+++ b/backend/plugins/github/impl/impl.go
@@ -234,6 +234,12 @@ func (p Github) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"PATCH": api.UpdateScopeConfig,
"GET": api.GetScopeConfig,
},
+ "connections/:connectionId/remote-scopes": {
+ "GET": api.RemoteScopes,
+ },
+ "connections/:connectionId/search-remote-scopes": {
+ "GET": api.SearchRemoteScopes,
+ },
"connections/:connectionId/proxy/rest/*path": {
"GET": api.Proxy,
},