@oneuptime/common 8.0.5466 → 8.0.5479
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Server/Services/DatabaseService.ts +70 -0
- package/Server/Services/ProjectService.ts +24 -0
- package/Server/Types/Database/FindAllBy.ts +25 -0
- package/Server/Utils/CodeRepository/CodeRepository.ts +189 -120
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +20 -9
- package/Server/Utils/Execute.ts +64 -4
- package/Server/Utils/LocalFile.ts +40 -0
- package/Server/Utils/Monitor/MonitorResource.ts +246 -256
- package/build/dist/Server/Services/DatabaseService.js +59 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +19 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Types/Database/FindAllBy.js +2 -0
- package/build/dist/Server/Types/Database/FindAllBy.js.map +1 -0
- package/build/dist/Server/Utils/CodeRepository/CodeRepository.js +137 -78
- package/build/dist/Server/Utils/CodeRepository/CodeRepository.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +15 -6
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/Execute.js +35 -4
- package/build/dist/Server/Utils/Execute.js.map +1 -1
- package/build/dist/Server/Utils/LocalFile.js +35 -0
- package/build/dist/Server/Utils/LocalFile.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +220 -206
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { EncryptionSecret, WorkflowHostname } from "../EnvironmentConfig";
|
|
|
2
2
|
import PostgresAppInstance from "../Infrastructure/PostgresDatabase";
|
|
3
3
|
import ClusterKeyAuthorization from "../Middleware/ClusterKeyAuthorization";
|
|
4
4
|
import CountBy from "../Types/Database/CountBy";
|
|
5
|
+
import FindAllBy from "../Types/Database/FindAllBy";
|
|
5
6
|
import CreateBy from "../Types/Database/CreateBy";
|
|
6
7
|
import DeleteBy from "../Types/Database/DeleteBy";
|
|
7
8
|
import DeleteById from "../Types/Database/DeleteById";
|
|
@@ -1168,6 +1169,75 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
|
|
|
1168
1169
|
}
|
|
1169
1170
|
}
|
|
1170
1171
|
|
|
1172
|
+
@CaptureSpan()
|
|
1173
|
+
public async findAllBy(
|
|
1174
|
+
findAllBy: FindAllBy<TBaseModel>,
|
|
1175
|
+
): Promise<Array<TBaseModel>> {
|
|
1176
|
+
const { limit, skip, ...rest } = findAllBy;
|
|
1177
|
+
|
|
1178
|
+
let remaining: number | undefined = this.normalizePositiveNumber(limit);
|
|
1179
|
+
let currentSkip: number = this.normalizePositiveNumber(skip) || 0;
|
|
1180
|
+
|
|
1181
|
+
const results: Array<TBaseModel> = [];
|
|
1182
|
+
|
|
1183
|
+
while (true) {
|
|
1184
|
+
const currentBatchSize: number =
|
|
1185
|
+
remaining !== undefined
|
|
1186
|
+
? Math.min(LIMIT_MAX, Math.max(remaining, 0))
|
|
1187
|
+
: LIMIT_MAX;
|
|
1188
|
+
|
|
1189
|
+
if (currentBatchSize <= 0) {
|
|
1190
|
+
break;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
const page: Array<TBaseModel> = await this.findBy({
|
|
1194
|
+
...rest,
|
|
1195
|
+
skip: currentSkip,
|
|
1196
|
+
limit: currentBatchSize,
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
if (page.length === 0) {
|
|
1200
|
+
break;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
results.push(...page);
|
|
1204
|
+
|
|
1205
|
+
currentSkip += page.length;
|
|
1206
|
+
|
|
1207
|
+
if (remaining !== undefined) {
|
|
1208
|
+
remaining -= page.length;
|
|
1209
|
+
|
|
1210
|
+
if (remaining <= 0) {
|
|
1211
|
+
break;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
if (page.length < currentBatchSize) {
|
|
1216
|
+
break;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return results;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
private normalizePositiveNumber(
|
|
1224
|
+
value?: PositiveNumber | number,
|
|
1225
|
+
): number | undefined {
|
|
1226
|
+
if (value === undefined || value === null) {
|
|
1227
|
+
return undefined;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
if (value instanceof PositiveNumber) {
|
|
1231
|
+
return value.toNumber();
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
if (typeof value === "number") {
|
|
1235
|
+
return value;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
return undefined;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1171
1241
|
@CaptureSpan()
|
|
1172
1242
|
public async findBy(findBy: FindBy<TBaseModel>): Promise<Array<TBaseModel>> {
|
|
1173
1243
|
return await this._findBy(findBy);
|
|
@@ -71,6 +71,8 @@ import URL from "../../Types/API/URL";
|
|
|
71
71
|
import Exception from "../../Types/Exception/Exception";
|
|
72
72
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
73
73
|
import DatabaseConfig from "../DatabaseConfig";
|
|
74
|
+
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
75
|
+
import PositiveNumber from "../../Types/PositiveNumber";
|
|
74
76
|
|
|
75
77
|
export interface CurrentPlan {
|
|
76
78
|
plan: PlanType | null;
|
|
@@ -1435,6 +1437,28 @@ export class ProjectService extends DatabaseService<Model> {
|
|
|
1435
1437
|
};
|
|
1436
1438
|
}
|
|
1437
1439
|
|
|
1440
|
+
@CaptureSpan()
|
|
1441
|
+
public async getAllActiveProjects(params?: {
|
|
1442
|
+
select?: Select<Model>;
|
|
1443
|
+
props?: DatabaseCommonInteractionProps;
|
|
1444
|
+
skip?: PositiveNumber | number;
|
|
1445
|
+
limit?: PositiveNumber | number;
|
|
1446
|
+
}): Promise<Array<Model>> {
|
|
1447
|
+
const select: Select<Model> | undefined =
|
|
1448
|
+
params?.select || ({ _id: true } as Select<Model>);
|
|
1449
|
+
const props: DatabaseCommonInteractionProps = params?.props || {
|
|
1450
|
+
isRoot: true,
|
|
1451
|
+
};
|
|
1452
|
+
|
|
1453
|
+
return await this.findAllBy({
|
|
1454
|
+
query: this.getActiveProjectStatusQuery(),
|
|
1455
|
+
select,
|
|
1456
|
+
props,
|
|
1457
|
+
skip: params?.skip,
|
|
1458
|
+
limit: params?.limit,
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1438
1462
|
@CaptureSpan()
|
|
1439
1463
|
public async getProjectLinkInDashboard(projectId: ObjectID): Promise<URL> {
|
|
1440
1464
|
const dashboardUrl: URL = await DatabaseConfig.getDashboardUrl();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
2
|
+
import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
3
|
+
import GroupBy from "./GroupBy";
|
|
4
|
+
import Query from "./Query";
|
|
5
|
+
import Select from "./Select";
|
|
6
|
+
import Sort from "./Sort";
|
|
7
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
8
|
+
|
|
9
|
+
export default interface FindAllBy<TBaseModel extends BaseModel> {
|
|
10
|
+
query: Query<TBaseModel>;
|
|
11
|
+
select?: Select<TBaseModel> | undefined;
|
|
12
|
+
sort?: Sort<TBaseModel> | undefined;
|
|
13
|
+
groupBy?: GroupBy<TBaseModel> | undefined;
|
|
14
|
+
props: DatabaseCommonInteractionProps;
|
|
15
|
+
/**
|
|
16
|
+
* Optional number of documents to skip before fetching results.
|
|
17
|
+
* Acts the same way as `skip` in `findBy` but defaults to 0 when omitted.
|
|
18
|
+
*/
|
|
19
|
+
skip?: PositiveNumber | number | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Optional total number of documents to return across all batches.
|
|
22
|
+
* When omitted, the method keeps fetching until no more data is returned.
|
|
23
|
+
*/
|
|
24
|
+
limit?: PositiveNumber | number | undefined;
|
|
25
|
+
}
|
|
@@ -1,33 +1,26 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
1
3
|
import Execute from "../Execute";
|
|
2
4
|
import LocalFile from "../LocalFile";
|
|
3
5
|
import logger from "../Logger";
|
|
4
6
|
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
5
7
|
import CodeRepositoryFile from "./CodeRepositoryFile";
|
|
6
8
|
import Dictionary from "../../../Types/Dictionary";
|
|
9
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
7
10
|
|
|
8
11
|
export default class CodeRepositoryUtil {
|
|
9
12
|
@CaptureSpan()
|
|
10
13
|
public static getCurrentCommitHash(data: {
|
|
11
14
|
repoPath: string;
|
|
12
15
|
}): Promise<string> {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
logger.debug("Executing command: " + command);
|
|
16
|
-
|
|
17
|
-
return Execute.executeCommand(command);
|
|
16
|
+
return this.runGitCommand(data.repoPath, ["rev-parse", "HEAD"]);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
@CaptureSpan()
|
|
21
20
|
public static async addAllChangedFilesToGit(data: {
|
|
22
21
|
repoPath: string;
|
|
23
22
|
}): Promise<void> {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
logger.debug("Executing command: " + command);
|
|
27
|
-
|
|
28
|
-
const stdout: string = await Execute.executeCommand(command);
|
|
29
|
-
|
|
30
|
-
logger.debug(stdout);
|
|
23
|
+
await this.runGitCommand(data.repoPath, ["add", "-A"]);
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
@CaptureSpan()
|
|
@@ -36,26 +29,26 @@ export default class CodeRepositoryUtil {
|
|
|
36
29
|
authorName: string;
|
|
37
30
|
authorEmail: string;
|
|
38
31
|
}): Promise<void> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
await this.runGitCommand(data.repoPath, [
|
|
33
|
+
"config",
|
|
34
|
+
"--global",
|
|
35
|
+
"user.name",
|
|
36
|
+
data.authorName,
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
await this.runGitCommand(data.repoPath, [
|
|
40
|
+
"config",
|
|
41
|
+
"--global",
|
|
42
|
+
"user.email",
|
|
43
|
+
data.authorEmail,
|
|
44
|
+
]);
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
@CaptureSpan()
|
|
49
48
|
public static async discardAllChangesOnCurrentBranch(data: {
|
|
50
49
|
repoPath: string;
|
|
51
50
|
}): Promise<void> {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
logger.debug("Executing command: " + command);
|
|
55
|
-
|
|
56
|
-
const stdout: string = await Execute.executeCommand(command);
|
|
57
|
-
|
|
58
|
-
logger.debug(stdout);
|
|
51
|
+
await this.runGitCommand(data.repoPath, ["checkout", "."]);
|
|
59
52
|
}
|
|
60
53
|
|
|
61
54
|
// returns the folder name of the cloned repository
|
|
@@ -64,33 +57,25 @@ export default class CodeRepositoryUtil {
|
|
|
64
57
|
repoPath: string;
|
|
65
58
|
repoUrl: string;
|
|
66
59
|
}): Promise<string> {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
logger.debug("Executing command: " + command);
|
|
70
|
-
|
|
71
|
-
const stdout: string = await Execute.executeCommand(command);
|
|
60
|
+
await this.runGitCommand(data.repoPath, ["clone", data.repoUrl]);
|
|
72
61
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const getFolderNameCommand: string = `cd ${data.repoPath} && ls`;
|
|
62
|
+
const normalizedUrl: string = data.repoUrl.trim().replace(/\/+$/g, "");
|
|
63
|
+
const lastSegment: string =
|
|
64
|
+
normalizedUrl.split("/").pop() || normalizedUrl.split(":").pop() || "";
|
|
65
|
+
const folderName: string = lastSegment.replace(/\.git$/i, "");
|
|
78
66
|
|
|
79
|
-
|
|
80
|
-
|
|
67
|
+
if (!folderName) {
|
|
68
|
+
throw new BadDataException(
|
|
69
|
+
"Unable to determine repository folder name after cloning.",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
81
72
|
|
|
82
73
|
return folderName.trim();
|
|
83
74
|
}
|
|
84
75
|
|
|
85
76
|
@CaptureSpan()
|
|
86
77
|
public static async pullChanges(data: { repoPath: string }): Promise<void> {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
logger.debug("Executing command: " + command);
|
|
90
|
-
|
|
91
|
-
const stdout: string = await Execute.executeCommand(command);
|
|
92
|
-
|
|
93
|
-
logger.debug(stdout);
|
|
78
|
+
await this.runGitCommand(data.repoPath, ["pull"]);
|
|
94
79
|
}
|
|
95
80
|
|
|
96
81
|
@CaptureSpan()
|
|
@@ -98,13 +83,26 @@ export default class CodeRepositoryUtil {
|
|
|
98
83
|
repoPath: string;
|
|
99
84
|
branchName: string;
|
|
100
85
|
}): Promise<void> {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
86
|
+
try {
|
|
87
|
+
await this.runGitCommand(data.repoPath, [
|
|
88
|
+
"rev-parse",
|
|
89
|
+
"--verify",
|
|
90
|
+
data.branchName,
|
|
91
|
+
]);
|
|
92
|
+
await this.runGitCommand(data.repoPath, ["checkout", data.branchName]);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
logger.debug(
|
|
95
|
+
`Branch ${data.branchName} not found. Creating a new branch instead.`,
|
|
96
|
+
);
|
|
104
97
|
|
|
105
|
-
|
|
98
|
+
logger.debug(error);
|
|
106
99
|
|
|
107
|
-
|
|
100
|
+
await this.runGitCommand(data.repoPath, [
|
|
101
|
+
"checkout",
|
|
102
|
+
"-b",
|
|
103
|
+
data.branchName,
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
@CaptureSpan()
|
|
@@ -112,15 +110,12 @@ export default class CodeRepositoryUtil {
|
|
|
112
110
|
repoPath: string;
|
|
113
111
|
filePath: string;
|
|
114
112
|
}): Promise<string> {
|
|
115
|
-
const
|
|
116
|
-
|
|
113
|
+
const absolutePath: string = this.resolvePathWithinRepo(
|
|
114
|
+
data.repoPath,
|
|
115
|
+
data.filePath,
|
|
117
116
|
);
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
logger.debug("Executing command: " + command);
|
|
122
|
-
|
|
123
|
-
return Execute.executeCommand(`${command}`);
|
|
118
|
+
return LocalFile.read(absolutePath);
|
|
124
119
|
}
|
|
125
120
|
|
|
126
121
|
// discard all changes in the working directory
|
|
@@ -128,13 +123,7 @@ export default class CodeRepositoryUtil {
|
|
|
128
123
|
public static async discardChanges(data: {
|
|
129
124
|
repoPath: string;
|
|
130
125
|
}): Promise<void> {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
logger.debug("Executing command: " + command);
|
|
134
|
-
|
|
135
|
-
const stdout: string = await Execute.executeCommand(command);
|
|
136
|
-
|
|
137
|
-
logger.debug(stdout);
|
|
126
|
+
await this.runGitCommand(data.repoPath, ["checkout", "."]);
|
|
138
127
|
}
|
|
139
128
|
|
|
140
129
|
@CaptureSpan()
|
|
@@ -183,13 +172,9 @@ export default class CodeRepositoryUtil {
|
|
|
183
172
|
`${data.repoPath}/${data.directoryPath}`,
|
|
184
173
|
);
|
|
185
174
|
|
|
186
|
-
|
|
175
|
+
logger.debug("Deleting directory: " + totalPath);
|
|
187
176
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const stdout: string = await Execute.executeCommand(command);
|
|
191
|
-
|
|
192
|
-
logger.debug(stdout);
|
|
177
|
+
await LocalFile.deleteDirectory(totalPath);
|
|
193
178
|
}
|
|
194
179
|
|
|
195
180
|
@CaptureSpan()
|
|
@@ -197,11 +182,15 @@ export default class CodeRepositoryUtil {
|
|
|
197
182
|
repoPath: string;
|
|
198
183
|
branchName: string;
|
|
199
184
|
}): Promise<void> {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
185
|
+
logger.debug(
|
|
186
|
+
`Creating git branch '${data.branchName}' in ${path.resolve(data.repoPath)}`,
|
|
187
|
+
);
|
|
203
188
|
|
|
204
|
-
const stdout: string = await
|
|
189
|
+
const stdout: string = await this.runGitCommand(data.repoPath, [
|
|
190
|
+
"checkout",
|
|
191
|
+
"-b",
|
|
192
|
+
data.branchName,
|
|
193
|
+
]);
|
|
205
194
|
|
|
206
195
|
logger.debug(stdout);
|
|
207
196
|
}
|
|
@@ -211,11 +200,14 @@ export default class CodeRepositoryUtil {
|
|
|
211
200
|
repoPath: string;
|
|
212
201
|
branchName: string;
|
|
213
202
|
}): Promise<void> {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
203
|
+
logger.debug(
|
|
204
|
+
`Checking out git branch '${data.branchName}' in ${path.resolve(data.repoPath)}`,
|
|
205
|
+
);
|
|
217
206
|
|
|
218
|
-
const stdout: string = await
|
|
207
|
+
const stdout: string = await this.runGitCommand(data.repoPath, [
|
|
208
|
+
"checkout",
|
|
209
|
+
data.branchName,
|
|
210
|
+
]);
|
|
219
211
|
|
|
220
212
|
logger.debug(stdout);
|
|
221
213
|
}
|
|
@@ -225,22 +217,51 @@ export default class CodeRepositoryUtil {
|
|
|
225
217
|
repoPath: string;
|
|
226
218
|
filePaths: Array<string>;
|
|
227
219
|
}): Promise<void> {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
220
|
+
const repoRoot: string = path.resolve(data.repoPath);
|
|
221
|
+
|
|
222
|
+
const sanitizedRelativeFilePaths: Array<string> = [];
|
|
223
|
+
|
|
224
|
+
for (const inputFilePath of data.filePaths) {
|
|
225
|
+
const normalizedPath: string = inputFilePath.startsWith("/")
|
|
226
|
+
? inputFilePath.substring(1)
|
|
227
|
+
: inputFilePath;
|
|
228
|
+
|
|
229
|
+
if (normalizedPath.trim() === "") {
|
|
230
|
+
continue;
|
|
232
231
|
}
|
|
233
232
|
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
const absoluteFilePath: string = this.resolvePathWithinRepo(
|
|
234
|
+
data.repoPath,
|
|
235
|
+
normalizedPath,
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const relativeFilePath: string = path.relative(
|
|
239
|
+
repoRoot,
|
|
240
|
+
absoluteFilePath,
|
|
241
|
+
);
|
|
236
242
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
if (relativeFilePath.trim() === "") {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
sanitizedRelativeFilePaths.push(
|
|
248
|
+
LocalFile.sanitizeFilePath(relativeFilePath),
|
|
249
|
+
);
|
|
250
|
+
}
|
|
240
251
|
|
|
241
|
-
|
|
252
|
+
if (sanitizedRelativeFilePaths.length === 0) {
|
|
253
|
+
logger.debug("git add skipped because no file paths were provided");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
logger.debug(
|
|
258
|
+
`Adding ${sanitizedRelativeFilePaths.length} file(s) to git in ${path.resolve(data.repoPath)}`,
|
|
259
|
+
);
|
|
242
260
|
|
|
243
|
-
const stdout: string = await
|
|
261
|
+
const stdout: string = await this.runGitCommand(data.repoPath, [
|
|
262
|
+
"add",
|
|
263
|
+
...sanitizedRelativeFilePaths,
|
|
264
|
+
]);
|
|
244
265
|
|
|
245
266
|
logger.debug(stdout);
|
|
246
267
|
}
|
|
@@ -250,11 +271,13 @@ export default class CodeRepositoryUtil {
|
|
|
250
271
|
repoPath: string;
|
|
251
272
|
username: string;
|
|
252
273
|
}): Promise<void> {
|
|
253
|
-
|
|
274
|
+
logger.debug(`Setting git user.name in ${path.resolve(data.repoPath)}`);
|
|
254
275
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
276
|
+
const stdout: string = await this.runGitCommand(data.repoPath, [
|
|
277
|
+
"config",
|
|
278
|
+
"user.name",
|
|
279
|
+
data.username,
|
|
280
|
+
]);
|
|
258
281
|
|
|
259
282
|
logger.debug(stdout);
|
|
260
283
|
}
|
|
@@ -264,11 +287,13 @@ export default class CodeRepositoryUtil {
|
|
|
264
287
|
repoPath: string;
|
|
265
288
|
message: string;
|
|
266
289
|
}): Promise<void> {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
logger.debug("Executing command: " + command);
|
|
290
|
+
logger.debug("Executing git commit");
|
|
270
291
|
|
|
271
|
-
const stdout: string = await Execute.
|
|
292
|
+
const stdout: string = await Execute.executeCommandFile({
|
|
293
|
+
command: "git",
|
|
294
|
+
args: ["commit", "-m", data.message],
|
|
295
|
+
cwd: data.repoPath,
|
|
296
|
+
});
|
|
272
297
|
|
|
273
298
|
logger.debug(stdout);
|
|
274
299
|
}
|
|
@@ -288,15 +313,28 @@ export default class CodeRepositoryUtil {
|
|
|
288
313
|
|
|
289
314
|
const { repoPath, filePath } = data;
|
|
290
315
|
|
|
291
|
-
const
|
|
316
|
+
const repoRoot: string = path.resolve(repoPath);
|
|
317
|
+
const absoluteTarget: string = this.resolvePathWithinRepo(
|
|
318
|
+
repoPath,
|
|
319
|
+
filePath,
|
|
320
|
+
);
|
|
321
|
+
const relativeTarget: string = path.relative(repoRoot, absoluteTarget);
|
|
322
|
+
const gitArgument: string = LocalFile.sanitizeFilePath(
|
|
323
|
+
`./${relativeTarget}`,
|
|
324
|
+
);
|
|
292
325
|
|
|
293
|
-
logger.debug(
|
|
326
|
+
logger.debug(`Getting last commit hash for ${gitArgument} in ${repoRoot}`);
|
|
294
327
|
|
|
295
|
-
const hash: string = await
|
|
328
|
+
const hash: string = await this.runGitCommand(repoRoot, [
|
|
329
|
+
"log",
|
|
330
|
+
"-1",
|
|
331
|
+
"--pretty=format:%H",
|
|
332
|
+
gitArgument,
|
|
333
|
+
]);
|
|
296
334
|
|
|
297
335
|
logger.debug(hash);
|
|
298
336
|
|
|
299
|
-
return hash;
|
|
337
|
+
return hash.trim();
|
|
300
338
|
}
|
|
301
339
|
|
|
302
340
|
@CaptureSpan()
|
|
@@ -318,11 +356,11 @@ export default class CodeRepositoryUtil {
|
|
|
318
356
|
|
|
319
357
|
totalPath = LocalFile.sanitizeFilePath(totalPath); // clean up the path
|
|
320
358
|
|
|
321
|
-
const
|
|
359
|
+
const entries: Array<fs.Dirent> = await LocalFile.readDirectory(totalPath);
|
|
322
360
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
361
|
+
return entries.map((entry: fs.Dirent) => {
|
|
362
|
+
return entry.name;
|
|
363
|
+
});
|
|
326
364
|
}
|
|
327
365
|
|
|
328
366
|
@CaptureSpan()
|
|
@@ -350,16 +388,12 @@ export default class CodeRepositoryUtil {
|
|
|
350
388
|
totalPath = LocalFile.sanitizeFilePath(totalPath); // clean up the path
|
|
351
389
|
|
|
352
390
|
const files: Dictionary<CodeRepositoryFile> = {};
|
|
353
|
-
const output: string = await Execute.executeCommand(`ls ${totalPath}`);
|
|
354
|
-
|
|
355
|
-
const fileNames: Array<string> = output.split("\n");
|
|
356
|
-
|
|
357
391
|
const subDirectories: Array<string> = [];
|
|
358
392
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
393
|
+
const entries: Array<fs.Dirent> = await LocalFile.readDirectory(totalPath);
|
|
394
|
+
|
|
395
|
+
for (const entry of entries) {
|
|
396
|
+
const fileName: string = entry.name;
|
|
363
397
|
|
|
364
398
|
const filePath: string = LocalFile.sanitizeFilePath(
|
|
365
399
|
`${directoryPath}/${fileName}`,
|
|
@@ -369,13 +403,7 @@ export default class CodeRepositoryUtil {
|
|
|
369
403
|
continue;
|
|
370
404
|
}
|
|
371
405
|
|
|
372
|
-
|
|
373
|
-
await Execute.executeCommand(
|
|
374
|
-
`file "${LocalFile.sanitizeFilePath(`${totalPath}/${fileName}`)}"`,
|
|
375
|
-
)
|
|
376
|
-
).includes("directory");
|
|
377
|
-
|
|
378
|
-
if (isDirectory) {
|
|
406
|
+
if (entry.isDirectory()) {
|
|
379
407
|
subDirectories.push(
|
|
380
408
|
LocalFile.sanitizeFilePath(`${directoryPath}/${fileName}`),
|
|
381
409
|
);
|
|
@@ -449,4 +477,45 @@ export default class CodeRepositoryUtil {
|
|
|
449
477
|
|
|
450
478
|
return files;
|
|
451
479
|
}
|
|
480
|
+
|
|
481
|
+
private static runGitCommand(
|
|
482
|
+
repoPath: string,
|
|
483
|
+
args: Array<string>,
|
|
484
|
+
): Promise<string> {
|
|
485
|
+
const cwd: string = path.resolve(repoPath);
|
|
486
|
+
|
|
487
|
+
logger.debug(
|
|
488
|
+
`Executing git command in ${cwd}: git ${args
|
|
489
|
+
.map((arg: string) => {
|
|
490
|
+
return arg.includes(" ") ? `"${arg}"` : arg;
|
|
491
|
+
})
|
|
492
|
+
.join(" ")}`,
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
return Execute.executeCommandFile({
|
|
496
|
+
command: "git",
|
|
497
|
+
args,
|
|
498
|
+
cwd,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private static resolvePathWithinRepo(
|
|
503
|
+
repoPath: string,
|
|
504
|
+
targetPath: string,
|
|
505
|
+
): string {
|
|
506
|
+
const root: string = path.resolve(repoPath);
|
|
507
|
+
const sanitizedTarget: string = LocalFile.sanitizeFilePath(
|
|
508
|
+
targetPath,
|
|
509
|
+
).replace(/^\/+/, "");
|
|
510
|
+
const absoluteTarget: string = path.resolve(root, sanitizedTarget);
|
|
511
|
+
|
|
512
|
+
if (
|
|
513
|
+
absoluteTarget !== root &&
|
|
514
|
+
!absoluteTarget.startsWith(root + path.sep)
|
|
515
|
+
) {
|
|
516
|
+
throw new BadDataException("File path is outside the repository");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return absoluteTarget;
|
|
520
|
+
}
|
|
452
521
|
}
|
|
@@ -170,13 +170,15 @@ export default class GitHubUtil extends HostedCodeRepository {
|
|
|
170
170
|
`https://github.com/${data.organizationName}/${data.repositoryName}.git`,
|
|
171
171
|
);
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
data.remoteName
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
logger.debug("Executing command: " + command);
|
|
173
|
+
logger.debug(
|
|
174
|
+
`Adding remote '${data.remoteName}' for ${data.organizationName}/${data.repositoryName}`,
|
|
175
|
+
);
|
|
178
176
|
|
|
179
|
-
const result: string = await Execute.
|
|
177
|
+
const result: string = await Execute.executeCommandFile({
|
|
178
|
+
command: "git",
|
|
179
|
+
args: ["remote", "add", data.remoteName, url.toString()],
|
|
180
|
+
cwd: process.cwd(),
|
|
181
|
+
});
|
|
180
182
|
|
|
181
183
|
logger.debug(result);
|
|
182
184
|
}
|
|
@@ -197,10 +199,19 @@ export default class GitHubUtil extends HostedCodeRepository {
|
|
|
197
199
|
"Pushing changes to remote repository with username: " + username,
|
|
198
200
|
);
|
|
199
201
|
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
+
const encodedUsername: string = encodeURIComponent(username);
|
|
203
|
+
const encodedPassword: string = encodeURIComponent(password);
|
|
204
|
+
const remoteUrl: string = `https://${encodedUsername}:${encodedPassword}@github.com/${data.organizationName}/${data.repositoryName}.git`;
|
|
202
205
|
|
|
203
|
-
|
|
206
|
+
logger.debug(
|
|
207
|
+
`Pushing branch '${branchName}' to ${data.organizationName}/${data.repositoryName}`,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const result: string = await Execute.executeCommandFile({
|
|
211
|
+
command: "git",
|
|
212
|
+
args: ["push", "-u", remoteUrl, branchName],
|
|
213
|
+
cwd: data.repoPath,
|
|
214
|
+
});
|
|
204
215
|
|
|
205
216
|
logger.debug(result);
|
|
206
217
|
}
|