├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md ├── backend ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── camunda │ │ └── start │ │ ├── Application.java │ │ ├── WebMvcConfig.java │ │ ├── headersec │ │ └── HeaderSecurityConfiguration.java │ │ ├── processing │ │ ├── Dependency.java │ │ ├── ProjectGenerator.java │ │ └── TemplateProcessor.java │ │ ├── rest │ │ ├── BadUserRequestException.java │ │ ├── GeneratingController.java │ │ ├── VersionsController.java │ │ └── dto │ │ │ └── DownloadProjectDto.java │ │ └── update │ │ ├── Constants.java │ │ ├── VersionUpdater.java │ │ └── dto │ │ ├── StarterVersionDto.java │ │ └── StarterVersionWrapperDto.java │ └── resources │ ├── application.yaml │ └── com │ └── camunda │ └── start │ └── templates │ ├── Application.java.vm │ ├── WorkflowTest.java.vm │ ├── application.yaml.test.vm │ ├── application.yaml.vm │ ├── logback-test.xml.vm │ ├── pom.xml.vm │ └── process.bpmn.vm ├── ecs-task-definition.json ├── frontend ├── .gitignore ├── package-lock.json ├── package.json ├── public │ ├── background.png │ ├── favicon.png │ ├── index.html │ ├── logo.svg │ ├── openapi.json │ └── robots.txt └── src │ ├── App.js │ ├── App.test.js │ └── index.js └── screenshot.png /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | backend/target 3 | frontend/build 4 | frontend/node_modules 5 | .git 6 | .dockerignore 7 | README.md 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | target/ 3 | *.iml -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.8.5-openjdk-17-slim as builder 2 | 3 | RUN apt-get update \ 4 | && apt-get install wget curl ca-certificates rsync -y \ 5 | && rm -rf /var/lib/apt/lists/* 6 | 7 | ENV NODE_VERSION=18.16.0 8 | RUN wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash 9 | 10 | ENV NVM_DIR=/root/.nvm 11 | RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION} \ 12 | && nvm use v${NODE_VERSION} \ 13 | && nvm alias default v${NODE_VERSION} 14 | 15 | WORKDIR /build/backend 16 | ADD . /build 17 | RUN . "$NVM_DIR/nvm.sh" && mvn clean install -Djdk.lang.Process.launchMechanism=vfork 18 | 19 | 20 | # ===== END BUILD STAGE ==== 21 | 22 | FROM openjdk:17-jdk-slim 23 | RUN apt-get update \ 24 | && apt-get install -y \ 25 | libcap2-bin \ 26 | && rm -rf /var/lib/apt/lists/* 27 | 28 | # Enable non-root processes to bind to ports <1024 29 | RUN setcap 'cap_net_bind_service=+ep' /usr/local/openjdk-17/bin/java 30 | 31 | COPY --from=builder /build/backend/target/start-camunda-0.0.1-SNAPSHOT.jar / 32 | 33 | CMD /usr/local/openjdk-17/bin/java -jar -Dserver.port=80 /start-camunda-0.0.1-SNAPSHOT.jar 34 | 35 | USER www-data 36 | EXPOSE 80 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Start Camunda Platform 2 | 3 | A Webapp to generate & customize your Camunda Spring Boot Starter project. 4 | 5 | ![Start Camunda Platform](./screenshot.png) 6 | 7 | ## Build & Run 8 | 9 | Make sure you have npm and maven installed. 10 | 11 | 1. Go to the backend folder `cd ./backend` 12 | 2. Run `mvn clean install` 13 | 3. Run the Uber-Jar `java -jar ./target/start-camunda-0.0.1-SNAPSHOT.jar` 14 | 4. Open the following link in your browser: [http://localhost:9090](http://localhost:9090) 15 | 16 | ### Using docker 17 | 1. run `docker build . -t start-camunda` 18 | 2. run `docker run --rm -it -p9090:9090 start-camunda` 19 | 3. Open the following link in your browser: [http://localhost:9090](http://localhost:9090) 20 | 21 | ### Deploy to ECS 22 | 23 | 1. `docker build --platform=amd64 -t registry.camunda.cloud/team-cambpm-public/start.camunda.com:$TAG .` 24 | * `$TAG`: Docker image tag 25 | 2. `docker push registry.camunda.cloud/team-cambpm-public/start.camunda.com:$TAG` 26 | 3. `aws ecs list-task-definitions --family-prefix ecs_start_camunda_com` 27 | * Shows a list of task definition versions 28 | 4. Adjust `$TAG` in `./ecs-task-definition.json` 29 | 5. ``` 30 | aws ecs register-task-definition \ 31 | --execution-role-arn arn:aws:iam::$ACCOUNT_ID:role/ecsTaskExecutionRole \ 32 | --cli-input-json file://./ecs-task-definition.json 33 | ``` 34 | * `$ACCOUNT_ID`: AWS Account ID 35 | 6. ``` 36 | aws ecs update-service --cluster arn:aws:ecs:eu-central-1:$ACCOUNT_ID:cluster/startcamundacom \ 37 | --service arn:aws:ecs:eu-central-1:$ACCOUNT_ID:service/startcamundacom/start_camunda_com_V2 \ 38 | --task-definition arn:aws:ecs:eu-central-1:$ACCOUNT_ID:task-definition/ecs_start_camunda_com:$VERSION 39 | ``` 40 | * `$VERSION`: New task definition version -------------------------------------------------------------------------------- /backend/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 3.1.4 11 | 12 | 13 | 14 | com.camunda.start 15 | start-camunda 16 | 0.0.1-SNAPSHOT 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-security 27 | 28 | 29 | 30 | commons-io 31 | commons-io 32 | 2.13.0 33 | 34 | 35 | 36 | org.apache.maven 37 | maven-artifact 38 | 3.9.3 39 | 40 | 41 | 42 | org.zeroturnaround 43 | zt-zip 44 | 1.15 45 | jar 46 | 47 | 48 | 49 | org.apache.velocity 50 | velocity-engine-core 51 | 2.3 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-maven-plugin 61 | 62 | 63 | 64 | org.codehaus.mojo 65 | exec-maven-plugin 66 | 3.1.0 67 | 68 | ../frontend 69 | 70 | 71 | 72 | npm install (initialize) 73 | 74 | exec 75 | 76 | initialize 77 | 78 | npm 79 | 80 | install 81 | --force 82 | 83 | 84 | 85 | 86 | npm run-script build 87 | 88 | exec 89 | 90 | generate-resources 91 | 92 | npm 93 | 94 | run 95 | build 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | maven-clean-plugin 104 | 105 | 106 | 107 | ../frontend/build 108 | 109 | **/* 110 | 111 | false 112 | 113 | 114 | 115 | 116 | 117 | 118 | maven-resources-plugin 119 | 120 | 121 | copy-resources 122 | process-resources 123 | 124 | copy-resources 125 | 126 | 127 | ${basedir}/target/classes/static 128 | 129 | 130 | ../frontend/build 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/Application.java: -------------------------------------------------------------------------------- 1 | package com.camunda.start; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @EnableScheduling 8 | @SpringBootApplication 9 | public class Application { 10 | 11 | public static void main(String... args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.camunda.start; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 6 | 7 | @Configuration 8 | public class WebMvcConfig implements WebMvcConfigurer { 9 | 10 | @Override 11 | public void addCorsMappings(CorsRegistry registry) { 12 | registry.addMapping("/**") 13 | .allowedOrigins("*") 14 | .allowedMethods("*"); 15 | } 16 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/headersec/HeaderSecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.camunda.start.headersec; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.web.SecurityFilterChain; 7 | import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter; 8 | import org.springframework.security.web.util.matcher.AnyRequestMatcher; 9 | 10 | @Configuration 11 | public class HeaderSecurityConfiguration { 12 | 13 | @Bean 14 | public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 15 | return http 16 | .csrf().disable() 17 | .authorizeHttpRequests() 18 | .anyRequest().permitAll() 19 | .and() 20 | .headers() 21 | .httpStrictTransportSecurity() 22 | .maxAgeInSeconds(63072000) 23 | .preload(true) 24 | .includeSubDomains(true) 25 | .requestMatcher(AnyRequestMatcher.INSTANCE) 26 | .and() 27 | .xssProtection(xss -> xss.headerValue(XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK)) 28 | .contentSecurityPolicy("default-src 'none'; script-src 'unsafe-inline' 'self'; connect-src 'self'; img-src 'self'; style-src 'unsafe-inline' 'self'; frame-ancestors 'self'; form-action 'self';") 29 | .and().and() 30 | .build(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/processing/Dependency.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.processing; 18 | 19 | public class Dependency { 20 | 21 | protected String group; 22 | protected String artifact; 23 | protected String version; 24 | 25 | public Dependency setGroup(String group) { 26 | this.group = group; 27 | return this; 28 | } 29 | 30 | public Dependency setArtifact(String artifact) { 31 | this.artifact = artifact; 32 | return this; 33 | } 34 | 35 | public Dependency setVersion(String version) { 36 | this.version = version; 37 | return this; 38 | } 39 | 40 | public String getGroup() { 41 | return group; 42 | } 43 | 44 | public String getArtifact() { 45 | return artifact; 46 | } 47 | 48 | public String getVersion() { 49 | return version; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/processing/ProjectGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.processing; 18 | 19 | import com.camunda.start.rest.dto.DownloadProjectDto; 20 | import com.camunda.start.update.VersionUpdater; 21 | import com.camunda.start.update.dto.StarterVersionDto; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.stereotype.Component; 24 | import org.zeroturnaround.zip.ByteSource; 25 | import org.zeroturnaround.zip.ZipEntrySource; 26 | import org.zeroturnaround.zip.ZipUtil; 27 | 28 | import java.io.ByteArrayOutputStream; 29 | import java.util.ArrayList; 30 | import java.util.Arrays; 31 | import java.util.Collections; 32 | import java.util.HashMap; 33 | import java.util.LinkedHashMap; 34 | import java.util.List; 35 | import java.util.Map; 36 | import java.util.stream.Collectors; 37 | 38 | @Component 39 | public class ProjectGenerator { 40 | 41 | protected static final String MAIN_PATH = "/src/main/"; 42 | protected static final String JAVA_PATH = MAIN_PATH + "java/"; 43 | protected static final String RESOURCES_PATH = MAIN_PATH + "resources/"; 44 | 45 | protected static final String TEST_MAIN_PATH = "/src/test/"; 46 | protected static final String TEST_JAVA_PATH = TEST_MAIN_PATH + "java/"; 47 | protected static final String TEST_RESOURCES_PATH = TEST_MAIN_PATH + "resources/"; 48 | 49 | protected static final String APPLICATION_CLASS_NAME = "Application.java"; 50 | protected static final String APPLICATION_YAML_NAME = "application.yaml"; 51 | protected static final String APPLICATION_YAML_TEST_NAME = "application.yaml"; 52 | protected static final String APPLICATION_POM_NAME = "pom.xml"; 53 | protected static final String APPLICATION_BPMN_NAME = "process.bpmn"; 54 | protected static final String APPLICATION_TEST_CASE_NAME = "WorkflowTest.java"; 55 | protected static final String APPLICATION_LOGCONFIG_NAME = "logback-test.xml"; 56 | 57 | protected static final String TEMPLATES_PATH = "/com/camunda/start/templates/"; 58 | 59 | 60 | protected DownloadProjectDto inputData; 61 | protected Map templateContext; 62 | protected Map versions; 63 | 64 | @Autowired 65 | protected VersionUpdater versionUpdater; 66 | 67 | @Autowired 68 | protected TemplateProcessor templateProcessor; 69 | 70 | public byte[] generate(DownloadProjectDto inputData) { 71 | initialize(inputData); 72 | 73 | byte[] applicationClass = processByFileName(APPLICATION_CLASS_NAME); 74 | byte[] applicationYaml = processByFileName(APPLICATION_YAML_NAME); 75 | byte[] pomXml = processByFileName(APPLICATION_POM_NAME); 76 | byte[] processBpmn = processByFileName(APPLICATION_BPMN_NAME); 77 | 78 | String projectName = (String) templateContext.get("artifact"); 79 | String packageName = dotToSlash((String) templateContext.get("group")); 80 | 81 | List entries = new ArrayList<>(Arrays.asList( 82 | new ByteSource(projectName + JAVA_PATH + packageName + "/" + APPLICATION_CLASS_NAME, applicationClass), 83 | new ByteSource(projectName + RESOURCES_PATH + APPLICATION_YAML_NAME, applicationYaml), 84 | new ByteSource(projectName + "/" + APPLICATION_POM_NAME, pomXml), 85 | new ByteSource(projectName + RESOURCES_PATH + APPLICATION_BPMN_NAME, processBpmn) 86 | )); 87 | 88 | boolean isCamundaAssert = (boolean) templateContext.get("isCamundaAssert"); 89 | if (isCamundaAssert) { 90 | byte[] logbackTestConfig = processByFileName(APPLICATION_LOGCONFIG_NAME); 91 | byte[] testCase = processByFileName(APPLICATION_TEST_CASE_NAME); 92 | byte[] applicationYamlTest = processByFileName(APPLICATION_YAML_TEST_NAME); 93 | 94 | entries.add(new ByteSource(projectName + TEST_JAVA_PATH + packageName + "/" + APPLICATION_TEST_CASE_NAME, testCase)); 95 | entries.add(new ByteSource(projectName + TEST_RESOURCES_PATH + APPLICATION_LOGCONFIG_NAME, logbackTestConfig)); 96 | entries.add(new ByteSource(projectName + TEST_RESOURCES_PATH + APPLICATION_YAML_TEST_NAME, applicationYamlTest)); 97 | } 98 | 99 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 100 | 101 | ZipUtil.pack(entries.toArray(new ZipEntrySource[0]), baos); 102 | 103 | return baos.toByteArray(); 104 | } 105 | 106 | public String generate(DownloadProjectDto inputData, String fileName) { 107 | initialize(inputData); 108 | 109 | return templateProcessor.process(templateContext, TEMPLATES_PATH + fileName + ".vm"); 110 | } 111 | 112 | protected byte[] processByFileName(String filename) { 113 | return templateProcessor.process(templateContext,TEMPLATES_PATH + filename + ".vm") 114 | .getBytes(); 115 | } 116 | 117 | public void initialize(DownloadProjectDto inputData) { 118 | this.inputData = inputData; 119 | 120 | versions = versionUpdater.getStarterVersionWrapper() 121 | .getStarterVersions() 122 | .stream() 123 | .collect(Collectors.toMap(StarterVersionDto::getStarterVersion, 124 | starterVersionDto -> starterVersionDto, (a, b) -> b, LinkedHashMap::new)); 125 | 126 | addDefaultValues(inputData); 127 | 128 | templateContext = initTemplateContext(inputData); 129 | } 130 | 131 | protected void addDefaultValues(DownloadProjectDto inputData) { 132 | if (isEmpty(inputData.getModules())) { 133 | inputData.setModules(Collections.singletonList("camunda-base")); 134 | } 135 | if (isEmpty(inputData.getGroup())) { 136 | inputData.setGroup("com.example.workflow"); 137 | } 138 | if (isEmpty(inputData.getPersistence())) { 139 | inputData.setPersistence("on-disk"); 140 | } 141 | if (isEmpty(inputData.getArtifact())) { 142 | inputData.setArtifact("my-project"); 143 | } 144 | if (isEmpty(inputData.getStarterVersion())) { 145 | String latestStarterVersion = versions.keySet() 146 | .iterator() 147 | .next(); 148 | 149 | inputData.setStarterVersion(latestStarterVersion); 150 | } 151 | if (isEmpty(inputData.getJavaVersion())) { 152 | inputData.setJavaVersion("12"); 153 | } 154 | if (isEmpty(inputData.getUsername())) { 155 | inputData.setUsername("demo"); 156 | } 157 | if (isEmpty(inputData.getPassword())) { 158 | inputData.setPassword("demo"); 159 | } 160 | if (isEmpty(inputData.getVersion())) { 161 | inputData.setVersion("1.0.0-SNAPSHOT"); 162 | } 163 | } 164 | 165 | private boolean isEmpty(String string) { 166 | return string == null || string.isEmpty(); 167 | } 168 | 169 | private boolean isEmpty(List set) { 170 | return set == null || set.isEmpty(); 171 | } 172 | 173 | protected Map initTemplateContext(DownloadProjectDto inputData) { 174 | Map context = new HashMap<>(); 175 | context.put("packageName", inputData.getGroup()); 176 | 177 | context.put("persistence", inputData.getPersistence()); 178 | 179 | context.put("adminUsername", inputData.getUsername()); 180 | context.put("adminPassword", inputData.getPassword()); 181 | 182 | context.put("camundaVersion", resolveCamundaVersion(inputData.getStarterVersion())); 183 | context.put("springBootVersion", resolveSpringBootVersion(inputData.getStarterVersion())); 184 | context.put("javaVersion", inputData.getJavaVersion()); 185 | 186 | context.put("group", inputData.getGroup()); 187 | context.put("artifact", inputData.getArtifact()); 188 | context.put("projectVersion", inputData.getVersion()); 189 | 190 | List modules = inputData.getModules(); 191 | context.put("dependencies", getDeps(inputData.getModules(), inputData.getPersistence())); 192 | 193 | boolean isCamundaAssert = modules.stream().anyMatch("camunda-assert"::equals); 194 | context.put("isCamundaAssert", isCamundaAssert); 195 | 196 | return context; 197 | } 198 | 199 | protected String resolveSpringBootVersion(String starterVersion) { 200 | return versions.get(starterVersion) 201 | .getSpringBootVersion(); 202 | } 203 | 204 | protected String resolveCamundaVersion(String starterVersion) { 205 | return versions.get(starterVersion) 206 | .getCamundaVersion(); 207 | } 208 | 209 | protected List getDeps(List modules, String persistence) { 210 | List dependencies = new ArrayList<>(); 211 | 212 | modules.forEach(module -> { 213 | switch (module) { 214 | case "camunda-base": 215 | 216 | Dependency camundaBase = new Dependency() 217 | .setGroup("org.camunda.bpm.springboot") 218 | .setArtifact("camunda-bpm-spring-boot-starter") 219 | .setVersion(inputData.getStarterVersion()); 220 | 221 | dependencies.add(camundaBase); 222 | break; 223 | case "camunda-webapps": 224 | 225 | Dependency camundaWebapps = new Dependency() 226 | .setGroup("org.camunda.bpm.springboot") 227 | .setArtifact("camunda-bpm-spring-boot-starter-webapp"); 228 | 229 | dependencies.add(camundaWebapps); 230 | break; 231 | case "camunda-rest": 232 | 233 | Dependency camundaRest = new Dependency() 234 | .setGroup("org.camunda.bpm.springboot") 235 | .setArtifact("camunda-bpm-spring-boot-starter-rest"); 236 | 237 | dependencies.add(camundaRest); 238 | break; 239 | case "camunda-spin": 240 | 241 | Dependency camundaSpin = new Dependency() 242 | .setGroup("org.camunda.bpm") 243 | .setArtifact("camunda-engine-plugin-spin"); 244 | 245 | dependencies.add(camundaSpin); 246 | 247 | Dependency spinDataformatAll = new Dependency() 248 | .setGroup("org.camunda.spin") 249 | .setArtifact("camunda-spin-dataformat-all"); 250 | 251 | dependencies.add(spinDataformatAll); 252 | break; 253 | case "camunda-assert": 254 | 255 | Dependency camundaTest = new Dependency() 256 | .setGroup("org.camunda.bpm.springboot") 257 | .setArtifact("camunda-bpm-spring-boot-starter-test"); 258 | 259 | dependencies.add(camundaTest); 260 | break; 261 | case "spring-boot-security": 262 | 263 | Dependency springSecurity = new Dependency() 264 | .setGroup("org.springframework.boot") 265 | .setArtifact("spring-boot-starter-security"); 266 | 267 | dependencies.add(springSecurity); 268 | break; 269 | case "spring-boot-web": 270 | 271 | Dependency springWeb = new Dependency() 272 | .setGroup("org.springframework.boot") 273 | .setArtifact("spring-boot-starter-web"); 274 | 275 | dependencies.add(springWeb); 276 | break; 277 | default: 278 | throw new RuntimeException("Unknown module!"); 279 | } 280 | }); 281 | 282 | dependencies.add(new Dependency() 283 | .setArtifact("h2") 284 | .setGroup("com.h2database")); 285 | 286 | if ("on-disk".equals(persistence)) { 287 | dependencies.add(new Dependency() 288 | .setArtifact("spring-boot-starter-jdbc") 289 | .setGroup("org.springframework.boot")); 290 | } // else: in-memory 291 | 292 | return dependencies; 293 | } 294 | 295 | protected String dotToSlash(String input) { 296 | return input.replace(".", "/"); 297 | } 298 | 299 | } 300 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/processing/TemplateProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.processing; 18 | 19 | import org.apache.velocity.Template; 20 | import org.apache.velocity.VelocityContext; 21 | import org.apache.velocity.app.VelocityEngine; 22 | import org.apache.velocity.runtime.RuntimeConstants; 23 | import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; 24 | import org.springframework.stereotype.Component; 25 | 26 | import java.io.StringWriter; 27 | import java.util.Map; 28 | 29 | @Component 30 | public class TemplateProcessor { 31 | 32 | public String process(Map context, String templateName) { 33 | 34 | VelocityEngine ve = new VelocityEngine(); 35 | ve.setProperty(RuntimeConstants.RESOURCE_LOADERS, "classpath"); 36 | ve.setProperty("resource.loader.classpath.class", ClasspathResourceLoader.class.getName()); 37 | ve.init(); 38 | 39 | Template applicationClass = ve.getTemplate(templateName); 40 | 41 | VelocityContext vc = new VelocityContext(); 42 | 43 | context.forEach(vc::put); 44 | 45 | StringWriter writer = new StringWriter(); 46 | applicationClass.merge(vc, writer); 47 | 48 | return writer.toString(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/rest/BadUserRequestException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.rest; 18 | 19 | import org.springframework.http.HttpStatus; 20 | import org.springframework.web.bind.annotation.ResponseStatus; 21 | 22 | @ResponseStatus(value = HttpStatus.BAD_REQUEST) 23 | public class BadUserRequestException extends RuntimeException { 24 | 25 | public BadUserRequestException(Throwable cause) { 26 | super(cause); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/rest/GeneratingController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.rest; 18 | 19 | import com.camunda.start.processing.ProjectGenerator; 20 | import com.camunda.start.rest.dto.DownloadProjectDto; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.web.bind.annotation.ExceptionHandler; 23 | import org.springframework.web.bind.annotation.PathVariable; 24 | import org.springframework.web.bind.annotation.PostMapping; 25 | import org.springframework.web.bind.annotation.RequestBody; 26 | import org.springframework.web.bind.annotation.ResponseBody; 27 | import org.springframework.web.bind.annotation.RestController; 28 | 29 | @RestController 30 | public class GeneratingController { 31 | 32 | @Autowired 33 | protected ProjectGenerator projectGenerator; 34 | 35 | @ExceptionHandler({ BadUserRequestException.class }) 36 | @PostMapping(value = "/download") 37 | public @ResponseBody byte[] downloadProject(@RequestBody DownloadProjectDto inputData) { 38 | 39 | return projectGenerator.generate(inputData); 40 | } 41 | 42 | @ExceptionHandler({ BadUserRequestException.class }) 43 | @PostMapping(value = "/show/{fileName}") 44 | public @ResponseBody String showFile(@RequestBody DownloadProjectDto inputData, 45 | @PathVariable String fileName) { 46 | 47 | return projectGenerator.generate(inputData, fileName); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/rest/VersionsController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.rest; 18 | 19 | import com.camunda.start.update.VersionUpdater; 20 | import com.camunda.start.update.dto.StarterVersionWrapperDto; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.web.bind.annotation.GetMapping; 23 | import org.springframework.web.bind.annotation.ResponseBody; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | @RestController 27 | public class VersionsController { 28 | 29 | @Autowired 30 | protected VersionUpdater versionUpdater; 31 | 32 | @GetMapping(value = "/versions.json") 33 | public @ResponseBody StarterVersionWrapperDto getVersions() { 34 | return versionUpdater.getStarterVersionWrapper(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/rest/dto/DownloadProjectDto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.rest.dto; 18 | 19 | import java.util.List; 20 | 21 | public class DownloadProjectDto { 22 | 23 | public String username; 24 | public String password; 25 | 26 | public String persistence; 27 | 28 | public String group; 29 | public String artifact; 30 | public String version; 31 | 32 | public String starterVersion; 33 | public String javaVersion; 34 | 35 | public List modules; 36 | 37 | public void setGroup(String group) { 38 | this.group = group; 39 | } 40 | 41 | public String getGroup() { 42 | return group; 43 | } 44 | 45 | public void setPersistence(String persistence) { 46 | this.persistence = persistence; 47 | } 48 | 49 | public String getPersistence() { 50 | return persistence; 51 | } 52 | 53 | public void setUsername(String username) { 54 | this.username = username; 55 | } 56 | 57 | public String getUsername() { 58 | return username; 59 | } 60 | 61 | public void setPassword(String password) { 62 | this.password = password; 63 | } 64 | 65 | public String getPassword() { 66 | return password; 67 | } 68 | 69 | public void setJavaVersion(String javaVersion) { 70 | this.javaVersion = javaVersion; 71 | } 72 | 73 | public String getJavaVersion() { 74 | return javaVersion; 75 | } 76 | 77 | public void setArtifact(String artifact) { 78 | this.artifact = artifact; 79 | } 80 | 81 | public String getArtifact() { 82 | return artifact; 83 | } 84 | 85 | public void setVersion(String version) { 86 | this.version = version; 87 | } 88 | 89 | public String getVersion() { 90 | return version; 91 | } 92 | 93 | public void setModules(List modules) { 94 | this.modules = modules; 95 | } 96 | 97 | public List getModules() { 98 | return modules; 99 | } 100 | 101 | public void setStarterVersion(String starterVersion) { 102 | this.starterVersion = starterVersion; 103 | } 104 | 105 | public String getStarterVersion() { 106 | return starterVersion; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/update/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.update; 18 | 19 | import java.util.HashSet; 20 | import java.util.Set; 21 | import java.util.regex.Pattern; 22 | 23 | public class Constants { 24 | 25 | protected static final String URL_MAVEN_BASE = 26 | "https://repo1.maven.org/maven2/org/camunda/bpm/"; 27 | 28 | protected static final String URL_MAVEN_SPRING_BOOT_URL = URL_MAVEN_BASE + "springboot/project/"; 29 | 30 | protected static final String URL_MAVEN_SPRING_BOOT_METADATA = 31 | URL_MAVEN_SPRING_BOOT_URL + "camunda-bpm-spring-boot-starter-root/maven-metadata.xml"; 32 | 33 | protected static final String URL_MAVEN_SPRING_BOOT_METADATA_MD5 = 34 | URL_MAVEN_SPRING_BOOT_METADATA + ".md5"; 35 | 36 | protected static final String URL_MAVEN_SPRING_BOOT_ROOT_POM_LEGACY = 37 | URL_MAVEN_SPRING_BOOT_URL + "camunda-bpm-spring-boot-starter-root/" + 38 | "{version}/camunda-bpm-spring-boot-starter-root-{version}.pom"; 39 | 40 | protected static final String URL_MAVEN_CAMUNDA_ROOT_POM = 41 | URL_MAVEN_BASE + "camunda-root/{version}/camunda-root-{version}.pom"; 42 | 43 | protected static final String URL_MAVEN_CAMUNDA_PARENT_POM = 44 | URL_MAVEN_BASE + "camunda-parent/{version}/camunda-parent-{version}.pom"; 45 | 46 | protected static final String XPATH_VERSIONS = "/metadata/versioning/versions/version"; 47 | 48 | protected static final Pattern REGEX_PATTERN_VERSION = Pattern.compile("^([0-9]+).([0-9]+)(.*)"); 49 | 50 | protected static final Set IGNORED_MINOR_VERSIONS = new HashSet() {{ 51 | add("3.1"); 52 | }}; 53 | 54 | protected static final Set IGNORED_VERSION_TAGS = new HashSet() {{ 55 | add("alpha"); 56 | }}; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/update/VersionUpdater.java: -------------------------------------------------------------------------------- 1 | package com.camunda.start.update; 2 | 3 | import com.camunda.start.update.dto.StarterVersionDto; 4 | import com.camunda.start.update.dto.StarterVersionWrapperDto; 5 | import org.apache.commons.io.IOUtils; 6 | import org.apache.maven.artifact.versioning.ComparableVersion; 7 | import org.springframework.scheduling.annotation.Scheduled; 8 | import org.springframework.stereotype.Component; 9 | import org.w3c.dom.Document; 10 | import org.w3c.dom.NodeList; 11 | import org.xml.sax.SAXException; 12 | 13 | import javax.xml.parsers.DocumentBuilder; 14 | import javax.xml.parsers.DocumentBuilderFactory; 15 | import javax.xml.parsers.ParserConfigurationException; 16 | import javax.xml.xpath.XPathConstants; 17 | import javax.xml.xpath.XPathExpressionException; 18 | import javax.xml.xpath.XPathFactory; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.net.MalformedURLException; 22 | import java.net.URL; 23 | import java.net.URLConnection; 24 | import java.nio.charset.Charset; 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.Collections; 28 | import java.util.HashMap; 29 | import java.util.HashSet; 30 | import java.util.Iterator; 31 | import java.util.List; 32 | import java.util.Map; 33 | import java.util.Objects; 34 | import java.util.Set; 35 | import java.util.regex.Matcher; 36 | 37 | import static com.camunda.start.update.Constants.IGNORED_MINOR_VERSIONS; 38 | import static com.camunda.start.update.Constants.IGNORED_VERSION_TAGS; 39 | import static com.camunda.start.update.Constants.REGEX_PATTERN_VERSION; 40 | import static com.camunda.start.update.Constants.URL_MAVEN_CAMUNDA_ROOT_POM; 41 | import static com.camunda.start.update.Constants.URL_MAVEN_CAMUNDA_PARENT_POM; 42 | import static com.camunda.start.update.Constants.URL_MAVEN_SPRING_BOOT_METADATA; 43 | import static com.camunda.start.update.Constants.URL_MAVEN_SPRING_BOOT_METADATA_MD5; 44 | import static com.camunda.start.update.Constants.URL_MAVEN_SPRING_BOOT_ROOT_POM_LEGACY; 45 | import static com.camunda.start.update.Constants.XPATH_VERSIONS; 46 | 47 | @Component 48 | public class VersionUpdater { 49 | 50 | protected Map cachedComparableVersions = new HashMap<>(); 51 | 52 | protected StarterVersionWrapperDto starterVersionWrapper; 53 | 54 | @Scheduled(cron = "0 * * * * *") 55 | public void updateVersions() { 56 | String fetchedChecksum = fetchChecksum(); 57 | 58 | if (!fetchedChecksum.equals(readChecksum())) { 59 | Set fetchedVersions = fetchVersions(); 60 | 61 | removeIgnoredVersions(fetchedVersions); 62 | 63 | List latestVersions = 64 | new ArrayList<>(getLatestVersions(fetchedVersions)); 65 | 66 | Collections.sort(latestVersions); 67 | Collections.reverse(latestVersions); 68 | 69 | starterVersionWrapper = new StarterVersionWrapperDto(); 70 | starterVersionWrapper.setStarterVersions(getLatestStarterVersions(latestVersions)); 71 | starterVersionWrapper.setChecksum(fetchedChecksum); 72 | } 73 | } 74 | 75 | protected void removeIgnoredVersions(Set fetchedVersions) { 76 | Iterator iterator = fetchedVersions.iterator(); 77 | while (iterator.hasNext()) { 78 | IGNORED_VERSION_TAGS.stream() 79 | .filter(iterator.next()::contains) 80 | .forEach(ignoredVersionTag -> iterator.remove()); 81 | } 82 | } 83 | 84 | protected Collection getLatestVersions(Set fetchedVersions) { 85 | // clear previously cached versions 86 | cachedComparableVersions.clear(); 87 | 88 | Map latestVersionsMap = new HashMap<>(); 89 | 90 | fetchedVersions.forEach(fetchedVersion -> { 91 | Matcher versionMatcher = REGEX_PATTERN_VERSION.matcher(fetchedVersion); 92 | if (versionMatcher.find()) { 93 | String minorVersion = versionMatcher.group(1) + "." + versionMatcher.group(2); 94 | if (!IGNORED_MINOR_VERSIONS.contains(minorVersion)) { 95 | ComparableVersion entireVersion = latestVersionsMap.get(minorVersion); 96 | 97 | ComparableVersion comparableVersion = 98 | getCachedComparableVersion(fetchedVersion); 99 | 100 | if (entireVersion == null) { 101 | latestVersionsMap.put(minorVersion, comparableVersion); 102 | 103 | } else if (entireVersion.compareTo(comparableVersion) < 0) { 104 | latestVersionsMap.put(minorVersion, comparableVersion); 105 | 106 | } 107 | } 108 | } 109 | }); 110 | 111 | return latestVersionsMap.values(); 112 | } 113 | 114 | protected List getLatestStarterVersions(List majorMinorVersions) { 115 | List starterVersions = new ArrayList<>(); 116 | 117 | for (int i = 0; i < 3; i++) { 118 | ComparableVersion majorMinorVersion = majorMinorVersions.get(i); 119 | 120 | String version = majorMinorVersion.toString(); 121 | 122 | StarterVersionDto starterVersion = new StarterVersionDto(); 123 | 124 | if (majorMinorVersion.compareTo(new ComparableVersion("7.13.0-alpha1")) > 0) { 125 | 126 | starterVersion.setStarterVersion(version); 127 | starterVersion.setCamundaVersion(version); 128 | 129 | String url = null; 130 | if (majorMinorVersion.compareTo(new ComparableVersion("7.14.0-alpha4")) > 0) { 131 | url = URL_MAVEN_CAMUNDA_PARENT_POM.replace("{version}", version); 132 | 133 | } else { 134 | url = URL_MAVEN_CAMUNDA_ROOT_POM.replace("{version}", version); 135 | 136 | } 137 | 138 | InputStream pom = getInputStreamByUrl(url); 139 | Document pomDocument = createPomDocument(pom); 140 | 141 | String springBootVersion = getVersion(pomDocument, 142 | "/project/properties/version.spring-boot"); 143 | 144 | starterVersion.setSpringBootVersion(springBootVersion); 145 | 146 | } else { // legacy versions 147 | 148 | starterVersion.setStarterVersion(version); 149 | 150 | String url = URL_MAVEN_SPRING_BOOT_ROOT_POM_LEGACY.replace("{version}", version); 151 | 152 | InputStream pom = getInputStreamByUrl(url); 153 | Document pomDocument = createPomDocument(pom); 154 | 155 | String springBootVersion = getVersion(pomDocument, 156 | "/project/properties/spring-boot.version"); 157 | 158 | String camundaVersion = getVersion(pomDocument, 159 | "/project/properties/camunda.version"); 160 | 161 | starterVersion.setCamundaVersion(camundaVersion); 162 | starterVersion.setSpringBootVersion(springBootVersion); 163 | } 164 | 165 | starterVersions.add(starterVersion); 166 | } 167 | 168 | return starterVersions; 169 | } 170 | 171 | protected String getVersion(Document documentByInputStream, String xPath) { 172 | try { 173 | return (String) XPathFactory.newInstance() 174 | .newXPath() 175 | .compile(xPath) 176 | .evaluate(documentByInputStream, XPathConstants.STRING); 177 | 178 | } catch (XPathExpressionException e) { 179 | throw new RuntimeException(e); 180 | } 181 | } 182 | 183 | protected ComparableVersion getCachedComparableVersion(String fetchedVersion) { 184 | ComparableVersion cachedVersion = cachedComparableVersions.get(fetchedVersion); 185 | 186 | if (cachedVersion == null) { 187 | ComparableVersion comparableVersion = new ComparableVersion(fetchedVersion); 188 | 189 | cachedComparableVersions.put(fetchedVersion, comparableVersion); 190 | 191 | return comparableVersion; 192 | 193 | } else { 194 | return cachedVersion; 195 | 196 | } 197 | } 198 | 199 | protected Set fetchVersions() { 200 | InputStream metadataInputStream = getInputStreamByUrl(URL_MAVEN_SPRING_BOOT_METADATA); 201 | Document xmlDocument = createPomDocument(metadataInputStream); 202 | 203 | NodeList nodeList = null; 204 | try { 205 | nodeList = (NodeList) XPathFactory.newInstance() 206 | .newXPath() 207 | .compile(XPATH_VERSIONS) 208 | .evaluate(xmlDocument, XPathConstants.NODESET); 209 | } catch (XPathExpressionException e) { 210 | throw new RuntimeException(e); 211 | } 212 | 213 | 214 | Set fetchedVersions = new HashSet<>(); 215 | for (int i = 0; i < nodeList.getLength(); i++) { 216 | fetchedVersions.add(nodeList.item(i).getTextContent()); 217 | } 218 | 219 | fetchedVersions.remove(null); 220 | 221 | return fetchedVersions; 222 | } 223 | 224 | protected String readChecksum() { 225 | return starterVersionWrapper == null ? null : starterVersionWrapper.getChecksum(); 226 | } 227 | 228 | protected String fetchChecksum() { 229 | try { 230 | return IOUtils.toString(getInputStreamByUrl(URL_MAVEN_SPRING_BOOT_METADATA_MD5), 231 | Charset.defaultCharset()); 232 | } catch (IOException e) { 233 | throw new RuntimeException(e); 234 | 235 | } 236 | } 237 | 238 | protected Document createPomDocument(InputStream inputStream) { 239 | DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 240 | DocumentBuilder builder = null; 241 | try { 242 | builder = builderFactory.newDocumentBuilder(); 243 | } catch (ParserConfigurationException e) { 244 | throw new RuntimeException(e); 245 | } 246 | 247 | try { 248 | return Objects.requireNonNull(builder).parse(inputStream); 249 | } catch (SAXException | IOException e) { 250 | throw new RuntimeException(e); 251 | } 252 | } 253 | 254 | protected InputStream getInputStreamByUrl(String url) { 255 | URL metadata = null; 256 | try { 257 | metadata = new URL(url); 258 | } catch (MalformedURLException e) { 259 | throw new RuntimeException(e); 260 | } 261 | 262 | URLConnection urlConnection = null; 263 | try { 264 | urlConnection = metadata.openConnection(); 265 | } catch (IOException e) { 266 | throw new RuntimeException(e); 267 | } 268 | 269 | try { 270 | return urlConnection.getInputStream(); 271 | } catch (IOException e) { 272 | throw new RuntimeException(e); 273 | } 274 | } 275 | 276 | public StarterVersionWrapperDto getStarterVersionWrapper() { 277 | updateVersions(); 278 | return starterVersionWrapper; 279 | } 280 | 281 | } -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/update/dto/StarterVersionDto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.update.dto; 18 | 19 | public class StarterVersionDto { 20 | 21 | protected String starterVersion; 22 | protected String camundaVersion; 23 | protected String springBootVersion; 24 | 25 | public String getCamundaVersion() { 26 | return camundaVersion; 27 | } 28 | 29 | public void setCamundaVersion(String camundaVersion) { 30 | this.camundaVersion = camundaVersion; 31 | } 32 | 33 | public String getSpringBootVersion() { 34 | return springBootVersion; 35 | } 36 | 37 | public void setSpringBootVersion(String springBootVersion) { 38 | this.springBootVersion = springBootVersion; 39 | } 40 | 41 | public String getStarterVersion() { 42 | return starterVersion; 43 | } 44 | 45 | public void setStarterVersion(String starterVersion) { 46 | this.starterVersion = starterVersion; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /backend/src/main/java/com/camunda/start/update/dto/StarterVersionWrapperDto.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH 3 | * under one or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information regarding copyright 5 | * ownership. Camunda licenses this file to you under the Apache License, 6 | * Version 2.0; you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.camunda.start.update.dto; 18 | 19 | import java.util.List; 20 | 21 | public class StarterVersionWrapperDto { 22 | 23 | protected String checksum; 24 | protected List starterVersions; 25 | 26 | public String getChecksum() { 27 | return checksum; 28 | } 29 | 30 | public void setChecksum(String checksum) { 31 | this.checksum = checksum; 32 | } 33 | 34 | public List getStarterVersions() { 35 | return starterVersions; 36 | } 37 | 38 | public void setStarterVersions(List starterVersions) { 39 | this.starterVersions = starterVersions; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /backend/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server.port: 9090 -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/Application.java.vm: -------------------------------------------------------------------------------- 1 | package $packageName; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String... args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/WorkflowTest.java.vm: -------------------------------------------------------------------------------- 1 | package $packageName; 2 | 3 | import org.camunda.bpm.engine.RuntimeService; 4 | import org.camunda.bpm.engine.runtime.ProcessInstance; 5 | import org.camunda.bpm.spring.boot.starter.test.helper.AbstractProcessEngineRuleTest; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | 12 | import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareTests.assertThat; 13 | 14 | @SpringBootTest 15 | @RunWith(SpringRunner.class) 16 | public class WorkflowTest extends AbstractProcessEngineRuleTest { 17 | 18 | @Autowired 19 | public RuntimeService runtimeService; 20 | 21 | @Test 22 | public void shouldExecuteHappyPath() { 23 | // given 24 | String processDefinitionKey = "$artifact-process"; 25 | 26 | // when 27 | ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey); 28 | 29 | // then 30 | assertThat(processInstance).isStarted() 31 | .task() 32 | .hasDefinitionKey("say-hello") 33 | .hasCandidateUser("$adminUsername") 34 | .isNotAssigned(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/application.yaml.test.vm: -------------------------------------------------------------------------------- 1 | camunda.bpm.job-execution: 2 | enabled: false 3 | -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/application.yaml.vm: -------------------------------------------------------------------------------- 1 | #if($persistence == "on-disk") 2 | spring.datasource.url: jdbc:h2:file:./camunda-h2-database 3 | 4 | #end 5 | camunda.bpm.admin-user: 6 | id: $adminUsername 7 | password: $adminPassword -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/logback-test.xml.vm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/pom.xml.vm: -------------------------------------------------------------------------------- 1 | 4 | 5 | 4.0.0 6 | 7 | $group 8 | $artifact 9 | $projectVersion 10 | 11 | 12 | UTF-8 13 | $javaVersion 14 | $javaVersion 15 | 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-dependencies 22 | $springBootVersion 23 | pom 24 | import 25 | 26 | 27 | 28 | org.camunda.bpm 29 | camunda-bom 30 | $camundaVersion 31 | import 32 | pom 33 | 34 | 35 | 36 | 37 | 38 | #foreach($dependency in $dependencies) 39 | 40 | $dependency.group 41 | $dependency.artifact 42 | #if($dependency.version) 43 | $dependency.version 44 | #end 45 | 46 | 47 | #end 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-maven-plugin 55 | $springBootVersion 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /backend/src/main/resources/com/camunda/start/templates/process.bpmn.vm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceFlow_1fp17al 6 | 7 | 8 | 9 | SequenceFlow_16gzt2m 10 | 11 | 12 | 13 | SequenceFlow_1fp17al 14 | SequenceFlow_16gzt2m 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ecs-task-definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "family": "ecs_start_camunda_com", 3 | "containerDefinitions": [ 4 | { 5 | "name": "start_camunda_com", 6 | "image": "registry.camunda.cloud/team-cambpm-public/start.camunda.com:v1.7", 7 | "cpu": 0, 8 | "links": [], 9 | "portMappings": [ 10 | { 11 | "containerPort": 80, 12 | "hostPort": 80, 13 | "protocol": "tcp" 14 | } 15 | ], 16 | "essential": true, 17 | "entryPoint": [], 18 | "command": [], 19 | "environment": [], 20 | "environmentFiles": [], 21 | "mountPoints": [], 22 | "volumesFrom": [], 23 | "secrets": [], 24 | "dnsServers": [], 25 | "dnsSearchDomains": [], 26 | "extraHosts": [], 27 | "dockerSecurityOptions": [], 28 | "dockerLabels": {}, 29 | "ulimits": [], 30 | "logConfiguration": { 31 | "logDriver": "awslogs", 32 | "options": { 33 | "awslogs-create-group": "true", 34 | "awslogs-group": "/ecs/ecs_start_camunda_com", 35 | "awslogs-region": "eu-central-1", 36 | "awslogs-stream-prefix": "ecs" 37 | }, 38 | "secretOptions": [] 39 | }, 40 | "systemControls": [] 41 | } 42 | ], 43 | "networkMode": "awsvpc", 44 | "requiresCompatibilities": [ 45 | "FARGATE" 46 | ], 47 | "cpu": "1024", 48 | "memory": "3072", 49 | "runtimePlatform": { 50 | "cpuArchitecture": "X86_64", 51 | "operatingSystemFamily": "LINUX" 52 | }, 53 | "tags": [ 54 | { 55 | "key": "ecs:taskDefinition:createdFrom", 56 | "value": "ecs-console-v2" 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | .eslintcache 23 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "start-camunda", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "18.2.0", 7 | "react-dom": "18.2.0", 8 | "react-scripts": "5.0.1", 9 | "@material-ui/core": "4.12.4", 10 | "@material-ui/icons": "4.11.3", 11 | "downloadjs": "1.4.7", 12 | "jss": "10.10.0", 13 | "react-syntax-highlighter": "15.5.0" 14 | }, 15 | "devDependencies": { 16 | "prettier": "2.7.1" 17 | }, 18 | "proxy": "http://localhost:9090", 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version", 38 | "last 1 edge version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /frontend/public/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasso94/start-camunda/ab9584f3f3f04b7ea38dd2a1492defd23d85eb3a/frontend/public/background.png -------------------------------------------------------------------------------- /frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasso94/start-camunda/ab9584f3f3f04b7ea38dd2a1492defd23d85eb3a/frontend/public/favicon.png -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | Camunda Automation Platform 7 Initializr 14 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /frontend/public/logo.svg: -------------------------------------------------------------------------------- 1 | Logo_White -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | 3 | import { 4 | Tooltip, 5 | Link, 6 | Box, 7 | Divider, 8 | ListItemText, 9 | ListItem, 10 | List, 11 | IconButton, 12 | Dialog, 13 | Button, 14 | Typography, 15 | Toolbar, 16 | AppBar, 17 | Paper, 18 | Grid, 19 | MenuItem, 20 | Select, 21 | InputLabel, 22 | Checkbox, 23 | FormControlLabel, 24 | FormGroup, 25 | FormLabel, 26 | FormControl, 27 | Container, 28 | TextField, 29 | } from "@material-ui/core"; 30 | 31 | import { createStyles, makeStyles } from "@material-ui/core/styles"; 32 | import { Close, BookOutlined } from "@material-ui/icons"; 33 | 34 | import SyntaxHighlighter from "react-syntax-highlighter"; 35 | import a11yLight from "react-syntax-highlighter/dist/esm/styles/hljs/a11y-light"; 36 | 37 | import downloadjs from "downloadjs"; 38 | 39 | const initialFormData = { 40 | artifact: { value: "my-project" }, 41 | group: { value: "com.example.workflow" }, 42 | username: { value: "" }, 43 | password: { value: "" }, 44 | persistence: { value: "on-disk" }, 45 | javaVersion: { value: "17" }, 46 | }; 47 | 48 | const initialModules = { 49 | "camunda-rest": true, 50 | "camunda-webapps": true, 51 | "camunda-spin": true, 52 | "camunda-assert": false, 53 | "spring-boot-security": false, 54 | "spring-boot-web": false, 55 | }; 56 | 57 | const mapVersions = (version, releases) => { 58 | for (const release of releases) { 59 | if (release.starterVersion === version) { 60 | return { 61 | starterVersion: { value: version }, 62 | springBootVersion: { value: release.springBootVersion }, 63 | camundaVersion: { value: release.camundaVersion }, 64 | }; 65 | } 66 | } 67 | }; 68 | 69 | const getModuleNames = (modules) => { 70 | const filteredModules = Object.keys(modules).filter((name) => { 71 | return modules[name]; 72 | }); 73 | 74 | if ( 75 | !filteredModules.includes("camunda-webapps") && 76 | !filteredModules.includes("camunda-rest") 77 | ) { 78 | return [...filteredModules, "camunda-base"]; 79 | } else { 80 | return filteredModules; 81 | } 82 | }; 83 | 84 | const getPayload = (formData) => 85 | Object.entries(formData).reduce((acc, [key, value]) => { 86 | if (key !== "springBootVersion" && key !== "starterVersions") { 87 | acc[key] = value.value; 88 | } 89 | return acc; 90 | }, {}); 91 | 92 | const useStyles = makeStyles((theme) => 93 | createStyles({ 94 | header: { 95 | position: "static", 96 | backgroundImage: "url(./background.png)", 97 | backgroundPosition: "50%", 98 | }, 99 | button: { 100 | marginTop: 25, 101 | }, 102 | headline: { 103 | marginBottom: 25, 104 | }, 105 | root: { 106 | marginTop: 60, 107 | width: 700, 108 | }, 109 | paper: { 110 | padding: theme.spacing(6, 4), 111 | }, 112 | appBar: { 113 | backgroundColor: theme.palette.secondary.main, 114 | }, 115 | footer: { 116 | top: "auto", 117 | bottom: 0, 118 | height: 40, 119 | padding: 10, 120 | }, 121 | list: { 122 | marginTop: 80, 123 | }, 124 | docs: { 125 | marginLeft: 15, 126 | verticalAlign: "text-top", 127 | }, 128 | }) 129 | ); 130 | 131 | const App = () => { 132 | const [formData, setFormData] = useState({}); 133 | const [modules, setModules] = useState(initialModules); 134 | const [error, setError] = useState(false); 135 | const [openExplorer, setOpenExplorer] = useState(false); 136 | const [sourceCode, setSourceCode] = useState(); 137 | 138 | useEffect(() => { 139 | fetch("./versions.json").then((response) => { 140 | if (response.status === 200) { 141 | response.json().then(({ starterVersions }) => { 142 | setFormData({ 143 | ...mapVersions(starterVersions[0].starterVersion, starterVersions), 144 | starterVersions: { value: starterVersions }, 145 | ...initialFormData, 146 | }); 147 | }); 148 | } 149 | }); 150 | 151 | const handler = (e) => { 152 | e.preventDefault(); 153 | e.returnValue = true; 154 | }; 155 | 156 | window.addEventListener("beforeunload", handler); 157 | return () => { 158 | window.removeEventListener("beforeunload", handler); 159 | }; 160 | }, []); 161 | 162 | useEffect(() => { 163 | setError( 164 | Object.values(formData).reduce( 165 | (acc, element) => acc || element.error, 166 | false 167 | ) 168 | ); 169 | }, [formData]); 170 | 171 | const handleClose = () => { 172 | setSourceCode(); 173 | setOpenExplorer(false); 174 | }; 175 | 176 | const getMajorMinor = (version) => { 177 | const versionTokens = version.split("."); 178 | return versionTokens[0] + "." + versionTokens[1]; 179 | }; 180 | 181 | const changeModules = (module) => { 182 | setModules({ ...modules, [module.name]: module.checked }); 183 | }; 184 | 185 | const generateProject = () => { 186 | const payload = getPayload(formData); 187 | fetch("./download", { 188 | method: "post", 189 | headers: { 190 | "Content-Type": "application/json", 191 | }, 192 | body: JSON.stringify({ 193 | ...payload, 194 | modules: getModuleNames(modules), 195 | }), 196 | }).then((response) => { 197 | if (response.status === 200) { 198 | response 199 | .blob() 200 | .then((blob) => downloadjs(blob, `${formData.artifact.value}.zip`)); 201 | } 202 | }); 203 | }; 204 | 205 | const highlight = (filename, type) => { 206 | const payload = getPayload(formData); 207 | fetch(`./show/${filename}`, { 208 | method: "post", 209 | headers: { 210 | "Content-Type": "application/json", 211 | }, 212 | body: JSON.stringify({ 213 | ...payload, 214 | modules: getModuleNames(modules), 215 | }), 216 | }).then((response) => { 217 | if (response.status === 200) { 218 | response.text().then((text) => { 219 | setSourceCode({ text, type }); 220 | }); 221 | } 222 | }); 223 | }; 224 | 225 | const handleChangeGroup = (newGroup) => { 226 | const regex = /^[a-z_]+(\.[a-z_][a-z0-9_]*)*$/i; 227 | const { group, ...rest } = formData; 228 | setFormData({ 229 | group: { value: newGroup, error: !regex.test(newGroup) }, 230 | ...rest, 231 | }); 232 | }; 233 | 234 | const classes = useStyles(); 235 | 236 | return ( 237 |
238 | 239 | 240 | Camunda 241 | 242 | 243 | 244 | 245 | 246 | Camunda Automation Platform 7 Initializr 247 | 248 | {Object.keys(formData).length === 0 && ( 249 | Loading... 250 | )} 251 | {Object.keys(formData).length > 0 && ( 252 | 253 | 254 | handleChangeGroup(e.target.value)} 261 | /> 262 | 263 | 264 | { 271 | const newArtifact = e.target.value; 272 | const { artifact, ...rest } = formData; 273 | setFormData({ 274 | artifact: { 275 | value: newArtifact, 276 | error: !newArtifact, 277 | }, 278 | ...rest, 279 | }); 280 | }} 281 | /> 282 | 283 | 284 | 285 | 286 | Version 287 | 288 | 314 | 315 | 316 | 317 | 324 | 325 | 326 | 327 | H2 Database 328 | 341 | 342 | 343 | 344 | { 352 | const newJavaVersion = e.target.value; 353 | const { javaVersion, ...rest } = formData; 354 | setFormData({ 355 | javaVersion: { 356 | value: newJavaVersion, 357 | error: !(newJavaVersion >= 8 && newJavaVersion <= 17), 358 | }, 359 | ...rest, 360 | }); 361 | }} 362 | /> 363 | 364 | 365 | 366 | Modules 367 | 368 | 369 | 373 | changeModules({ 374 | name: "camunda-rest", 375 | checked: e.target.checked, 376 | }) 377 | } 378 | defaultChecked={modules["camunda-rest"]} 379 | /> 380 | } 381 | label={ 382 | <> 383 | REST API 384 | 393 | 394 | 395 | 396 | 397 | 398 | } 399 | /> 400 | 404 | changeModules({ 405 | name: "camunda-webapps", 406 | checked: e.target.checked, 407 | }) 408 | } 409 | defaultChecked={modules["camunda-webapps"]} 410 | /> 411 | } 412 | label={ 413 | <> 414 | Webapps 415 | 424 | 425 | 426 | 427 | 428 | 429 | } 430 | /> 431 | 435 | changeModules({ 436 | name: "camunda-spin", 437 | checked: e.target.checked, 438 | }) 439 | } 440 | defaultChecked={modules["camunda-spin"]} 441 | /> 442 | } 443 | label={ 444 | <> 445 | Spin (XML & JSON) 446 | 453 | 454 | 455 | 456 | 457 | 458 | } 459 | /> 460 | 464 | changeModules({ 465 | name: "camunda-assert", 466 | checked: e.target.checked, 467 | }) 468 | } 469 | defaultChecked={modules["camunda-assert"]} 470 | /> 471 | } 472 | label={ 473 | <> 474 | Assert 475 | 482 | 483 | 484 | 485 | 486 | 487 | } 488 | /> 489 | 490 | 491 | 492 | 493 | 494 | Spring Boot Modules 495 | 496 | 497 | 501 | changeModules({ 502 | name: "spring-boot-security", 503 | checked: e.target.checked, 504 | }) 505 | } 506 | defaultChecked={modules["spring-boot-security"]} 507 | /> 508 | } 509 | label="Security" 510 | /> 511 | 515 | changeModules({ 516 | name: "spring-boot-web", 517 | checked: e.target.checked, 518 | }) 519 | } 520 | defaultChecked={modules["spring-boot-web"]} 521 | /> 522 | } 523 | label="Web" 524 | /> 525 | 526 | 527 | 528 | 529 | { 535 | const { username, ...rest } = formData; 536 | setFormData({ 537 | username: { value: e.target.value }, 538 | ...rest, 539 | }); 540 | }} 541 | /> 542 | 543 | 544 | { 551 | const { password, ...rest } = formData; 552 | setFormData({ 553 | password: { value: e.target.value }, 554 | ...rest, 555 | }); 556 | }} 557 | /> 558 | 559 | 560 | 569 | 570 | 571 | 580 | 581 | 582 | )} 583 | 584 | 585 | 586 | 587 | 588 | Privacy Statement 589 | {" "} 590 | | Imprint | 591 | Camunda Services GmbH © 2019 - {new Date().getFullYear()} 592 | 593 | 594 | {Object.keys(formData).length > 0 && ( 595 | 596 | 597 | 598 | 604 | 605 | 606 | 607 | Project Explorer 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | highlight("pom.xml", "xml")} 618 | primary="pom.xml" 619 | secondary={formData.artifact.value + "/"} 620 | /> 621 | 622 | 623 | 624 | highlight("application.yaml", "yaml")} 626 | primary="application.yaml" 627 | secondary={formData.artifact.value + "/src/main/resources/"} 628 | /> 629 | 630 | 631 | 632 | highlight("process.bpmn", "xml")} 634 | primary="process.bpmn" 635 | secondary={formData.artifact.value + "/src/main/resources/"} 636 | /> 637 | 638 | 639 | 640 | highlight("Application.java", "java")} 642 | primary="Application.java" 643 | secondary={ 644 | formData.artifact.value + 645 | "/src/main/java/" + 646 | formData.group.value.replace(/\./g, "/") + 647 | "/" 648 | } 649 | /> 650 | 651 | {modules["camunda-assert"] && ( 652 | <> 653 | 654 | 655 | highlight("WorkflowTest.java", "java")} 657 | primary="WorkflowTest.java" 658 | secondary={ 659 | formData.artifact.value + 660 | "/src/test/java/" + 661 | formData.group.value.replace(/\./g, "/") + 662 | "/" 663 | } 664 | /> 665 | 666 | 667 | 668 | highlight("application.yaml", "yaml")} 670 | primary="application.yaml" 671 | secondary={formData.artifact.value + "/src/test/resources/"} 672 | /> 673 | 674 | 675 | 676 | highlight("logback-test.xml", "xml")} 678 | primary="logback-test.xml" 679 | secondary={ 680 | formData.artifact.value + "/src/test/resources/" 681 | } 682 | /> 683 | 684 | 685 | )} 686 | 687 | 688 | 689 | 690 | {sourceCode && ( 691 |
692 |                     
693 |                       
699 |                         {sourceCode.text}
700 |                       
701 |                     
702 |                   
703 | )} 704 |
705 |
706 |
707 |
708 | )} 709 |
710 | ); 711 | }; 712 | 713 | export default App; 714 | -------------------------------------------------------------------------------- /frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {createRoot} from 'react-dom/client'; 3 | import App from './App'; 4 | 5 | import { ThemeProvider } from '@material-ui/styles'; 6 | import CssBaseline from '@material-ui/core/CssBaseline'; 7 | import { red } from '@material-ui/core/colors'; 8 | import { createTheme } from '@material-ui/core/styles' 9 | 10 | const theme = createTheme({ 11 | palette: { 12 | primary: { 13 | main: 'rgb(255,138,1)', 14 | }, 15 | secondary: { 16 | main: '#14d890', 17 | }, 18 | error: { 19 | main: red.A400, 20 | }, 21 | background: { 22 | default: '#fafafa', 23 | }, 24 | }, 25 | }); 26 | 27 | const root = createRoot(document.querySelector('#root')); 28 | root.render( 29 | 30 | 31 | 32 | 33 | ); 34 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasso94/start-camunda/ab9584f3f3f04b7ea38dd2a1492defd23d85eb3a/screenshot.png --------------------------------------------------------------------------------