@apexdevtools/git-ops 1.4.1 → 1.4.2
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/CHANGELOG.md +4 -0
- package/lib/{src/changes.js → changes.js} +52 -74
- package/lib/{src/git.d.ts → git.d.ts} +1 -1
- package/lib/git.js +93 -0
- package/lib/tracking.js +154 -0
- package/package.json +17 -17
- package/lib/src/git.js +0 -114
- package/lib/src/tracking.js +0 -162
- package/lib/test/changes.spec.d.ts +0 -1
- package/lib/test/changes.spec.js +0 -195
- package/lib/test/git.spec.d.ts +0 -1
- package/lib/test/git.spec.js +0 -210
- package/lib/test/helpers/repo.d.ts +0 -24
- package/lib/test/helpers/repo.js +0 -131
- package/lib/test/tracking.spec.d.ts +0 -1
- package/lib/test/tracking.spec.js +0 -312
- /package/lib/{src/changes.d.ts → changes.d.ts} +0 -0
- /package/lib/{src/index.d.ts → index.d.ts} +0 -0
- /package/lib/{src/index.js → index.js} +0 -0
- /package/lib/{src/tracking.d.ts → tracking.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,20 +2,15 @@
|
|
|
2
2
|
/*
|
|
3
3
|
* Copyright (c) 2024 Certinia Inc. All rights reserved.
|
|
4
4
|
*/
|
|
5
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
5
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
6
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
7
|
};
|
|
17
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.
|
|
9
|
+
exports.getDefaultBranchDiff = getDefaultBranchDiff;
|
|
10
|
+
exports.getDefaultBranchDiffByRef = getDefaultBranchDiffByRef;
|
|
11
|
+
exports.getDiffRange = getDiffRange;
|
|
12
|
+
exports.getLocalChanges = getLocalChanges;
|
|
13
|
+
exports.getDeployableClasses = getDeployableClasses;
|
|
19
14
|
const path_1 = __importDefault(require("path"));
|
|
20
15
|
const git_1 = require("./git");
|
|
21
16
|
/**
|
|
@@ -23,12 +18,9 @@ const git_1 = require("./git");
|
|
|
23
18
|
* @param dir: string of the directory thr operation should be performed on
|
|
24
19
|
* @returns set of absolute paths of changed files
|
|
25
20
|
*/
|
|
26
|
-
function getDefaultBranchDiff(dir) {
|
|
27
|
-
return
|
|
28
|
-
return getDefaultBranchDiffByRef(dir, 'HEAD');
|
|
29
|
-
});
|
|
21
|
+
async function getDefaultBranchDiff(dir) {
|
|
22
|
+
return getDefaultBranchDiffByRef(dir, 'HEAD');
|
|
30
23
|
}
|
|
31
|
-
exports.getDefaultBranchDiff = getDefaultBranchDiff;
|
|
32
24
|
/**
|
|
33
25
|
* Works out changed files using the default branch in that repo given a ref.
|
|
34
26
|
* This find the default branch in the repo using `git symbolic-ref 'refs/remotes/origin/HEAD'`
|
|
@@ -39,18 +31,15 @@ exports.getDefaultBranchDiff = getDefaultBranchDiff;
|
|
|
39
31
|
* @param refTo: string git ref. i.e HEAD, or commit hash
|
|
40
32
|
* @returns set of absolute paths of changed files
|
|
41
33
|
*/
|
|
42
|
-
function getDefaultBranchDiffByRef(dir, refTo) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
throw new NoLocalBranchException(er);
|
|
50
|
-
});
|
|
34
|
+
async function getDefaultBranchDiffByRef(dir, refTo) {
|
|
35
|
+
const git = new git_1.Git(dir);
|
|
36
|
+
return git
|
|
37
|
+
.getDefaultBranchName()
|
|
38
|
+
.then(branch => getDiffRange(dir, branch, refTo))
|
|
39
|
+
.catch(er => {
|
|
40
|
+
throw new NoLocalBranchException(er);
|
|
51
41
|
});
|
|
52
42
|
}
|
|
53
|
-
exports.getDefaultBranchDiffByRef = getDefaultBranchDiffByRef;
|
|
54
43
|
/**
|
|
55
44
|
* Works out the diff between a given range. Equivalent to `git diff ref1...ref2`
|
|
56
45
|
* @param dir string of the directory thr operation should be performed on
|
|
@@ -58,37 +47,31 @@ exports.getDefaultBranchDiffByRef = getDefaultBranchDiffByRef;
|
|
|
58
47
|
* @param toRef string git ref. i.e HEAD, or commit hash
|
|
59
48
|
* @returns set of absolute paths of changed files
|
|
60
49
|
*/
|
|
61
|
-
function getDiffRange(dir, fromRef, toRef) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
throw new DiffFailedException(er);
|
|
69
|
-
});
|
|
50
|
+
async function getDiffRange(dir, fromRef, toRef) {
|
|
51
|
+
const git = new git_1.Git(dir);
|
|
52
|
+
const root = await git.gitRoot();
|
|
53
|
+
return getDiffChanges(git, fromRef, toRef)
|
|
54
|
+
.then(changes => resolvePaths(changes, root))
|
|
55
|
+
.catch(er => {
|
|
56
|
+
throw new DiffFailedException(er);
|
|
70
57
|
});
|
|
71
58
|
}
|
|
72
|
-
exports.getDiffRange = getDiffRange;
|
|
73
59
|
/**
|
|
74
60
|
* Get the local changes that not have been committed. Equivalent to `git status`
|
|
75
61
|
* Files with the status of deleted (`D`) and ignored (`!`) will not be included in the change set.
|
|
76
62
|
* @param dir tring of the directory thr operation should be performed on
|
|
77
63
|
* @returns set of absolute paths of un committed files
|
|
78
64
|
*/
|
|
79
|
-
function getLocalChanges(dir) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
throw new LocalChangeException(er);
|
|
88
|
-
});
|
|
65
|
+
async function getLocalChanges(dir) {
|
|
66
|
+
const git = new git_1.Git(dir);
|
|
67
|
+
const root = await git.gitRoot();
|
|
68
|
+
return git
|
|
69
|
+
.getLocalChangedAndCreated()
|
|
70
|
+
.then(changes => resolvePaths(changes, root))
|
|
71
|
+
.catch(er => {
|
|
72
|
+
throw new LocalChangeException(er);
|
|
89
73
|
});
|
|
90
74
|
}
|
|
91
|
-
exports.getLocalChanges = getLocalChanges;
|
|
92
75
|
/**
|
|
93
76
|
* Get the locally changed class files, based on source tracking repo. Note that it does
|
|
94
77
|
* not respect the `.forceignore` yet.
|
|
@@ -97,40 +80,35 @@ exports.getLocalChanges = getLocalChanges;
|
|
|
97
80
|
* @param orgId SF org ID, used to select tracking repo
|
|
98
81
|
* @returns paths of class files that may need deploying
|
|
99
82
|
*/
|
|
100
|
-
function getDeployableClasses(projectDir, orgId) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
throw new LocalChangeException(er);
|
|
116
|
-
});
|
|
83
|
+
async function getDeployableClasses(projectDir, orgId) {
|
|
84
|
+
const git = new git_1.Git(projectDir);
|
|
85
|
+
const trackingDir = getTrackingGitDir(projectDir, orgId);
|
|
86
|
+
const stats = [
|
|
87
|
+
git_1.FileStatus.Modified,
|
|
88
|
+
git_1.FileStatus.Added,
|
|
89
|
+
git_1.FileStatus.Renamed,
|
|
90
|
+
git_1.FileStatus.Copied,
|
|
91
|
+
git_1.FileStatus.Untracked,
|
|
92
|
+
];
|
|
93
|
+
return git
|
|
94
|
+
.getFilteredStatus(f => f.path.endsWith('.cls') && stats.includes(f.working_dir), trackingDir)
|
|
95
|
+
.then(changes => resolvePaths(changes, projectDir))
|
|
96
|
+
.catch(er => {
|
|
97
|
+
throw new LocalChangeException(er);
|
|
117
98
|
});
|
|
118
99
|
}
|
|
119
|
-
exports.getDeployableClasses = getDeployableClasses;
|
|
120
100
|
function resolvePaths(paths, root) {
|
|
121
101
|
const fullPaths = [...paths].map(p => path_1.default.resolve(root, p));
|
|
122
102
|
return new Set(fullPaths);
|
|
123
103
|
}
|
|
124
|
-
function getDiffChanges(git, ref1, ref2) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return allChanges;
|
|
133
|
-
});
|
|
104
|
+
async function getDiffChanges(git, ref1, ref2) {
|
|
105
|
+
const changes = await Promise.all([
|
|
106
|
+
git.diffRange(ref1, ref2),
|
|
107
|
+
git.getLocalChangedAndCreated(),
|
|
108
|
+
]);
|
|
109
|
+
const allChanges = new Set();
|
|
110
|
+
changes.forEach(set => set.forEach(file => allChanges.add(file)));
|
|
111
|
+
return allChanges;
|
|
134
112
|
}
|
|
135
113
|
function getTrackingGitDir(projectDir, orgId) {
|
|
136
114
|
return path_1.default.resolve(projectDir, '.sf', 'orgs', orgId, 'localSourceTracking');
|
|
@@ -23,5 +23,5 @@ export declare class Git {
|
|
|
23
23
|
getDefaultBranchName(): Promise<string>;
|
|
24
24
|
diffRange(fromRef: string, toRef: string): Promise<Set<string>>;
|
|
25
25
|
getLocalChangedAndCreated(): Promise<Set<string>>;
|
|
26
|
-
getFilteredStatus(filterFn: (result: FileStatusResult) => boolean, gitDir?: string
|
|
26
|
+
getFilteredStatus(filterFn: (result: FileStatusResult) => boolean, gitDir?: string): Promise<Set<string>>;
|
|
27
27
|
}
|
package/lib/git.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2024 Certinia Inc. All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Git = exports.FileStatus = void 0;
|
|
7
|
+
const simple_git_1 = require("simple-git");
|
|
8
|
+
var FileStatus;
|
|
9
|
+
(function (FileStatus) {
|
|
10
|
+
FileStatus["Unmodified"] = " ";
|
|
11
|
+
FileStatus["Modified"] = "M";
|
|
12
|
+
FileStatus["TypeChanged"] = "T";
|
|
13
|
+
FileStatus["Added"] = "A";
|
|
14
|
+
FileStatus["Deleted"] = "D";
|
|
15
|
+
FileStatus["Renamed"] = "R";
|
|
16
|
+
FileStatus["Copied"] = "C";
|
|
17
|
+
FileStatus["Updated"] = "U";
|
|
18
|
+
FileStatus["Untracked"] = "?";
|
|
19
|
+
FileStatus["Ignore"] = "!";
|
|
20
|
+
})(FileStatus || (exports.FileStatus = FileStatus = {}));
|
|
21
|
+
class Git {
|
|
22
|
+
static MIN_GIT_VERSION_MAJOR = 2;
|
|
23
|
+
static MIN_GIT_VERSION_MINOR = 20;
|
|
24
|
+
gitInstance = undefined;
|
|
25
|
+
dir;
|
|
26
|
+
constructor(dir) {
|
|
27
|
+
this.dir = dir;
|
|
28
|
+
}
|
|
29
|
+
static async versionCheck(git) {
|
|
30
|
+
const version = await git.version();
|
|
31
|
+
const isSupported = version.major >= this.MIN_GIT_VERSION_MAJOR &&
|
|
32
|
+
version.minor >= this.MIN_GIT_VERSION_MINOR;
|
|
33
|
+
if (!version.installed) {
|
|
34
|
+
throw new Error('"git" is not installed or available on the PATH');
|
|
35
|
+
}
|
|
36
|
+
if (!isSupported)
|
|
37
|
+
throw new Error(`Unsupported version of git. Min version must be ${this.MIN_GIT_VERSION_MAJOR}.${this.MIN_GIT_VERSION_MINOR}`);
|
|
38
|
+
}
|
|
39
|
+
get git() {
|
|
40
|
+
if (this.gitInstance)
|
|
41
|
+
return Promise.resolve(this.gitInstance);
|
|
42
|
+
const git = (0, simple_git_1.simpleGit)(this.dir);
|
|
43
|
+
return Git.versionCheck(git).then(() => {
|
|
44
|
+
this.gitInstance = git;
|
|
45
|
+
return git;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async gitRoot() {
|
|
49
|
+
return (await this.git).revparse('--show-toplevel');
|
|
50
|
+
}
|
|
51
|
+
async getDefaultBranchName() {
|
|
52
|
+
return this.git
|
|
53
|
+
.then(git => git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD', '--short']))
|
|
54
|
+
.catch(error => {
|
|
55
|
+
if (error instanceof Error)
|
|
56
|
+
throw Error(`Failed to find symbolic ref no remote HEAD with message: '${error.message.trim()}'`);
|
|
57
|
+
else
|
|
58
|
+
throw new Error('Failed to find symbolic ref no remote HEAD');
|
|
59
|
+
})
|
|
60
|
+
.then(branch => {
|
|
61
|
+
if (branch.startsWith('origin/'))
|
|
62
|
+
return branch.trim();
|
|
63
|
+
else
|
|
64
|
+
throw new Error(`Expected default branch '${branch}' to start with 'origin/'`);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async diffRange(fromRef, toRef) {
|
|
68
|
+
return this.git
|
|
69
|
+
.then(git => git.diff([`${fromRef}...${toRef}`, '--name-only', '-z']))
|
|
70
|
+
.then(diff => {
|
|
71
|
+
const files = diff
|
|
72
|
+
.split('\u0000')
|
|
73
|
+
.map(s => s.trim())
|
|
74
|
+
.filter(s => s); //Removes any falsy values
|
|
75
|
+
return new Set([...files]);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async getLocalChangedAndCreated() {
|
|
79
|
+
const excludeStatus = [FileStatus.Deleted, FileStatus.Ignore];
|
|
80
|
+
return this.getFilteredStatus(f => !excludeStatus.includes(f.index) &&
|
|
81
|
+
!excludeStatus.includes(f.working_dir));
|
|
82
|
+
}
|
|
83
|
+
async getFilteredStatus(filterFn, gitDir) {
|
|
84
|
+
return this.git
|
|
85
|
+
.then(git => {
|
|
86
|
+
return gitDir ? git.env('GIT_DIR', gitDir).status() : git.status();
|
|
87
|
+
})
|
|
88
|
+
.then(status => {
|
|
89
|
+
return new Set(...[status.files.filter(filterFn).map(f => f.path)]);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.Git = Git;
|
package/lib/tracking.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2024 Certinia Inc. All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OrgTracking = exports.FileState = void 0;
|
|
7
|
+
const core_1 = require("@salesforce/core");
|
|
8
|
+
const process_1 = require("process");
|
|
9
|
+
const source_tracking_1 = require("@salesforce/source-tracking");
|
|
10
|
+
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
11
|
+
var FileState;
|
|
12
|
+
(function (FileState) {
|
|
13
|
+
FileState["Added"] = "add";
|
|
14
|
+
FileState["Modified"] = "modify";
|
|
15
|
+
FileState["Deleted"] = "delete";
|
|
16
|
+
FileState["NonDelete"] = "nondelete";
|
|
17
|
+
FileState["Ignored"] = "ignore";
|
|
18
|
+
FileState["Conflicted"] = "conflict";
|
|
19
|
+
})(FileState || (exports.FileState = FileState = {}));
|
|
20
|
+
class OrgTracking {
|
|
21
|
+
options;
|
|
22
|
+
logger;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.options = options;
|
|
25
|
+
this.logger = options.logger;
|
|
26
|
+
}
|
|
27
|
+
async getLocalStatus(withConflicts = false) {
|
|
28
|
+
// source-tracking currently brings its own @salesforce/core type graph,
|
|
29
|
+
// so keep the runtime object and relax the compile-time boundary here.
|
|
30
|
+
const project = core_1.SfProject.getInstance(this.options.projectDir);
|
|
31
|
+
const org = (await core_1.Org.create({
|
|
32
|
+
connection: this.options.connection,
|
|
33
|
+
}));
|
|
34
|
+
return await this.withWorkingDir(this.options.projectDir, async () => {
|
|
35
|
+
const tracking = await source_tracking_1.SourceTracking.create({
|
|
36
|
+
org,
|
|
37
|
+
project,
|
|
38
|
+
ignoreLocalCache: true,
|
|
39
|
+
});
|
|
40
|
+
await tracking.ensureRemoteTracking(true);
|
|
41
|
+
const initValue = { local: [], remote: [] };
|
|
42
|
+
const status = await tracking
|
|
43
|
+
.getStatus({ local: true, remote: false })
|
|
44
|
+
.then(async (res) => {
|
|
45
|
+
if (withConflicts) {
|
|
46
|
+
//Taken from sourceTracking.ts from the @salesforce/source-tracking lib
|
|
47
|
+
const conflictFiles = (await tracking.getConflicts())
|
|
48
|
+
.flatMap(conflict => conflict.filenames)
|
|
49
|
+
.filter((value) => typeof value === 'string');
|
|
50
|
+
res = res.map(row => ({
|
|
51
|
+
...row,
|
|
52
|
+
conflict: !!row.filePath && conflictFiles.includes(row.filePath),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
return res;
|
|
56
|
+
})
|
|
57
|
+
.catch(e => {
|
|
58
|
+
this.logger.logError(e);
|
|
59
|
+
return [];
|
|
60
|
+
});
|
|
61
|
+
return status.reduce((acc, row) => {
|
|
62
|
+
acc[row.origin].push(this.toSyncStatusRow(row));
|
|
63
|
+
return acc;
|
|
64
|
+
}, initValue);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async deployAndUpdateSourceTracking(paths) {
|
|
68
|
+
return await this.withWorkingDir(this.options.projectDir, async () => {
|
|
69
|
+
try {
|
|
70
|
+
this.logger.logDeployProgress('Starting deploy');
|
|
71
|
+
const result = await this.deploy(paths);
|
|
72
|
+
if (result.response.success) {
|
|
73
|
+
await this.updateSourceTracking(result);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.reportDeployErrors(result);
|
|
77
|
+
}
|
|
78
|
+
this.logger.logDeployProgress('Finished deploy');
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
this.logger.logError(e);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async deploy(paths) {
|
|
86
|
+
const deploy = await source_deploy_retrieve_1.ComponentSet.fromSource(paths).deploy({
|
|
87
|
+
usernameOrConnection: this.options.connection,
|
|
88
|
+
});
|
|
89
|
+
deploy.onUpdate(response => this.reportDeployStatus(response));
|
|
90
|
+
const result = await deploy.pollStatus();
|
|
91
|
+
this.reportDeployStatus(result.response);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
reportDeployStatus(response) {
|
|
95
|
+
const { status, numberComponentsDeployed, numberComponentsTotal, numberComponentErrors, } = response;
|
|
96
|
+
const progress = `${numberComponentsDeployed}/${numberComponentsTotal}`;
|
|
97
|
+
const message = `Status: ${status} | Progress: ${progress} | Errors: ${numberComponentErrors}`;
|
|
98
|
+
this.logger.logDeployProgress(message);
|
|
99
|
+
}
|
|
100
|
+
reportDeployErrors(result) {
|
|
101
|
+
const errors = result.getFileResponses().reduce((a, c) => {
|
|
102
|
+
if (c.state === source_deploy_retrieve_1.ComponentStatus.Failed) {
|
|
103
|
+
a.push(new Error(`${c.fullName}: ${c.error}`));
|
|
104
|
+
}
|
|
105
|
+
return a;
|
|
106
|
+
}, []);
|
|
107
|
+
if (errors.length) {
|
|
108
|
+
this.logger.logDeployProgress('Deploy errors:');
|
|
109
|
+
errors.forEach(err => this.logger.logError(err));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async updateSourceTracking(result) {
|
|
113
|
+
this.logger.logDeployProgress('Starting source tracking update');
|
|
114
|
+
const project = core_1.SfProject.getInstance(this.options.projectDir);
|
|
115
|
+
const org = (await core_1.Org.create({
|
|
116
|
+
connection: this.options.connection,
|
|
117
|
+
}));
|
|
118
|
+
const tracking = await source_tracking_1.SourceTracking.create({
|
|
119
|
+
org,
|
|
120
|
+
project,
|
|
121
|
+
ignoreLocalCache: true,
|
|
122
|
+
});
|
|
123
|
+
await tracking.updateTrackingFromDeploy(result);
|
|
124
|
+
this.logger.logDeployProgress('Finished source tracking update');
|
|
125
|
+
}
|
|
126
|
+
toSyncStatusRow(from) {
|
|
127
|
+
const state = [];
|
|
128
|
+
if (from.ignored) {
|
|
129
|
+
state.push(FileState.Ignored);
|
|
130
|
+
}
|
|
131
|
+
if (from.conflict) {
|
|
132
|
+
state.push(FileState.Conflicted);
|
|
133
|
+
}
|
|
134
|
+
state.push(from.state);
|
|
135
|
+
return {
|
|
136
|
+
fullName: from.fullName,
|
|
137
|
+
path: from.filePath,
|
|
138
|
+
state: state,
|
|
139
|
+
type: from.type,
|
|
140
|
+
origin: from.origin,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async withWorkingDir(path, op) {
|
|
144
|
+
const startDir = (0, process_1.cwd)();
|
|
145
|
+
(0, process_1.chdir)(path);
|
|
146
|
+
try {
|
|
147
|
+
return await op();
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
(0, process_1.chdir)(startDir);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.OrgTracking = OrgTracking;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apexdevtools/git-ops",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Library to do git operations to find changed files in a given git repository",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Apex Dev Tools Team",
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
"url": "https://github.com/apex-dev-tools/git-ops/issues"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/apex-dev-tools/git-ops#readme",
|
|
28
|
-
"
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
30
|
+
},
|
|
29
31
|
"dependencies": {
|
|
30
32
|
"@salesforce/core": "^4.3.11",
|
|
31
33
|
"@salesforce/source-deploy-retrieve": "^9.2.8",
|
|
@@ -33,22 +35,20 @@
|
|
|
33
35
|
"simple-git": "^3.16.0"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
38
|
+
"@eslint/js": "^10.0.1",
|
|
36
39
|
"@ryansonshine/commitizen": "^4.2.8",
|
|
37
40
|
"@ryansonshine/cz-conventional-changelog": "^3.3.4",
|
|
38
|
-
"@types/jest": "^
|
|
39
|
-
"@types/node": "^
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"prettier": "^2.8.8",
|
|
50
|
-
"ts-jest": "^29.1.0",
|
|
51
|
-
"typescript": "^4.9.5"
|
|
41
|
+
"@types/jest": "^30.0.0",
|
|
42
|
+
"@types/node": "^22.19.17",
|
|
43
|
+
"eslint": "^10.2.1",
|
|
44
|
+
"eslint-config-prettier": "^10.1.8",
|
|
45
|
+
"husky": "^9.1.7",
|
|
46
|
+
"jest": "^30.3.0",
|
|
47
|
+
"lint-staged": "^17.0.2",
|
|
48
|
+
"prettier": "^3.8.3",
|
|
49
|
+
"ts-jest": "^29.4.5",
|
|
50
|
+
"typescript": "^6.0.3",
|
|
51
|
+
"typescript-eslint": "^8.59.0"
|
|
52
52
|
},
|
|
53
53
|
"config": {
|
|
54
54
|
"commitizen": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"build": "tsc",
|
|
63
63
|
"clean": "rm -rf ./lib/",
|
|
64
64
|
"commit": "cz",
|
|
65
|
-
"lint": "eslint ./src
|
|
65
|
+
"lint": "eslint --cache --cache-location .eslintcache ./src --fix",
|
|
66
66
|
"test": "jest --coverage --runInBand",
|
|
67
67
|
"test:watch": "jest --watch"
|
|
68
68
|
}
|
package/lib/src/git.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2024 Certinia Inc. All rights reserved.
|
|
4
|
-
*/
|
|
5
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.Git = exports.FileStatus = void 0;
|
|
16
|
-
const simple_git_1 = require("simple-git");
|
|
17
|
-
var FileStatus;
|
|
18
|
-
(function (FileStatus) {
|
|
19
|
-
FileStatus["Unmodified"] = " ";
|
|
20
|
-
FileStatus["Modified"] = "M";
|
|
21
|
-
FileStatus["TypeChanged"] = "T";
|
|
22
|
-
FileStatus["Added"] = "A";
|
|
23
|
-
FileStatus["Deleted"] = "D";
|
|
24
|
-
FileStatus["Renamed"] = "R";
|
|
25
|
-
FileStatus["Copied"] = "C";
|
|
26
|
-
FileStatus["Updated"] = "U";
|
|
27
|
-
FileStatus["Untracked"] = "?";
|
|
28
|
-
FileStatus["Ignore"] = "!";
|
|
29
|
-
})(FileStatus = exports.FileStatus || (exports.FileStatus = {}));
|
|
30
|
-
class Git {
|
|
31
|
-
constructor(dir) {
|
|
32
|
-
this.gitInstance = undefined;
|
|
33
|
-
this.dir = dir;
|
|
34
|
-
}
|
|
35
|
-
static versionCheck(git) {
|
|
36
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
const version = yield git.version();
|
|
38
|
-
const isSupported = version.major >= this.MIN_GIT_VERSION_MAJOR &&
|
|
39
|
-
version.minor >= this.MIN_GIT_VERSION_MINOR;
|
|
40
|
-
if (!version.installed) {
|
|
41
|
-
throw new Error('"git" is not installed or available on the PATH');
|
|
42
|
-
}
|
|
43
|
-
if (!isSupported)
|
|
44
|
-
throw new Error(`Unsupported version of git. Min version must be ${this.MIN_GIT_VERSION_MAJOR}.${this.MIN_GIT_VERSION_MINOR}`);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
get git() {
|
|
48
|
-
if (this.gitInstance)
|
|
49
|
-
return Promise.resolve(this.gitInstance);
|
|
50
|
-
//eslint-disable-next-line
|
|
51
|
-
const git = (0, simple_git_1.simpleGit)(this.dir);
|
|
52
|
-
return Git.versionCheck(git).then(() => {
|
|
53
|
-
this.gitInstance = git;
|
|
54
|
-
return git;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
gitRoot() {
|
|
58
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
return (yield this.git).revparse('--show-toplevel');
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
getDefaultBranchName() {
|
|
63
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
return this.git
|
|
65
|
-
.then(git => git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD', '--short']))
|
|
66
|
-
.catch(error => {
|
|
67
|
-
if (error instanceof Error)
|
|
68
|
-
throw Error(`Failed to find symbolic ref no remote HEAD with message: '${error.message.trim()}'`);
|
|
69
|
-
else
|
|
70
|
-
throw new Error('Failed to find symbolic ref no remote HEAD');
|
|
71
|
-
})
|
|
72
|
-
.then(branch => {
|
|
73
|
-
if (branch.startsWith('origin/'))
|
|
74
|
-
return branch.trim();
|
|
75
|
-
else
|
|
76
|
-
throw new Error(`Expected default branch '${branch}' to start with 'origin/'`);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
diffRange(fromRef, toRef) {
|
|
81
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
-
return this.git
|
|
83
|
-
.then(git => git.diff([`${fromRef}...${toRef}`, '--name-only', '-z']))
|
|
84
|
-
.then(diff => {
|
|
85
|
-
const files = diff
|
|
86
|
-
.split('\u0000')
|
|
87
|
-
.map(s => s.trim())
|
|
88
|
-
.filter(s => s); //Removes any falsy values
|
|
89
|
-
return new Set([...files]);
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
getLocalChangedAndCreated() {
|
|
94
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
-
const excludeStatus = [FileStatus.Deleted, FileStatus.Ignore];
|
|
96
|
-
return this.getFilteredStatus(f => !excludeStatus.includes(f.index) &&
|
|
97
|
-
!excludeStatus.includes(f.working_dir));
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
getFilteredStatus(filterFn, gitDir) {
|
|
101
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
-
return this.git
|
|
103
|
-
.then(git => {
|
|
104
|
-
return gitDir ? git.env('GIT_DIR', gitDir).status() : git.status();
|
|
105
|
-
})
|
|
106
|
-
.then(status => {
|
|
107
|
-
return new Set(...[status.files.filter(filterFn).map(f => f.path)]);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
exports.Git = Git;
|
|
113
|
-
Git.MIN_GIT_VERSION_MAJOR = 2;
|
|
114
|
-
Git.MIN_GIT_VERSION_MINOR = 20;
|