Skip to content

Commit

Permalink
Merge branch 'main' into profile-management
Browse files Browse the repository at this point in the history
  • Loading branch information
JillieBeanSim authored Oct 9, 2023
2 parents b55efdc + 5f77386 commit 60e3c9d
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 5 deletions.
2 changes: 1 addition & 1 deletion packages/zowe-explorer/.vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
!resources/**/*.png
!resources/**/*.svg
!prebuilds/**
!webviews/*/dist/
!src/webviews/dist/**

!CHANGELOG.md
!LICENSE
Expand Down
1 change: 1 addition & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen
### Bug fixes

- Fixed submitting local JCL using command pallet option `Zowe Explorer: Submit JCL` by adding a check for chosen profile returned to continue the action. [#1625](https://github.com/zowe/vscode-extension-for-zowe/issues/1625)
- Fixed conflict resolution being skipped if local and remote file have different contents but are the same size. [#2496](https://github.com/zowe/vscode-extension-for-zowe/issues/2496)

## `2.11.0`

Expand Down
6 changes: 3 additions & 3 deletions packages/zowe-explorer/__mocks__/mockCreators/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,12 @@ export function createTextDocument(name: string, sessionNode?: ZoweDatasetNode |
isDirty: null,
isClosed: null,
save: null,
eol: null,
eol: 1,
lineCount: null,
lineAt: null,
offsetAt: null,
positionAt: null,
getText: jest.fn(),
positionAt: jest.fn(),
getText: jest.fn().mockReturnValue(""),
getWordRangeAtPosition: null,
validateRange: null,
validatePosition: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1454,6 +1454,74 @@ describe("Dataset Actions Unit Tests - Function saveFile", () => {
logSpy.mockClear();
commandSpy.mockClear();
});

it("Checking common dataset saving failed due to conflict with server version when file size has not changed", async () => {
globals.defineGlobals("");
createGlobalMocks();
const blockMocks = createBlockMocks();
const node = new ZoweDatasetNode(
"HLQ.TEST.AFILE",
vscode.TreeItemCollapsibleState.None,
blockMocks.datasetSessionNode,
null,
undefined,
undefined,
blockMocks.imperativeProfile
);
blockMocks.datasetSessionNode.children.push(node);

mocked(sharedUtils.concatChildNodes).mockReturnValueOnce([node]);
blockMocks.testDatasetTree.getChildren.mockReturnValueOnce([blockMocks.datasetSessionNode]);
mocked(zowe.List.dataSet).mockResolvedValue({
success: true,
commandResponse: "",
apiResponse: {
items: [{ dsname: "HLQ.TEST.AFILE" }],
},
});
mocked(zowe.Upload.pathToDataSet).mockResolvedValueOnce({
success: false,
commandResponse: "Rest API failure with HTTP(S) status 412",
apiResponse: [],
});

mocked(vscode.window.withProgress).mockImplementation((progLocation, callback) => {
return callback();
});
const profile = blockMocks.imperativeProfile;
profile.profile.encoding = 1047;
blockMocks.profileInstance.loadNamedProfile.mockReturnValueOnce(blockMocks.imperativeProfile);
mocked(Profiles.getInstance).mockReturnValue(blockMocks.profileInstance);
Object.defineProperty(wsUtils, "markDocumentUnsaved", {
value: jest.fn(),
configurable: true,
});
Object.defineProperty(context, "isTypeUssTreeNode", {
value: jest.fn().mockReturnValueOnce(false),
configurable: true,
});
Object.defineProperty(ZoweExplorerApiRegister.getMvsApi, "getContents", {
value: jest.fn(),
configurable: true,
});

const testDocument = createTextDocument("HLQ.TEST.AFILE", blockMocks.datasetSessionNode);
(testDocument as any).fileName = path.join(globals.DS_DIR, testDocument.fileName);
const logSpy = jest.spyOn(ZoweLogger, "warn");
const commandSpy = jest.spyOn(vscode.commands, "executeCommand");
const applyEditSpy = jest.spyOn(vscode.workspace, "applyEdit");
jest.spyOn(fs, "statSync").mockReturnValueOnce({ size: 0 } as any);

await dsActions.saveFile(testDocument, blockMocks.testDatasetTree);

expect(logSpy).toBeCalledWith("Remote file has changed. Presenting with way to resolve file.");
expect(mocked(sharedUtils.concatChildNodes)).toBeCalled();
expect(commandSpy).toBeCalledWith("workbench.files.action.compareWithSaved");
expect(applyEditSpy).toHaveBeenCalledTimes(2);
logSpy.mockClear();
commandSpy.mockClear();
applyEditSpy.mockClear();
});
});

describe("Dataset Actions Unit Tests - Function showAttributes", () => {
Expand Down
22 changes: 21 additions & 1 deletion packages/zowe-explorer/src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

// Generic utility functions related to all node types. See ./src/utils.ts for other utility functions.

import * as fs from "fs";
import * as vscode from "vscode";
import * as path from "path";
import * as globals from "../globals";
Expand Down Expand Up @@ -383,8 +384,27 @@ export async function compareFileContent(
responseTimeout: prof.profile?.responseTimeout,
});
}

// If local and remote file size are the same, then VS Code won't detect
// there is a conflict and remote changes may get overwritten. To work
// around this limitation of VS Code, when the sizes are identical we
// temporarily add a trailing newline byte to the local copy which forces
// the file size to be different. This is a terrible hack but it works.
// See https://github.com/microsoft/vscode/issues/119002
const oldSize = doc.getText().length;
const newSize = fs.statSync(doc.fileName).size;
if (newSize === oldSize) {
const edits = new vscode.WorkspaceEdit();
edits.insert(doc.uri, doc.positionAt(oldSize), doc.eol.toString());
await vscode.workspace.applyEdit(edits);
}
ZoweLogger.warn(localize("saveFile.etagMismatch.log.warning", "Remote file has changed. Presenting with way to resolve file."));
vscode.commands.executeCommand("workbench.files.action.compareWithSaved");
await vscode.commands.executeCommand("workbench.files.action.compareWithSaved");
if (newSize === oldSize) {
const edits2 = new vscode.WorkspaceEdit();
edits2.delete(doc.uri, new vscode.Range(doc.positionAt(oldSize), doc.positionAt(oldSize + doc.eol.toString().length)));
await vscode.workspace.applyEdit(edits2);
}
// re-assign etag, so that it can be used with subsequent requests
const downloadEtag = downloadResponse?.apiResponse?.etag;
if (node && downloadEtag !== node.getEtag()) {
Expand Down

0 comments on commit 60e3c9d

Please sign in to comment.