Skip to content

Commit d652c87

Browse files
authored
Merge pull request #3128 from SamJessep/feat/deploy_selected_files
Added the ability to deploy selected files from the explorer
2 parents 7a64c21 + 3570197 commit d652c87

6 files changed

Lines changed: 74 additions & 10 deletions

File tree

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,13 @@
13171317
"icon": "$(cloud-upload)",
13181318
"enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly && workspaceFolderCount >= 1"
13191319
},
1320+
{
1321+
"command": "code-for-ibmi.deploySelected",
1322+
"title": "Deploy Selected Files",
1323+
"category": "IBM i",
1324+
"icon": "$(cloud-upload)",
1325+
"enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly"
1326+
},
13201327
{
13211328
"command": "code-for-ibmi.setDeployLocation",
13221329
"enablement": "code-for-ibmi:connected && !code-for-ibmi:isReadonly",
@@ -3216,6 +3223,11 @@
32163223
"command": "code-for-ibmi.runAction",
32173224
"when": "code-for-ibmi:connected && !explorerResourceIsFolder && code-for-ibmi:hasLocalActions",
32183225
"group": "1_localactions@01"
3226+
},
3227+
{
3228+
"command": "code-for-ibmi.deploySelected",
3229+
"when": "code-for-ibmi:connected && resource",
3230+
"group": "1_localactions@02"
32193231
}
32203232
]
32213233
},

src/api/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Variables } from "./variables";
22

3-
export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare";
3+
export type DeploymentMethod = "all" | "staged" | "unstaged" | "changed" | "compare" | "selected";
44

