Skip to content

Commit

Permalink
feat: support both .sfdx/.sf
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed May 8, 2022
1 parent 94e610a commit 3d52e66
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/compatibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const messages = Messages.load('@salesforce/source-tracking', 'compatibility', [
]);

type TrackingFileVersion = 'plugin-source' | 'toolbelt' | 'none';

export const hasSfdxTrackingFiles = (orgId: string, projectPath: string): boolean =>
fs.existsSync(path.join(projectPath, '.sfdx', 'orgs', orgId));

/**
* A project can have "old" (toolbelt), "new" (plugin-source) or "none" tracking files
*
Expand Down
7 changes: 4 additions & 3 deletions src/shared/localShadowRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import * as git from 'isomorphic-git';
import { chunkArray, pathIsInFolder } from './functions';

/** returns the full path to where we store the shadow repo */
const getGitDir = (orgId: string, projectPath: string): string => {
return path.join(projectPath, '.sfdx', 'orgs', orgId, 'localSourceTracking');
const getGitDir = (orgId: string, projectPath: string, useSfdxTrackingFiles = false): string => {
return path.join(projectPath, useSfdxTrackingFiles ? '.sfdx' : '.sf', 'orgs', orgId, 'localSourceTracking');
};

// filenames were normalized when read from isogit
Expand All @@ -24,6 +24,7 @@ interface ShadowRepoOptions {
orgId: string;
projectPath: string;
packageDirs: NamedPackageDir[];
hasSfdxTrackingFiles: boolean;
}

// https://isomorphic-git.org/docs/en/statusMatrix#docsNav
Expand Down Expand Up @@ -56,7 +57,7 @@ export class ShadowRepo {
private maxFileAdd: number;

private constructor(options: ShadowRepoOptions) {
this.gitDir = getGitDir(options.orgId, options.projectPath);
this.gitDir = getGitDir(options.orgId, options.projectPath, options.hasSfdxTrackingFiles);
this.projectPath = options.projectPath;
this.packageDirs = options.packageDirs;
this.isWindows = os.type() === 'Windows_NT';
Expand Down
32 changes: 18 additions & 14 deletions src/shared/remoteSourceTrackingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { env, Duration } from '@salesforce/kit';
import { ChangeResult, RemoteChangeElement, MemberRevision, SourceMember, RemoteSyncInput } from './types';
import { getMetadataKeyFromFileResponse, mappingsForSourceMemberTypesToMetadataType } from './metadataKeys';
import { getMetadataKey } from './functions';

// represents the contents of the config file stored in 'maxRevision.json'
type Contents = {
serverMaxRevisionCounter: number;
Expand All @@ -34,9 +33,9 @@ const CONSECUTIVE_EMPTY_POLLING_RESULT_LIMIT =
export namespace RemoteSourceTrackingService {
// Constructor Options for RemoteSourceTrackingService.
export interface Options extends ConfigFile.Options {
orgId: string;
/** only used for connecting to the org */
username: string;
org: Org;
projectPath: string;
useSfdxTrackingFiles: boolean;
}
}

Expand Down Expand Up @@ -98,18 +97,19 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
* @returns {Promise<RemoteSourceTrackingService>} the remoteSourceTrackingService object for the given username
*/
public static async getInstance(options: RemoteSourceTrackingService.Options): Promise<RemoteSourceTrackingService> {
if (!this.remoteSourceTrackingServiceDictionary[options.orgId]) {
this.remoteSourceTrackingServiceDictionary[options.orgId] = await RemoteSourceTrackingService.create(options);
const orgId = options.org.getOrgId();
if (!this.remoteSourceTrackingServiceDictionary[orgId]) {
this.remoteSourceTrackingServiceDictionary[orgId] = await RemoteSourceTrackingService.create(options);
}
return this.remoteSourceTrackingServiceDictionary[options.orgId] as RemoteSourceTrackingService;
return this.remoteSourceTrackingServiceDictionary[orgId] as RemoteSourceTrackingService;
}

public static getFileName(): string {
return 'maxRevision.json';
}

public static getFilePath(orgId: string): string {
return path.join('.sfdx', 'orgs', orgId, RemoteSourceTrackingService.getFileName());
public static getFilePath(orgId: string, useSfdxTrackingFiles = false): string {
return path.join(useSfdxTrackingFiles ? '.sfdx' : '.sf', 'orgs', orgId, RemoteSourceTrackingService.getFileName());
}

/**
Expand All @@ -118,8 +118,8 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
* @param orgId
* @returns the path of the deleted source tracking file
*/
public static async delete(orgId: string): Promise<string> {
const fileToDelete = RemoteSourceTrackingService.getFilePath(orgId);
public static async delete(orgId: string, useSfdxTrackingFiles = false): Promise<string> {
const fileToDelete = RemoteSourceTrackingService.getFilePath(orgId, useSfdxTrackingFiles);
// the file might not exist, in which case we don't need to delete it
if (fs.existsSync(fileToDelete)) {
await fs.promises.unlink(fileToDelete);
Expand All @@ -132,10 +132,14 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
* the state to begin source tracking of metadata changes in the org.
*/
public async init(): Promise<void> {
this.org = await Org.create({ aliasOrUsername: this.options.username });
this.org = this.options.org;
this.logger = await Logger.child(this.constructor.name);
this.options.filePath = path.join('orgs', this.org.getOrgId());
this.options.filename = RemoteSourceTrackingService.getFileName();
this.options = {
...this.options,
stateFolder: this.options.useSfdxTrackingFiles ? '.sfdx' : '.sf',
filename: RemoteSourceTrackingService.getFileName(),
filePath: path.join('orgs', this.org.getOrgId()),
};

try {
await super.init();
Expand Down
26 changes: 14 additions & 12 deletions src/sourceTracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as fs from 'fs';
import { isAbsolute, relative, resolve, sep, normalize } from 'path';
import { EOL } from 'os';
import { NamedPackageDir, Logger, Org, SfdxProject } from '@salesforce/core';
import { NamedPackageDir, Logger, Org, SfProject } from '@salesforce/core';
import { AsyncCreatable } from '@salesforce/kit';
import { getString, isString } from '@salesforce/ts-types';
import {
Expand Down Expand Up @@ -36,10 +36,10 @@ import {
import { sourceComponentGuard, metadataMemberGuard } from './shared/guards';
import { getKeyFromObject, getMetadataKey, isBundle, pathIsInFolder } from './shared/functions';
import { mappingsForSourceMemberTypesToMetadataType } from './shared/metadataKeys';

import { hasSfdxTrackingFiles } from './compatibility';
export interface SourceTrackingOptions {
org: Org;
project: SfdxProject;
project: SfProject;
/** @deprecated not used defaults to sfdxProject sourceApiVersion unless provided */
apiVersion?: string;
}
Expand All @@ -51,26 +51,26 @@ export interface SourceTrackingOptions {
*
*/
export class SourceTracking extends AsyncCreatable {
private orgId: string;
private project: SfdxProject;
private org: Org;
private project: SfProject;
private projectPath: string;
private packagesDirs: NamedPackageDir[];
private username: string;
private logger: Logger;
private registry = new RegistryAccess();
// remote and local tracking may not exist if not initialized
private localRepo!: ShadowRepo;
private remoteSourceTrackingService!: RemoteSourceTrackingService;
private forceIgnore!: ForceIgnore;
private hasSfdxTrackingFiles: boolean;

public constructor(options: SourceTrackingOptions) {
super(options);
this.orgId = options.org.getOrgId();
this.username = options.org.getUsername() as string;
this.org = options.org;
this.projectPath = options.project.getPath();
this.packagesDirs = options.project.getPackageDirectories();
this.logger = Logger.childFromRoot('SourceTracking');
this.project = options.project;
this.hasSfdxTrackingFiles = hasSfdxTrackingFiles(this.org.getOrgId(), this.projectPath);
}

public async init(): Promise<void> {
Expand Down Expand Up @@ -427,9 +427,10 @@ export class SourceTracking extends AsyncCreatable {
return;
}
this.localRepo = await ShadowRepo.getInstance({
orgId: this.orgId,
orgId: this.org.getOrgId(),
projectPath: normalize(this.projectPath),
packageDirs: this.packagesDirs,
hasSfdxTrackingFiles: this.hasSfdxTrackingFiles,
});
// loads the status from file so that it's cached
await this.localRepo.getStatus();
Expand All @@ -447,8 +448,9 @@ export class SourceTracking extends AsyncCreatable {
}
this.logger.debug('ensureRemoteTracking: remote tracking does not exist yet; getting instance');
this.remoteSourceTrackingService = await RemoteSourceTrackingService.getInstance({
username: this.username,
orgId: this.orgId,
org: this.org,
projectPath: this.projectPath,
useSfdxTrackingFiles: this.hasSfdxTrackingFiles,
});
if (initializeWithQuery) {
await this.remoteSourceTrackingService.retrieveUpdates();
Expand Down Expand Up @@ -485,7 +487,7 @@ export class SourceTracking extends AsyncCreatable {
* Deletes the remote tracking files
*/
public async clearRemoteTracking(): Promise<string> {
return RemoteSourceTrackingService.delete(this.orgId);
return RemoteSourceTrackingService.delete(this.org.getOrgId(), this.hasSfdxTrackingFiles);
}

/**
Expand Down
1 change: 1 addition & 0 deletions test/nuts/local/commitPerf.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('perf testing for big commits', () => {
orgId: 'fakeOrgId',
projectPath: session.project.dir,
packageDirs: [{ path: 'force-app', name: 'force-app', fullPath: path.join(session.project.dir, 'force-app') }],
hasSfdxTrackingFiles: false,
});
});

Expand Down
1 change: 1 addition & 0 deletions test/nuts/local/localTrackingScenario.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('end-to-end-test for local tracking', () => {
orgId: 'fakeOrgId',
projectPath: session.project.dir,
packageDirs: [{ path: 'force-app', name: 'force-app', fullPath: path.join(session.project.dir, 'force-app') }],
hasSfdxTrackingFiles: false,
});
// verify the local tracking files/directories
expect(fs.existsSync(repo.gitDir));
Expand Down
2 changes: 2 additions & 0 deletions test/nuts/local/nonTopLevelIgnore.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('handles non-top-level ignore inside project dir', () => {
orgId: 'fakeOrgId2',
projectPath: session.project.dir,
packageDirs: [{ path: 'classes', name: 'classes', fullPath: path.join(session.project.dir, 'classes') }],
hasSfdxTrackingFiles: false,
});
// verify the local tracking files/directories
expect(fs.existsSync(repo.gitDir));
Expand Down Expand Up @@ -61,6 +62,7 @@ describe('handles non-top-level ignore outside project dir', () => {
orgId: 'fakeOrgId2',
projectPath: session.project.dir,
packageDirs: [{ path: 'classes', name: 'classes', fullPath: path.join(session.project.dir, 'classes') }],
hasSfdxTrackingFiles: false,
});
// verify the local tracking files/directories
expect(fs.existsSync(repo.gitDir));
Expand Down
1 change: 1 addition & 0 deletions test/nuts/local/pkgDirMatching.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe('verifies exact match of pkgDirs', () => {
orgId: 'fakeOrgId3',
projectPath: session.project.dir,
packageDirs: [{ path: 'force-app', name: 'force-app', fullPath: path.join(session.project.dir, 'force-app') }],
hasSfdxTrackingFiles: false,
});
// verify the local tracking files/directories
expect(fs.existsSync(repo.gitDir));
Expand Down
1 change: 1 addition & 0 deletions test/nuts/local/relativePkgDirs.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('verifies behavior of relative pkgDirs', () => {
packageDirs: [
{ path: './force-app', name: 'force-app', fullPath: path.join(session.project.dir, './force-app') },
],
hasSfdxTrackingFiles: false,
});
// verify the local tracking files/directories
expect(fs.existsSync(repo.gitDir));
Expand Down
1 change: 1 addition & 0 deletions test/nuts/local/tracking-scale.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe(`verify tracking handles an add of ${classCount.toLocaleString()} class
orgId: 'fakeOrgId',
projectPath: session.project.dir,
packageDirs: [{ path: 'force-app', name: 'force-app', fullPath: path.join(session.project.dir, 'force-app') }],
hasSfdxTrackingFiles: false,
});
});

Expand Down
1 change: 1 addition & 0 deletions test/unit/localShadowRepo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ describe('localShadowRepo', () => {
path: path.join(projectDir, 'force-app'),
},
],
hasSfdxTrackingFiles: false,
});

const gitAdd = sinon.spy(git, 'add');
Expand Down

0 comments on commit 3d52e66

Please sign in to comment.