Add version command

- Add new styling system which works around concept that
  you use tags to request jline styles where tags comes
  from an activated theme.
- There is a default theme with options to add custom
  ones and change it via property.
- Add templating system which uses antlr stringtemplate which
  allows to write output with a template instead of manually
  crafting code.
- Add version command which integrates to Boot's BuildProperties
  and GitProperties. Only version field is visible on default
  and others can be enabled/disable via properties.
- Fixes #352
- Fixes #353
This commit is contained in:
Janne Valkealahti
2022-01-23 09:23:16 +00:00
parent 0fb5b5ee7a
commit 52ff4a2d85
23 changed files with 1208 additions and 6 deletions

View File

@@ -28,6 +28,7 @@ public class SpringShellProperties {
private Script script = new Script();
private Interactive interactive = new Interactive();
private Noninteractive noninteractive = new Noninteractive();
private Theme theme = new Theme();
private Command command = new Command();
public void setScript(Script script) {
@@ -54,6 +55,14 @@ public class SpringShellProperties {
this.noninteractive = noninteractive;
}
public Theme getTheme() {
return theme;
}
public void setTheme(Theme theme) {
this.theme = theme;
}
public Command getCommand() {
return command;
}
@@ -101,6 +110,19 @@ public class SpringShellProperties {
}
}
public static class Theme {
private String name = "default";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class HelpCommand {
private boolean enabled = true;
@@ -210,6 +232,7 @@ public class SpringShellProperties {
private ScriptCommand script = new ScriptCommand();
private HistoryCommand history = new HistoryCommand();
private CompletionCommand completion = new CompletionCommand();
private VersionCommand version = new VersionCommand();
public void setHelp(HelpCommand help) {
this.help = help;
@@ -266,5 +289,116 @@ public class SpringShellProperties {
public void setCompletion(CompletionCommand completion) {
this.completion = completion;
}
public VersionCommand getVersion() {
return version;
}
public void setVersion(VersionCommand version) {
this.version = version;
}
}
public static class VersionCommand {
private boolean enabled = true;
private String template = "classpath:template/version-default.st";
private boolean showBuildGroup = false;
private boolean showBuildArtifact = false;
private boolean showBuildName = false;
private boolean showBuildVersion = true;
private boolean showBuildTime = false;
private boolean showGitBranch = false;
private boolean showGitCommitId = false;
private boolean showGitShortCommitId = false;
private boolean showGitCommitTime = false;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
public boolean isShowBuildGroup() {
return showBuildGroup;
}
public void setShowBuildGroup(boolean showBuildGroup) {
this.showBuildGroup = showBuildGroup;
}
public boolean isShowBuildArtifact() {
return showBuildArtifact;
}
public void setShowBuildArtifact(boolean showBuildArtifact) {
this.showBuildArtifact = showBuildArtifact;
}
public boolean isShowBuildName() {
return showBuildName;
}
public void setShowBuildName(boolean showBuildName) {
this.showBuildName = showBuildName;
}
public boolean isShowBuildVersion() {
return showBuildVersion;
}
public void setShowBuildVersion(boolean showBuildVersion) {
this.showBuildVersion = showBuildVersion;
}
public boolean isShowBuildTime() {
return showBuildTime;
}
public void setShowBuildTime(boolean showBuildTime) {
this.showBuildTime = showBuildTime;
}
public boolean isShowGitBranch() {
return showGitBranch;
}
public void setShowGitBranch(boolean showGitBranch) {
this.showGitBranch = showGitBranch;
}
public boolean isShowGitCommitId() {
return showGitCommitId;
}
public void setShowGitCommitId(boolean showGitCommitId) {
this.showGitCommitId = showGitCommitId;
}
public boolean isShowGitShortCommitId() {
return showGitShortCommitId;
}
public void setShowGitShortCommitId(boolean showGitShortCommitId) {
this.showGitShortCommitId = showGitShortCommitId;
}
public boolean isShowGitCommitTime() {
return showGitCommitTime;
}
public void setShowGitCommitTime(boolean showGitCommitTime) {
this.showGitCommitTime = showGitCommitTime;
}
}
}

View File

@@ -23,9 +23,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.info.BuildProperties;
import org.springframework.boot.info.GitProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.shell.boot.SpringShellProperties.VersionCommand;
import org.springframework.shell.boot.condition.OnCompletionCommandCondition;
import org.springframework.shell.result.ThrowableResultHandler;
import org.springframework.shell.standard.commands.Clear;
@@ -35,6 +38,8 @@ import org.springframework.shell.standard.commands.History;
import org.springframework.shell.standard.commands.Quit;
import org.springframework.shell.standard.commands.Script;
import org.springframework.shell.standard.commands.Stacktrace;
import org.springframework.shell.standard.commands.Version;
import org.springframework.shell.style.TemplateExecutor;
/**
* Creates beans for standard commands.
@@ -94,4 +99,26 @@ public class StandardCommandsAutoConfiguration {
public Completion completion(SpringShellProperties properties) {
return new Completion(properties.getCommand().getCompletion().getRootCommand());
}
@Bean
@ConditionalOnMissingBean(Version.Command.class)
@ConditionalOnProperty(prefix = "spring.shell.command.version", value = "enabled", havingValue = "true", matchIfMissing = true)
public Version version(SpringShellProperties properties, ObjectProvider<BuildProperties> buildProperties,
ObjectProvider<GitProperties> gitProperties, ObjectProvider<TemplateExecutor> templateExecutor) {
Version version = new Version(templateExecutor.getIfAvailable());
version.setBuildProperties(buildProperties.getIfAvailable());
version.setGitProperties(gitProperties.getIfAvailable());
VersionCommand versionProperties = properties.getCommand().getVersion();
version.setTemplate(versionProperties.getTemplate());
version.setShowBuildArtifact(versionProperties.isShowBuildArtifact());
version.setShowBuildGroup(versionProperties.isShowBuildGroup());
version.setShowBuildName(versionProperties.isShowBuildName());
version.setShowBuildTime(versionProperties.isShowBuildTime());
version.setShowBuildVersion(versionProperties.isShowBuildVersion());
version.setShowGitBranch(versionProperties.isShowGitBranch());
version.setShowGitCommitId(versionProperties.isShowGitCommitId());
version.setShowGitShortCommitId(versionProperties.isShowGitShortCommitId());
version.setShowGitCommitTime(versionProperties.isShowGitCommitTime());
return version;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.boot;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.shell.style.TemplateExecutor;
import org.springframework.shell.style.Theme;
import org.springframework.shell.style.ThemeRegistry;
import org.springframework.shell.style.ThemeResolver;
import org.springframework.shell.style.ThemeSettings;
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SpringShellProperties.class)
public class ThemingAutoConfiguration {
@Bean
public ThemeRegistry themeRegistry(ObjectProvider<Theme> themes) {
ThemeRegistry registry = new ThemeRegistry();
registry.register(Theme.of("default", ThemeSettings.themeSettings()));
themes.orderedStream().forEachOrdered(theme -> registry.register(theme));
return registry;
}
@Bean
public ThemeResolver themeResolver(ThemeRegistry themeRegistry, SpringShellProperties properties) {
return new ThemeResolver(themeRegistry, properties.getTheme().getName());
}
@Bean
public TemplateExecutor templateExecutor(ThemeResolver themeResolver) {
return new TemplateExecutor(themeResolver);
}
}

View File

@@ -11,4 +11,5 @@ org.springframework.shell.boot.JLineShellAutoConfiguration,\
org.springframework.shell.boot.JCommanderParameterResolverAutoConfiguration,\
org.springframework.shell.boot.ParameterResolverAutoConfiguration,\
org.springframework.shell.boot.StandardAPIAutoConfiguration,\
org.springframework.shell.boot.ThemingAutoConfiguration,\
org.springframework.shell.boot.StandardCommandsAutoConfiguration

View File

@@ -35,6 +35,7 @@ public class SpringShellPropertiesTests {
assertThat(properties.getScript().isEnabled()).isTrue();
assertThat(properties.getInteractive().isEnabled()).isTrue();
assertThat(properties.getNoninteractive().isEnabled()).isTrue();
assertThat(properties.getTheme().getName()).isEqualTo("default");
assertThat(properties.getCommand().getClear().isEnabled()).isTrue();
assertThat(properties.getCommand().getHelp().isEnabled()).isTrue();
assertThat(properties.getCommand().getHistory().isEnabled()).isTrue();
@@ -43,6 +44,17 @@ public class SpringShellPropertiesTests {
assertThat(properties.getCommand().getStacktrace().isEnabled()).isTrue();
assertThat(properties.getCommand().getCompletion().isEnabled()).isTrue();
assertThat(properties.getCommand().getCompletion().getRootCommand()).isNull();
assertThat(properties.getCommand().getVersion().isEnabled()).isTrue();
assertThat(properties.getCommand().getVersion().getTemplate()).isNotNull();
assertThat(properties.getCommand().getVersion().isShowBuildArtifact()).isFalse();
assertThat(properties.getCommand().getVersion().isShowBuildGroup()).isFalse();
assertThat(properties.getCommand().getVersion().isShowBuildName()).isFalse();
assertThat(properties.getCommand().getVersion().isShowBuildTime()).isFalse();
assertThat(properties.getCommand().getVersion().isShowBuildVersion()).isTrue();
assertThat(properties.getCommand().getVersion().isShowGitBranch()).isFalse();
assertThat(properties.getCommand().getVersion().isShowGitCommitId()).isFalse();
assertThat(properties.getCommand().getVersion().isShowGitShortCommitId()).isFalse();
assertThat(properties.getCommand().getVersion().isShowGitCommitTime()).isFalse();
});
}
@@ -52,6 +64,7 @@ public class SpringShellPropertiesTests {
.withPropertyValues("spring.shell.script.enabled=false")
.withPropertyValues("spring.shell.interactive.enabled=false")
.withPropertyValues("spring.shell.noninteractive.enabled=false")
.withPropertyValues("spring.shell.theme.name=fake")
.withPropertyValues("spring.shell.command.clear.enabled=false")
.withPropertyValues("spring.shell.command.help.enabled=false")
.withPropertyValues("spring.shell.command.history.enabled=false")
@@ -60,12 +73,24 @@ public class SpringShellPropertiesTests {
.withPropertyValues("spring.shell.command.stacktrace.enabled=false")
.withPropertyValues("spring.shell.command.completion.enabled=false")
.withPropertyValues("spring.shell.command.completion.root-command=fake")
.withPropertyValues("spring.shell.command.version.enabled=false")
.withPropertyValues("spring.shell.command.version.template=fake")
.withPropertyValues("spring.shell.command.version.show-build-artifact=true")
.withPropertyValues("spring.shell.command.version.show-build-group=true")
.withPropertyValues("spring.shell.command.version.show-build-name=true")
.withPropertyValues("spring.shell.command.version.show-build-time=true")
.withPropertyValues("spring.shell.command.version.show-build-version=false")
.withPropertyValues("spring.shell.command.version.show-git-branch=true")
.withPropertyValues("spring.shell.command.version.show-git-commit-id=true")
.withPropertyValues("spring.shell.command.version.show-git-short-commit-id=true")
.withPropertyValues("spring.shell.command.version.show-git-commit-time=true")
.withUserConfiguration(Config1.class)
.run((context) -> {
SpringShellProperties properties = context.getBean(SpringShellProperties.class);
assertThat(properties.getScript().isEnabled()).isFalse();
assertThat(properties.getInteractive().isEnabled()).isFalse();
assertThat(properties.getNoninteractive().isEnabled()).isFalse();
assertThat(properties.getTheme().getName()).isEqualTo("fake");
assertThat(properties.getCommand().getClear().isEnabled()).isFalse();
assertThat(properties.getCommand().getHelp().isEnabled()).isFalse();
assertThat(properties.getCommand().getHistory().isEnabled()).isFalse();
@@ -74,6 +99,17 @@ public class SpringShellPropertiesTests {
assertThat(properties.getCommand().getStacktrace().isEnabled()).isFalse();
assertThat(properties.getCommand().getCompletion().isEnabled()).isFalse();
assertThat(properties.getCommand().getCompletion().getRootCommand()).isEqualTo("fake");
assertThat(properties.getCommand().getVersion().isEnabled()).isFalse();
assertThat(properties.getCommand().getVersion().getTemplate()).isEqualTo("fake");
assertThat(properties.getCommand().getVersion().isShowBuildArtifact()).isTrue();
assertThat(properties.getCommand().getVersion().isShowBuildGroup()).isTrue();
assertThat(properties.getCommand().getVersion().isShowBuildName()).isTrue();
assertThat(properties.getCommand().getVersion().isShowBuildTime()).isTrue();
assertThat(properties.getCommand().getVersion().isShowBuildVersion()).isFalse();
assertThat(properties.getCommand().getVersion().isShowGitBranch()).isTrue();
assertThat(properties.getCommand().getVersion().isShowGitCommitId()).isTrue();
assertThat(properties.getCommand().getVersion().isShowGitShortCommitId()).isTrue();
assertThat(properties.getCommand().getVersion().isShowGitCommitTime()).isTrue();
});
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.boot;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.shell.style.TemplateExecutor;
import org.springframework.shell.style.Theme;
import org.springframework.shell.style.ThemeRegistry;
import org.springframework.shell.style.ThemeResolver;
import org.springframework.shell.style.ThemeSettings;
import static org.assertj.core.api.Assertions.assertThat;
public class ThemingAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ThemingAutoConfiguration.class));
@Test
public void testDefaults() {
this.contextRunner
.run(context -> {
assertThat(context).hasSingleBean(TemplateExecutor.class);
assertThat(context).hasSingleBean(ThemeRegistry.class);
ThemeRegistry registry = context.getBean(ThemeRegistry.class);
assertThat(registry.get("default")).isNotNull();
assertThat(context).hasSingleBean(ThemeResolver.class);
});
}
@Test
public void testRegistersCustomTheme() {
this.contextRunner
.withUserConfiguration(CustomThemeConfig.class)
.run(context -> {
assertThat(context).hasSingleBean(ThemeRegistry.class);
ThemeRegistry registry = context.getBean(ThemeRegistry.class);
assertThat(registry.get("default")).isNotNull();
assertThat(registry.get("mytheme")).isNotNull();
});
}
@Configuration
static class CustomThemeConfig {
@Bean
public Theme myTheme() {
return new Theme() {
@Override
public String getName() {
return "mytheme";
}
@Override
public ThemeSettings getSettings() {
return new MyThemeSettings();
}
};
}
}
static class MyThemeSettings extends ThemeSettings {
}
}