55
export interface StandardIO {
66
onStdout?: (data: Buffer) => void;

src/filesystems/local/deployTools.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ export namespace DeployTools {
8181
* @param workspaceIndex if no index is provided, a prompt will be shown to pick one if there are multiple workspaces,
8282
* otherwise the current workspace will be used.
8383
* @param method if no method is provided, a prompt will be shown to pick the deployment method.
84+
* @param selectedFiles if the "selected" deployment method is used, these files will be deployed.
8485
* @returns the index of the deployed workspace or `undefined` if the deployment failed
8586
*/
86-
export async function launchDeploy(workspaceIndex?: number, method?: DeploymentMethod): Promise<{ remoteDirectory: string, workspaceId: number } | undefined> {
87+
export async function launchDeploy(workspaceIndex?: number, method?: DeploymentMethod, selectedFiles?: Uri[]): Promise<{ remoteDirectory: string, workspaceId: number } | undefined> {
8788
const folder = await Deployment.getWorkspaceFolder(workspaceIndex);
8889
if (folder) {
8990
const remotePath = getRemoteDeployDirectory(folder);
@@ -127,7 +128,8 @@ export namespace DeployTools {
127128
const parameters: DeploymentParameters = {
128129
workspaceFolder: folder,
129130
remotePath,
130-
method
131+
method,
132+
selectedFiles
131133
};
132134

133135
if (await deploy(parameters)) {
@@ -140,7 +142,7 @@ export namespace DeployTools {
140142
}
141143
} else {
142144
if (await vscode.window.showErrorMessage(`Chosen location (${folder.uri.fsPath}) is not configured for deployment.`, 'Set deploy location')) {
143-
setDeployLocation(undefined, folder, buildPossibleDeploymentDirectory(folder));
145+
setDeployLocation(undefined, folder, buildPossibleDeploymentDirectory(folder), method, selectedFiles);
144146
}
145147
}
146148
}
@@ -187,6 +189,10 @@ export namespace DeployTools {
187189
deletes.push(...relativeRemoteDeletes);
188190
break;
189191

192+
case "selected":
193+
files.push(...parameters.selectedFiles || []);
194+
break;
195+
190196
case "all":
191197
files.push(...await getDeployAllFiles(parameters));
192198
break;
@@ -333,7 +339,7 @@ export namespace DeployTools {
333339
return (await Deployment.findFiles(parameters, "**/*", "**/.git*"));
334340
}
335341

336-
export async function setDeployLocation(node: any, workspaceFolder?: WorkspaceFolder, value?: string) {
342+
export async function setDeployLocation(node: any, workspaceFolder?: WorkspaceFolder, value?: string, method?: DeploymentMethod, selectedFiles?: Uri[]) {
337343
const path = node?.path || await vscode.window.showInputBox({
338344
prompt: `Enter IFS directory to deploy to`,
339345
value
@@ -353,7 +359,7 @@ export namespace DeployTools {
353359
instance.fire(`deployLocation`);
354360

355361
if (await vscode.window.showInformationMessage(`Deployment location set to ${path}`, `Deploy now`)) {
356-
vscode.commands.executeCommand(`code-for-ibmi.launchDeploy`, chosenWorkspaceFolder.index);
362+
vscode.commands.executeCommand(`code-for-ibmi.launchDeploy`, chosenWorkspaceFolder.index, method, selectedFiles);
357363
}
358364
}
359365
}

src/filesystems/local/deployment.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import path from 'path';
33
import { create as tarCreate, t as tarT } from 'tar';
44
import tmp from 'tmp';
5-
import vscode from 'vscode';
5+
import vscode, { Uri } from 'vscode';
66
import { getActions, getLocalActionsFiles } from '../../api/actions';
77
import IBMi from '../../api/IBMi';
88
import IBMiContent from '../../api/IBMiContent';
@@ -38,6 +38,27 @@ export namespace Deployment {
3838
deploymentLog,
3939
vscode.commands.registerCommand(`code-for-ibmi.launchActionsSetup`, DeployTools.launchActionsSetup),
4040
vscode.commands.registerCommand(`code-for-ibmi.launchDeploy`, DeployTools.launchDeploy),
41+
vscode.commands.registerCommand(`code-for-ibmi.deploySelected`, async (item?: Uri, items?: Uri[]) => {
42+
if(!(item instanceof Uri)) {
43+
vscode.window.showErrorMessage(`No files selected for deployment.`);
44+
return;
45+
}
46+
const selectedItems = Array.isArray(items) && items.length > 0 ? items : [item];
47+
const itemsByWorkspace: Uri[][] = [];
48+
selectedItems.forEach(uri => {
49+
const workspace = vscode.workspace.getWorkspaceFolder(uri);
50+
if (workspace) {
51+
let uris = itemsByWorkspace[workspace.index];
52+
if (!uris) uris = [];
53+
uris.push(uri);
54+
itemsByWorkspace[workspace.index] = uris;
55+
}
56+
});
57+
58+
await Promise.all(
59+
itemsByWorkspace.map((workspaceItems, workspaceIndex) => DeployTools.launchDeploy(workspaceIndex, "selected", workspaceItems))
60+
);
61+
}),
4162
vscode.commands.registerCommand(`code-for-ibmi.setDeployLocation`, DeployTools.setDeployLocation)
4263
);
4364

src/testing/deployTools.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,19 @@ export const DeployToolsSuite: TestSuite = {
147147
assert.strictEqual(deleted, 1);
148148
}
149149
},
150+
{
151+
name: `Test 'Selected' deployment`, test: async () => {
152+
const filesToDeploy = [
153+
fakeProject.files![1].localPath!,
154+
fakeProject.folders![0].localPath!,
155+
]
156+
157+
const locals = await getLocalFilesInfoForSelected(filesToDeploy);
158+
const remotes = await deploy("selected", filesToDeploy);
159+
assert.strictEqual(remotes.size, 4, "Expected 1 root file and 3 files from the folder to be deployed");
160+
assertFilesInfoEquals(locals, remotes);
161+
}
162+
},
150163
{
151164
name: `postDownload test`, test: async () => {
152165
const action: Action = {
@@ -215,7 +228,7 @@ export const DeployToolsSuite: TestSuite = {
215228
},
216229
}
217230

218-
async function deploy(method: DeploymentMethod) {
231+
async function deploy(method: DeploymentMethod, selectedFiles?: vscode.Uri[]) {
219232
assert.ok(fakeProject.localPath, "No local path");
220233
assert.ok(fakeProject.remotePath, "No remote path");
221234
const workspaceFolder = vscode.workspace.getWorkspaceFolder(fakeProject.localPath);
@@ -227,7 +240,7 @@ async function deploy(method: DeploymentMethod) {
227240
`!${basename(fakeProject.localPath.path)}/**` //Allow content
228241
]);
229242

230-
assert.ok(await DeployTools.deploy({ method, remotePath: fakeProject.remotePath, workspaceFolder, ignoreRules }), `"${method}" deployment failed`);
243+
assert.ok(await DeployTools.deploy({ method, remotePath: fakeProject.remotePath, workspaceFolder, ignoreRules, selectedFiles }), `"${method}" deployment failed`);
231244
return await getRemoteFilesInfo();
232245
}
233246

@@ -265,6 +278,17 @@ async function getLocalFilesInfo() {
265278
return localFiles;
266279
}
267280

281+
async function getLocalFilesInfoForSelected(selectedFiles: vscode.Uri[]) {
282+
const localFiles = await getLocalFilesInfo();
283+
const selectedPaths = selectedFiles.map(file => posix.join(basename(fakeProject.localPath!.path), posix.relative(fakeProject.localPath!.path, file.path)));
284+
for (const path of localFiles.keys()) {
285+
if (!selectedPaths.some(selected => selected === path || path.startsWith(selected+'/'))) {
286+
localFiles.delete(path);
287+
}
288+
}
289+
return localFiles;
290+
}
291+
268292
async function getRemoteFilesInfo() {
269293
const remoteFiles: FilesInfo = new Map;
270294

src/typings.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Ignore } from "ignore";
2-
import { WorkspaceFolder } from "vscode";
2+
import { Uri, WorkspaceFolder } from "vscode";
33
import Instance from "./Instance";
44
import { ComponentRegistry } from './api/components/manager';
55
import { ConnectionManager } from "./api/configuration/config/ConnectionManager";
@@ -27,6 +27,7 @@ export interface DeploymentParameters {
2727
workspaceFolder: WorkspaceFolder
2828
remotePath: string
2929
ignoreRules?: Ignore
30+
selectedFiles?: Uri[]
3031
}
3132

3233
export * from "./api/types";

0 commit comments

Comments
 (0)