Last active
February 23, 2019 02:41
-
-
Save RickStrahl/e2a8ab089a02d2b79fbfe79cb2ba0ffe to your computer and use it in GitHub Desktop.
Recursively parse a Github Repository with GraphQL
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
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using Octokit.GraphQL; | |
using Octokit.GraphQL.Model; | |
namespace GithubGraphQl | |
{ | |
public class GithubRepositoryTree | |
{ | |
private readonly string _token; | |
private readonly string _owner; | |
private readonly string _repository; | |
public string ApiName { get; set; } = "GraphQLTest"; | |
public string ApiVersion { get; set; } = "0.1"; | |
public GithubRepositoryTree(string token, string owner, string repository, | |
string apiName = null, string apiVersion = null) | |
{ | |
_token = token; | |
_owner = owner; | |
_repository = repository; | |
if (apiName != null) | |
ApiName = apiName; | |
if (apiVersion != null) | |
ApiName = apiName; | |
} | |
/// <summary> | |
/// Retrieves all files in a given Github branch/path. Optionally | |
/// allows recursively retrieving all content in child folders/trees. | |
/// | |
/// Note: child folders are lazy loaded so recursive action can | |
/// result in a lot of separate HTTP requests made to the server | |
/// </summary> | |
/// <param name="path">Branch and path to to start parsing on using `branch:path` syntax: | |
/// Example: `master:` or `master:subpath\subpath2`</param> | |
/// <param name="recursive">If true recurses any subpaths</param> | |
/// <returns>List of Items optionally with child items</returns> | |
public async Task<List<GithubFolderItem>> GetFolder(string path = "master:", bool recursive = true) | |
{ | |
var productInformation = new ProductHeaderValue(ApiName, ApiVersion); | |
var connection = new Connection(productInformation, _token); | |
var query = new Query() | |
.Repository(name: _repository, owner: _owner) | |
.Object(expression: path) | |
.Cast<Tree>() | |
.Entries.Select(x => new GithubFolderItem | |
{ | |
Name = x.Name, | |
Type = x.Type, | |
}) | |
.Compile(); | |
var entries = await connection.Run(query); | |
foreach (var entry in entries) | |
{ | |
entry.FullPath = path + entry.Name; | |
if (!recursive || entry.Type != "tree") | |
continue; | |
entry.Items = await GetFolder(entry.FullPath + "/"); | |
} | |
return entries.ToList(); | |
} | |
/// <summary> | |
/// Retrieve the contents of an file/resource from a | |
/// from a Github repository. Provide a path to retrieve in | |
/// `branch:path\file.md` format. | |
/// </summary> | |
/// <param name="path">path to a resource: `master:file.txt` or `master:path/file.txt`</param> | |
/// <returns>file content or throws</returns> | |
public async Task<GithubItem> GetItemContent(string path) | |
{ | |
var productInformation = new ProductHeaderValue(ApiName, ApiVersion); | |
var connection = new Connection(productInformation, _token); | |
var query = new Query() | |
.Repository(name: _repository, owner: _owner) | |
.Object(expression: path) | |
.Cast<Blob>() | |
.Select(x => new GithubItem | |
{ | |
FullPath = path, | |
IsBinary = x.IsBinary, | |
ByteSize = x.ByteSize, | |
Text = x.Text | |
}).Compile(); | |
var result = await connection.Run(query); | |
result.Name = Path.GetFileName(path); | |
return result; | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="item"></param> | |
/// <returns></returns> | |
public async Task<GithubItem> GetItemContent(GithubFolderItem item) | |
{ | |
return await GetItemContent(item.FullPath); | |
} | |
} | |
/// <summary> | |
/// Holds information about an individual folder item | |
/// </summary> | |
public class GithubFolderItem | |
{ | |
/// <summary> | |
/// The simple name of this file/resource | |
/// </summary> | |
public string Name { get; set; } | |
/// <summary> | |
/// Type: blob or tree | |
/// </summary> | |
public string Type { get; set; } | |
/// <summary> | |
/// Full Github path to this item | |
/// </summary> | |
public string FullPath { get; set; } | |
/// <summary> | |
/// If this is a tree, contains child FolderItems entries | |
/// </summary> | |
public List<GithubFolderItem> Items { get; set; } | |
public override string ToString() | |
{ | |
return $"{Name} ({Items?.Count ?? 0})"; | |
} | |
} | |
/// <summary> | |
/// An individual Github file/resource item | |
/// </summary> | |
public class GithubItem | |
{ | |
/// <summary> | |
/// The simple name of the resource blob | |
/// </summary> | |
public string Name { get; set; } | |
/// <summary> | |
/// The full path to the resource | |
/// </summary> | |
public string FullPath { get; set; } | |
/// <summary> | |
/// Size in bytes | |
/// </summary> | |
public int ByteSize { get; set; } | |
/// <summary> | |
/// If the contents is binary data | |
/// </summary> | |
public bool IsBinary { get; set; } | |
/// <summary> | |
/// Contents of the file/resource | |
/// </summary> | |
public string Text { get; set; } | |
public override string ToString() | |
{ | |
return $"{Name} ({ByteSize.ToString("n0")})"; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment