mirror of
https://github.com/silvanocerza/github-gitless-sync.git
synced 2026-07-22 12:10:28 +00:00
193 lines
4.8 KiB
TypeScript
193 lines
4.8 KiB
TypeScript
import { Vault, requestUrl, normalizePath } from "obsidian";
|
|
import MetadataStore, { Metadata } from "../metadata-store";
|
|
|
|
export type RepoContent = {
|
|
files: { [key: string]: GetTreeResponseItem };
|
|
sha: string;
|
|
};
|
|
|
|
/**
|
|
* Represents a single item in a tree response from the GitHub API.
|
|
*/
|
|
export type GetTreeResponseItem = {
|
|
path: string;
|
|
mode: string;
|
|
type: string;
|
|
sha: string;
|
|
size: number;
|
|
url: string;
|
|
};
|
|
|
|
export type NewTreeRequestItem = {
|
|
path: string;
|
|
mode: string;
|
|
type: string;
|
|
sha?: string | null;
|
|
content?: string;
|
|
};
|
|
|
|
/**
|
|
* Represents a git blob response from the GitHub API.
|
|
*/
|
|
export type BlobFile = {
|
|
sha: string;
|
|
node_id: string;
|
|
size: number;
|
|
url: string;
|
|
content: string;
|
|
encoding: string;
|
|
};
|
|
|
|
export default class GithubClient {
|
|
constructor(
|
|
private token: string,
|
|
private owner: string,
|
|
private repo: string,
|
|
private branch: string,
|
|
private repoContentDir: string,
|
|
private configDir: string,
|
|
) {}
|
|
|
|
headers() {
|
|
return {
|
|
Accept: "application/vnd.github+json",
|
|
Authorization: `Bearer ${this.token}`,
|
|
"X-GitHub-Api-Version": "2022-11-28",
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Gets the content of the repo.
|
|
*
|
|
* @returns Array of files in the directory in the remote repo
|
|
*/
|
|
async getRepoContent(): Promise<RepoContent> {
|
|
const res = await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/git/trees/${this.branch}?recursive=1`,
|
|
headers: this.headers(),
|
|
});
|
|
const files = res.json.tree
|
|
.filter((file: GetTreeResponseItem) => file.type === "blob")
|
|
.reduce(
|
|
(
|
|
acc: { [key: string]: GetTreeResponseItem },
|
|
file: GetTreeResponseItem,
|
|
) => ({ ...acc, [file.path]: file }),
|
|
{},
|
|
);
|
|
return { files, sha: res.json.sha };
|
|
}
|
|
|
|
async createTree(tree: { tree: NewTreeRequestItem[]; base_tree: string }) {
|
|
const res = await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/git/trees`,
|
|
headers: this.headers(),
|
|
method: "POST",
|
|
body: JSON.stringify(tree),
|
|
});
|
|
return res.json.sha;
|
|
}
|
|
|
|
async createCommit(message: string, treeSha: string, parent: string) {
|
|
const res = await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/git/commits`,
|
|
headers: this.headers(),
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
message: message,
|
|
tree: treeSha,
|
|
parents: [parent],
|
|
}),
|
|
});
|
|
return res.json.sha;
|
|
}
|
|
|
|
async getBranchHeadSha() {
|
|
const res = await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/git/refs/heads/${this.branch}`,
|
|
headers: this.headers(),
|
|
});
|
|
return res.json.object.sha;
|
|
}
|
|
|
|
async updateBranchHead(sha: string) {
|
|
await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/git/refs/heads/${this.branch}`,
|
|
headers: this.headers(),
|
|
method: "PATCH",
|
|
body: JSON.stringify({
|
|
sha: sha,
|
|
}),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gets a blob from a blob url
|
|
* @param url blob url
|
|
*/
|
|
async getBlob(url: string): Promise<BlobFile> {
|
|
const res = await requestUrl({
|
|
url: url,
|
|
headers: this.headers(),
|
|
});
|
|
return res.json;
|
|
}
|
|
|
|
/**
|
|
* Create or edit a remote file to GitHub.
|
|
*
|
|
* @param remoteFilePath Path to remote file
|
|
* @param fileContent Content of the file
|
|
* @param sha SHA of the file
|
|
*/
|
|
async uploadFile(
|
|
remoteFilePath: string,
|
|
fileContent: ArrayBuffer,
|
|
sha: string | null,
|
|
) {
|
|
await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/contents/${remoteFilePath}`,
|
|
method: "PUT",
|
|
headers: this.headers(),
|
|
body: JSON.stringify({
|
|
message: `Edit ${remoteFilePath}`,
|
|
branch: this.branch,
|
|
content: Buffer.from(fileContent).toString("base64"),
|
|
sha: sha,
|
|
}),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gets the SHA of a file in the remote repo.
|
|
*
|
|
* @param remoteFilePath Path to remote file
|
|
* @returns sha of the file as string
|
|
*/
|
|
async getFileSha(remoteFilePath: string) {
|
|
const res = await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/contents/${remoteFilePath}?ref=${this.branch}`,
|
|
headers: this.headers(),
|
|
});
|
|
return res.json.sha;
|
|
}
|
|
|
|
/**
|
|
* Delete a single file from GitHub.
|
|
*
|
|
* @param remoteFilePath Path to remote file
|
|
* @param sha SHA of the file
|
|
*/
|
|
async deleteFile(remoteFilePath: string, sha: string) {
|
|
await requestUrl({
|
|
url: `https://api.github.com/repos/${this.owner}/${this.repo}/contents/${remoteFilePath}`,
|
|
method: "DELETE",
|
|
headers: this.headers(),
|
|
body: JSON.stringify({
|
|
message: `Delete ${remoteFilePath}`,
|
|
branch: this.branch,
|
|
sha: sha,
|
|
}),
|
|
});
|
|
}
|
|
}
|