Skip to content

Commit

Permalink
feat: non-delete push works
Browse files Browse the repository at this point in the history
  • Loading branch information
mshanemc committed Aug 10, 2021
1 parent 367bb56 commit 487a20e
Show file tree
Hide file tree
Showing 6 changed files with 441 additions and 27 deletions.
34 changes: 33 additions & 1 deletion package.json
Expand Up @@ -22,6 +22,7 @@
"lint": "sf-lint",
"lint-fix": "yarn sf-lint --fix",
"prepack": "sf-build",
"postpack": "shx rm -f oclif.manifest.json",
"pretest": "sf-compile-test",
"test": "sf-test --require ts-node/register",
"test:nuts": "nyc mocha \"**/*.nut.ts\" --slow 4500 --timeout 600000 --parallel"
Expand All @@ -38,7 +39,8 @@
"docs",
"lib",
"messages",
"!lib/**/*.map"
"!lib/**/*.map",
"/oclif.manifest.json"
],
"husky": {
"hooks": {
Expand All @@ -52,13 +54,16 @@
"@salesforce/command": "^4.0.0",
"@salesforce/core": "^2.27.0",
"@salesforce/kit": "^1.5.17",
"@salesforce/source-deploy-retrieve": "^4.0.2",
"isomorphic-git": "^1.9.2",
"ts-retry-promise": "^0.6.0"
},
"devDependencies": {
"@oclif/plugin-command-snapshot": "^2.2.2",
"@salesforce/cli-plugins-testkit": "^1.2.11",
"@salesforce/dev-config": "^2.1.2",
"@salesforce/dev-scripts": "^0.9.18",
"@salesforce/plugin-command-reference": "^1.3.4",
"@salesforce/prettier-config": "^0.0.2",
"@salesforce/ts-sinon": "^1.3.21",
"@types/sinon": "^10.0.2",
Expand All @@ -84,6 +89,33 @@
"ts-node": "^10.1.0",
"typescript": "^4.3.5"
},
"oclif": {
"commands": "./lib/commands",
"bin": "sfdx",
"devPlugins": [
"@oclif/plugin-help",
"@oclif/plugin-command-snapshot",
"@salesforce/plugin-command-reference"
],
"topics": {
"force": {
"external": true,
"subtopics": {
"user": {
"description": "commands that perform user-related admin tasks",
"subtopics": {
"permset": {
"description": "Use to interact with permission sets assigned to a user"
},
"password": {
"description": "Used to generate and set passwords for users"
}
}
}
}
}
}
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
Expand Down
61 changes: 61 additions & 0 deletions src/commands/source/push.ts
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { FlagsConfig, flags, SfdxCommand } from '@salesforce/command';
import { SfdxProject, Org } from '@salesforce/core';
import { ComponentSet, FileResponse } from '@salesforce/source-deploy-retrieve';

import { SourceTracking } from '../../sourceTracking';

export default class SourcePush extends SfdxCommand {
public static description = 'get local changes';
protected static readonly flagsConfig: FlagsConfig = {
forceoverwrite: flags.boolean({ char: 'f', description: 'overwrite files without prompting' }),
};
protected static requiresUsername = true;
protected static requiresProject = true;
protected project!: SfdxProject;
protected org!: Org;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
public async run(): Promise<FileResponse[]> {
const tracking = new SourceTracking({
orgId: this.org.getOrgId(),
projectPath: this.project.getPath(),
packageDirs: this.project.getPackageDirectories(),
});
if (!this.flags.forceoverwrite) {
// TODO: check for conflicts
}
// give me the deletes and nonDeletes
// const [deletes, nonDeletes] = await Promise.all([
// tracking.getChanges({ origin: 'local', state: 'delete' }),
// tracking.getChanges({ origin: 'local', state: 'changed' }),
// ]);
const nonDeletes = await tracking.getChanges({ origin: 'local', state: 'changed' });
const deletes = await tracking.getChanges({ origin: 'local', state: 'delete' });

this.ux.warn(
`Delete not yet implemented in SDR. Would have deleted ${deletes.length > 0 ? deletes.join(',') : 'nothing'}`
);
// create ComponentSet
if (nonDeletes.length === 0) {
this.ux.log('There are no changes to deploy');
return [];
}
this.ux.log(`should build component set from ${nonDeletes.join(',')}`);
const componentSet = ComponentSet.fromSource(nonDeletes);
// this.ux.logJson(componentSet.getSourceComponents());
const deploy = await componentSet.deploy({ usernameOrConnection: this.org.getUsername() as string });
const result = await deploy.pollStatus();

// then commit to local tracking;
await tracking.update({ files: result.getFileResponses().map((file) => file.filePath) as string[] });
return result.getFileResponses();
// return [];
}
}
4 changes: 4 additions & 0 deletions src/commands/source/status.ts
Expand Up @@ -50,6 +50,10 @@ export default class SourceStatus extends SfdxCommand {
adds,
modifies,
};
if (!this.flags.json) {
this.ux.logJson(output);
}

return output;
}
}
18 changes: 15 additions & 3 deletions src/shared/localShadowRepo.ts
Expand Up @@ -48,7 +48,7 @@ export class ShadowRepo extends AsyncCreatable<ShadowRepoOptions> {
private packageDirs!: NamedPackageDir[];
private status!: StatusRow[];
private logger!: Logger;

private stashed = false;
private options: ShadowRepoOptions;

public constructor(options: ShadowRepoOptions) {
Expand Down Expand Up @@ -170,10 +170,22 @@ export class ShadowRepo extends AsyncCreatable<ShadowRepoOptions> {
}

private async stashIgnoreFile(): Promise<void> {
await fs.promises.rename(path.join(this.projectPath, '.gitignore'), path.join(this.projectPath, '.BAK.gitignore'));
if (!this.stashed) {
this.stashed = true;
await fs.promises.rename(
path.join(this.projectPath, '.gitignore'),
path.join(this.projectPath, '.BAK.gitignore')
);
}
}

private async unStashIgnoreFile(): Promise<void> {
await fs.promises.rename(path.join(this.projectPath, '.BAK.gitignore'), path.join(this.projectPath, '.gitignore'));
if (this.stashed) {
this.stashed = false;
await fs.promises.rename(
path.join(this.projectPath, '.BAK.gitignore'),
path.join(this.projectPath, '.gitignore')
);
}
}
}
51 changes: 50 additions & 1 deletion src/sourceTracking.ts
Expand Up @@ -4,6 +4,8 @@
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { NamedPackageDir } from '@salesforce/core';
import { ShadowRepo } from './shared/localShadowRepo';

export interface ChangeOptions {
origin?: 'local' | 'remote';
Expand All @@ -15,13 +17,42 @@ export interface UpdateOptions {
}

export class SourceTracking {
private orgId: string;
private projectPath: string;
private packagesDirs: NamedPackageDir[];
private localRepo!: ShadowRepo;

public constructor({
orgId,
projectPath,
packageDirs,
}: {
orgId: string;
projectPath: string;
packageDirs: NamedPackageDir[];
}) {
this.orgId = orgId;
this.projectPath = projectPath;
this.packagesDirs = packageDirs;
}

/**
* Get metadata changes made locally and in the org.
*
* @returns local and remote changed metadata
*/
// eslint-disable-next-line @typescript-eslint/require-await
public async getChanges(options?: ChangeOptions): Promise<string[]> {
if (options?.origin === 'local') {
await this.ensureLocalTracking();
if (options.state === 'changed') {
return this.localRepo.getNonDeleteFilenames();
}
if (options.state === 'delete') {
return this.localRepo.getDeleteFilenames();
}
}

// by default return all local and remote changes
// eslint-disable-next-line no-console
console.log(options);
Expand All @@ -38,6 +69,24 @@ export class SourceTracking {
// update local and remote tracking
// by default update everything
// eslint-disable-next-line no-console
console.log(options);
// console.log(options);
await this.ensureLocalTracking();
await this.localRepo.commitChanges({ deployedFiles: options?.files });
}

/**
* If the local tracking shadowRepo doesn't exist, it will be created.
* Does nothing if it already exists.
* Useful before parallel operations
*/
public async ensureLocalTracking(): Promise<void> {
if (this.localRepo) {
return;
}
this.localRepo = await ShadowRepo.create({
orgId: this.orgId,
projectPath: this.projectPath,
packageDirs: this.packagesDirs,
});
}
}

0 comments on commit 487a20e

Please sign in to comment.