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

#317: added BuildCommandlet #340

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.devonfw.tools.ide.commandlet;

import com.devonfw.tools.ide.cli.CliException;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.property.StringProperty;
import com.devonfw.tools.ide.tool.ToolCommandlet;
import com.devonfw.tools.ide.tool.gradle.Gradle;
import com.devonfw.tools.ide.tool.mvn.Mvn;
import com.devonfw.tools.ide.tool.npm.Npm;

import java.nio.file.Files;
import java.nio.file.Path;

import static com.devonfw.tools.ide.variable.IdeVariables.GRADLE_BUILD_OPTS;
import static com.devonfw.tools.ide.variable.IdeVariables.MVN_BUILD_OPTS;
import static com.devonfw.tools.ide.variable.IdeVariables.NPM_BUILD_OPTS;

/**
* Build tool {@link Commandlet} for automatically detecting build configuration files and running the respective tool.
*/
public class BuildCommandlet extends Commandlet {

/**
* The arguments to build with.
*/
public StringProperty arguments;

/**
* The constructor.
*
* @param context the {@link IdeContext}.
*/
public BuildCommandlet(IdeContext context) {

super(context);
addKeyword(getName());
this.arguments = add(new StringProperty("", false, true, "args"));
}

@Override
public String getName() {

return "build";
}

@Override
public void run() {

Path buildPath = this.context.getCwd();
String[] defaultToolOptions = new String[0];

if (buildPath != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if buildPath (aka cwd) would be null then we do nothing?
IMHO this will never happen but if we want to handle this explicitly, I would rather do something like this:

if (buildPath == null) {
  throw new CliException("Missing current working directory!");
}

ToolCommandlet commandlet = null;
if (Files.exists(buildPath.resolve("pom.xml"))) {
commandlet = this.context.getCommandletManager().getCommandlet(Mvn.class);
defaultToolOptions = getDefaultToolOptions(MVN_BUILD_OPTS.getName());
} else if (Files.exists(buildPath.resolve("build.gradle"))) {
commandlet = this.context.getCommandletManager().getCommandlet(Gradle.class);
defaultToolOptions = getDefaultToolOptions(GRADLE_BUILD_OPTS.getName());
} else if (Files.exists(buildPath.resolve("package.json"))) {
if (Files.exists(buildPath.resolve("yarn.lock"))) {
// TODO: add yarn here
} else {
commandlet = this.context.getCommandletManager().getCommandlet(Npm.class);

defaultToolOptions = getDefaultToolOptions(NPM_BUILD_OPTS.getName());
}
} else {
throw new CliException("Could not find build descriptor - no pom.xml, build.gradle, or package.json found!");
}
jan-vcapgemini marked this conversation as resolved.
Show resolved Hide resolved

if (this.arguments.asArray().length != 0) {
defaultToolOptions = this.arguments.asArray();
}

if (commandlet != null) {
commandlet.runTool(null, defaultToolOptions);
}
}

}

private String[] getDefaultToolOptions(String buildOptionName) {

String[] defaultToolOptions;
defaultToolOptions = this.context.getVariables().get(buildOptionName).split(" ");
return defaultToolOptions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public CommandletManagerImpl(IdeContext context) {
add(new UninstallCommandlet(context));
add(new UpdateCommandlet(context));
add(new CreateCommandlet(context));
add(new BuildCommandlet(context));
add(new Gh(context));
add(new Helm(context));
add(new Java(context));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ public interface IdeVariables {

/** {@link VariableDefinition} for {@link com.devonfw.tools.ide.context.IdeContext#getWorkspaceName() WORKSPACE}. */

/** {@link VariableDefinition} for default build options of mvn */
VariableDefinitionString MVN_BUILD_OPTS = new VariableDefinitionString("MVN_BUILD_OPTS", null, c -> "");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pointed out: https://github.com/devonfw/ide/blob/cdf4af5de21489f3fdcbfdab41af858822e0d598/scripts/src/main/resources/scripts/command/mvn#L354

Suggested change
VariableDefinitionString MVN_BUILD_OPTS = new VariableDefinitionString("MVN_BUILD_OPTS", null, c -> "");
VariableDefinitionString MVN_BUILD_OPTS = new VariableDefinitionString("MVN_BUILD_OPTS", null, c -> "clean deploy");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the code snippet it uses clean install instead of clean deploy. Adjusted.


/** {@link VariableDefinition} for default build options of npm */
VariableDefinitionString NPM_BUILD_OPTS = new VariableDefinitionString("NPM_BUILD_OPTS", null, c -> "");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one seems more tricky - see
https://github.com/devonfw/ide/blob/cdf4af5de21489f3fdcbfdab41af858822e0d598/scripts/src/main/resources/scripts/command/npm#L118-L124
and
https://github.com/devonfw/ide/blob/cdf4af5de21489f3fdcbfdab41af858822e0d598/scripts/src/main/resources/scripts/command/npm#L92-L98

Maybe we should address this one in a separate PR and merge as is? So far this would be my suggestion to make better progress... So either create an issue for this and link here as comment so I can resolve or already address in this PR adding even more new features and complexity.


/** {@link VariableDefinition} for default build options of gradle */
VariableDefinitionString GRADLE_BUILD_OPTS = new VariableDefinitionString("GRADLE_BUILD_OPTS", null, c -> "");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again see here: https://github.com/devonfw/ide/blob/cdf4af5de21489f3fdcbfdab41af858822e0d598/scripts/src/main/resources/scripts/command/gradle#L91

Suggested change
VariableDefinitionString GRADLE_BUILD_OPTS = new VariableDefinitionString("GRADLE_BUILD_OPTS", null, c -> "");
VariableDefinitionString GRADLE_BUILD_OPTS = new VariableDefinitionString("GRADLE_BUILD_OPTS", null, c -> "clean dist");


/** {@link VariableDefinition} for default build options of yarn */
VariableDefinitionString YARN_BUILD_OPTS = new VariableDefinitionString("YARN_BUILD_OPTS", null, c -> "");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


/** {@link VariableDefinition} for options of jasypt */
VariableDefinitionString JASYPT_OPTS = new VariableDefinitionString("JASYPT_OPTS", null,
c -> "algorithm=PBEWITHHMACSHA512ANDAES_256 ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator");
Expand All @@ -61,7 +73,7 @@ public interface IdeVariables {

/** A {@link Collection} with all pre-defined {@link VariableDefinition}s. */
Collection<VariableDefinition<?>> VARIABLES = List.of(PATH, HOME, WORKSPACE_PATH, IDE_HOME, IDE_ROOT, WORKSPACE, IDE_TOOLS, CREATE_START_SCRIPTS,
IDE_MIN_VERSION, MVN_VERSION, M2_REPO, DOCKER_EDITION, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME);
IDE_MIN_VERSION, MVN_VERSION, M2_REPO, DOCKER_EDITION, MVN_BUILD_OPTS, NPM_BUILD_OPTS, GRADLE_BUILD_OPTS, YARN_BUILD_OPTS, JASYPT_OPTS, MAVEN_ARGS, PROJECT_NAME);

/**
* @param name the name of the requested {@link VariableDefinition}.
Expand Down
2 changes: 2 additions & 0 deletions cli/src/main/resources/nls/Help.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ cmd.aws=Tool commandlet for AWS CLI.
cmd.aws.detail=TODO AWS
cmd.az=Tool commandlet for Azure CLI.
cmd.az.detail=TODO AZ
cmd.build=Runs a build job with given arguments.
cmd.build.val.args=Build arguments to be used when running a build job.
cmd.cobigen=Tool commandlet for Cobigen (code-generator).
cmd.cobigen.detail=TODO cobigen
cmd.complete=Internal commandlet for bash auto-completion.
Expand Down
2 changes: 2 additions & 0 deletions cli/src/main/resources/nls/Help_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ cmd.aws=Werkzeug Kommando für AWS Kommandoschnittstelle.
cmd.aws.detail=TODO DE AWS
cmd.az=Werkzeug Kommando für Azure Kommandoschnittstelle.
cmd.az.detail=TODO DE AZ
cmd.build=Startet einen build Prozess mit übergebenen Argumenten.
cmd.build.val.args=Argumente die bei dem build Prozess genutzt werden sollen.
cmd.cobigen=Werkzeug Kommando für Cobigen.
cmd.cobigen.detail=TODO DE cobigen
cmd.complete=Internes Werkzeug für bash Autovervollständigung.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.devonfw.tools.ide.commandlet;

import com.devonfw.tools.ide.context.AbstractIdeContextTest;
import com.devonfw.tools.ide.context.IdeTestContext;
import com.devonfw.tools.ide.log.IdeLogLevel;
import com.devonfw.tools.ide.os.SystemInfo;
import com.devonfw.tools.ide.os.SystemInfoMock;
import org.junit.jupiter.api.Test;

/**
* Test of {@link BuildCommandlet}.
*/
public class BuildCommandletTest extends AbstractIdeContextTest {

private static final String PROJECT_BUILD = "build";

/**
* Tests a {@link com.devonfw.tools.ide.tool.mvn.Mvn} build without arguments and expects defaults to be taken from ide.properties.
*/
@Test
public void testMvnBuildWithoutProvidedArgumentsUsesDefaultOptions() {

IdeTestContext context = newContext(PROJECT_BUILD);
BuildCommandlet buildCommandlet = context.getCommandletManager().getCommandlet(BuildCommandlet.class);
context.setCwd(context.getWorkspacePath().resolve("mvn"), context.getWorkspacePath().toString(), context.getIdeHome());
buildCommandlet.run();
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed java in version 17.0.10_7");
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed mvn in version 3.9.6");
assertLogMessage(context, IdeLogLevel.INFO, "mvn clean install");
}

/**
* Tests a {@link com.devonfw.tools.ide.tool.mvn.Mvn} build with provided arguments.
*/
@Test
public void testMvnBuildWithProvidedArguments() {

IdeTestContext context = newContext(PROJECT_BUILD);
BuildCommandlet buildCommandlet = context.getCommandletManager().getCommandlet(BuildCommandlet.class);
context.setCwd(context.getWorkspacePath().resolve("mvn"), context.getWorkspacePath().toString(), context.getIdeHome());
buildCommandlet.arguments.addValue("clean");
buildCommandlet.arguments.addValue("install");
buildCommandlet.run();
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed java in version 17.0.10_7");
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed mvn in version 3.9.6");
assertLogMessage(context, IdeLogLevel.INFO, "mvn clean install");
}

/**
* Tests a {@link com.devonfw.tools.ide.tool.gradle.Gradle} build with provided arguments.
*/
@Test
public void testGradleBuildWithProvidedArguments() {

IdeTestContext context = newContext(PROJECT_BUILD);
BuildCommandlet buildCommandlet = context.getCommandletManager().getCommandlet(BuildCommandlet.class);
context.setCwd(context.getWorkspacePath().resolve("gradle"), context.getWorkspacePath().toString(), context.getIdeHome());
buildCommandlet.arguments.addValue("task1");
buildCommandlet.arguments.addValue("task2");
buildCommandlet.run();
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed java in version 17.0.10_7");
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed gradle in version 8.7");
assertLogMessage(context, IdeLogLevel.INFO, "gradle task1 task2");
}

/**
* Tests a {@link com.devonfw.tools.ide.tool.npm.Npm} build with provided arguments.
*/
@Test
public void testNpmBuildWithProvidedArguments() {

SystemInfo systemInfo = SystemInfoMock.of("linux");
IdeTestContext context = newContext(PROJECT_BUILD);
context.setSystemInfo(systemInfo);
BuildCommandlet buildCommandlet = context.getCommandletManager().getCommandlet(BuildCommandlet.class);
context.setCwd(context.getWorkspacePath().resolve("npm"), context.getWorkspacePath().toString(), context.getIdeHome());
buildCommandlet.arguments.addValue("start");
buildCommandlet.arguments.addValue("test");
buildCommandlet.run();
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed node in version v18.19.1");
assertLogMessage(context, IdeLogLevel.SUCCESS, "Successfully installed npm in version 9.9.2");
assertLogMessage(context, IdeLogLevel.INFO, "npm start test");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
JAVA_VERSION=17.0.10_7
MAVEN_VERSION=3.9.6
NODE_VERSION=v18.19.1
NPM_VERSION=9.9.2
GRADLE_VERSION=8.7
MVN_BUILD_OPTS=clean install
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default that is supposed to be build-in. Either remove or override with something else to test the overriding mechanism.

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo "gradle $*"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo "mvn $*"

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
echo "npm $*"
12 changes: 12 additions & 0 deletions documentation/build.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
:toc:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in our meetings we do not want to come back to having help documentation on github in asciidoc.
This has many disadvantages (not available offline, esp. not accurate if the installed release differs from the latest documentation in development, no localization, not intuitive for CLI users, etc.).
Simply use your invest to put this into the CLI help output. Also please add the new variables to the variables.adoc. Then you can remove these 5 added adocs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this we already agreed in the team to add yet another help property for the detailed description of a commandlet.
So ide help «commandlet» will not only print cmd.build but also cmd.build.detail.
I can prepare the PR for this change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented:
#389

toc::[]

= build
The `build` commandlet is an abstraction of build systems like link:mvn.asciidoc[maven], link:gradle.asciidoc[gradle], link:npm.asciidoc[yarn], link:npm.asciidoc[npm], etc.
It will auto-detect your build-system (via existence of files like `pom.xml`, `package.json`, etc.). According to this detection, it will simply delegate to the according commandlet of the specific build system. If that build-system is not yet available it will be downloaded and installed automatically.

So `ide build` allows users to build any project without bothering about the build-system. Further specific build options can be configured per project. This makes `ide build` a universal part of every _definition of done_. Before pushing your changes, please always run the following command to verify the build:

`ide build`

You may also supply additional arguments as `ide build «args»`. This will simply delegate these arguments to the detected build command (e.g. call `mvn «args»`).
26 changes: 26 additions & 0 deletions documentation/gradle.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
:toc:
toc::[]

= gradle

The `gradle` commandlet allows to install, configure, and launch https://gradle.org/[gradle]. It is similar to https://docs.gradle.org/5.3.1/userguide/gradle_wrapper.html[gradle-wrapper]. So calling `ide gradle «args»` is more or less the same as calling `gradle «args»` but with the benefit that the version of gradle preferred by your project is used (and will be installed if not yet available).

The arguments (`ide gradle «args»`) are explained by the following table:

.Usage of `ide gradle`
[options="header"]
|=======================
|*Argument(s)* |*Meaning*
|`«args»` |run gradle with the given arguments (`«args»`)
|=======================

There are link:variables.asciidoc[variables] that can be used for gradle.
These are explained by the following table:

.Variables of IDEasy for gradle
[options="header"]
|=======================
|*Variable*|*Meaning*
|*`GRADLE_VERSION`* |The version of the tool gradle to install and use.
|*`GRADLE_BUILD_OPTS`* |The default arguments to use for the gradle build process e.g. `project1`.
|=======================
27 changes: 27 additions & 0 deletions documentation/mvn.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
:toc:
toc::[]

= mvn

The `mvn` commandlet allows to install, configure, and launch https://maven.apache.org/[maven]. It is similar to https://github.com/takari/maven-wrapper[maven-wrapper] and https://github.com/dansomething/mdub[mdub]. So calling `ide mvn «args»` is more or less the same as calling `mvn «args»` but with the benefit that the version of maven preferred by your project is used (and will be installed if not yet available).

The arguments (`ide mvn «args»`) are explained by the following table:

.Usage of `ide mvn`
[options="header"]
|=======================
|*Argument(s)* |*Meaning*
| |run default build, link:configuration.asciidoc[configurable] via `MVN_BUILD_OPTS`
|`«args»` |run maven with the given arguments (`«args»`)
|=======================

There are link:variables.asciidoc[variables] that can be used for mvn.
These are explained by the following table:

.Variables of IDEasy for mvn
[options="header"]
|=======================
|*Variable*|*Meaning*
|*`MVN_VERSION`* |The version of the tool mvn to install and use.
|*`MVN_BUILD_OPTS`* |The default options to use for the mvn build process e.g. `clean install`.
|=======================
27 changes: 27 additions & 0 deletions documentation/npm.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
:toc:
toc::[]

= npm

The `npm` commandlet allows to install, configure, and launch https://www.npmjs.com/[npm]. Calling `ide npm «args»` is more or less the same as calling `npm «args»` but with the benefit that the version of npm preferred by your project is used (and will be installed if not yet available).

The arguments (`ide npm «args»`) are explained by the following table:

.Usage of `ide npm`
[options="header"]
|=======================
|*Argument(s)* |*Meaning*
| |run default build, link:configuration.asciidoc[configurable] via `NPM_BUILD_OPTS`
|`«args»` |run NPM with the given arguments (`«args»`)
|=======================

There are link:variables.asciidoc[variables] that can be used for npm.
These are explained by the following table:

.Variables of IDEasy for npm
[options="header"]
|=======================
|*Variable*|*Meaning*
|*`NPM_VERSION`* |The version of the tool npm to install and use.
|*`NPM_BUILD_OPTS`* |The default options to use for the npm build process e.g. `run start`.
|=======================
26 changes: 26 additions & 0 deletions documentation/yarn.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
:toc:
toc::[]

= yarn

The `yarn` commandlet allows to install, configure, and launch https://www.npmjs.com/[npm]. Calling `ide yarn «args»` is more or less the same as calling `yarn «args»` but with the benefit that the version of npm preferred by your project is used (and will be installed if not yet available).

The arguments (`ide yarn «args»`) are explained by the following table:

.Usage of `ide yarn`
[options="header"]
|=======================
|*Argument(s)* |*Meaning*
|`«args»` |run yarn with the given arguments (`«args»`)
|=======================

There are link:variables.asciidoc[variables] that can be used for yarn.
These are explained by the following table:

.Variables of IDEasy for yarn
[options="header"]
|=======================
|*Variable*|*Meaning*
|*`YARN_VERSION`* |The version of the tool yarn to install and use.
|*`YARN_BUILD_OPTS`* |The default options to use for the yarn build process e.g. `run start`.
|=======================
Loading