Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ux - display maven and gradle dependencies with pattern 'groupId:artifactId:version ' #859

Merged
merged 16 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
{
"type": "java",
"name": "Attach to Plugin",
"projectName": "com.microsoft.jdtls.ext.core",
"request": "attach",
"hostName": "localhost",
"port": 1044
Expand Down
37 changes: 37 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# How to Contribute
jdneo marked this conversation as resolved.
Show resolved Hide resolved

We greatly appreciate contributions to the vscode-java-dependency project. Your efforts help us maintain and improve this extension. To ensure a smooth contribution process, please follow these guidelines.

## Prerequisites
- [JDK](https://www.oracle.com/java/technologies/downloads/?er=221886)
- [Node.JS](https://nodejs.org/en/)
- [VSCode](https://code.visualstudio.com/)

## Build and Run

To set up the vscode-java-dependency project, follow these steps:

1. **Build the Server JAR**:
- The server JAR (Java application) is located in the [jdtls.ext](./jdtls.ext) directory.
- Run the following command to build the server:
```shell
npm run build-server
```

2. **Install Dependencies**:
- Execute the following command to install the necessary dependencies:
```shell
npm install
```

3. **Run/Debug the Extension**:
- Open the "Run and Debug" view in Visual Studio Code.
- Run the "Run Extension" task.

4. **Attach to Plugin[Debug Java]**:
- Prerequisite: Ensure that the extension is activated, meaning the Java process is already launched. This is required for the task to run properly.
- Open the "Run and Debug" view in Visual Studio Code.
- Run the "Attach to Plugin" task.
jdneo marked this conversation as resolved.
Show resolved Hide resolved
- Note: This task is required only if you want to debug Java code [jdtls.ext](./jdtls.ext). It requires the [vscode-pde](https://marketplace.visualstudio.com/items?itemName=yaozheng.vscode-pde) extension to be installed.

Thank you for your contributions and support!
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -78,7 +79,7 @@ public class PackageCommand {
private static final Map<NodeKind, BiFunction<PackageParams, IProgressMonitor, List<PackageNode>>> commands;

static {
commands = new HashMap<>();
commands = new EnumMap<>(NodeKind.class);
commands.put(NodeKind.PROJECT, PackageCommand::getProjectChildren);
commands.put(NodeKind.CONTAINER, PackageCommand::getContainerChildren);
commands.put(NodeKind.PACKAGEROOT, PackageCommand::getPackageRootChildren);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
Expand Down Expand Up @@ -273,11 +274,32 @@ public static PackageRootNode createNodeForPackageFragmentRoot(IPackageFragmentR
for (IClasspathAttribute attribute : resolvedClasspathEntry.getExtraAttributes()) {
node.setMetaDataValue(attribute.getName(), attribute.getValue());
}

String computedDisplayName = computeDisplayName(node);
if (StringUtils.isNotBlank(computedDisplayName)) {
node.setDisplayName(computedDisplayName);
}
}

return node;
}

private static String computeDisplayName(PackageRootNode node) {
if (node.getMetaData() == null || node.getMetaData().isEmpty()) {
return node.getName();
}

String version = (String) node.getMetaData().get("maven.version");
String groupId = (String) node.getMetaData().get("maven.groupId");
String artifactId = (String) node.getMetaData().get("maven.artifactId");

if (StringUtils.isBlank(version) || StringUtils.isBlank(groupId) || StringUtils.isBlank(artifactId)) {
return node.getName();
}

return groupId + ":" + artifactId + ":" + version;
}

/**
* Get the correspond node of classpath, it may be container or a package root.
*
Expand Down
4 changes: 4 additions & 0 deletions src/views/PrimaryTypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export class PrimaryTypeNode extends DataNode {
return "";
}

public getLabel(): string {
jdneo marked this conversation as resolved.
Show resolved Hide resolved
return this._nodeData.displayName ?? this._nodeData.name;
}

protected async loadData(): Promise<SymbolInformation[] | DocumentSymbol[] | undefined> {
if (!this.hasChildren() || !this.nodeData.uri) {
return undefined;
Expand Down
25 changes: 19 additions & 6 deletions src/views/containerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,36 @@ export class ContainerNode extends DataNode {
super(nodeData, parent);
}

private _containerType: ContainerType;
jdneo marked this conversation as resolved.
Show resolved Hide resolved

public get projectBasePath() {
return this._project.uri && Uri.parse(this._project.uri).fsPath;
}

public getContainerType(): string {
public getContainerType(): ContainerType {
if (this._containerType) {
return this._containerType;
}

const containerPath: string = this._nodeData.path || "";
if (containerPath.startsWith(ContainerPath.JRE)) {
return ContainerType.JRE;
this._containerType = ContainerType.JRE;
} else if (containerPath.startsWith(ContainerPath.Maven)) {
return ContainerType.Maven;
this._containerType = ContainerType.Maven;
} else if (containerPath.startsWith(ContainerPath.Gradle)) {
return ContainerType.Gradle;
this._containerType = ContainerType.Gradle;
} else if (containerPath.startsWith(ContainerPath.ReferencedLibrary) && this._project.isUnmanagedFolder()) {
// currently, we only support editing referenced libraries in unmanaged folders
return ContainerType.ReferencedLibrary;
this._containerType = ContainerType.ReferencedLibrary;
} else {
this._containerType = ContainerType.Unknown;
}
return ContainerType.Unknown;

return this._containerType;
}

public isMavenType(): boolean {
return this._containerType === ContainerType.Maven;
}

protected async loadData(): Promise<INodeData[]> {
Expand Down
4 changes: 4 additions & 0 deletions src/views/dataNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export abstract class DataNode extends ExplorerNode {
return item;
}

public getDisplayName(): string {
return this._nodeData.displayName || this._nodeData.name;
}

public get nodeData(): INodeData {
return this._nodeData;
}
Expand Down
10 changes: 9 additions & 1 deletion src/views/dependencyDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
RelativePattern, TreeDataProvider, TreeItem, Uri, window, workspace,
} from "vscode";
import { instrumentOperationAsVsCodeCommand, sendError } from "vscode-extension-telemetry-wrapper";
import { contextManager } from "../../extension.bundle";
import { ContainerNode, contextManager } from "../../extension.bundle";
import { Commands } from "../commands";
import { Context } from "../constants";
import { appendOutput, executeExportJarTask } from "../tasks/buildArtifact/BuildArtifactTaskProvider";
Expand Down Expand Up @@ -124,6 +124,14 @@ export class DependencyDataProvider implements TreeDataProvider<ExplorerNode> {
const children = (!this._rootItems || !element) ?
await this.getRootNodes() : await element.getChildren();

if (children && element instanceof ContainerNode) {
if (element.isMavenType()) {
jdneo marked this conversation as resolved.
Show resolved Hide resolved
children.sort((a, b) => {
return a.getDisplayName().localeCompare(b.getDisplayName());
});
}
}

explorerNodeCache.saveNodes(children || []);
return children;
}
Expand Down
6 changes: 5 additions & 1 deletion src/views/documentSymbolNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export class DocumentSymbolNode extends ExplorerNode {
super(parent);
}

public getDisplayName(): string {
return this.symbolInfo.name;
}

public getChildren(): ExplorerNode[] | Promise<ExplorerNode[]> {
const res: ExplorerNode[] = [];
if (this.symbolInfo?.children?.length) {
Expand All @@ -39,7 +43,7 @@ export class DocumentSymbolNode extends ExplorerNode {
}

public getTreeItem(): TreeItem | Promise<TreeItem> {
const item = new TreeItem(this.symbolInfo.name,
const item = new TreeItem(this.getDisplayName(),
this.symbolInfo?.children?.length ? TreeItemCollapsibleState.Collapsed
: TreeItemCollapsibleState.None);
item.iconPath = this.iconPath;
Expand Down
2 changes: 2 additions & 0 deletions src/views/explorerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ export abstract class ExplorerNode {
public abstract getTreeItem(): TreeItem | Promise<TreeItem>;

public abstract computeContextValue(): string | undefined;

public abstract getDisplayName(): string;
}
6 changes: 5 additions & 1 deletion test/gradle-suite/projectView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@

import * as assert from "assert";
import { ContainerNode, contextManager, DataNode, DependencyExplorer,
languageServerApiManager,
PackageRootNode, PrimaryTypeNode, ProjectNode } from "../../extension.bundle";
import { fsPath, setupTestEnv, Uris } from "../shared";

// tslint:disable: only-arrow-functions
suite("Gradle Project View Tests", () => {

suiteSetup(setupTestEnv);
suiteSetup(async () => {
await setupTestEnv();
await languageServerApiManager.ready();
});

test("Can node render correctly", async function() {
const explorer = DependencyExplorer.getInstance(contextManager.context);
Expand Down
14 changes: 5 additions & 9 deletions test/invisible-suite/projectView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@

import * as assert from "assert";
import * as fse from "fs-extra";
import { platform } from "os";
import * as path from "path";
import * as vscode from "vscode";
import { Commands, contextManager, DependencyExplorer, PackageNode, PackageRootNode, ProjectNode } from "../../extension.bundle";
import { Commands, contextManager, DependencyExplorer, languageServerApiManager, PackageNode, PackageRootNode, ProjectNode } from "../../extension.bundle";
import { setupTestEnv } from "../shared";
import { sleep } from "../util";

// tslint:disable: only-arrow-functions
suite("Invisible Project View Tests", () => {

suiteSetup(setupTestEnv);
suiteSetup(async () => {
await setupTestEnv();
await languageServerApiManager.ready();
});

test("Can execute command java.project.refreshLibraries correctly", async function() {
if (platform() === "darwin") {
this.skip();
}
const explorer = DependencyExplorer.getInstance(contextManager.context);

let projectNode = (await explorer.dataProvider.getChildren())![0] as ProjectNode;
Expand All @@ -37,9 +36,6 @@ suite("Invisible Project View Tests", () => {
});

test("Can execute command java.project.removeLibrary correctly", async function() {
if (platform() === "darwin") {
this.skip();
}
const explorer = DependencyExplorer.getInstance(contextManager.context);

let projectNode = (await explorer.dataProvider.getChildren())![0] as ProjectNode;
Expand Down
20 changes: 18 additions & 2 deletions test/maven-suite/projectView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import * as assert from "assert";
import * as vscode from "vscode";
import { Commands, ContainerNode, contextManager, DataNode, DependencyExplorer, FileNode,
INodeData, Jdtls, NodeKind, PackageNode, PackageRootNode, PrimaryTypeNode, ProjectNode } from "../../extension.bundle";
INodeData, Jdtls, languageServerApiManager, NodeKind, PackageNode, PackageRootNode, PrimaryTypeNode, ProjectNode } from "../../extension.bundle";
import { fsPath, printNodes, setupTestEnv, Uris } from "../shared";

// tslint:disable: only-arrow-functions
suite("Maven Project View Tests", () => {

suiteSetup(setupTestEnv);
suiteSetup(async () => {
await setupTestEnv();
await languageServerApiManager.ready();
});

test("Can node render correctly in hierarchical view", async function() {
await vscode.workspace.getConfiguration("java.dependency").update("packagePresentation", "hierarchical");
Expand Down Expand Up @@ -253,6 +256,19 @@ suite("Maven Project View Tests", () => {
assert.equal(projectChildren.length, 4);
});

test("Can maven dependency nodes display in correct groupId:artifactId:version format", async function() {
const explorer = DependencyExplorer.getInstance(contextManager.context);

const roots = await explorer.dataProvider.getChildren();
const projectNode = roots![0] as ProjectNode;
const projectChildren = await projectNode.getChildren();
const mavenDependency = projectChildren[3] as ContainerNode;
const mavenChildren = await mavenDependency.getChildren();

assert.equal(mavenChildren[0].getDisplayName(), "org.hamcrest:hamcrest-core:1.3");
assert.equal(mavenChildren[1].getDisplayName(), "junit:junit:4.13.1");
});

teardown(async () => {
// Restore default settings. Some tests might alter them and others depend on a specific setting.
// Not resetting to the default settings will also show the file as changed in the source control view.
Expand Down
Loading