mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-19 17:01:13 +00:00
Use graphql in GitHubClient and misc fixes (#8)
* Use graphql in GitHubClient * Replace usage of Array.find with _.find
This commit is contained in:
@@ -1,92 +1,110 @@
|
||||
import ko from "knockout";
|
||||
import { HttpStatusCodes } from "../Common/Constants";
|
||||
import { GitHubClient, IGitHubBranch, IGitHubRepo } from "./GitHubClient";
|
||||
import { GitHubClient, IGitHubFile } from "./GitHubClient";
|
||||
import { SamplesRepo, SamplesBranch, SamplesContentsQueryResponse } from "../Explorer/Notebook/NotebookSamples";
|
||||
|
||||
const invalidTokenCallback = jest.fn();
|
||||
// Use a dummy token to get around API rate limit (same as AZURESAMPLESCOSMOSDBPAT in webpack.config.js)
|
||||
const gitHubClient = new GitHubClient("99e38770e29b4a61d7c49f188780504efd35cc86", invalidTokenCallback);
|
||||
const samplesRepo: IGitHubRepo = {
|
||||
name: "cosmos-notebooks",
|
||||
owner: {
|
||||
login: "Azure-Samples"
|
||||
},
|
||||
private: false
|
||||
};
|
||||
const samplesBranch: IGitHubBranch = {
|
||||
name: "master"
|
||||
};
|
||||
const sampleFilePath = ".gitignore";
|
||||
const sampleDirPath = ".github";
|
||||
// Use a dummy token to get around API rate limit (something which doesn't affect the API quota for AZURESAMPLESCOSMOSDBPAT in Config.ts)
|
||||
const gitHubClient = new GitHubClient("cd1906b9534362fab6ce45d6db6c76b59e55bc50", invalidTokenCallback);
|
||||
|
||||
describe.skip("GitHubClient", () => {
|
||||
const validateGitHubFile = (file: IGitHubFile) => {
|
||||
expect(file.branch).toEqual(SamplesBranch);
|
||||
expect(file.commit).toBeDefined();
|
||||
expect(file.name).toBeDefined();
|
||||
expect(file.path).toBeDefined();
|
||||
expect(file.repo).toEqual(SamplesRepo);
|
||||
expect(file.type).toBeDefined();
|
||||
|
||||
switch (file.type) {
|
||||
case "blob":
|
||||
expect(file.sha).toBeDefined();
|
||||
expect(file.size).toBeDefined();
|
||||
break;
|
||||
|
||||
case "tree":
|
||||
expect(file.sha).toBeUndefined();
|
||||
expect(file.size).toBeUndefined();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported github file type: ${file.type}`);
|
||||
}
|
||||
};
|
||||
|
||||
describe("GitHubClient", () => {
|
||||
it("getRepoAsync returns valid repo", async () => {
|
||||
const response = await gitHubClient.getRepoAsync(samplesRepo.owner.login, samplesRepo.name);
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data.name).toBe(samplesRepo.name);
|
||||
expect(response.data.owner.login).toBe(samplesRepo.owner.login);
|
||||
const response = await gitHubClient.getRepoAsync(SamplesRepo.owner, SamplesRepo.name);
|
||||
expect(response).toEqual({
|
||||
status: HttpStatusCodes.OK,
|
||||
data: SamplesRepo
|
||||
});
|
||||
});
|
||||
|
||||
it("getReposAsync returns repos for authenticated user", async () => {
|
||||
const response = await gitHubClient.getReposAsync(1, 1);
|
||||
const response = await gitHubClient.getReposAsync(1);
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data).toBeDefined();
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.pageInfo).toBeDefined();
|
||||
});
|
||||
|
||||
it("getBranchesAsync returns branches for a repo", async () => {
|
||||
const response = await gitHubClient.getBranchesAsync(samplesRepo.owner.login, samplesRepo.name, 1, 1);
|
||||
const response = await gitHubClient.getBranchesAsync(SamplesRepo.owner, SamplesRepo.name, 1);
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.data).toEqual([SamplesBranch]);
|
||||
expect(response.pageInfo).toBeDefined();
|
||||
});
|
||||
|
||||
it("getCommitsAsync returns commits for a file", async () => {
|
||||
const response = await gitHubClient.getCommitsAsync(
|
||||
samplesRepo.owner.login,
|
||||
samplesRepo.name,
|
||||
samplesBranch.name,
|
||||
sampleFilePath,
|
||||
1,
|
||||
1
|
||||
);
|
||||
it("getContentsAsync returns files in the repo", async () => {
|
||||
const response = await gitHubClient.getContentsAsync(SamplesRepo.owner, SamplesRepo.name, SamplesBranch.name);
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.data).toBeDefined();
|
||||
|
||||
const data = response.data as IGitHubFile[];
|
||||
expect(data.length).toBeGreaterThan(0);
|
||||
data.forEach(content => validateGitHubFile(content));
|
||||
});
|
||||
|
||||
it("getDirContentsAsync returns files in the repo", async () => {
|
||||
const response = await gitHubClient.getDirContentsAsync(
|
||||
samplesRepo.owner.login,
|
||||
samplesRepo.name,
|
||||
samplesBranch.name,
|
||||
""
|
||||
it("getContentsAsync returns files in a dir", async () => {
|
||||
const samplesDir = SamplesContentsQueryResponse.repository.object.entries.find(file => file.type === "tree");
|
||||
const response = await gitHubClient.getContentsAsync(
|
||||
SamplesRepo.owner,
|
||||
SamplesRepo.name,
|
||||
SamplesBranch.name,
|
||||
samplesDir.name
|
||||
);
|
||||
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data.length).toBeGreaterThan(0);
|
||||
expect(response.data[0].repo).toEqual(samplesRepo);
|
||||
expect(response.data[0].branch).toEqual(samplesBranch);
|
||||
expect(response.data).toBeDefined();
|
||||
|
||||
const data = response.data as IGitHubFile[];
|
||||
expect(data.length).toBeGreaterThan(0);
|
||||
data.forEach(content => validateGitHubFile(content));
|
||||
});
|
||||
|
||||
it("getDirContentsAsync returns files in a dir", async () => {
|
||||
const response = await gitHubClient.getDirContentsAsync(
|
||||
samplesRepo.owner.login,
|
||||
samplesRepo.name,
|
||||
samplesBranch.name,
|
||||
sampleDirPath
|
||||
it("getContentsAsync returns a file", async () => {
|
||||
const samplesFile = SamplesContentsQueryResponse.repository.object.entries.find(file => file.type === "blob");
|
||||
const response = await gitHubClient.getContentsAsync(
|
||||
SamplesRepo.owner,
|
||||
SamplesRepo.name,
|
||||
SamplesBranch.name,
|
||||
samplesFile.name
|
||||
);
|
||||
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data.length).toBeGreaterThan(0);
|
||||
expect(response.data[0].repo).toEqual(samplesRepo);
|
||||
expect(response.data[0].branch).toEqual(samplesBranch);
|
||||
expect(response.data).toBeDefined();
|
||||
|
||||
const file = response.data as IGitHubFile;
|
||||
expect(file.type).toBe("blob");
|
||||
validateGitHubFile(file);
|
||||
expect(file.content).toBeUndefined();
|
||||
});
|
||||
|
||||
it("getFileContentsAsync returns a file", async () => {
|
||||
const response = await gitHubClient.getFileContentsAsync(
|
||||
samplesRepo.owner.login,
|
||||
samplesRepo.name,
|
||||
samplesBranch.name,
|
||||
sampleFilePath
|
||||
);
|
||||
it("getBlobAsync returns file content", async () => {
|
||||
const samplesFile = SamplesContentsQueryResponse.repository.object.entries.find(file => file.type === "blob");
|
||||
const response = await gitHubClient.getBlobAsync(SamplesRepo.owner, SamplesRepo.name, samplesFile.object.oid);
|
||||
|
||||
expect(response.status).toBe(HttpStatusCodes.OK);
|
||||
expect(response.data.path).toBe(sampleFilePath);
|
||||
expect(response.data.repo).toEqual(samplesRepo);
|
||||
expect(response.data.branch).toEqual(samplesBranch);
|
||||
expect(response.data).toBeDefined();
|
||||
expect(typeof response.data).toBe("string");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,163 +1,228 @@
|
||||
import { Octokit } from "@octokit/rest";
|
||||
import { RequestHeaders } from "@octokit/types";
|
||||
import { HttpStatusCodes } from "../Common/Constants";
|
||||
import { Logger } from "../Common/Logger";
|
||||
import UrlUtility from "../Common/UrlUtility";
|
||||
import { isSamplesCall, SamplesContentsQueryResponse } from "../Explorer/Notebook/NotebookSamples";
|
||||
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
|
||||
|
||||
export interface IGitHubPageInfo {
|
||||
endCursor: string;
|
||||
hasNextPage: boolean;
|
||||
}
|
||||
|
||||
export interface IGitHubResponse<T> {
|
||||
status: number;
|
||||
data: T;
|
||||
pageInfo?: IGitHubPageInfo;
|
||||
}
|
||||
|
||||
export interface IGitHubRepo {
|
||||
// API properties
|
||||
name: string;
|
||||
owner: {
|
||||
login: string;
|
||||
};
|
||||
owner: string;
|
||||
private: boolean;
|
||||
|
||||
// Custom properties
|
||||
children?: IGitHubFile[];
|
||||
}
|
||||
|
||||
export interface IGitHubFile {
|
||||
// API properties
|
||||
type: "file" | "dir" | "symlink" | "submodule";
|
||||
encoding?: string;
|
||||
size: number;
|
||||
type: "blob" | "tree";
|
||||
size?: number;
|
||||
name: string;
|
||||
path: string;
|
||||
content?: string;
|
||||
sha: string;
|
||||
|
||||
// Custom properties
|
||||
sha?: string;
|
||||
children?: IGitHubFile[];
|
||||
repo?: IGitHubRepo;
|
||||
branch?: IGitHubBranch;
|
||||
repo: IGitHubRepo;
|
||||
branch: IGitHubBranch;
|
||||
commit: IGitHubCommit;
|
||||
}
|
||||
|
||||
export interface IGitHubCommit {
|
||||
// API properties
|
||||
sha: string;
|
||||
message: string;
|
||||
committer: {
|
||||
date: string;
|
||||
};
|
||||
commitDate: string;
|
||||
}
|
||||
|
||||
export interface IGitHubBranch {
|
||||
// API properties
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface IGitHubUser {
|
||||
// API properties
|
||||
login: string;
|
||||
// graphql schema
|
||||
interface Collection<T> {
|
||||
pageInfo?: PageInfo;
|
||||
nodes: T[];
|
||||
}
|
||||
|
||||
interface Repository {
|
||||
isPrivate: boolean;
|
||||
name: string;
|
||||
owner: {
|
||||
login: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Ref {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface History {
|
||||
history: Collection<Commit>;
|
||||
}
|
||||
|
||||
interface Commit {
|
||||
committer: {
|
||||
date: string;
|
||||
};
|
||||
message: string;
|
||||
oid: string;
|
||||
}
|
||||
|
||||
interface Tree extends Blob {
|
||||
entries: TreeEntry[];
|
||||
}
|
||||
|
||||
interface TreeEntry {
|
||||
name: string;
|
||||
type: string;
|
||||
object: Blob;
|
||||
}
|
||||
|
||||
interface Blob {
|
||||
byteSize?: number;
|
||||
oid?: string;
|
||||
}
|
||||
|
||||
interface PageInfo {
|
||||
endCursor: string;
|
||||
hasNextPage: boolean;
|
||||
}
|
||||
|
||||
// graphql queries and types
|
||||
const repositoryQuery = `query($owner: String!, $repo: String!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
owner {
|
||||
login
|
||||
}
|
||||
name
|
||||
isPrivate
|
||||
}
|
||||
}`;
|
||||
type RepositoryQueryParams = {
|
||||
owner: string;
|
||||
repo: string;
|
||||
};
|
||||
type RepositoryQueryResponse = {
|
||||
repository: Repository;
|
||||
};
|
||||
|
||||
const repositoriesQuery = `query($pageSize: Int!, $endCursor: String) {
|
||||
viewer {
|
||||
repositories(first: $pageSize, after: $endCursor) {
|
||||
pageInfo {
|
||||
endCursor,
|
||||
hasNextPage
|
||||
}
|
||||
nodes {
|
||||
owner {
|
||||
login
|
||||
}
|
||||
name
|
||||
isPrivate
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
type RepositoriesQueryParams = {
|
||||
pageSize: number;
|
||||
endCursor?: string;
|
||||
};
|
||||
type RepositoriesQueryResponse = {
|
||||
viewer: {
|
||||
repositories: Collection<Repository>;
|
||||
};
|
||||
};
|
||||
|
||||
const branchesQuery = `query($owner: String!, $repo: String!, $refPrefix: String!, $pageSize: Int!, $endCursor: String) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
refs(refPrefix: $refPrefix, first: $pageSize, after: $endCursor) {
|
||||
pageInfo {
|
||||
endCursor,
|
||||
hasNextPage
|
||||
}
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
type BranchesQueryParams = {
|
||||
owner: string;
|
||||
repo: string;
|
||||
refPrefix: string;
|
||||
pageSize: number;
|
||||
endCursor?: string;
|
||||
};
|
||||
type BranchesQueryResponse = {
|
||||
repository: {
|
||||
refs: Collection<Ref>;
|
||||
};
|
||||
};
|
||||
|
||||
const contentsQuery = `query($owner: String!, $repo: String!, $ref: String!, $path: String, $objectExpression: String!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
owner {
|
||||
login
|
||||
}
|
||||
name
|
||||
isPrivate
|
||||
ref(qualifiedName: $ref) {
|
||||
name
|
||||
target {
|
||||
... on Commit {
|
||||
history(first: 1, path: $path) {
|
||||
nodes {
|
||||
oid
|
||||
message
|
||||
committer {
|
||||
date
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
object(expression: $objectExpression) {
|
||||
... on Blob {
|
||||
oid
|
||||
byteSize
|
||||
}
|
||||
... on Tree {
|
||||
entries {
|
||||
name
|
||||
type
|
||||
object {
|
||||
... on Blob {
|
||||
oid
|
||||
byteSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
type ContentsQueryParams = {
|
||||
owner: string;
|
||||
repo: string;
|
||||
ref: string;
|
||||
path?: string;
|
||||
objectExpression: string;
|
||||
};
|
||||
type ContentsQueryResponse = {
|
||||
repository: Repository & { ref: Ref & { target: History } } & { object: Tree };
|
||||
};
|
||||
|
||||
export class GitHubClient {
|
||||
private static readonly gitHubApiEndpoint = "https://api.github.com";
|
||||
|
||||
private static readonly samplesRepo: IGitHubRepo = {
|
||||
name: "cosmos-notebooks",
|
||||
private: false,
|
||||
owner: {
|
||||
login: "Azure-Samples"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly samplesBranch: IGitHubBranch = {
|
||||
name: "master"
|
||||
};
|
||||
|
||||
private static readonly samplesTopCommit: IGitHubCommit = {
|
||||
sha: "41b964f442b638097a75a3f3b6a6451db05a12bf",
|
||||
committer: {
|
||||
date: "2020-05-19T05:03:30Z"
|
||||
},
|
||||
message: "Fixing formatting"
|
||||
};
|
||||
|
||||
private static readonly samplesFiles: IGitHubFile[] = [
|
||||
{
|
||||
name: ".github",
|
||||
path: ".github",
|
||||
sha: "5e6794a8177a0c07a8719f6e1d7b41cce6f92e1e",
|
||||
size: 0,
|
||||
type: "dir"
|
||||
},
|
||||
{
|
||||
name: ".gitignore",
|
||||
path: ".gitignore",
|
||||
sha: "3e759b75bf455ac809d0987d369aab89137b5689",
|
||||
size: 5582,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "1. GettingStarted.ipynb",
|
||||
path: "1. GettingStarted.ipynb",
|
||||
sha: "0732ff5366e4aefdc4c378c61cbd968664f0acec",
|
||||
size: 3933,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "2. Visualization.ipynb",
|
||||
path: "2. Visualization.ipynb",
|
||||
sha: "f480134ac4adf2f50ce5fe66836c6966749d3ca1",
|
||||
size: 814261,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "3. RequestUnits.ipynb",
|
||||
path: "3. RequestUnits.ipynb",
|
||||
sha: "252b79a4adc81e9f2ffde453231b695d75e270e8",
|
||||
size: 9490,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "4. Indexing.ipynb",
|
||||
path: "4. Indexing.ipynb",
|
||||
sha: "e10dd67bd1c55c345226769e4f80e43659ef9cd5",
|
||||
size: 10394,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "5. StoredProcedures.ipynb",
|
||||
path: "5. StoredProcedures.ipynb",
|
||||
sha: "949941949920de4d2d111149e2182e9657cc8134",
|
||||
size: 11818,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "6. GlobalDistribution.ipynb",
|
||||
path: "6. GlobalDistribution.ipynb",
|
||||
sha: "b91c31dacacbc9e35750d9054063dda4a5309f3b",
|
||||
size: 11375,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "7. IoTAnomalyDetection.ipynb",
|
||||
path: "7. IoTAnomalyDetection.ipynb",
|
||||
sha: "82057ae52a67721a5966e2361317f5dfbd0ee595",
|
||||
size: 377939,
|
||||
type: "file"
|
||||
},
|
||||
{
|
||||
name: "All_API_quickstarts",
|
||||
path: "All_API_quickstarts",
|
||||
sha: "07054293e6c8fc00771fccd0cde207f5c8053978",
|
||||
size: 0,
|
||||
type: "dir"
|
||||
},
|
||||
{
|
||||
name: "CSharp_quickstarts",
|
||||
path: "CSharp_quickstarts",
|
||||
sha: "10e7f5704e6b56a40cac74bc39f15b7708954f52",
|
||||
size: 0,
|
||||
type: "dir"
|
||||
}
|
||||
];
|
||||
|
||||
private static readonly SelfErrorCode = 599;
|
||||
private ocktokit: Octokit;
|
||||
|
||||
constructor(token: string, private errorCallback: (error: any) => void) {
|
||||
@@ -169,167 +234,136 @@ export class GitHubClient {
|
||||
}
|
||||
|
||||
public async getRepoAsync(owner: string, repo: string): Promise<IGitHubResponse<IGitHubRepo>> {
|
||||
if (GitHubClient.isSamplesCall(owner, repo)) {
|
||||
try {
|
||||
const response = (await this.ocktokit.graphql(repositoryQuery, {
|
||||
owner,
|
||||
repo
|
||||
} as RepositoryQueryParams)) as RepositoryQueryResponse;
|
||||
|
||||
return {
|
||||
status: HttpStatusCodes.OK,
|
||||
data: GitHubClient.samplesRepo
|
||||
data: GitHubClient.toGitHubRepo(response.repository)
|
||||
};
|
||||
} catch (error) {
|
||||
GitHubClient.log(Logger.logError, `GitHubClient.getRepoAsync failed: ${error}`);
|
||||
return {
|
||||
status: GitHubClient.SelfErrorCode,
|
||||
data: undefined
|
||||
};
|
||||
}
|
||||
|
||||
const response = await this.ocktokit.repos.get({
|
||||
owner,
|
||||
repo,
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
});
|
||||
|
||||
let data: IGitHubRepo;
|
||||
if (response.data) {
|
||||
data = GitHubClient.toGitHubRepo(response.data);
|
||||
}
|
||||
|
||||
return { status: response.status, data };
|
||||
}
|
||||
|
||||
public async getReposAsync(page: number, perPage: number): Promise<IGitHubResponse<IGitHubRepo[]>> {
|
||||
const response = await this.ocktokit.repos.listForAuthenticatedUser({
|
||||
page,
|
||||
per_page: perPage,
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
});
|
||||
public async getReposAsync(pageSize: number, endCursor?: string): Promise<IGitHubResponse<IGitHubRepo[]>> {
|
||||
try {
|
||||
const response = (await this.ocktokit.graphql(repositoriesQuery, {
|
||||
pageSize,
|
||||
endCursor
|
||||
} as RepositoriesQueryParams)) as RepositoriesQueryResponse;
|
||||
|
||||
let data: IGitHubRepo[];
|
||||
if (response.data) {
|
||||
data = [];
|
||||
response.data?.forEach((element: any) => data.push(GitHubClient.toGitHubRepo(element)));
|
||||
return {
|
||||
status: HttpStatusCodes.OK,
|
||||
data: response.viewer.repositories.nodes.map(repo => GitHubClient.toGitHubRepo(repo)),
|
||||
pageInfo: GitHubClient.toGitHubPageInfo(response.viewer.repositories.pageInfo)
|
||||
};
|
||||
} catch (error) {
|
||||
GitHubClient.log(Logger.logError, `GitHubClient.getReposAsync failed: ${error}`);
|
||||
return {
|
||||
status: GitHubClient.SelfErrorCode,
|
||||
data: undefined
|
||||
};
|
||||
}
|
||||
|
||||
return { status: response.status, data };
|
||||
}
|
||||
|
||||
public async getBranchesAsync(
|
||||
owner: string,
|
||||
repo: string,
|
||||
page: number,
|
||||
perPage: number
|
||||
pageSize: number,
|
||||
endCursor?: string
|
||||
): Promise<IGitHubResponse<IGitHubBranch[]>> {
|
||||
const response = await this.ocktokit.repos.listBranches({
|
||||
owner,
|
||||
repo,
|
||||
page,
|
||||
per_page: perPage,
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
});
|
||||
try {
|
||||
const response = (await this.ocktokit.graphql(branchesQuery, {
|
||||
owner,
|
||||
repo,
|
||||
refPrefix: "refs/heads/",
|
||||
pageSize,
|
||||
endCursor
|
||||
} as BranchesQueryParams)) as BranchesQueryResponse;
|
||||
|
||||
let data: IGitHubBranch[];
|
||||
if (response.data) {
|
||||
data = [];
|
||||
response.data?.forEach(element => data.push(GitHubClient.toGitHubBranch(element)));
|
||||
}
|
||||
|
||||
return { status: response.status, data };
|
||||
}
|
||||
|
||||
public async getCommitsAsync(
|
||||
owner: string,
|
||||
repo: string,
|
||||
branch: string,
|
||||
path: string,
|
||||
page: number,
|
||||
perPage: number
|
||||
): Promise<IGitHubResponse<IGitHubCommit[]>> {
|
||||
if (GitHubClient.isSamplesCall(owner, repo, branch) && path === "" && page === 1 && perPage === 1) {
|
||||
return {
|
||||
status: HttpStatusCodes.OK,
|
||||
data: [GitHubClient.samplesTopCommit]
|
||||
data: response.repository.refs.nodes.map(ref => GitHubClient.toGitHubBranch(ref)),
|
||||
pageInfo: GitHubClient.toGitHubPageInfo(response.repository.refs.pageInfo)
|
||||
};
|
||||
} catch (error) {
|
||||
GitHubClient.log(Logger.logError, `GitHubClient.getBranchesAsync failed: ${error}`);
|
||||
return {
|
||||
status: GitHubClient.SelfErrorCode,
|
||||
data: undefined
|
||||
};
|
||||
}
|
||||
|
||||
const response = await this.ocktokit.repos.listCommits({
|
||||
owner,
|
||||
repo,
|
||||
sha: branch,
|
||||
path,
|
||||
page,
|
||||
per_page: perPage,
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
});
|
||||
|
||||
let data: IGitHubCommit[];
|
||||
if (response.data) {
|
||||
data = [];
|
||||
response.data?.forEach(element =>
|
||||
data.push(GitHubClient.toGitHubCommit({ ...element.commit, sha: element.sha }))
|
||||
);
|
||||
}
|
||||
|
||||
return { status: response.status, data };
|
||||
}
|
||||
|
||||
public async getDirContentsAsync(
|
||||
owner: string,
|
||||
repo: string,
|
||||
branch: string,
|
||||
path: string
|
||||
): Promise<IGitHubResponse<IGitHubFile[]>> {
|
||||
return (await this.getContentsAsync(owner, repo, branch, path)) as IGitHubResponse<IGitHubFile[]>;
|
||||
}
|
||||
|
||||
public async getFileContentsAsync(
|
||||
owner: string,
|
||||
repo: string,
|
||||
branch: string,
|
||||
path: string
|
||||
): Promise<IGitHubResponse<IGitHubFile>> {
|
||||
return (await this.getContentsAsync(owner, repo, branch, path)) as IGitHubResponse<IGitHubFile>;
|
||||
}
|
||||
|
||||
public async getContentsAsync(
|
||||
owner: string,
|
||||
repo: string,
|
||||
branch: string,
|
||||
path: string
|
||||
path?: string
|
||||
): Promise<IGitHubResponse<IGitHubFile | IGitHubFile[]>> {
|
||||
if (GitHubClient.isSamplesCall(owner, repo, branch) && path === "") {
|
||||
try {
|
||||
let response: ContentsQueryResponse;
|
||||
if (isSamplesCall(owner, repo, branch) && !path) {
|
||||
response = SamplesContentsQueryResponse;
|
||||
} else {
|
||||
response = (await this.ocktokit.graphql(contentsQuery, {
|
||||
owner,
|
||||
repo,
|
||||
ref: `refs/heads/${branch}`,
|
||||
path: path || undefined,
|
||||
objectExpression: `refs/heads/${branch}:${path || ""}`
|
||||
} as ContentsQueryParams)) as ContentsQueryResponse;
|
||||
}
|
||||
|
||||
let data: IGitHubFile | IGitHubFile[];
|
||||
const entries = response.repository.object.entries;
|
||||
const gitHubRepo = GitHubClient.toGitHubRepo(response.repository);
|
||||
const gitHubBranch = GitHubClient.toGitHubBranch(response.repository.ref);
|
||||
const gitHubCommit = GitHubClient.toGitHubCommit(response.repository.ref.target.history.nodes[0]);
|
||||
|
||||
if (Array.isArray(entries)) {
|
||||
data = entries.map(entry =>
|
||||
GitHubClient.toGitHubFile(
|
||||
entry,
|
||||
(path && UrlUtility.createUri(path, entry.name)) || entry.name,
|
||||
gitHubRepo,
|
||||
gitHubBranch,
|
||||
gitHubCommit
|
||||
)
|
||||
);
|
||||
} else {
|
||||
data = GitHubClient.toGitHubFile(
|
||||
{
|
||||
name: NotebookUtil.getName(path),
|
||||
type: "blob",
|
||||
object: response.repository.object
|
||||
},
|
||||
path,
|
||||
gitHubRepo,
|
||||
gitHubBranch,
|
||||
gitHubCommit
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
status: HttpStatusCodes.OK,
|
||||
data: GitHubClient.samplesFiles.map(file =>
|
||||
GitHubClient.toGitHubFile(file, GitHubClient.samplesRepo, GitHubClient.samplesBranch)
|
||||
)
|
||||
data
|
||||
};
|
||||
} catch (error) {
|
||||
GitHubClient.log(Logger.logError, `GitHubClient.getContentsAsync failed: ${error}`);
|
||||
return {
|
||||
status: GitHubClient.SelfErrorCode,
|
||||
data: undefined
|
||||
};
|
||||
}
|
||||
|
||||
const response = await this.ocktokit.repos.getContents({
|
||||
owner,
|
||||
repo,
|
||||
path,
|
||||
ref: branch,
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
});
|
||||
|
||||
let data: IGitHubFile | IGitHubFile[];
|
||||
if (response.data) {
|
||||
const repoResponse = await this.getRepoAsync(owner, repo);
|
||||
if (repoResponse.data) {
|
||||
const fileRepo: IGitHubRepo = GitHubClient.toGitHubRepo(repoResponse.data);
|
||||
const fileBranch: IGitHubBranch = { name: branch };
|
||||
|
||||
if (Array.isArray(response.data)) {
|
||||
const contents: IGitHubFile[] = [];
|
||||
response.data.forEach((element: any) =>
|
||||
contents.push(GitHubClient.toGitHubFile(element, fileRepo, fileBranch))
|
||||
);
|
||||
data = contents;
|
||||
} else {
|
||||
data = GitHubClient.toGitHubFile(
|
||||
{ ...response.data, type: response.data.type as "file" | "dir" | "symlink" | "submodule" },
|
||||
fileRepo,
|
||||
fileBranch
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { status: response.status, data };
|
||||
}
|
||||
|
||||
public async createOrUpdateFileAsync(
|
||||
@@ -372,7 +406,9 @@ export class GitHubClient {
|
||||
owner,
|
||||
repo,
|
||||
ref,
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
headers: {
|
||||
"If-None-Match": "" // disable 60s cache
|
||||
}
|
||||
});
|
||||
|
||||
const currentTree = await this.ocktokit.git.getTree({
|
||||
@@ -380,7 +416,9 @@ export class GitHubClient {
|
||||
repo,
|
||||
tree_sha: currentRef.data.object.sha,
|
||||
recursive: "1",
|
||||
headers: GitHubClient.getDisableCacheHeaders()
|
||||
headers: {
|
||||
"If-None-Match": "" // disable 60s cache
|
||||
}
|
||||
});
|
||||
|
||||
// API infers tree from paths so we need to filter them out
|
||||
@@ -425,7 +463,7 @@ export class GitHubClient {
|
||||
|
||||
public async deleteFileAsync(file: IGitHubFile, message: string): Promise<IGitHubResponse<IGitHubCommit>> {
|
||||
const response = await this.ocktokit.repos.deleteFile({
|
||||
owner: file.repo.owner.login,
|
||||
owner: file.repo.owner,
|
||||
repo: file.repo.name,
|
||||
path: file.path,
|
||||
message,
|
||||
@@ -441,10 +479,31 @@ export class GitHubClient {
|
||||
return { status: response.status, data };
|
||||
}
|
||||
|
||||
private initOctokit(token: string) {
|
||||
public async getBlobAsync(owner: string, repo: string, sha: string): Promise<IGitHubResponse<string>> {
|
||||
const response = await this.ocktokit.git.getBlob({
|
||||
owner,
|
||||
repo,
|
||||
file_sha: sha,
|
||||
mediaType: {
|
||||
format: "raw"
|
||||
},
|
||||
headers: {
|
||||
"If-None-Match": "" // disable 60s cache
|
||||
}
|
||||
});
|
||||
|
||||
return { status: response.status, data: <string>(<unknown>response.data) };
|
||||
}
|
||||
|
||||
private async initOctokit(token: string) {
|
||||
this.ocktokit = new Octokit({
|
||||
auth: token,
|
||||
baseUrl: GitHubClient.gitHubApiEndpoint
|
||||
log: {
|
||||
debug: () => {},
|
||||
info: (message?: any) => GitHubClient.log(Logger.logInfo, message),
|
||||
warn: (message?: any) => GitHubClient.log(Logger.logWarning, message),
|
||||
error: (message?: any) => GitHubClient.log(Logger.logError, message)
|
||||
}
|
||||
});
|
||||
|
||||
this.ocktokit.hook.error("request", error => {
|
||||
@@ -453,53 +512,69 @@ export class GitHubClient {
|
||||
});
|
||||
}
|
||||
|
||||
private static getDisableCacheHeaders(): RequestHeaders {
|
||||
private static log(logger: (message: string, area: string) => void, message?: any) {
|
||||
if (message) {
|
||||
message = typeof message === "string" ? message : JSON.stringify(message);
|
||||
logger(message, "GitHubClient.Octokit");
|
||||
}
|
||||
}
|
||||
|
||||
private static toGitHubRepo(object: Repository): IGitHubRepo {
|
||||
return {
|
||||
"If-None-Match": ""
|
||||
owner: object.owner.login,
|
||||
name: object.name,
|
||||
private: object.isPrivate
|
||||
};
|
||||
}
|
||||
|
||||
private static toGitHubRepo(element: IGitHubRepo): IGitHubRepo {
|
||||
private static toGitHubBranch(object: Ref): IGitHubBranch {
|
||||
return {
|
||||
name: element.name,
|
||||
owner: {
|
||||
login: element.owner.login
|
||||
},
|
||||
private: element.private
|
||||
name: object.name
|
||||
};
|
||||
}
|
||||
|
||||
private static toGitHubBranch(element: IGitHubBranch): IGitHubBranch {
|
||||
private static toGitHubCommit(object: {
|
||||
message: string;
|
||||
committer: {
|
||||
date: string;
|
||||
};
|
||||
sha?: string;
|
||||
oid?: string;
|
||||
}): IGitHubCommit {
|
||||
return {
|
||||
name: element.name
|
||||
sha: object.sha || object.oid,
|
||||
message: object.message,
|
||||
commitDate: object.committer.date
|
||||
};
|
||||
}
|
||||
|
||||
private static toGitHubCommit(element: IGitHubCommit): IGitHubCommit {
|
||||
private static toGitHubPageInfo(object: PageInfo): IGitHubPageInfo {
|
||||
return {
|
||||
sha: element.sha,
|
||||
message: element.message,
|
||||
committer: {
|
||||
date: element.committer.date
|
||||
}
|
||||
endCursor: object.endCursor,
|
||||
hasNextPage: object.hasNextPage
|
||||
};
|
||||
}
|
||||
|
||||
private static toGitHubFile(element: IGitHubFile, repo: IGitHubRepo, branch: IGitHubBranch): IGitHubFile {
|
||||
private static toGitHubFile(
|
||||
entry: TreeEntry,
|
||||
path: string,
|
||||
repo: IGitHubRepo,
|
||||
branch: IGitHubBranch,
|
||||
commit: IGitHubCommit
|
||||
): IGitHubFile {
|
||||
if (entry.type !== "blob" && entry.type !== "tree") {
|
||||
throw new Error(`Unsupported file type: ${entry.type}`);
|
||||
}
|
||||
|
||||
return {
|
||||
type: element.type,
|
||||
encoding: element.encoding,
|
||||
size: element.size,
|
||||
name: element.name,
|
||||
path: element.path,
|
||||
content: element.content,
|
||||
sha: element.sha,
|
||||
type: entry.type,
|
||||
name: entry.name,
|
||||
path,
|
||||
repo,
|
||||
branch
|
||||
branch,
|
||||
commit,
|
||||
size: entry.object?.byteSize,
|
||||
sha: entry.object?.oid
|
||||
};
|
||||
}
|
||||
|
||||
private static isSamplesCall(owner: string, repo: string, branch?: string): boolean {
|
||||
return owner === "Azure-Samples" && repo === "cosmos-notebooks" && (!branch || branch === "master");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,27 +10,30 @@ const gitHubContentProvider = new GitHubContentProvider({
|
||||
gitHubClient,
|
||||
promptForCommitMsg: () => Promise.resolve("commit msg")
|
||||
});
|
||||
const gitHubCommit: IGitHubCommit = {
|
||||
sha: "sha",
|
||||
message: "message",
|
||||
commitDate: "date"
|
||||
};
|
||||
const sampleFile: IGitHubFile = {
|
||||
type: "file",
|
||||
encoding: "encoding",
|
||||
type: "blob",
|
||||
size: 0,
|
||||
name: "name.ipynb",
|
||||
path: "dir/name.ipynb",
|
||||
content: btoa(fixture),
|
||||
content: fixture,
|
||||
sha: "sha",
|
||||
repo: {
|
||||
owner: {
|
||||
login: "login"
|
||||
},
|
||||
owner: "owner",
|
||||
name: "repo",
|
||||
private: false
|
||||
},
|
||||
branch: {
|
||||
name: "branch"
|
||||
}
|
||||
},
|
||||
commit: gitHubCommit
|
||||
};
|
||||
const sampleGitHubUri = GitHubUtils.toContentUri(
|
||||
sampleFile.repo.owner.login,
|
||||
sampleFile.repo.owner,
|
||||
sampleFile.repo.name,
|
||||
sampleFile.branch.name,
|
||||
sampleFile.path
|
||||
@@ -43,16 +46,9 @@ const sampleNotebookModel: IContent<"notebook"> = {
|
||||
created: "",
|
||||
last_modified: "date",
|
||||
mimetype: "application/x-ipynb+json",
|
||||
content: sampleFile.content ? JSON.parse(atob(sampleFile.content)) : null,
|
||||
content: sampleFile.content ? JSON.parse(sampleFile.content) : null,
|
||||
format: "json"
|
||||
};
|
||||
const gitHubCommit: IGitHubCommit = {
|
||||
sha: "sha",
|
||||
message: "message",
|
||||
committer: {
|
||||
date: "date"
|
||||
}
|
||||
};
|
||||
|
||||
describe("GitHubContentProvider remove", () => {
|
||||
it("errors on invalid path", async () => {
|
||||
@@ -125,9 +121,6 @@ describe("GitHubContentProvider get", () => {
|
||||
spyOn(GitHubClient.prototype, "getContentsAsync").and.returnValue(
|
||||
Promise.resolve({ status: HttpStatusCodes.OK, data: sampleFile })
|
||||
);
|
||||
spyOn(GitHubClient.prototype, "getCommitsAsync").and.returnValue(
|
||||
Promise.resolve({ status: HttpStatusCodes.OK, data: [gitHubCommit] })
|
||||
);
|
||||
|
||||
const response = await gitHubContentProvider.get(null, sampleGitHubUri, {}).toPromise();
|
||||
expect(response).toBeDefined();
|
||||
@@ -176,9 +169,6 @@ describe("GitHubContentProvider update", () => {
|
||||
spyOn(GitHubClient.prototype, "renameFileAsync").and.returnValue(
|
||||
Promise.resolve({ status: HttpStatusCodes.OK, data: gitHubCommit })
|
||||
);
|
||||
spyOn(GitHubClient.prototype, "getCommitsAsync").and.returnValue(
|
||||
Promise.resolve({ status: HttpStatusCodes.OK, data: [gitHubCommit] })
|
||||
);
|
||||
|
||||
const response = await gitHubContentProvider.update(null, sampleGitHubUri, sampleNotebookModel).toPromise();
|
||||
expect(response).toBeDefined();
|
||||
@@ -215,18 +205,14 @@ describe("GitHubContentProvider create", () => {
|
||||
spyOn(GitHubClient.prototype, "createOrUpdateFileAsync").and.returnValue(
|
||||
Promise.resolve({ status: HttpStatusCodes.Created, data: gitHubCommit })
|
||||
);
|
||||
spyOn(GitHubClient.prototype, "getContentsAsync").and.returnValue(
|
||||
Promise.resolve({ status: HttpStatusCodes.OK, data: sampleFile })
|
||||
);
|
||||
|
||||
const response = await gitHubContentProvider.create(null, sampleGitHubUri, sampleNotebookModel).toPromise();
|
||||
expect(response).toBeDefined();
|
||||
expect(response.status).toBe(HttpStatusCodes.Created);
|
||||
expect(gitHubClient.createOrUpdateFileAsync).toBeCalled();
|
||||
expect(gitHubClient.getContentsAsync).toBeCalled();
|
||||
expect(response.response.type).toEqual(sampleNotebookModel.type);
|
||||
expect(response.response.name).toEqual(sampleNotebookModel.name);
|
||||
expect(response.response.path).toEqual(sampleNotebookModel.path);
|
||||
expect(response.response.name).toBeDefined();
|
||||
expect(response.response.path).toBeDefined();
|
||||
expect(response.response.content).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { AjaxResponse } from "rxjs/ajax";
|
||||
import { HttpStatusCodes } from "../Common/Constants";
|
||||
import { Logger } from "../Common/Logger";
|
||||
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
|
||||
import { GitHubClient, IGitHubFile, IGitHubResponse, IGitHubCommit } from "./GitHubClient";
|
||||
import { GitHubClient, IGitHubFile, IGitHubResponse, IGitHubCommit, IGitHubBranch } from "./GitHubClient";
|
||||
import { GitHubUtils } from "../Utils/GitHubUtils";
|
||||
import UrlUtility from "../Common/UrlUtility";
|
||||
|
||||
@@ -54,23 +54,14 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
throw new GitHubContentProviderError("Failed to get content", content.status);
|
||||
}
|
||||
|
||||
const contentInfo = GitHubUtils.fromContentUri(uri);
|
||||
const commitResponse = await this.params.gitHubClient.getCommitsAsync(
|
||||
contentInfo.owner,
|
||||
contentInfo.repo,
|
||||
contentInfo.branch,
|
||||
contentInfo.path,
|
||||
1,
|
||||
1
|
||||
);
|
||||
if (commitResponse.status !== HttpStatusCodes.OK) {
|
||||
throw new GitHubContentProviderError("Failed to get commit", commitResponse.status);
|
||||
if (!Array.isArray(content.data) && !content.data.content && params.content !== 0) {
|
||||
const file = content.data;
|
||||
file.content = (
|
||||
await this.params.gitHubClient.getBlobAsync(file.repo.owner, file.repo.name, file.sha)
|
||||
).data;
|
||||
}
|
||||
|
||||
return this.createSuccessAjaxResponse(
|
||||
HttpStatusCodes.OK,
|
||||
this.createContentModel(uri, content.data, commitResponse.data[0], params)
|
||||
);
|
||||
return this.createSuccessAjaxResponse(HttpStatusCodes.OK, this.createContentModel(uri, content.data, params));
|
||||
} catch (error) {
|
||||
Logger.logError(error, "GitHubContentProvider/get", error.errno);
|
||||
return this.createErrorAjaxResponse(error);
|
||||
@@ -90,26 +81,26 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
const gitHubFile = content.data as IGitHubFile;
|
||||
const commitMsg = await this.validateContentAndGetCommitMsg(content, "Rename", "Rename");
|
||||
const newUri = model.path;
|
||||
const newPath = GitHubUtils.fromContentUri(newUri).path;
|
||||
const response = await this.params.gitHubClient.renameFileAsync(
|
||||
gitHubFile.repo.owner.login,
|
||||
gitHubFile.repo.owner,
|
||||
gitHubFile.repo.name,
|
||||
gitHubFile.branch.name,
|
||||
commitMsg,
|
||||
gitHubFile.path,
|
||||
GitHubUtils.fromContentUri(newUri).path
|
||||
newPath
|
||||
);
|
||||
if (response.status !== HttpStatusCodes.OK) {
|
||||
throw new GitHubContentProviderError("Failed to rename", response.status);
|
||||
}
|
||||
|
||||
const updatedContentResponse = await this.getContent(model.path);
|
||||
if (updatedContentResponse.status !== HttpStatusCodes.OK) {
|
||||
throw new GitHubContentProviderError("Failed to get content after renaming", updatedContentResponse.status);
|
||||
}
|
||||
gitHubFile.commit = response.data;
|
||||
gitHubFile.path = newPath;
|
||||
gitHubFile.name = NotebookUtil.getName(gitHubFile.path);
|
||||
|
||||
return this.createSuccessAjaxResponse(
|
||||
HttpStatusCodes.OK,
|
||||
this.createContentModel(newUri, updatedContentResponse.data, response.data, { content: 0 })
|
||||
this.createContentModel(newUri, gitHubFile, { content: 0 })
|
||||
);
|
||||
} catch (error) {
|
||||
Logger.logError(error, "GitHubContentProvider/update", error.errno);
|
||||
@@ -169,14 +160,24 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
}
|
||||
|
||||
const newUri = GitHubUtils.toContentUri(contentInfo.owner, contentInfo.repo, contentInfo.branch, path);
|
||||
const newContentResponse = await this.getContent(newUri);
|
||||
if (newContentResponse.status !== HttpStatusCodes.OK) {
|
||||
throw new GitHubContentProviderError("Failed to get content after creating", newContentResponse.status);
|
||||
}
|
||||
const newGitHubFile: IGitHubFile = {
|
||||
type: "blob",
|
||||
name: NotebookUtil.getName(newUri),
|
||||
path,
|
||||
repo: {
|
||||
owner: contentInfo.owner,
|
||||
name: contentInfo.repo,
|
||||
private: undefined
|
||||
},
|
||||
branch: {
|
||||
name: contentInfo.branch
|
||||
},
|
||||
commit: response.data
|
||||
};
|
||||
|
||||
return this.createSuccessAjaxResponse(
|
||||
HttpStatusCodes.Created,
|
||||
this.createContentModel(newUri, newContentResponse.data, response.data, { content: 0 })
|
||||
this.createContentModel(newUri, newGitHubFile, { content: 0 })
|
||||
);
|
||||
} catch (error) {
|
||||
Logger.logError(error, "GitHubContentProvider/create", error.errno);
|
||||
@@ -209,7 +210,7 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
|
||||
const gitHubFile = content.data as IGitHubFile;
|
||||
const response = await this.params.gitHubClient.createOrUpdateFileAsync(
|
||||
gitHubFile.repo.owner.login,
|
||||
gitHubFile.repo.owner,
|
||||
gitHubFile.repo.name,
|
||||
gitHubFile.branch.name,
|
||||
gitHubFile.path,
|
||||
@@ -221,14 +222,11 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
throw new GitHubContentProviderError("Failed to update", response.status);
|
||||
}
|
||||
|
||||
const savedContentResponse = await this.getContent(uri);
|
||||
if (savedContentResponse.status !== HttpStatusCodes.OK) {
|
||||
throw new GitHubContentProviderError("Failed to get content after updating", savedContentResponse.status);
|
||||
}
|
||||
gitHubFile.commit = response.data;
|
||||
|
||||
return this.createSuccessAjaxResponse(
|
||||
HttpStatusCodes.OK,
|
||||
this.createContentModel(uri, savedContentResponse.data, response.data, { content: 0 })
|
||||
this.createContentModel(uri, gitHubFile, { content: 0 })
|
||||
);
|
||||
} catch (error) {
|
||||
Logger.logError(error, "GitHubContentProvider/update", error.errno);
|
||||
@@ -283,7 +281,7 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
return commitMsg;
|
||||
}
|
||||
|
||||
private getContent(uri: string): Promise<IGitHubResponse<IGitHubFile | IGitHubFile[]>> {
|
||||
private async getContent(uri: string): Promise<IGitHubResponse<IGitHubFile | IGitHubFile[]>> {
|
||||
const contentInfo = GitHubUtils.fromContentUri(uri);
|
||||
if (contentInfo) {
|
||||
const { owner, repo, branch, path } = contentInfo;
|
||||
@@ -296,43 +294,37 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
private createContentModel(
|
||||
uri: string,
|
||||
content: IGitHubFile | IGitHubFile[],
|
||||
commit: IGitHubCommit,
|
||||
params: Partial<IGetParams>
|
||||
): IContent<FileType> {
|
||||
if (Array.isArray(content)) {
|
||||
return this.createDirectoryModel(uri, content, commit);
|
||||
return this.createDirectoryModel(uri, content);
|
||||
}
|
||||
|
||||
if (content.type !== "file") {
|
||||
return this.createDirectoryModel(uri, undefined, commit);
|
||||
if (content.type === "tree") {
|
||||
return this.createDirectoryModel(uri, undefined);
|
||||
}
|
||||
|
||||
if (NotebookUtil.isNotebookFile(uri)) {
|
||||
return this.createNotebookModel(content, commit, params);
|
||||
return this.createNotebookModel(content, params);
|
||||
}
|
||||
|
||||
return this.createFileModel(content, commit, params);
|
||||
return this.createFileModel(content, params);
|
||||
}
|
||||
|
||||
private createDirectoryModel(
|
||||
uri: string,
|
||||
gitHubFiles: IGitHubFile[] | undefined,
|
||||
commit: IGitHubCommit
|
||||
): IContent<"directory"> {
|
||||
private createDirectoryModel(uri: string, gitHubFiles: IGitHubFile[] | undefined): IContent<"directory"> {
|
||||
return {
|
||||
name: GitHubUtils.fromContentUri(uri).path,
|
||||
name: NotebookUtil.getName(uri),
|
||||
path: uri,
|
||||
type: "directory",
|
||||
writable: true, // TODO: tamitta: we don't know this info here
|
||||
created: "", // TODO: tamitta: we don't know this info here
|
||||
last_modified: commit.committer.date,
|
||||
last_modified: "", // TODO: tamitta: we don't know this info here
|
||||
mimetype: undefined,
|
||||
content: gitHubFiles?.map(
|
||||
(file: IGitHubFile) =>
|
||||
this.createContentModel(
|
||||
GitHubUtils.toContentUri(file.repo.owner.login, file.repo.name, file.branch.name, file.path),
|
||||
GitHubUtils.toContentUri(file.repo.owner, file.repo.name, file.branch.name, file.path),
|
||||
file,
|
||||
commit,
|
||||
{
|
||||
content: 0
|
||||
}
|
||||
@@ -342,17 +334,12 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
};
|
||||
}
|
||||
|
||||
private createNotebookModel(
|
||||
gitHubFile: IGitHubFile,
|
||||
commit: IGitHubCommit,
|
||||
params: Partial<IGetParams>
|
||||
): IContent<"notebook"> {
|
||||
const content: Notebook =
|
||||
gitHubFile.content && params.content !== 0 ? JSON.parse(atob(gitHubFile.content)) : undefined;
|
||||
private createNotebookModel(gitHubFile: IGitHubFile, params: Partial<IGetParams>): IContent<"notebook"> {
|
||||
const content: Notebook = gitHubFile.content && params.content !== 0 ? JSON.parse(gitHubFile.content) : undefined;
|
||||
return {
|
||||
name: gitHubFile.name,
|
||||
path: GitHubUtils.toContentUri(
|
||||
gitHubFile.repo.owner.login,
|
||||
gitHubFile.repo.owner,
|
||||
gitHubFile.repo.name,
|
||||
gitHubFile.branch.name,
|
||||
gitHubFile.path
|
||||
@@ -360,23 +347,19 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
type: "notebook",
|
||||
writable: true, // TODO: tamitta: we don't know this info here
|
||||
created: "", // TODO: tamitta: we don't know this info here
|
||||
last_modified: commit.committer.date,
|
||||
last_modified: gitHubFile.commit.commitDate,
|
||||
mimetype: content ? "application/x-ipynb+json" : undefined,
|
||||
content,
|
||||
format: content ? "json" : undefined
|
||||
};
|
||||
}
|
||||
|
||||
private createFileModel(
|
||||
gitHubFile: IGitHubFile,
|
||||
commit: IGitHubCommit,
|
||||
params: Partial<IGetParams>
|
||||
): IContent<"file"> {
|
||||
const content: string = gitHubFile.content && params.content !== 0 ? atob(gitHubFile.content) : undefined;
|
||||
private createFileModel(gitHubFile: IGitHubFile, params: Partial<IGetParams>): IContent<"file"> {
|
||||
const content: string = gitHubFile.content && params.content !== 0 ? gitHubFile.content : undefined;
|
||||
return {
|
||||
name: gitHubFile.name,
|
||||
path: GitHubUtils.toContentUri(
|
||||
gitHubFile.repo.owner.login,
|
||||
gitHubFile.repo.owner,
|
||||
gitHubFile.repo.name,
|
||||
gitHubFile.branch.name,
|
||||
gitHubFile.path
|
||||
@@ -384,7 +367,7 @@ export class GitHubContentProvider implements IContentProvider {
|
||||
type: "file",
|
||||
writable: true, // TODO: tamitta: we don't know this info here
|
||||
created: "", // TODO: tamitta: we don't know this info here
|
||||
last_modified: commit.committer.date,
|
||||
last_modified: gitHubFile.commit.commitDate,
|
||||
mimetype: content ? "text/plain" : undefined,
|
||||
content,
|
||||
format: content ? "text" : undefined
|
||||
|
||||
Reference in New Issue
Block a user