зеркало из https://github.com/Azure/git-rest-api.git
Add tree route and recursive option (#52)
* Add tree route and recursive option * Add recursive to swagger * Fix lint * Address feedback * Fix lint * Bump package * Rename variable * Fix missing path in spec * Fix logic * Add content test * Add test for tree controller * Update branches snap * Fix snap * Small fixes * Fix lint
This commit is contained in:
Родитель
638ea5b524
Коммит
c4a58efd9d
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "git-rest-api",
|
||||
"version": "0.3.2",
|
||||
"version": "0.3.3",
|
||||
"description": "This project welcomes contributions and suggestions. Most contributions require you to agree to a\r Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us\r the rights to use your contribution. For details, visit https://cla.microsoft.com.",
|
||||
"main": "bin/main.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
ContentController,
|
||||
HealthCheckController,
|
||||
} from "./controllers";
|
||||
import { TreeController } from "./controllers/tree/tree.controller";
|
||||
import { Telemetry, createTelemetry } from "./core";
|
||||
import { ContextMiddleware, LoggingInterceptor } from "./middlewares";
|
||||
import {
|
||||
|
@ -31,7 +32,14 @@ import { RepoIndexService } from "./services/repo-index";
|
|||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [HealthCheckController, BranchesController, CommitsController, CompareController, ContentController],
|
||||
controllers: [
|
||||
HealthCheckController,
|
||||
BranchesController,
|
||||
CommitsController,
|
||||
CompareController,
|
||||
ContentController,
|
||||
TreeController,
|
||||
],
|
||||
providers: [
|
||||
AppService,
|
||||
CompareService,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Controller, Get, HttpException, Param } from "@nestjs/common";
|
|||
import { ApiNotFoundResponse, ApiOkResponse, ApiOperation } from "@nestjs/swagger";
|
||||
|
||||
import { ApiHasPassThruAuth, Auth, RepoAuth } from "../../core";
|
||||
import { GitDiff } from "../../dtos/git-diff";
|
||||
import { GitDiff } from "../../dtos";
|
||||
import { CompareService } from "../../services";
|
||||
|
||||
@Controller("/repos/:remote/compare")
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/contents' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir1",
|
||||
"path": "dir1",
|
||||
"sha": "b638a8a4a9f44184a3a430988a9c5ef383bad364",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"content": "IyBMb2dzCmxvZ3MKKi5sb2cKbnBtLWRlYnVnLmxvZyoKeWFybi1kZWJ1Zy5sb2cqCnlhcm4tZXJyb3IubG9nKgoKIyBSdW50aW1lIGRhdGEKcGlkcwoqLnBpZAoqLnNlZWQKKi5waWQubG9jawoKIyBEaXJlY3RvcnkgZm9yIGluc3RydW1lbnRlZCBsaWJzIGdlbmVyYXRlZCBieSBqc2NvdmVyYWdlL0pTQ292ZXIKbGliLWNvdgoKIyBDb3ZlcmFnZSBkaXJlY3RvcnkgdXNlZCBieSB0b29scyBsaWtlIGlzdGFuYnVsCmNvdmVyYWdlCgojIG55YyB0ZXN0IGNvdmVyYWdlCi5ueWNfb3V0cHV0CgojIEdydW50IGludGVybWVkaWF0ZSBzdG9yYWdlIChodHRwOi8vZ3J1bnRqcy5jb20vY3JlYXRpbmctcGx1Z2lucyNzdG9yaW5nLXRhc2stZmlsZXMpCi5ncnVudAoKIyBCb3dlciBkZXBlbmRlbmN5IGRpcmVjdG9yeSAoaHR0cHM6Ly9ib3dlci5pby8pCmJvd2VyX2NvbXBvbmVudHMKCiMgbm9kZS13YWYgY29uZmlndXJhdGlvbgoubG9jay13c2NyaXB0CgojIENvbXBpbGVkIGJpbmFyeSBhZGRvbnMgKGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvYWRkb25zLmh0bWwpCmJ1aWxkL1JlbGVhc2UKCiMgRGVwZW5kZW5jeSBkaXJlY3Rvcmllcwpub2RlX21vZHVsZXMvCmpzcG1fcGFja2FnZXMvCgojIFR5cGVTY3JpcHQgdjEgZGVjbGFyYXRpb24gZmlsZXMKdHlwaW5ncy8KCiMgT3B0aW9uYWwgbnBtIGNhY2hlIGRpcmVjdG9yeQoubnBtCgojIE9wdGlvbmFsIGVzbGludCBjYWNoZQouZXNsaW50Y2FjaGUKCiMgT3B0aW9uYWwgUkVQTCBoaXN0b3J5Ci5ub2RlX3JlcGxfaGlzdG9yeQoKIyBPdXRwdXQgb2YgJ25wbSBwYWNrJwoqLnRnegoKIyBZYXJuIEludGVncml0eSBmaWxlCi55YXJuLWludGVncml0eQoKIyBkb3RlbnYgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZpbGUKLmVudgoKIyBuZXh0LmpzIGJ1aWxkIG91dHB1dAoubmV4dAo=",
|
||||
"encoding": "base64",
|
||||
"name": ".gitignore",
|
||||
"path": ".gitignore",
|
||||
"sha": "ad46b30886fa350c1f59761b100e5e4b01f9a7ec",
|
||||
"size": 914,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAxOSB0ZXN0LXJlcG8tYmlsbHkKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==",
|
||||
"encoding": "base64",
|
||||
"name": "LICENSE",
|
||||
"path": "LICENSE",
|
||||
"sha": "98023418cdb98210a5f71ea74ec557dbbd8f0e83",
|
||||
"size": 1072,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "IyBnaXQtYXBpLXRlc3RzClJlcG8gdXNlZCBmb3IgaW50ZWdyYXRpb24gdGVzdGluZyBvZiB0aGUgZ2l0LXRlc3QtYXBpIHByb2plY3QK",
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/contents/' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir1",
|
||||
"path": "dir1",
|
||||
"sha": "b638a8a4a9f44184a3a430988a9c5ef383bad364",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"content": "IyBMb2dzCmxvZ3MKKi5sb2cKbnBtLWRlYnVnLmxvZyoKeWFybi1kZWJ1Zy5sb2cqCnlhcm4tZXJyb3IubG9nKgoKIyBSdW50aW1lIGRhdGEKcGlkcwoqLnBpZAoqLnNlZWQKKi5waWQubG9jawoKIyBEaXJlY3RvcnkgZm9yIGluc3RydW1lbnRlZCBsaWJzIGdlbmVyYXRlZCBieSBqc2NvdmVyYWdlL0pTQ292ZXIKbGliLWNvdgoKIyBDb3ZlcmFnZSBkaXJlY3RvcnkgdXNlZCBieSB0b29scyBsaWtlIGlzdGFuYnVsCmNvdmVyYWdlCgojIG55YyB0ZXN0IGNvdmVyYWdlCi5ueWNfb3V0cHV0CgojIEdydW50IGludGVybWVkaWF0ZSBzdG9yYWdlIChodHRwOi8vZ3J1bnRqcy5jb20vY3JlYXRpbmctcGx1Z2lucyNzdG9yaW5nLXRhc2stZmlsZXMpCi5ncnVudAoKIyBCb3dlciBkZXBlbmRlbmN5IGRpcmVjdG9yeSAoaHR0cHM6Ly9ib3dlci5pby8pCmJvd2VyX2NvbXBvbmVudHMKCiMgbm9kZS13YWYgY29uZmlndXJhdGlvbgoubG9jay13c2NyaXB0CgojIENvbXBpbGVkIGJpbmFyeSBhZGRvbnMgKGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvYWRkb25zLmh0bWwpCmJ1aWxkL1JlbGVhc2UKCiMgRGVwZW5kZW5jeSBkaXJlY3Rvcmllcwpub2RlX21vZHVsZXMvCmpzcG1fcGFja2FnZXMvCgojIFR5cGVTY3JpcHQgdjEgZGVjbGFyYXRpb24gZmlsZXMKdHlwaW5ncy8KCiMgT3B0aW9uYWwgbnBtIGNhY2hlIGRpcmVjdG9yeQoubnBtCgojIE9wdGlvbmFsIGVzbGludCBjYWNoZQouZXNsaW50Y2FjaGUKCiMgT3B0aW9uYWwgUkVQTCBoaXN0b3J5Ci5ub2RlX3JlcGxfaGlzdG9yeQoKIyBPdXRwdXQgb2YgJ25wbSBwYWNrJwoqLnRnegoKIyBZYXJuIEludGVncml0eSBmaWxlCi55YXJuLWludGVncml0eQoKIyBkb3RlbnYgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZpbGUKLmVudgoKIyBuZXh0LmpzIGJ1aWxkIG91dHB1dAoubmV4dAo=",
|
||||
"encoding": "base64",
|
||||
"name": ".gitignore",
|
||||
"path": ".gitignore",
|
||||
"sha": "ad46b30886fa350c1f59761b100e5e4b01f9a7ec",
|
||||
"size": 914,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAxOSB0ZXN0LXJlcG8tYmlsbHkKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==",
|
||||
"encoding": "base64",
|
||||
"name": "LICENSE",
|
||||
"path": "LICENSE",
|
||||
"sha": "98023418cdb98210a5f71ea74ec557dbbd8f0e83",
|
||||
"size": 1072,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "IyBnaXQtYXBpLXRlc3RzClJlcG8gdXNlZCBmb3IgaW50ZWdyYXRpb24gdGVzdGluZyBvZiB0aGUgZ2l0LXRlc3QtYXBpIHByb2plY3QK",
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/contents/README.md' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [],
|
||||
"files": Array [
|
||||
Object {
|
||||
"content": "IyBnaXQtYXBpLXRlc3RzClJlcG8gdXNlZCBmb3IgaW50ZWdyYXRpb24gdGVzdGluZyBvZiB0aGUgZ2l0LXRlc3QtYXBpIHByb2plY3QK",
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/contents/dir1' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir2",
|
||||
"path": "dir1/dir2",
|
||||
"sha": "483221c9d8371862bdb2c5d452130ab5ca0534a3",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"content": "ZmlsZUEK",
|
||||
"encoding": "base64",
|
||||
"name": "fileA.txt",
|
||||
"path": "dir1/fileA.txt",
|
||||
"sha": "ab47708c98ac88bbdf3ca75f4730d86a84f702a2",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/contents/dir1?recursive=true' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir2",
|
||||
"path": "dir1/dir2",
|
||||
"sha": "483221c9d8371862bdb2c5d452130ab5ca0534a3",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"content": "ZmlsZUEK",
|
||||
"encoding": "base64",
|
||||
"name": "fileA.txt",
|
||||
"path": "dir1/fileA.txt",
|
||||
"sha": "ab47708c98ac88bbdf3ca75f4730d86a84f702a2",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "ZmlsZUIK",
|
||||
"encoding": "base64",
|
||||
"name": "fileB.txt",
|
||||
"path": "dir1/dir2/fileB.txt",
|
||||
"sha": "78ed112c991c8abeba325c039a398ba626c425ab",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/contents?recursive=true' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir1",
|
||||
"path": "dir1",
|
||||
"sha": "b638a8a4a9f44184a3a430988a9c5ef383bad364",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
Object {
|
||||
"name": "dir2",
|
||||
"path": "dir1/dir2",
|
||||
"sha": "483221c9d8371862bdb2c5d452130ab5ca0534a3",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"content": "IyBMb2dzCmxvZ3MKKi5sb2cKbnBtLWRlYnVnLmxvZyoKeWFybi1kZWJ1Zy5sb2cqCnlhcm4tZXJyb3IubG9nKgoKIyBSdW50aW1lIGRhdGEKcGlkcwoqLnBpZAoqLnNlZWQKKi5waWQubG9jawoKIyBEaXJlY3RvcnkgZm9yIGluc3RydW1lbnRlZCBsaWJzIGdlbmVyYXRlZCBieSBqc2NvdmVyYWdlL0pTQ292ZXIKbGliLWNvdgoKIyBDb3ZlcmFnZSBkaXJlY3RvcnkgdXNlZCBieSB0b29scyBsaWtlIGlzdGFuYnVsCmNvdmVyYWdlCgojIG55YyB0ZXN0IGNvdmVyYWdlCi5ueWNfb3V0cHV0CgojIEdydW50IGludGVybWVkaWF0ZSBzdG9yYWdlIChodHRwOi8vZ3J1bnRqcy5jb20vY3JlYXRpbmctcGx1Z2lucyNzdG9yaW5nLXRhc2stZmlsZXMpCi5ncnVudAoKIyBCb3dlciBkZXBlbmRlbmN5IGRpcmVjdG9yeSAoaHR0cHM6Ly9ib3dlci5pby8pCmJvd2VyX2NvbXBvbmVudHMKCiMgbm9kZS13YWYgY29uZmlndXJhdGlvbgoubG9jay13c2NyaXB0CgojIENvbXBpbGVkIGJpbmFyeSBhZGRvbnMgKGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvYWRkb25zLmh0bWwpCmJ1aWxkL1JlbGVhc2UKCiMgRGVwZW5kZW5jeSBkaXJlY3Rvcmllcwpub2RlX21vZHVsZXMvCmpzcG1fcGFja2FnZXMvCgojIFR5cGVTY3JpcHQgdjEgZGVjbGFyYXRpb24gZmlsZXMKdHlwaW5ncy8KCiMgT3B0aW9uYWwgbnBtIGNhY2hlIGRpcmVjdG9yeQoubnBtCgojIE9wdGlvbmFsIGVzbGludCBjYWNoZQouZXNsaW50Y2FjaGUKCiMgT3B0aW9uYWwgUkVQTCBoaXN0b3J5Ci5ub2RlX3JlcGxfaGlzdG9yeQoKIyBPdXRwdXQgb2YgJ25wbSBwYWNrJwoqLnRnegoKIyBZYXJuIEludGVncml0eSBmaWxlCi55YXJuLWludGVncml0eQoKIyBkb3RlbnYgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZpbGUKLmVudgoKIyBuZXh0LmpzIGJ1aWxkIG91dHB1dAoubmV4dAo=",
|
||||
"encoding": "base64",
|
||||
"name": ".gitignore",
|
||||
"path": ".gitignore",
|
||||
"sha": "ad46b30886fa350c1f59761b100e5e4b01f9a7ec",
|
||||
"size": 914,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAxOSB0ZXN0LXJlcG8tYmlsbHkKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==",
|
||||
"encoding": "base64",
|
||||
"name": "LICENSE",
|
||||
"path": "LICENSE",
|
||||
"sha": "98023418cdb98210a5f71ea74ec557dbbd8f0e83",
|
||||
"size": 1072,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "IyBnaXQtYXBpLXRlc3RzClJlcG8gdXNlZCBmb3IgaW50ZWdyYXRpb24gdGVzdGluZyBvZiB0aGUgZ2l0LXRlc3QtYXBpIHByb2plY3QK",
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "ZmlsZUEK",
|
||||
"encoding": "base64",
|
||||
"name": "fileA.txt",
|
||||
"path": "dir1/fileA.txt",
|
||||
"sha": "ab47708c98ac88bbdf3ca75f4730d86a84f702a2",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"content": "ZmlsZUIK",
|
||||
"encoding": "base64",
|
||||
"name": "fileB.txt",
|
||||
"path": "dir1/dir2/fileB.txt",
|
||||
"sha": "78ed112c991c8abeba325c039a398ba626c425ab",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,15 @@
|
|||
import { TEST_REPO, e2eClient } from "../../../test/e2e";
|
||||
|
||||
describe("Test content controller", () => {
|
||||
const base = `/repos/${TEST_REPO}/contents`;
|
||||
test.each(["", "/", "/README.md", "/dir1", "/dir1?recursive=true", "?recursive=true"])(
|
||||
`for path '${base}%s'`,
|
||||
async tail => {
|
||||
const response = await e2eClient.fetch(`${base}${tail}`);
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
const body = await response.json();
|
||||
expect(body).toMatchSnapshot();
|
||||
},
|
||||
);
|
||||
});
|
|
@ -1,27 +1,40 @@
|
|||
import { Controller, Get, HttpException, Param, Query } from "@nestjs/common";
|
||||
import { ApiImplicitQuery, ApiNotFoundResponse, ApiOkResponse, ApiOperation } from "@nestjs/swagger";
|
||||
import { ApiImplicitParam, ApiImplicitQuery, ApiNotFoundResponse, ApiOkResponse, ApiOperation } from "@nestjs/swagger";
|
||||
|
||||
import { ApiHasPassThruAuth, Auth, RepoAuth } from "../../core";
|
||||
import { GitContents } from "../../dtos/git-contents";
|
||||
import { GitContents } from "../../dtos";
|
||||
import { ContentService } from "../../services/content";
|
||||
import { parseBooleanFromURLParam } from "../../utils";
|
||||
|
||||
@Controller("/repos/:remote/contents")
|
||||
export class ContentController {
|
||||
constructor(private contentService: ContentService) {}
|
||||
|
||||
@Get([":path([^/]*)", "*"])
|
||||
@Get([":path([^/]*)", ""])
|
||||
@ApiHasPassThruAuth()
|
||||
@ApiOkResponse({ type: GitContents })
|
||||
@ApiImplicitQuery({ name: "ref", required: false, type: "string" })
|
||||
@ApiImplicitQuery({ name: "recursive", required: false, type: "string" })
|
||||
@ApiImplicitParam({ name: "path", type: "string" })
|
||||
@ApiOperation({ title: "Get content", operationId: "contents_get" })
|
||||
@ApiNotFoundResponse({})
|
||||
public async getContents(
|
||||
@Param("remote") remote: string,
|
||||
@Param("path") path: string | undefined,
|
||||
@Query("ref") ref: string | undefined,
|
||||
@Query("recursive") recursive: string | undefined,
|
||||
@Auth() auth: RepoAuth,
|
||||
) {
|
||||
const content = await this.contentService.getContents(remote, path, ref, { auth });
|
||||
const content = await this.contentService.getContents(
|
||||
remote,
|
||||
path,
|
||||
ref,
|
||||
parseBooleanFromURLParam(recursive),
|
||||
true,
|
||||
{
|
||||
auth,
|
||||
},
|
||||
);
|
||||
if (content instanceof HttpException) {
|
||||
throw content;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/tree' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir1",
|
||||
"path": "dir1",
|
||||
"sha": "b638a8a4a9f44184a3a430988a9c5ef383bad364",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
Object {
|
||||
"name": "dir2",
|
||||
"path": "dir1/dir2",
|
||||
"sha": "483221c9d8371862bdb2c5d452130ab5ca0534a3",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": ".gitignore",
|
||||
"path": ".gitignore",
|
||||
"sha": "ad46b30886fa350c1f59761b100e5e4b01f9a7ec",
|
||||
"size": 914,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "LICENSE",
|
||||
"path": "LICENSE",
|
||||
"sha": "98023418cdb98210a5f71ea74ec557dbbd8f0e83",
|
||||
"size": 1072,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "fileA.txt",
|
||||
"path": "dir1/fileA.txt",
|
||||
"sha": "ab47708c98ac88bbdf3ca75f4730d86a84f702a2",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "fileB.txt",
|
||||
"path": "dir1/dir2/fileB.txt",
|
||||
"sha": "78ed112c991c8abeba325c039a398ba626c425ab",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/tree/' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir1",
|
||||
"path": "dir1",
|
||||
"sha": "b638a8a4a9f44184a3a430988a9c5ef383bad364",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
Object {
|
||||
"name": "dir2",
|
||||
"path": "dir1/dir2",
|
||||
"sha": "483221c9d8371862bdb2c5d452130ab5ca0534a3",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": ".gitignore",
|
||||
"path": ".gitignore",
|
||||
"sha": "ad46b30886fa350c1f59761b100e5e4b01f9a7ec",
|
||||
"size": 914,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "LICENSE",
|
||||
"path": "LICENSE",
|
||||
"sha": "98023418cdb98210a5f71ea74ec557dbbd8f0e83",
|
||||
"size": 1072,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "fileA.txt",
|
||||
"path": "dir1/fileA.txt",
|
||||
"sha": "ab47708c98ac88bbdf3ca75f4730d86a84f702a2",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "fileB.txt",
|
||||
"path": "dir1/dir2/fileB.txt",
|
||||
"sha": "78ed112c991c8abeba325c039a398ba626c425ab",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/tree/README.md' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [],
|
||||
"files": Array [
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "b5fd37e731f1e7931da42484ae0290554cb42c0f",
|
||||
"size": 78,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Test content controller for path '/repos/github.com%2Ftest-repo-billy%2Fgit-api-tests/tree/dir1' 1`] = `
|
||||
Object {
|
||||
"dirs": Array [
|
||||
Object {
|
||||
"name": "dir2",
|
||||
"path": "dir1/dir2",
|
||||
"sha": "483221c9d8371862bdb2c5d452130ab5ca0534a3",
|
||||
"size": 0,
|
||||
"type": "dir",
|
||||
},
|
||||
],
|
||||
"files": Array [
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "fileA.txt",
|
||||
"path": "dir1/fileA.txt",
|
||||
"sha": "ab47708c98ac88bbdf3ca75f4730d86a84f702a2",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
Object {
|
||||
"encoding": "base64",
|
||||
"name": "fileB.txt",
|
||||
"path": "dir1/dir2/fileB.txt",
|
||||
"sha": "78ed112c991c8abeba325c039a398ba626c425ab",
|
||||
"size": 6,
|
||||
"type": "file",
|
||||
},
|
||||
],
|
||||
"submodules": Array [],
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,12 @@
|
|||
import { TEST_REPO, e2eClient } from "../../../test/e2e";
|
||||
|
||||
describe("Test content controller", () => {
|
||||
const base = `/repos/${TEST_REPO}/tree`;
|
||||
test.each(["", "/", "/README.md", "/dir1"])(`for path '${base}%s'`, async tail => {
|
||||
const response = await e2eClient.fetch(`${base}${tail}`);
|
||||
expect(response.status).toEqual(200);
|
||||
|
||||
const body = await response.json();
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
import { Controller, Get, HttpException, Param, Query } from "@nestjs/common";
|
||||
import { ApiImplicitParam, ApiImplicitQuery, ApiNotFoundResponse, ApiOkResponse, ApiOperation } from "@nestjs/swagger";
|
||||
|
||||
import { ApiHasPassThruAuth, Auth, RepoAuth } from "../../core";
|
||||
import { GitTree } from "../../dtos";
|
||||
import { ContentService } from "../../services/content";
|
||||
|
||||
@Controller("/repos/:remote/tree")
|
||||
export class TreeController {
|
||||
constructor(private contentService: ContentService) {}
|
||||
|
||||
@Get([":path([^/]*)", ""])
|
||||
@ApiHasPassThruAuth()
|
||||
@ApiOkResponse({ type: GitTree })
|
||||
@ApiImplicitQuery({ name: "ref", required: false, type: "string" })
|
||||
@ApiOperation({ title: "Get tree", operationId: "tree_get" })
|
||||
@ApiImplicitParam({ name: "path", type: "string" })
|
||||
@ApiNotFoundResponse({})
|
||||
public async getTree(
|
||||
@Param("remote") remote: string,
|
||||
@Param("path") path: string | undefined,
|
||||
@Query("ref") ref: string | undefined,
|
||||
@Auth() auth: RepoAuth,
|
||||
) {
|
||||
const tree = await this.contentService.getContents(remote, path, ref, true, false, { auth });
|
||||
if (tree instanceof HttpException) {
|
||||
throw tree;
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
import { ApiModelProperty } from "@nestjs/swagger";
|
||||
|
||||
import { GitDirObjectContent } from "./git-dir-object-content";
|
||||
import { GitFileObjectContent } from "./git-file-object-content";
|
||||
import { GitFileObjectWithContent } from "./git-file-object-with-content";
|
||||
import { GitSubmoduleObjectContent } from "./git-submodule-object-content";
|
||||
|
||||
export class GitContents {
|
||||
export class GitTree {
|
||||
@ApiModelProperty({ type: GitDirObjectContent, isArray: true })
|
||||
public dirs: GitDirObjectContent[];
|
||||
@ApiModelProperty({ type: GitFileObjectContent, isArray: true })
|
||||
public files: GitFileObjectContent[];
|
||||
@ApiModelProperty({ type: GitFileObjectWithContent, isArray: true })
|
||||
public files: GitFileObjectWithContent[];
|
||||
@ApiModelProperty({ type: GitSubmoduleObjectContent, isArray: true })
|
||||
public submodules: GitSubmoduleObjectContent[];
|
||||
|
||||
constructor(gitObjectContent: GitContents) {
|
||||
constructor(gitObjectContent: GitTree) {
|
||||
this.dirs = gitObjectContent.dirs;
|
||||
this.files = gitObjectContent.files;
|
||||
this.submodules = gitObjectContent.submodules;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { ApiModelProperty } from "@nestjs/swagger";
|
||||
|
||||
import { GitFileObjectWithoutContent } from "./git-file-object-without-content";
|
||||
|
||||
export class GitFileObjectWithContent extends GitFileObjectWithoutContent {
|
||||
@ApiModelProperty({ type: String })
|
||||
public content: string;
|
||||
|
||||
constructor(gitObjectContent: GitFileObjectWithContent) {
|
||||
super(gitObjectContent);
|
||||
this.content = gitObjectContent.content;
|
||||
}
|
||||
}
|
|
@ -2,15 +2,12 @@ import { ApiModelProperty } from "@nestjs/swagger";
|
|||
|
||||
import { GitObjectContent } from "./git-object-content";
|
||||
|
||||
export class GitFileObjectContent extends GitObjectContent {
|
||||
@ApiModelProperty({ type: String })
|
||||
public content: string;
|
||||
export class GitFileObjectWithoutContent extends GitObjectContent {
|
||||
@ApiModelProperty({ type: String })
|
||||
public encoding: string;
|
||||
|
||||
constructor(gitObjectContent: GitFileObjectContent) {
|
||||
constructor(gitObjectContent: GitFileObjectWithoutContent) {
|
||||
super(gitObjectContent);
|
||||
this.content = gitObjectContent.content;
|
||||
this.encoding = gitObjectContent.encoding;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { ApiModelProperty } from "@nestjs/swagger";
|
||||
|
||||
import { GitDirObjectContent } from "./git-dir-object-content";
|
||||
import { GitFileObjectWithoutContent } from "./git-file-object-without-content";
|
||||
import { GitSubmoduleObjectContent } from "./git-submodule-object-content";
|
||||
|
||||
export class GitContents {
|
||||
@ApiModelProperty({ type: GitDirObjectContent, isArray: true })
|
||||
public dirs: GitDirObjectContent[];
|
||||
@ApiModelProperty({ type: GitFileObjectWithoutContent, isArray: true })
|
||||
public files: GitFileObjectWithoutContent[];
|
||||
@ApiModelProperty({ type: GitSubmoduleObjectContent, isArray: true })
|
||||
public submodules: GitSubmoduleObjectContent[];
|
||||
|
||||
constructor(gitObjectContent: GitContents) {
|
||||
this.dirs = gitObjectContent.dirs;
|
||||
this.files = gitObjectContent.files;
|
||||
this.submodules = gitObjectContent.submodules;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,13 @@
|
|||
export * from "./git-branch";
|
||||
export * from "./git-commit";
|
||||
export * from "./git-commit-ref";
|
||||
export * from "./git-signature";
|
||||
export * from "./git-commit";
|
||||
export * from "./git-contents";
|
||||
export * from "./git-diff";
|
||||
export * from "./git-dir-object-content";
|
||||
export * from "./git-file-diff";
|
||||
export * from "./git-file-object-with-content";
|
||||
export * from "./git-file-object-without-content";
|
||||
export * from "./git-object-content";
|
||||
export * from "./git-signature";
|
||||
export * from "./git-submodule-object-content";
|
||||
export * from "./git-tree";
|
||||
|
|
|
@ -2,8 +2,7 @@ import { Injectable, NotFoundException } from "@nestjs/common";
|
|||
import { Commit, Oid, Repository, Revwalk, Signature, Time } from "nodegit";
|
||||
|
||||
import { PaginatedList, Pagination, getPage, getPaginationSkip } from "../../core";
|
||||
import { GitCommit, GitCommitRef } from "../../dtos";
|
||||
import { GitSignature } from "../../dtos/git-signature";
|
||||
import { GitCommit, GitCommitRef, GitSignature } from "../../dtos";
|
||||
import { GitBaseOptions, RepoService } from "../repo";
|
||||
|
||||
const LIST_COMMIT_PAGE_SIZE = 100;
|
||||
|
|
|
@ -2,8 +2,7 @@ import { Injectable, NotFoundException } from "@nestjs/common";
|
|||
import { Commit, ConvenientPatch, Diff, Merge, Oid, Repository } from "nodegit";
|
||||
|
||||
import { Logger } from "../../core";
|
||||
import { GitFileDiff, PatchStatus } from "../../dtos";
|
||||
import { GitDiff } from "../../dtos/git-diff";
|
||||
import { GitDiff, GitFileDiff, PatchStatus } from "../../dtos";
|
||||
import { GitUtils, notUndefined } from "../../utils";
|
||||
import { CommitService, toGitCommit } from "../commit";
|
||||
import { GitBaseOptions, RepoService } from "../repo";
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Repository, TreeEntry } from "nodegit";
|
||||
import { Repository, Tree, TreeEntry } from "nodegit";
|
||||
|
||||
import { GitContents } from "../../dtos/git-contents";
|
||||
import { GitDirObjectContent } from "../../dtos/git-dir-object-content";
|
||||
import { GitFileObjectContent } from "../../dtos/git-file-object-content";
|
||||
import { GitSubmoduleObjectContent } from "../../dtos/git-submodule-object-content";
|
||||
import {
|
||||
GitContents,
|
||||
GitDirObjectContent,
|
||||
GitFileObjectWithContent,
|
||||
GitFileObjectWithoutContent,
|
||||
GitSubmoduleObjectContent,
|
||||
GitTree,
|
||||
} from "../../dtos";
|
||||
import { CommitService } from "../commit";
|
||||
import { GitBaseOptions, RepoService } from "../repo";
|
||||
|
||||
|
@ -16,14 +20,22 @@ export class ContentService {
|
|||
remote: string,
|
||||
path: string | undefined,
|
||||
ref: string | undefined = "master",
|
||||
recursive: boolean = false,
|
||||
includeContents: boolean = true,
|
||||
options: GitBaseOptions = {},
|
||||
): Promise<GitContents | NotFoundException> {
|
||||
): Promise<GitContents | GitTree | NotFoundException> {
|
||||
return this.repoService.use(remote, options, async repo => {
|
||||
return this.getGitContents(repo, path, ref);
|
||||
return this.getGitContents(repo, path, recursive, includeContents, ref);
|
||||
});
|
||||
}
|
||||
|
||||
public async getGitContents(repo: Repository, path: string | undefined, ref: string | undefined = "master") {
|
||||
public async getGitContents(
|
||||
repo: Repository,
|
||||
path: string | undefined,
|
||||
recursive: boolean,
|
||||
includeContents: boolean,
|
||||
ref: string | undefined = "master",
|
||||
) {
|
||||
const commit = await this.commitService.getCommit(repo, ref);
|
||||
if (!commit) {
|
||||
return new NotFoundException(`Ref '${ref}' not found.`);
|
||||
|
@ -33,32 +45,58 @@ export class ContentService {
|
|||
|
||||
if (path) {
|
||||
try {
|
||||
const pathEntry = await commit.getEntry(path);
|
||||
|
||||
if (pathEntry.isTree()) {
|
||||
const tree = await pathEntry.getTree();
|
||||
|
||||
// for directories, either
|
||||
if (recursive) {
|
||||
// recursively get children
|
||||
entries = await this.getAllChildEntries(tree);
|
||||
} else {
|
||||
// get children immediate children
|
||||
entries = tree.entries();
|
||||
}
|
||||
} else {
|
||||
// for files get array of size 1
|
||||
entries = [await commit.getEntry(path)];
|
||||
}
|
||||
} catch (e) {
|
||||
return new NotFoundException(`${path} not found.`);
|
||||
return new NotFoundException(`Path '${path}' not found.`);
|
||||
}
|
||||
} else {
|
||||
const tree = await commit.getTree();
|
||||
entries = await tree.entries();
|
||||
entries = recursive ? await this.getAllChildEntries(tree) : tree.entries();
|
||||
}
|
||||
|
||||
return this.getEntries(entries);
|
||||
return this.getEntries(entries, includeContents);
|
||||
}
|
||||
|
||||
private async getFileEntryAsObject(entry: TreeEntry): Promise<GitFileObjectContent> {
|
||||
private async getFileEntryAsObject(
|
||||
entry: TreeEntry,
|
||||
includeContents: boolean,
|
||||
): Promise<GitFileObjectWithContent | GitFileObjectWithoutContent> {
|
||||
const blob = await entry.getBlob();
|
||||
|
||||
return new GitFileObjectContent({
|
||||
const file = {
|
||||
type: "file",
|
||||
encoding: "base64",
|
||||
size: blob.rawsize(),
|
||||
name: entry.name(),
|
||||
path: entry.path(),
|
||||
content: blob.content().toString("base64"),
|
||||
sha: entry.sha(),
|
||||
};
|
||||
|
||||
if (includeContents) {
|
||||
return new GitFileObjectWithContent({
|
||||
...file,
|
||||
content: blob.content().toString("base64"),
|
||||
});
|
||||
}
|
||||
|
||||
return new GitFileObjectWithoutContent(file);
|
||||
}
|
||||
|
||||
private async getDirEntryAsObject(entry: TreeEntry): Promise<GitDirObjectContent> {
|
||||
return new GitDirObjectContent({
|
||||
type: "dir",
|
||||
|
@ -78,15 +116,37 @@ export class ContentService {
|
|||
});
|
||||
}
|
||||
|
||||
private async getEntries(entries: TreeEntry[]): Promise<GitContents> {
|
||||
private async getEntries(entries: TreeEntry[], includeContents: boolean): Promise<GitContents | GitTree> {
|
||||
const [files, dirs, submodules] = await Promise.all([
|
||||
Promise.all(entries.filter(entry => entry.isFile()).map(async entry => this.getFileEntryAsObject(entry))),
|
||||
Promise.all(
|
||||
entries.filter(entry => entry.isFile()).map(async entry => this.getFileEntryAsObject(entry, includeContents)),
|
||||
),
|
||||
Promise.all(entries.filter(entry => entry.isDirectory()).map(async entry => this.getDirEntryAsObject(entry))),
|
||||
Promise.all(
|
||||
entries.filter(entry => entry.isSubmodule()).map(async entry => this.getSubmoduleEntryAsObject(entry)),
|
||||
),
|
||||
]);
|
||||
|
||||
if (includeContents) {
|
||||
return new GitContents({ files, dirs, submodules });
|
||||
}
|
||||
|
||||
return new GitTree({ files: files as GitFileObjectWithContent[], dirs, submodules });
|
||||
}
|
||||
|
||||
private async getAllChildEntries(tree: Tree): Promise<TreeEntry[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const eventEmitter = tree.walk(false);
|
||||
|
||||
eventEmitter.on("end", (trees: TreeEntry[]) => {
|
||||
resolve(trees);
|
||||
});
|
||||
|
||||
eventEmitter.on("error", error => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
eventEmitter.start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export const notUndefined = <T>(x: T | undefined): x is T => x !== undefined;
|
||||
export const delay = (timeout?: number) => new Promise(r => setTimeout(r, timeout));
|
||||
export const parseBooleanFromURLParam = (bool: string | undefined) => bool === "" || bool === "true";
|
||||
|
||||
export class Deferred<T = void> {
|
||||
public promise: Promise<T>;
|
||||
|
|
|
@ -271,6 +271,18 @@
|
|||
"required": true,
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "path",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "recursive",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "ref",
|
||||
"required": false,
|
||||
|
@ -311,6 +323,64 @@
|
|||
"application/json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/repos/{remote}/tree/{path}": {
|
||||
"get": {
|
||||
"summary": "Get tree",
|
||||
"operationId": "tree_get",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "remote",
|
||||
"required": true,
|
||||
"in": "path"
|
||||
},
|
||||
{
|
||||
"name": "path",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "ref",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "x-authorization",
|
||||
"required": false,
|
||||
"in": "header",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "x-github-token",
|
||||
"required": false,
|
||||
"in": "header",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/GitTree"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "When the x-authorization header is malformed"
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
|
@ -498,7 +568,7 @@
|
|||
"sha"
|
||||
]
|
||||
},
|
||||
"GitFileObjectContent": {
|
||||
"GitFileObjectWithoutContent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
|
@ -516,9 +586,6 @@
|
|||
"sha": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -529,7 +596,6 @@
|
|||
"name",
|
||||
"path",
|
||||
"sha",
|
||||
"content",
|
||||
"encoding"
|
||||
]
|
||||
},
|
||||
|
@ -572,7 +638,70 @@
|
|||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/GitFileObjectContent"
|
||||
"$ref": "#/definitions/GitFileObjectWithoutContent"
|
||||
}
|
||||
},
|
||||
"submodules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/GitSubmoduleObjectContent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"dirs",
|
||||
"files",
|
||||
"submodules"
|
||||
]
|
||||
},
|
||||
"GitFileObjectWithContent": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "number"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"sha": {
|
||||
"type": "string"
|
||||
},
|
||||
"encoding": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"size",
|
||||
"name",
|
||||
"path",
|
||||
"sha",
|
||||
"encoding",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
"GitTree": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dirs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/GitDirObjectContent"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/GitFileObjectWithContent"
|
||||
}
|
||||
},
|
||||
"submodules": {
|
||||
|
|
Загрузка…
Ссылка в новой задаче