-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add github_repository_content table
- Loading branch information
1 parent
150a7e5
commit c0f1fd4
Showing
2 changed files
with
99 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"github.com/google/go-github/v45/github" | ||
"github.com/turbot/steampipe-plugin-sdk/v4/grpc/proto" | ||
"github.com/turbot/steampipe-plugin-sdk/v4/plugin" | ||
"github.com/turbot/steampipe-plugin-sdk/v4/plugin/transform" | ||
) | ||
|
||
//// TABLE DEFINITION | ||
|
||
func tableGitHubRepositoryContent() *plugin.Table { | ||
return &plugin.Table{ | ||
Name: "github_repository_content", | ||
Description: "List the content in a repository (list directory, or get file content", | ||
List: &plugin.ListConfig{ | ||
Hydrate: tableGitHubRepositoryContentList, | ||
KeyColumns: []*plugin.KeyColumn{ | ||
{Name: "repository_full_name", Require: plugin.Required}, | ||
{Name: "requested_path", Require: plugin.Optional}, | ||
}, | ||
}, | ||
Columns: []*plugin.Column{ | ||
{Name: "repository_full_name", Description: "The full name of the repository (login/repo-name).", Type: proto.ColumnType_STRING, Transform: transform.FromQual("repository_full_name")}, | ||
{Name: "type", Description: "The file type (directory or file).", Type: proto.ColumnType_STRING}, | ||
{Name: "name", Description: "The file name.", Type: proto.ColumnType_STRING}, | ||
{Name: "requested_path", Description: "The requested path in repository search.", Type: proto.ColumnType_STRING, Transform: transform.FromQual("requested_path")}, | ||
{Name: "path", Description: "The path of the file.", Type: proto.ColumnType_STRING}, | ||
{Name: "size", Description: "The size of the file.", Type: proto.ColumnType_INT}, | ||
{Name: "content", Description: "The decoded file content (if the element is a file).", Type: proto.ColumnType_STRING, Transform: transform.FromMethod("GetContent")}, | ||
{Name: "target", Description: "Target is only set if the type is \"symlink\" and the target is not a normal file. If Target is set, Path will be the symlink path.", Type: proto.ColumnType_STRING}, | ||
{Name: "sha", Description: "The sha of the file.", Type: proto.ColumnType_STRING, Transform: transform.FromField("SHA")}, | ||
{Name: "url", Description: "Url of file's metadata", Type: proto.ColumnType_STRING}, | ||
{Name: "git_url", Description: "Git url (with SHA) of the file", Type: proto.ColumnType_STRING}, | ||
{Name: "html_url", Description: "Raw file url in GitHub", Type: proto.ColumnType_STRING}, | ||
{Name: "download_url", Description: "Download URL : it expires and can be be used just once.", Type: proto.ColumnType_STRING}, | ||
}, | ||
} | ||
} | ||
|
||
//// LIST FUNCTION | ||
|
||
func tableGitHubRepositoryContentList(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { | ||
plugin.Logger(ctx).Trace("github_repository_content.tableGitHubRepositoryContentList") | ||
|
||
owner, repo := parseRepoFullName(d.KeyColumnQuals["repository_full_name"].GetStringValue()) | ||
var requestedPath string | ||
if d.KeyColumnQuals["requested_path"] != nil { | ||
requestedPath = d.KeyColumnQuals["requested_path"].GetStringValue() | ||
} | ||
|
||
type ListPageResponse struct { | ||
repositoryContent []*github.RepositoryContent | ||
resp *github.Response | ||
} | ||
client := connect(ctx, d) | ||
opt := &github.RepositoryContentGetOptions{} | ||
listPage := func(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { | ||
fileContent, directoryContent, resp, err := client.Repositories.GetContents(ctx, owner, repo, requestedPath, opt) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if fileContent != nil { | ||
directoryContent = []*github.RepositoryContent{fileContent} | ||
} | ||
|
||
return ListPageResponse{ | ||
repositoryContent: directoryContent, | ||
resp: resp, | ||
}, err | ||
} | ||
|
||
for { | ||
listPageResponse, err := retryHydrate(ctx, d, h, listPage) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, i := range listPageResponse.(ListPageResponse).repositoryContent { | ||
if i != nil { | ||
d.StreamListItem(ctx, i) | ||
} | ||
|
||
// Context can be cancelled due to manual cancellation or the limit has been hit | ||
if d.QueryStatus.RowsRemaining(ctx) == 0 { | ||
return nil, nil | ||
} | ||
} | ||
|
||
if listPageResponse.(ListPageResponse).resp.NextPage == 0 { | ||
break | ||
} | ||
} | ||
return nil, nil | ||
} |