diff --git a/.github/workflows/broken_links_checker.yml b/.github/workflows/broken_links_checker.yml
index d7a38b46..39612b76 100644
--- a/.github/workflows/broken_links_checker.yml
+++ b/.github/workflows/broken_links_checker.yml
@@ -13,6 +13,8 @@ on:
jobs:
linkChecker:
runs-on: ubuntu-latest
+ permissions:
+ contents: read
defaults:
run:
shell: "bash"
diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 5e98525e..2d4aee00 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -17,7 +17,6 @@ jobs:
}
permissions: {
contents: read,
- checks: write,
issues: read
}
concurrency: {
diff --git a/.github/workflows/test_linux_build_on_windows.yml b/.github/workflows/test_linux_build_on_windows.yml
index 53d206ff..78115ff1 100644
--- a/.github/workflows/test_linux_build_on_windows.yml
+++ b/.github/workflows/test_linux_build_on_windows.yml
@@ -9,6 +9,8 @@ on:
jobs:
build-on-linux:
runs-on: ubuntu-latest
+ permissions:
+ contents: read
defaults:
run:
shell: "bash"
@@ -24,9 +26,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: "temurin"
- java-version: |
- 11
- 17
+ java-version: 17
cache: "maven"
- name: Set up Go
uses: actions/setup-go@v5
@@ -64,8 +64,11 @@ jobs:
name: project-keeper-jar
path: artifact
retention-days: 1
+
run-on-windows:
runs-on: windows-latest
+ permissions:
+ contents: read
needs: build-on-linux
steps:
- name: Checkout the repository
diff --git a/.github/workflows/test_on_windows.yml b/.github/workflows/test_on_windows.yml
index 0c054630..9292d3a4 100644
--- a/.github/workflows/test_on_windows.yml
+++ b/.github/workflows/test_on_windows.yml
@@ -9,6 +9,8 @@ on:
jobs:
test:
runs-on: windows-latest
+ permissions:
+ contents: read
defaults:
run:
shell: "bash"
@@ -24,6 +26,7 @@ jobs:
uses: actions/setup-java@v4
with:
distribution: "temurin"
+ # Java 11 required for test project "my-test-project"
java-version: |
11
17
diff --git a/doc/changes/changes_4.3.1.md b/doc/changes/changes_4.3.1.md
index 026984d8..076ab297 100644
--- a/doc/changes/changes_4.3.1.md
+++ b/doc/changes/changes_4.3.1.md
@@ -1,6 +1,6 @@
-# Project Keeper 4.3.1, released 2024-05-??
+# Project Keeper 4.3.1, released 2024-05-13
-Code name: Fix CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar:2.9.1:test`
+Code name: Environment for GitHub workflow `ci-build.yml`
## Summary
@@ -10,6 +10,10 @@ This release fixes vulnerability CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar
* #570: Fixed CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar:2.9.1:test`
+## Features
+
+* #566: Allowed specifying an environment for GitHub workflow `ci-build.yml`
+
## Bugfixes
* #571: Fixed failing version increment during dependency update
@@ -17,8 +21,18 @@ This release fixes vulnerability CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar
## Dependency Updates
+### Project Keeper Root Project
+
+#### Plugin Dependency Updates
+
+* Updated `com.exasol:error-code-crawler-maven-plugin:2.0.1` to `2.0.3`
+
### Project Keeper Shared Model Classes
+#### Test Dependency Updates
+
+* Updated `org.mockito:mockito-core:5.11.0` to `5.12.0`
+
#### Plugin Dependency Updates
* Updated `com.exasol:error-code-crawler-maven-plugin:2.0.2` to `2.0.3`
@@ -40,6 +54,7 @@ This release fixes vulnerability CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar
#### Test Dependency Updates
* Updated `com.exasol:project-keeper-shared-test-setup:4.3.0` to `4.3.1`
+* Updated `org.mockito:mockito-junit-jupiter:5.11.0` to `5.12.0`
* Updated `org.xmlunit:xmlunit-matchers:2.9.1` to `2.10.0`
#### Plugin Dependency Updates
@@ -77,6 +92,7 @@ This release fixes vulnerability CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar
#### Test Dependency Updates
* Updated `org.jacoco:org.jacoco.agent:0.8.11` to `0.8.12`
+* Updated `org.mockito:mockito-core:5.11.0` to `5.12.0`
* Updated `org.xmlunit:xmlunit-matchers:2.9.1` to `2.10.0`
#### Plugin Dependency Updates
@@ -95,6 +111,8 @@ This release fixes vulnerability CVE-2024-31573 in `org.xmlunit:xmlunit-core:jar
#### Test Dependency Updates
* Updated `org.jacoco:org.jacoco.agent:0.8.11` to `0.8.12`
+* Updated `org.mockito:mockito-core:5.11.0` to `5.12.0`
+* Updated `org.mockito:mockito-junit-jupiter:5.11.0` to `5.12.0`
* Updated `org.xmlunit:xmlunit-matchers:2.9.1` to `2.10.0`
#### Plugin Dependency Updates
diff --git a/doc/requirements/design.md b/doc/requirements/design.md
index c5c61828..94285813 100644
--- a/doc/requirements/design.md
+++ b/doc/requirements/design.md
@@ -424,6 +424,19 @@ Covers:
Needs: impl, utest, itest
+#### Customize Environment for GitHub Workflow `ci-build.yml`
+`dsn~customize-build-process.ci-build.environment~1`
+
+PK allows configuring a custom GitHub environment for `ci-build.yml`.
+
+Rationale:
+* Some projects use GitHub Environments to manually approve running expensive builds.
+
+Covers:
+* [`req~customize-build-process~0`](system_requirements.md#customize-build-process)
+
+Needs: impl, utest
+
#### Customize GitHub Workflow `release.yml`
`dsn~customize-build-process.release~0`
diff --git a/doc/user_guide/user_guide.md b/doc/user_guide/user_guide.md
index e88aaba4..7a8926fe 100644
--- a/doc/user_guide/user_guide.md
+++ b/doc/user_guide/user_guide.md
@@ -254,6 +254,17 @@ build:
Sonar will only run for the first version in the list.
+#### Customize Workflow Environment
+
+If your project requires running workflow `ci-build.yml` in a certain GitHub environment, you can specify it like this:
+
+```yml
+build:
+ workflows:
+ - name: "ci-build.yml"
+ environment: aws
+```
+
#### Customize Workflow Steps
If your project requires additional or modified steps in the generated GitHub workflow `ci-build.yml` you can replace existing steps or insert additional steps:
diff --git a/parent-pom/pom.xml b/parent-pom/pom.xml
index 5ca2a132..6063a3e4 100644
--- a/parent-pom/pom.xml
+++ b/parent-pom/pom.xml
@@ -35,7 +35,7 @@
3.6.3
5.10.2
2.10.0
- 5.11.0
+ 5.12.0
UTF-8
UTF-8
true
diff --git a/pom.xml b/pom.xml
index 9ecddcae..72463692 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,7 +78,7 @@
com.exasol
error-code-crawler-maven-plugin
- 2.0.1
+ 2.0.3
verify
diff --git a/project-keeper/error_code_config.yml b/project-keeper/error_code_config.yml
index 5238762f..c634c6c1 100644
--- a/project-keeper/error_code_config.yml
+++ b/project-keeper/error_code_config.yml
@@ -2,4 +2,4 @@ error-tags:
PK-CORE:
packages:
- com.exasol.projectkeeper
- highest-index: 206
+ highest-index: 207
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReader.java b/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReader.java
index 548f43fb..4171e945 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReader.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReader.java
@@ -150,20 +150,16 @@ private CustomWorkflow convertWorkflow(final Workflow workflow) {
supportedWorkflowNames)
.toString());
}
- if (workflow.stepCustomizations == null || workflow.stepCustomizations.isEmpty()) {
- throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-203")
- .message("Missing customized steps for workflow {{workflow name}} in file {{config file name}}.",
- workflow.name, CONFIG_FILE_NAME)
- .mitigation("Add at least one step or remove the workflow.").toString());
- }
return CustomWorkflow.builder() //
.workflowName(workflow.name) //
+ .environment(workflow.environment) //
.steps(convertSteps(workflow.stepCustomizations)) //
.build();
}
private List convertSteps(final List stepCustomizations) {
- return stepCustomizations.stream().map(this::convertStep).toList();
+ return Optional.ofNullable(stepCustomizations).orElseGet(Collections::emptyList) //
+ .stream().map(this::convertStep).toList();
}
private StepCustomization convertStep(final RawStepCustomization step) {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperRawConfig.java b/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperRawConfig.java
index e4a69047..831a8f10 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperRawConfig.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/config/ProjectKeeperRawConfig.java
@@ -395,6 +395,8 @@ public void setExasolDbVersions(final List exasolDbVersions) {
public static class Workflow {
/** Workflow name, e.g. {@code ci-build.yml} or {@code release.yml}. */
public String name;
+ /** GitHub environment, e.g. {@code aws}. */
+ public String environment;
/** List of customizations for the workflow. */
public List stepCustomizations;
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGenerator.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGenerator.java
index 14fddd98..dcd92e89 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGenerator.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGenerator.java
@@ -35,9 +35,21 @@ FileTemplate createCiBuildWorkflow() {
buildOptions.getExasolDbVersions().stream().map(this::quote).collect(joining(", ")));
template.replacing("defaultExasolDbVersion", quote(buildOptions.getExasolDbVersions().get(0)));
}
- // [impl->dsn~customize-build-process.ci-build~0]
- return new ContentCustomizingTemplate(template,
- new GitHubWorkflowStepCustomizer(findCustomizations(CI_BUILD_WORKFLOW_NAME), buildType.buildJobId));
+ final String buildJobId = buildType.buildJobId;
+ return createTemplate(template, CI_BUILD_WORKFLOW_NAME, buildJobId);
+ }
+
+ private FileTemplate createTemplate(final FileTemplateFromResource template, final String workflowName,
+ final String buildJobId) {
+ final Optional workflow = buildOptions.getWorkflow(workflowName);
+ final List customizations = workflow.map(CustomWorkflow::getSteps)
+ .orElseGet(Collections::emptyList);
+ final String environmentName = workflow.map(CustomWorkflow::getEnvironment).orElse(null);
+ return new ContentCustomizingTemplate(template, new GitHubWorkflowCustomizer(
+ // [impl->dsn~customize-build-process.ci-build~0]
+ new GitHubWorkflowStepCustomizer(customizations, buildJobId),
+ // [impl->dsn~customize-build-process.ci-build.environment~1]
+ new GitHubWorkflowEnvironmentCustomizer(buildJobId, environmentName)));
}
private List findCustomizations(final String workflowName) {
@@ -94,8 +106,9 @@ private FileTemplate createCustomizedWorkflow(final String workflowName, final S
final FileTemplateFromResource template = new FileTemplateFromResource(WORKFLOW_PATH + workflowName,
REQUIRE_EXACT);
templateCustomizer.accept(template);
+ final List customizations = findCustomizations(workflowName);
return new ContentCustomizingTemplate(template,
- new GitHubWorkflowStepCustomizer(findCustomizations(workflowName), jobName));
+ new GitHubWorkflowCustomizer(new GitHubWorkflowStepCustomizer(customizations, jobName)));
}
enum CiTemplateType {
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflow.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflow.java
index ddcc2e47..d4c25f31 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflow.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflow.java
@@ -98,6 +98,14 @@ Map getEnv() {
return asMap(rawJob.get("env"));
}
+ public String getEnvironment() {
+ return (String) rawJob.get("environment");
+ }
+
+ public void setEnvironment(final String environmentName) {
+ rawJob.put("environment", environmentName);
+ }
+
private Predicate super Step> hasId(final String id) {
return step -> step.getId().equals(id);
}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowCustomizer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowCustomizer.java
new file mode 100644
index 00000000..40de021f
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowCustomizer.java
@@ -0,0 +1,47 @@
+package com.exasol.projectkeeper.validators.files;
+
+import static java.util.Arrays.asList;
+
+import java.util.List;
+
+/**
+ * This class customizes a GitHub workflow by delegating to a list of {@link WorkflowCustomizer}s.
+ */
+class GitHubWorkflowCustomizer implements ContentCustomizingTemplate.ContentCustomizer {
+ private static final String GENERATED_COMMENT = "# This file was generated by Project Keeper.\n";
+ private final GitHubWorkflowIO yaml;
+ private final List customizer;
+
+ GitHubWorkflowCustomizer(final WorkflowCustomizer... customizer) {
+ this(GitHubWorkflowIO.create(), asList(customizer));
+ }
+
+ GitHubWorkflowCustomizer(final GitHubWorkflowIO yaml, final List customizer) {
+ this.yaml = yaml;
+ this.customizer = customizer;
+ }
+
+ @Override
+ public String customizeContent(final String content) {
+ final GitHubWorkflow workflow = yaml.loadWorkflow(content);
+ customizeWorkflow(workflow);
+ return GENERATED_COMMENT + yaml.dumpWorkflow(workflow);
+ }
+
+ private void customizeWorkflow(final GitHubWorkflow workflow) {
+ this.customizer.forEach(c -> c.applyCustomization(workflow));
+ }
+
+ /**
+ * Interface for customizing a GitHub workflow. Implementations of this interface can modify the given workflow as
+ * required.
+ */
+ interface WorkflowCustomizer {
+ /**
+ * Apply the customization to the given workflow.
+ *
+ * @param workflow workflow to customize
+ */
+ void applyCustomization(GitHubWorkflow workflow);
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowEnvironmentCustomizer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowEnvironmentCustomizer.java
new file mode 100644
index 00000000..1bd64dcc
--- /dev/null
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowEnvironmentCustomizer.java
@@ -0,0 +1,29 @@
+package com.exasol.projectkeeper.validators.files;
+
+import com.exasol.errorreporting.ExaError;
+import com.exasol.projectkeeper.validators.files.GitHubWorkflow.Job;
+
+class GitHubWorkflowEnvironmentCustomizer implements GitHubWorkflowCustomizer.WorkflowCustomizer {
+
+ private final String environmentName;
+ private final String jobId;
+
+ GitHubWorkflowEnvironmentCustomizer(final String jobId, final String environmentName) {
+ this.jobId = jobId;
+ this.environmentName = environmentName;
+ }
+
+ // [impl->dsn~customize-build-process.ci-build.environment~1]
+ @Override
+ public void applyCustomization(final GitHubWorkflow workflow) {
+ if (environmentName == null) {
+ return;
+ }
+ final Job job = workflow.getJob(jobId);
+ if (job == null) {
+ throw new IllegalArgumentException(ExaError.messageBuilder("E-PK-CORE-207")
+ .message("GitHub Workflow does not have a job with ID {{job id}}", jobId).toString());
+ }
+ job.setEnvironment(this.environmentName);
+ }
+}
diff --git a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizer.java b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizer.java
index 72136c9d..c9a27417 100644
--- a/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizer.java
+++ b/project-keeper/src/main/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizer.java
@@ -5,31 +5,17 @@
import com.exasol.projectkeeper.shared.config.workflow.StepCustomization;
import com.exasol.projectkeeper.validators.files.GitHubWorkflow.Job;
-class GitHubWorkflowStepCustomizer implements ContentCustomizingTemplate.ContentCustomizer {
- private static final String GENERATED_COMMENT = "# This file was generated by Project Keeper.\n";
+class GitHubWorkflowStepCustomizer implements GitHubWorkflowCustomizer.WorkflowCustomizer {
private final List customizations;
- private final GitHubWorkflowIO yaml;
private final String jobId;
GitHubWorkflowStepCustomizer(final List customizations, final String jobId) {
- this(GitHubWorkflowIO.create(), customizations, jobId);
- }
-
- GitHubWorkflowStepCustomizer(final GitHubWorkflowIO yaml, final List customizations,
- final String jobId) {
- this.yaml = yaml;
this.customizations = customizations;
this.jobId = jobId;
}
@Override
- public String customizeContent(final String content) {
- final GitHubWorkflow workflow = yaml.loadWorkflow(content);
- customizeWorkflow(workflow);
- return GENERATED_COMMENT + yaml.dumpWorkflow(workflow);
- }
-
- private void customizeWorkflow(final GitHubWorkflow workflow) {
+ public void applyCustomization(final GitHubWorkflow workflow) {
final Job job = workflow.getJob(jobId);
for (final StepCustomization customization : customizations) {
applyCustomization(job, customization);
diff --git a/project-keeper/src/main/resources/templates/.github/workflows/broken_links_checker.yml b/project-keeper/src/main/resources/templates/.github/workflows/broken_links_checker.yml
index d7a38b46..39612b76 100644
--- a/project-keeper/src/main/resources/templates/.github/workflows/broken_links_checker.yml
+++ b/project-keeper/src/main/resources/templates/.github/workflows/broken_links_checker.yml
@@ -13,6 +13,8 @@ on:
jobs:
linkChecker:
runs-on: ubuntu-latest
+ permissions:
+ contents: read
defaults:
run:
shell: "bash"
diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml
index 5e8cd865..801937f8 100644
--- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml
+++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-db-version-matrix.yml
@@ -14,7 +14,6 @@ jobs:
shell: "bash"
permissions:
contents: read
- checks: write # Allow scacap/action-surefire-report
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.exasol_db_version }}
cancel-in-progress: true
diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml
index a3f12f55..07e17a51 100644
--- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml
+++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-native-build.yml
@@ -10,6 +10,8 @@ jobs:
build:
name: Build native-image on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
+ permissions:
+ contents: read
defaults:
run:
shell: "bash"
diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-next-java.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-next-java.yml
index 07b10b07..d33f3c0a 100644
--- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build-next-java.yml
+++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build-next-java.yml
@@ -15,7 +15,6 @@ jobs:
shell: "bash"
permissions:
contents: read
- checks: write # Allow scacap/action-surefire-report
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -35,9 +34,3 @@ jobs:
mvn --batch-mode --update-snapshots clean package -DtrimStackTrace=false $skipNativeImage \
-Djava.version=17 \
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
- - name: Publish Test Report for Java 17
- uses: scacap/action-surefire-report@v1
- if: ${{ always() && github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- fail_if_no_tests: false
diff --git a/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml b/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml
index 69c260db..b10243b5 100644
--- a/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml
+++ b/project-keeper/src/main/resources/templates/.github/workflows/ci-build.yml
@@ -13,7 +13,6 @@ jobs:
shell: "bash"
permissions:
contents: read
- checks: write # Allow scacap/action-surefire-report
issues: read # Required for PK verify-release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReaderTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReaderTest.java
index e106b010..e7c6db62 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReaderTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/config/ProjectKeeperConfigReaderTest.java
@@ -260,20 +260,7 @@ static Stream invalidConfig() {
stepId: step-id-to-replace
content:
""", equalTo(
- "E-PK-CORE-202: Missing content in step customization of file '.project-keeper.yml'. Add content to the step customization.")),
- Arguments.of("workflow: missing step customization list", """
- build:
- workflows:
- - name: ci-build.yml
- """, equalTo(
- "E-PK-CORE-203: Missing customized steps for workflow 'ci-build.yml' in file '.project-keeper.yml'. Add at least one step or remove the workflow.")),
- Arguments.of("workflow: empty step customization list", """
- build:
- workflows:
- - name: ci-build.yml
- stepCustomizations:
- """, equalTo(
- "E-PK-CORE-203: Missing customized steps for workflow 'ci-build.yml' in file '.project-keeper.yml'. Add at least one step or remove the workflow.")));
+ "E-PK-CORE-202: Missing content in step customization of file '.project-keeper.yml'. Add content to the step customization.")));
}
@ParameterizedTest(name = "{0}")
@@ -287,6 +274,16 @@ void testReadingFails(final String testName, final String content, final Matcher
assertThat(testName, exception.getMessage(), expectedErrorMessage);
}
+ @Test
+ void readWorkflowWithoutCustomization() throws IOException {
+ writeProjectKeeperConfig("""
+ build:
+ workflows:
+ - name: ci-build.yml
+ """);
+ assertThat(readConfig().getCiBuildConfig().getWorkflows().get(0).getSteps(), empty());
+ }
+
@Test
void readWorkflowCustomization() throws IOException {
writeProjectKeeperConfig("""
@@ -331,6 +328,27 @@ void readWorkflowStepAction(final String action, final StepCustomization.Type ex
equalTo(expected));
}
+ @Test
+ void readWorkflowWithoutEnvironment() throws IOException {
+ writeProjectKeeperConfig("""
+ build:
+ workflows:
+ - name: ci-build.yml
+ """);
+ assertThat(readConfig().getCiBuildConfig().getWorkflows().get(0).getEnvironment(), nullValue());
+ }
+
+ @Test
+ void readWorkflowWithEnvironment() throws IOException {
+ writeProjectKeeperConfig("""
+ build:
+ workflows:
+ - name: ci-build.yml
+ environment: aws
+ """);
+ assertThat(readConfig().getCiBuildConfig().getWorkflows().get(0).getEnvironment(), equalTo("aws"));
+ }
+
@Test
void notInProjectRoot() throws IOException {
Files.delete(this.tempDir.resolve(".git"));
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java
index 42c685f8..46a1036c 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/dependencies/DependenciesValidatorIT.java
@@ -101,7 +101,7 @@ void testBrokenLinkReplacing() throws IOException {
private void createExamplePomFile() throws IOException {
final TestMavenModel pomModel = new TestMavenModel();
- pomModel.addDependency("error-reporting-java", "com.exasol", "compile", "0.1.0");
+ pomModel.addDependency("error-reporting-java", "com.exasol", "compile", "1.0.1");
pomModel.configureAssemblyPluginFinalName();
pomModel.writeAsPomToProject(this.projectDir);
}
@@ -113,7 +113,7 @@ private void createExamplePomFileWithNonDefaultRepo() throws IOException {
exasolRepo.setUrl("https://repo1.maven.org/maven2");
exasolRepo.setId("maven.exasol.com");
pomModel.addRepository(exasolRepo);
- pomModel.addDependency("exasol-jdbc", "com.exasol", "compile", "7.0.4");
+ pomModel.addDependency("exasol-jdbc", "com.exasol", "compile", "24.1.0");
pomModel.writeAsPomToProject(this.projectDir);
}
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGeneratorTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGeneratorTest.java
index f8764842..d5eb8c6b 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGeneratorTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/CiBuildWorkflowGeneratorTest.java
@@ -133,6 +133,21 @@ void ciBuildMatrixBuildSingleVersion() {
"${{ env.SONAR_TOKEN != null && matrix.exasol_db_version == env.DEFAULT_EXASOL_DB_VERSION }}")));
}
+ // [utest->dsn~customize-build-process.ci-build.environment~1]
+ @Test
+ void ciBuildCustomEnvironment() {
+ final Job job = ciBuildContent(BuildOptions.builder()
+ .workflows(List.of(CustomWorkflow.builder().workflowName("ci-build.yml").environment("aws").build())))
+ .getJob("build");
+ assertThat(job.getEnvironment(), equalTo("aws"));
+ }
+
+ @Test
+ void ciBuildDefaultHasNoEnvironment() {
+ final Job job = ciBuildContent(BuildOptions.builder()).getJob("build");
+ assertThat(job.getEnvironment(), nullValue());
+ }
+
// [utest->dsn~release-workflow.deploy-maven-central~1]
@Test
void releaseBuildWithMavenRelease() {
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/FileTemplatesFactoryTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/FileTemplatesFactoryTest.java
index 36f8305a..7dd05ac6 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/FileTemplatesFactoryTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/FileTemplatesFactoryTest.java
@@ -26,7 +26,6 @@
@ExtendWith(MockitoExtension.class)
class FileTemplatesFactoryTest {
private static final String OWN_VERSION = "version";
- private static final String NEWLINE = System.lineSeparator();
@Mock
Logger loggerMock;
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowCustomizerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowCustomizerTest.java
new file mode 100644
index 00000000..06c5379d
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowCustomizerTest.java
@@ -0,0 +1,104 @@
+package com.exasol.projectkeeper.validators.files;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.startsWith;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.inOrder;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.exasol.projectkeeper.shared.config.workflow.WorkflowStep;
+
+@ExtendWith(MockitoExtension.class)
+class GitHubWorkflowCustomizerTest {
+
+ @Mock
+ GitHubWorkflowCustomizer.WorkflowCustomizer customizerMock1;
+ @Mock
+ GitHubWorkflowCustomizer.WorkflowCustomizer customizerMock2;
+
+ @Test
+ void startsWithGeneratedComment() {
+ final String yaml = getCustomizedContent("""
+ jobs:
+ build:
+ steps:
+ """);
+ assertThat(yaml, startsWith("# This file was generated by Project Keeper.\n"));
+ }
+
+ @Test
+ void noChangesWithEmptyCustomizerList() {
+ assertThat(getCustomizedContent("""
+ jobs:
+ build:
+ steps:
+ """), equalTo("""
+ # This file was generated by Project Keeper.
+ jobs:
+ build: {
+ steps: null
+ }
+ """));
+ }
+
+ @Test
+ void noChangesWithNoOpCustomizer() {
+ assertThat(getCustomizedContent("""
+ jobs:
+ build:
+ steps:
+ """, (workflow) -> {
+ }), equalTo("""
+ # This file was generated by Project Keeper.
+ jobs:
+ build: {
+ steps: null
+ }
+ """));
+ }
+
+ @Test
+ void customizerUpdatesWorkflow() {
+ assertThat(getCustomizedContent("""
+ jobs:
+ build:
+ steps:
+ - id: step1
+ """, (workflow) -> {
+ workflow.getJob("build").insertStepAfter("step1", WorkflowStep.createStep(Map.of("id", "step2")));
+ }), equalTo("""
+ # This file was generated by Project Keeper.
+ jobs:
+ build:
+ steps:
+ - {
+ id: step1
+ }
+ - {
+ id: step2
+ }
+ """));
+ }
+
+ @Test
+ void customizerCalledInOrder() {
+ new GitHubWorkflowCustomizer(customizerMock1, customizerMock2).customizeContent("");
+ final InOrder inOrder = inOrder(customizerMock1, customizerMock2);
+ inOrder.verify(customizerMock1).applyCustomization(any());
+ inOrder.verify(customizerMock2).applyCustomization(any());
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ private String getCustomizedContent(final String workflowTemplate,
+ final GitHubWorkflowCustomizer.WorkflowCustomizer... customizer) {
+ return new GitHubWorkflowCustomizer(customizer).customizeContent(workflowTemplate);
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowEnvironmentCustomizerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowEnvironmentCustomizerTest.java
new file mode 100644
index 00000000..13744964
--- /dev/null
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowEnvironmentCustomizerTest.java
@@ -0,0 +1,50 @@
+package com.exasol.projectkeeper.validators.files;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+class GitHubWorkflowEnvironmentCustomizerTest {
+
+ @Test
+ void updateEnvironment() {
+ final GitHubWorkflow workflow = customize("""
+ jobs:
+ build:
+ steps:
+ """, new GitHubWorkflowEnvironmentCustomizer("build", "my-env"));
+ assertThat(workflow.getJob("build").getEnvironment(), equalTo("my-env"));
+ }
+
+ @Test
+ void environmentIsNull() {
+ final GitHubWorkflow workflow = customize("""
+ jobs:
+ build:
+ steps:
+ """, new GitHubWorkflowEnvironmentCustomizer("build", null));
+ assertThat(workflow.getJob("build").getEnvironment(), nullValue());
+ }
+
+ @Test
+ void unknownJobId() {
+ final GitHubWorkflowEnvironmentCustomizer customizer = new GitHubWorkflowEnvironmentCustomizer("unknown-job",
+ "my-env");
+ final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> customize("""
+ jobs:
+ build:
+ steps:
+ """, customizer));
+ assertThat(exception.getMessage(),
+ equalTo("E-PK-CORE-207: GitHub Workflow does not have a job with ID 'unknown-job'"));
+ }
+
+ GitHubWorkflow customize(final String yaml, final GitHubWorkflowCustomizer.WorkflowCustomizer customizer) {
+ final GitHubWorkflow workflow = GitHubWorkflowIO.create().loadWorkflow(yaml);
+ customizer.applyCustomization(workflow);
+ return workflow;
+ }
+}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizerTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizerTest.java
index 1e93e207..6e2d0ba8 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizerTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowStepCustomizerTest.java
@@ -214,6 +214,7 @@ private GitHubWorkflow validate(final String workflowTemplate, final StepCustomi
}
private String getCustomizedContent(final String workflowTemplate, final StepCustomization... customizations) {
- return new GitHubWorkflowStepCustomizer(asList(customizations), "build").customizeContent(workflowTemplate);
+ return new GitHubWorkflowCustomizer(new GitHubWorkflowStepCustomizer(asList(customizations), "build"))
+ .customizeContent(workflowTemplate);
}
}
diff --git a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowTest.java b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowTest.java
index 212997a8..6d3995a9 100644
--- a/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowTest.java
+++ b/project-keeper/src/test/java/com/exasol/projectkeeper/validators/files/GitHubWorkflowTest.java
@@ -322,6 +322,17 @@ void insertStepMissing() {
"E-PK-CORE-205: No step found for id 'missing' in {steps=[{id=step-to-replace, name=Old Step}]}"));
}
+ @Test
+ void setEnvironment() {
+ final Job job = read("""
+ jobs:
+ build:
+ steps:
+ """).getJob("build");
+ job.setEnvironment("my-env");
+ assertThat(job.getEnvironment(), equalTo("my-env"));
+ }
+
private GitHubWorkflow read(final String yaml) {
return GitHubWorkflowIO.create().loadWorkflow(yaml);
}
diff --git a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/config/workflow/CustomWorkflow.java b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/config/workflow/CustomWorkflow.java
index f3d7a9a3..6a393a67 100644
--- a/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/config/workflow/CustomWorkflow.java
+++ b/shared-model-classes/src/main/java/com/exasol/projectkeeper/shared/config/workflow/CustomWorkflow.java
@@ -10,10 +10,12 @@
public final class CustomWorkflow {
private final String workflowName;
+ private final String environment;
private final List steps;
private CustomWorkflow(final Builder builder) {
this.workflowName = Objects.requireNonNull(builder.workflowName, "workflowName");
+ this.environment = builder.environment;
this.steps = builder.steps == null ? emptyList() : builder.steps;
}
@@ -35,6 +37,16 @@ public List getSteps() {
return steps;
}
+ /**
+ * Get the GitHub environment for the workflow, e.g. {@code aws}. If this is {@code null}, the workflow will not use
+ * an environment.
+ *
+ * @return the GitHub environment
+ */
+ public String getEnvironment() {
+ return environment;
+ }
+
/**
* Create a new builder for the {@link CustomWorkflow}.
*
@@ -46,12 +58,13 @@ public static Builder builder() {
@Override
public String toString() {
- return "WorkflowOptions [workflowName=" + workflowName + ", steps=" + steps + "]";
+ return "WorkflowOptions [workflowName=" + workflowName + ", environment=" + environment + ", steps=" + steps
+ + "]";
}
@Override
public int hashCode() {
- return Objects.hash(workflowName, steps);
+ return Objects.hash(workflowName, environment, steps);
}
@Override
@@ -66,7 +79,8 @@ public boolean equals(final Object obj) {
return false;
}
final CustomWorkflow other = (CustomWorkflow) obj;
- return Objects.equals(workflowName, other.workflowName) && Objects.equals(steps, other.steps);
+ return Objects.equals(workflowName, other.workflowName) && Objects.equals(environment, other.environment)
+ && Objects.equals(steps, other.steps);
}
/**
@@ -74,6 +88,7 @@ public boolean equals(final Object obj) {
*/
public static class Builder {
private String workflowName;
+ private String environment;
private List steps = null;
private Builder() {
@@ -115,6 +130,18 @@ public Builder steps(final List steps) {
return this;
}
+ /**
+ * Set GitHub environment for the workflow, e.g. {@code aws}. If this is {@code null}, the workflow will not use
+ * an environment.
+ *
+ * @param environment the GitHub environment
+ * @return the builder instance
+ */
+ public Builder environment(final String environment) {
+ this.environment = environment;
+ return this;
+ }
+
/**
* Build the BuildWorkflow instance.
*