From 144adea8c9392df12ac688a5bcd521a7fa286e4a Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 19:23:05 +0100 Subject: [PATCH 1/9] add validation workflow --- .github/workflows/validate-openapi.yml | 125 +++++++++++++++++++++++++ .gitignore | 5 + openapitools.json | 7 ++ 3 files changed, 137 insertions(+) create mode 100644 .github/workflows/validate-openapi.yml create mode 100644 openapitools.json diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml new file mode 100644 index 0000000..527c0d9 --- /dev/null +++ b/.github/workflows/validate-openapi.yml @@ -0,0 +1,125 @@ +name: Validate OpenAPI Spec and Generated Client Code + +on: + pull_request: + branches: [main] + types: [opened, reopened, edited, synchronize] + +jobs: + validate-openapi: + name: Validate OpenAPI Spec + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + - name: Run Gradle to generate OpenAPI docs + working-directory: ./server/application-server + run: ./gradlew generateOpenApiDocs + + - name: Check for OpenAPI spec differences + id: check_openapi + run: | + if git diff --exit-code ./server/application-server/openapi.yml; then + echo "OpenAPI spec is up-to-date." + else + echo "OpenAPI specs in openapi.yml differ from the generated version." + exit 1 + + - name: Post comment about OpenAPI validation failure + if: failure() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: openapi-validation-yml + message: | + 🚨 **OpenAPI Validation Failed** 🚨 + + The OpenAPI specs in `openapi.yml` differ from the generated version. + Please update the OpenAPI specs by running: + ```bash + cd ./server/application-server + ./gradlew generateOpenApiDocs + ``` + Commit and push the updated file. + + - name: Remove sticky comment on OpenAPI validation success + if: success() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: openapi-validation-yml + delete: true + + validate-client-code: + name: Validate Client Code + runs-on: ubuntu-latest + needs: validate-openapi + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install OpenAPI Generator CLI + run: npm install -g @openapitools/openapi-generator-cli + + - name: Generate client code + run: | + npx openapi-generator-cli generate \ + -i ./server/application-server/openapi.yaml \ + -g typescript-angular \ + -o ./client/src/app/core/modules/openapi \ + --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model + + - name: Check for client code differences + id: check_client_code + run: | + if git diff --exit-code ./client/src/app/core/modules/openapi; then + echo "Client code is up-to-date." + else + echo "Client code in /client/src/app/core/modules/openapi is not up-to-date." + exit 1 + + - name: Post comment about client code validation failure + if: failure() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: client-code-validation + message: | + 🚨 **Client Code Validation Failed** 🚨 + + The client code in `/client/src/app/core/modules/openapi` is not up-to-date. + Please regenerate the client code by running: + ```bash + npm install -g @openapitools/openapi-generator-cli + cd ./server/application-server + npx openapi-generator-cli generate -i ./server/application-server/openapi.yaml -g typescript-angular -o ../../client/src/app/core/modules/openapi --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model + ``` + Commit and push the updated files. + + - name: Remove sticky comment on client code validation success + if: success() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: client-code-validation + delete: true \ No newline at end of file diff --git a/.gitignore b/.gitignore index f39ecdb..1cb557b 100644 --- a/.gitignore +++ b/.gitignore @@ -162,6 +162,11 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. .idea/ +# Node +/node_modules +npm-debug.log +yarn-error.log + CMakeLists.txt.user CMakeCache.txt CMakeFiles diff --git a/openapitools.json b/openapitools.json new file mode 100644 index 0000000..f80faaa --- /dev/null +++ b/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.9.0" + } +} From f90e77929ae85d9046733c2b612d09b7c159046c Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 21:26:47 +0100 Subject: [PATCH 2/9] update active profiles and seperate dev profile --- .gitignore | 2 + server/application-server/README.md | 6 +- server/application-server/build.gradle | 93 +++++++++++++------ server/application-server/openapi.yaml | 2 +- .../tum/cit/aet/helios/config/NatsConfig.java | 23 +++++ .../helios/syncing/NatsConsumerService.java | 32 ++++--- .../src/main/resources/application-dev.yml | 41 ++++++++ .../main/resources/application-openapi.yml | 37 ++++++++ .../src/main/resources/application.yml | 39 -------- 9 files changed, 195 insertions(+), 80 deletions(-) create mode 100644 server/application-server/src/main/resources/application-dev.yml create mode 100644 server/application-server/src/main/resources/application-openapi.yml diff --git a/.gitignore b/.gitignore index 1cb557b..cb843a5 100644 --- a/.gitignore +++ b/.gitignore @@ -167,6 +167,8 @@ cython_debug/ npm-debug.log yarn-error.log +.sdkmanrc + CMakeLists.txt.user CMakeCache.txt CMakeFiles diff --git a/server/application-server/README.md b/server/application-server/README.md index 69dcecd..aabfc92 100644 --- a/server/application-server/README.md +++ b/server/application-server/README.md @@ -4,7 +4,7 @@ Helios Application Server is a [Spring Boot application](https://spring.io/proje ## Prerequisites -- [Java 22](https://www.oracle.com/java/technologies/downloads/) (or higher) +- [Java 21](https://www.oracle.com/java/technologies/downloads/) (or higher) - [Postgres 16](https://www.postgresql.org/download/) (is automatically started with the provided Docker Compose setup) ## Getting Started @@ -34,10 +34,10 @@ Copy the file `.env.example` to `.env` and adjust the values to your needs. It i $ cp .env.example .env ``` -**4. Run the Application** +**4. Run the Application in Development Mode** ```bash -$ ./gradlew bootRun +$ ./gradlew bootRunDev ``` The application will be accessible at [http://localhost:8080/status/health](http://localhost:8080/status/health) diff --git a/server/application-server/build.gradle b/server/application-server/build.gradle index c0c84ec..73822a9 100644 --- a/server/application-server/build.gradle +++ b/server/application-server/build.gradle @@ -1,3 +1,5 @@ +import org.springframework.boot.gradle.tasks.run.BootRun + plugins { id 'java' id 'war' @@ -21,32 +23,17 @@ repositories { mavenCentral() } -def loadEnvFile() { - def env = [:] - def envFile = file('.env') - if (envFile.exists()) { - envFile.eachLine { line -> - line = line.trim() - if (line && !line.startsWith('#')) { - def keyValue = line.split('=', 2) - if (keyValue.length == 2) { - def key = keyValue[0].trim() - def value = keyValue[1].trim() - // Remove surrounding quotes if present - if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { - value = value.substring(1, value.length() - 1) - } - env[key] = value - } - } +// Detect if the generateOpenApiDocs task is being executed +gradle.taskGraph.whenReady { taskGraph -> + if (taskGraph.hasTask(':generateOpenApiDocs')) { + println "Generating OpenAPI documentation..." + // Add the H2 dependency dynamically + dependencies { + runtimeOnly 'com.h2database:h2' } - } else { - println ".env file not found in project root." } - return env } - dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' @@ -62,17 +49,71 @@ dependencies { testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } -tasks.named('test') { - useJUnitPlatform() +springBoot { + mainClass = "de.tum.cit.aet.helios.HeliosApplication" +} + +// Custom bootRun task to force the user to specify an active profile +tasks.named("bootRun") { + doFirst { + def activeProfile = System.getProperty("spring.profiles.active") + ?: project.findProperty("spring.profiles.active") + ?: System.getenv("SPRING_PROFILES_ACTIVE") + if (!activeProfile) { + throw new GradleException(""" + Error: 'spring.profiles.active' is not set. + + Please specify an active profile using one of the following methods: + + - Use a predefined task like 'bootRunDev'. + - Set the 'SPRING_PROFILES_ACTIVE' environment variable. + - Use the '-Dspring.profiles.active=' JVM argument. + + Available profiles: dev, openapi (Don't use this profile directly). + + Examples: + + 1. Using predefined task: + ./gradlew bootRunDev + + 2. Setting environment variable: + export SPRING_PROFILES_ACTIVE=dev + ./gradlew bootRun + + 3. Passing JVM argument: + ./gradlew -Dspring.profiles.active=dev bootRun + + 4. Using project property: + ./gradlew bootRun -Pspring.profiles.active=dev + """ + ) + } else { + println "Running with profile: ${activeProfile}" + systemProperty "spring.profiles.active", activeProfile + } + } +} + +tasks.register("bootRunDev", BootRun) { + group = "application" + description = "Runs the Spring Boot application with the dev profile" + // Set the active profile to 'dev' + systemProperty "spring.profiles.active", "dev" + classpath = sourceSets.main.runtimeClasspath + mainClass.set("de.tum.cit.aet.helios.HeliosApplication") } + openApi { apiDocsUrl = 'http://localhost:8080/v3/api-docs.yaml' outputDir = file('.') outputFileName = 'openapi.yaml' - def envVars = loadEnvFile() + // Set the active profile to 'openapi' customBootRun { - args.set(["--spring.profiles.active=dev", "--DATASOURCE_URL=${envVars['DATASOURCE_URL'] ?: ''}", "--DATASOURCE_USERNAME=${envVars['DATASOURCE_USERNAME'] ?: ''}", "--DATASOURCE_PASSWORD=${envVars['DATASOURCE_PASSWORD'] ?: ''}"]) + args.set(["--spring.profiles.active=openapi"]) } +} +tasks.named('test') { + useJUnitPlatform() } \ No newline at end of file diff --git a/server/application-server/openapi.yaml b/server/application-server/openapi.yaml index 6ebda1e..29604f8 100644 --- a/server/application-server/openapi.yaml +++ b/server/application-server/openapi.yaml @@ -22,7 +22,7 @@ paths: "200": description: OK content: - '*/*': + application/json: schema: type: string components: {} diff --git a/server/application-server/src/main/java/de/tum/cit/aet/helios/config/NatsConfig.java b/server/application-server/src/main/java/de/tum/cit/aet/helios/config/NatsConfig.java index 6ba2a6e..29eb86a 100644 --- a/server/application-server/src/main/java/de/tum/cit/aet/helios/config/NatsConfig.java +++ b/server/application-server/src/main/java/de/tum/cit/aet/helios/config/NatsConfig.java @@ -1,5 +1,7 @@ package de.tum.cit.aet.helios.config; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -13,14 +15,35 @@ @Configuration public class NatsConfig { + private static final Logger logger = LoggerFactory.getLogger(NatsConfig.class); + + @Value("${nats.enabled}") + private boolean isNatsEnabled; + @Value("${nats.server}") private String natsServer; @Value("${nats.auth.token}") private String natsAuthToken; + private final Environment environment; + + @Autowired + public NatsConfig(Environment env) { + this.environment = env; + } + @Bean public Connection natsConnection() throws Exception { + if (environment.matchesProfiles("openapi")) { + logger.info("NOpenAPI profile detected. Skipping NATS connection."); + return null; + } + + if (!isNatsEnabled) { + logger.info("NATS is disabled. Skipping NATS connection."); + return null; + } Options options = Options.builder().server(natsServer).token(natsAuthToken).build(); return Nats.connect(options); diff --git a/server/application-server/src/main/java/de/tum/cit/aet/helios/syncing/NatsConsumerService.java b/server/application-server/src/main/java/de/tum/cit/aet/helios/syncing/NatsConsumerService.java index 97e4dcd..8f0b3b3 100644 --- a/server/application-server/src/main/java/de/tum/cit/aet/helios/syncing/NatsConsumerService.java +++ b/server/application-server/src/main/java/de/tum/cit/aet/helios/syncing/NatsConsumerService.java @@ -14,9 +14,10 @@ import io.nats.client.Options; import io.nats.client.StreamContext; import io.nats.client.api.ConsumerConfiguration; -import io.nats.client.api.ConsumerInfo; import io.nats.client.api.DeliverPolicy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; @@ -55,19 +56,28 @@ public class NatsConsumerService { @Value("${nats.auth.token}") private String natsAuthToken; + private final Environment environment; + private Connection natsConnection; private ConsumerContext consumerContext; private final GitHubMessageHandlerRegistry handlerRegistry; - public NatsConsumerService(GitHubMessageHandlerRegistry handlerRegistry) { + @Autowired + public NatsConsumerService(Environment environment, GitHubMessageHandlerRegistry handlerRegistry) { + this.environment = environment; this.handlerRegistry = handlerRegistry; } @EventListener(ApplicationReadyEvent.class) public void init() { + if (environment.matchesProfiles("openapi")) { + logger.info("OpenAPI profile detected. Skipping NATS initialization."); + return; + } + if (!isNatsEnabled) { - logger.info("NATS is disabled. Skipping initialization."); + logger.info("NATS is disabled. Skipping NATS initialization."); return; } @@ -108,7 +118,7 @@ private Options buildNatsOptions() { private void setupConsumer(Connection connection) throws IOException, InterruptedException { try { StreamContext streamContext = connection.getStreamContext("github"); - + // Check if consumer already exists if (durableConsumerName != null && !durableConsumerName.isEmpty()) { try { @@ -121,13 +131,13 @@ private void setupConsumer(Connection connection) throws IOException, Interrupte if (consumerContext == null) { logger.info("Setting up consumer for subjects: {}", Arrays.toString(getSubjects())); ConsumerConfiguration.Builder consumerConfigBuilder = ConsumerConfiguration.builder() - .filterSubjects(getSubjects()) - .deliverPolicy(DeliverPolicy.ByStartTime) - .startTime(ZonedDateTime.now().minusDays(timeframe)); - + .filterSubjects(getSubjects()) + .deliverPolicy(DeliverPolicy.ByStartTime) + .startTime(ZonedDateTime.now().minusDays(timeframe)); + if (durableConsumerName != null && !durableConsumerName.isEmpty()) { consumerConfigBuilder.durable(durableConsumerName); - } + } ConsumerConfiguration consumerConfig = consumerConfigBuilder.build(); consumerContext = streamContext.createOrUpdateConsumer(consumerConfig); @@ -170,7 +180,7 @@ private void handleMessage(Message msg) { /** * Subjects to monitor. - * + * * @return The subjects to monitor. */ private String[] getSubjects() { @@ -187,7 +197,7 @@ private String[] getSubjects() { /** * Get subject prefix from ownerWithName for the given repository. - * + * * @param ownerWithName The owner and name of the repository. * @return The subject prefix, i.e. "github.owner.name" sanitized. * @throws IllegalArgumentException if the repository string is improperly diff --git a/server/application-server/src/main/resources/application-dev.yml b/server/application-server/src/main/resources/application-dev.yml new file mode 100644 index 0000000..baae8d7 --- /dev/null +++ b/server/application-server/src/main/resources/application-dev.yml @@ -0,0 +1,41 @@ +spring: + datasource: + driver-class-name: org.postgresql.Driver + url: ${DATASOURCE_URL} + username: ${DATASOURCE_USERNAME} + password: ${DATASOURCE_PASSWORD} + jpa: + database: POSTGRESQL + show-sql: false + hibernate: + ddl-auto: update + +nats: + enabled: true + timeframe: ${MONITORING_TIMEFRAME:7} + durableConsumerName: "" + server: ${NATS_SERVER} + auth: + token: ${NATS_AUTH_TOKEN} + + +github: + organizationName: ${ORGANIZATION_NAME} + # Can be any OAuth token, such as the PAT + authToken: ${GITHUB_AUTH_TOKEN:} + cache: + enabled: true + ttl: 500 + # in MB + size: 50 + +monitoring: + # List of repositories to monitor in the format owner/repository + # Example: ls1intum/Helios or ls1intum/Helios,ls1intum/Artemis + repositories: ${REPOSITORY_NAME} + runOnStartup: true + # Fetching timeframe in days + timeframe: 7 + # Cooldown in minutes before running the monitoring again + runOnStartupCooldownInMinutes: 15 + repository-sync-cron: "0 0 * * * *" diff --git a/server/application-server/src/main/resources/application-openapi.yml b/server/application-server/src/main/resources/application-openapi.yml new file mode 100644 index 0000000..abc3083 --- /dev/null +++ b/server/application-server/src/main/resources/application-openapi.yml @@ -0,0 +1,37 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb + driver-class-name: org.h2.Driver + username: sa + password: password + jpa: + database-platform: org.hibernate.dialect.H2Dialect + hibernate: + ddl-auto: none + +nats: + enabled: false + timeframe: 0 + server: "" + durableConsumerName: "" + auth: + token: "" + +github: + organizationName: "" + authToken: "" + cache: + enabled: false + ttl: 0 + size: 0 + +monitoring: + repositories: "" + runOnStartup: false + timeframe: 0 + runOnStartupCooldownInMinutes: 0 + repository-sync-cron: "0 0 5 31 2 ?" + +logging: + level: + root: INFO diff --git a/server/application-server/src/main/resources/application.yml b/server/application-server/src/main/resources/application.yml index 0af410e..81d8189 100644 --- a/server/application-server/src/main/resources/application.yml +++ b/server/application-server/src/main/resources/application.yml @@ -3,49 +3,10 @@ spring: name: Helios config: import: optional:file:.env[.properties] - datasource: - driver-class-name: org.postgresql.Driver - url: ${DATASOURCE_URL} - username: ${DATASOURCE_USERNAME} - password: ${DATASOURCE_PASSWORD} - jpa: - database: POSTGRESQL - show-sql: false - hibernate: - ddl-auto: update springdoc: default-produces-media-type: application/json -nats: - enabled: true - timeframe: ${MONITORING_TIMEFRAME:7} - durableConsumerName: "" - server: ${NATS_SERVER} - auth: - token: ${NATS_AUTH_TOKEN} - -github: - organizationName: ${ORGANIZATION_NAME} - # Can be any OAuth token, such as the PAT - authToken: ${GITHUB_AUTH_TOKEN:} - cache: - enabled: true - ttl: 500 - # in MB - size: 50 - -monitoring: - # List of repositories to monitor in the format owner/repository - # Example: ls1intum/Helios or ls1intum/Helios,ls1intum/Artemis - repositories: ${REPOSITORY_NAME} - runOnStartup: true - # Fetching timeframe in days - timeframe: 7 - # Cooldown in minutes before running the monitoring again - runOnStartupCooldownInMinutes: 15 - repository-sync-cron: "0 0 * * * *" - logging: level: org.kohsuke.github.GitHubClient: DEBUG \ No newline at end of file From bda7c23462cf368702f1b82848dd13a65a3b1c9d Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 21:57:49 +0100 Subject: [PATCH 3/9] update workflow --- .github/workflows/validate-openapi.yml | 44 ++++++++++++++++--- .../application-server/openapitools.json | 0 2 files changed, 37 insertions(+), 7 deletions(-) rename openapitools.json => server/application-server/openapitools.json (100%) diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml index 527c0d9..eb51d42 100644 --- a/.github/workflows/validate-openapi.yml +++ b/.github/workflows/validate-openapi.yml @@ -12,31 +12,53 @@ jobs: permissions: contents: read pull-requests: write + outputs: + CHANGE_DETECTED: ${{ steps.check_changes.outputs.CHANGE_DETECTED }} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Check for changes in specified paths + id: check_changes + run: | + # Check whether server changes, openapi.yaml changes, or client openapi folder changes + CHANGED_PATHS=$(git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }} | grep -E \ + '^(server/application-server/src/main/java/|server/application-server/openapi.yaml|client/src/app/core/modules/openapi/)') + + if [[ -z "$CHANGED_PATHS" ]]; then + echo "CHANGE_DETECTED=true" >> "$GITHUB_OUTPUT" + echo "No OpenAPI changes detected." + else + echo "CHANGE_DETECTED=false" >> "$GITHUB_OUTPUT" + echo "OpenAPI changes detected in the following paths:" + echo "$CHANGED_PATHS" + fi + - name: Set up Java + if: steps.check_changes.outputs.CHANGE_DETECTED == 'true' uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '21' - name: Run Gradle to generate OpenAPI docs + if: steps.check_changes.outputs.CHANGE_DETECTED == 'true' working-directory: ./server/application-server run: ./gradlew generateOpenApiDocs - name: Check for OpenAPI spec differences - id: check_openapi + if: steps.check_changes.outputs.CHANGE_DETECTED == 'true' + id: check_openapi_spec run: | if git diff --exit-code ./server/application-server/openapi.yml; then echo "OpenAPI spec is up-to-date." else echo "OpenAPI specs in openapi.yml differ from the generated version." exit 1 + fi - name: Post comment about OpenAPI validation failure - if: failure() + if: failure() && steps.check_changes.outputs.CHANGE_DETECTED == 'true' uses: marocchino/sticky-pull-request-comment@v2 with: header: openapi-validation-yml @@ -52,7 +74,7 @@ jobs: Commit and push the updated file. - name: Remove sticky comment on OpenAPI validation success - if: success() + if: success() || steps.check_changes.outputs.CHANGE_DETECTED == 'false' uses: marocchino/sticky-pull-request-comment@v2 with: header: openapi-validation-yml @@ -65,25 +87,32 @@ jobs: permissions: contents: read pull-requests: write + env: + CHANGE_DETECTED: ${{needs.validate-openapi.outputs.CHANGE_DETECTED}} steps: - name: Checkout code + if: env.CHANGE_DETECTED == 'true' uses: actions/checkout@v4 - name: Set up Java + if: env.CHANGE_DETECTED == 'true' uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '21' - name: Set up Node.js + if: env.CHANGE_DETECTED == 'true' uses: actions/setup-node@v4 with: node-version: '22' - name: Install OpenAPI Generator CLI + if: env.CHANGE_DETECTED == 'true' run: npm install -g @openapitools/openapi-generator-cli - name: Generate client code + if: env.CHANGE_DETECTED == 'true' run: | npx openapi-generator-cli generate \ -i ./server/application-server/openapi.yaml \ @@ -92,6 +121,7 @@ jobs: --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model - name: Check for client code differences + if: env.CHANGE_DETECTED == 'true' id: check_client_code run: | if git diff --exit-code ./client/src/app/core/modules/openapi; then @@ -101,7 +131,7 @@ jobs: exit 1 - name: Post comment about client code validation failure - if: failure() + if: failure() && env.CHANGE_DETECTED == 'true' uses: marocchino/sticky-pull-request-comment@v2 with: header: client-code-validation @@ -112,13 +142,13 @@ jobs: Please regenerate the client code by running: ```bash npm install -g @openapitools/openapi-generator-cli - cd ./server/application-server - npx openapi-generator-cli generate -i ./server/application-server/openapi.yaml -g typescript-angular -o ../../client/src/app/core/modules/openapi --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model + # In root directory + npx openapi-generator-cli generate -i ./server/application-server/openapi.yaml -g typescript-angular -o ./client/src/app/core/modules/openapi --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model ``` Commit and push the updated files. - name: Remove sticky comment on client code validation success - if: success() + if: success() || env.CHANGE_DETECTED == 'false' uses: marocchino/sticky-pull-request-comment@v2 with: header: client-code-validation diff --git a/openapitools.json b/server/application-server/openapitools.json similarity index 100% rename from openapitools.json rename to server/application-server/openapitools.json From f4c55fd167e4c8d115622d144c2c36bc68b06a25 Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 22:02:18 +0100 Subject: [PATCH 4/9] update workflow --- .github/workflows/validate-openapi.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml index eb51d42..26fce1a 100644 --- a/.github/workflows/validate-openapi.yml +++ b/.github/workflows/validate-openapi.yml @@ -12,18 +12,24 @@ jobs: permissions: contents: read pull-requests: write + env: + # Check whether server changes, openapi.yaml changes, or client openapi folder changes + PATHS_TO_CHECK: | + server/application-server/src/main/java/ + server/application-server/openapi.yaml + client/src/app/core/modules/openapi/ outputs: CHANGE_DETECTED: ${{ steps.check_changes.outputs.CHANGE_DETECTED }} steps: - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Check for changes in specified paths id: check_changes run: | - # Check whether server changes, openapi.yaml changes, or client openapi folder changes - CHANGED_PATHS=$(git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }} | grep -E \ - '^(server/application-server/src/main/java/|server/application-server/openapi.yaml|client/src/app/core/modules/openapi/)') + CHANGED_PATHS=$(git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }} | grep -E "^($(echo "$PATHS_TO_CHECK" | tr '\n' '|'))") if [[ -z "$CHANGED_PATHS" ]]; then echo "CHANGE_DETECTED=true" >> "$GITHUB_OUTPUT" From e43a4c9b5416c55e9e096cd21814db08083e1dcc Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 22:04:30 +0100 Subject: [PATCH 5/9] update workflow --- .github/workflows/validate-openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml index 26fce1a..3ae0a4a 100644 --- a/.github/workflows/validate-openapi.yml +++ b/.github/workflows/validate-openapi.yml @@ -29,7 +29,7 @@ jobs: - name: Check for changes in specified paths id: check_changes run: | - CHANGED_PATHS=$(git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }} | grep -E "^($(echo "$PATHS_TO_CHECK" | tr '\n' '|'))") + CHANGED_PATHS=$(git diff --name-only origin/main ${{ github.head_ref }} | grep -E "^($(echo "$PATHS_TO_CHECK" | tr '\n' '|'))") if [[ -z "$CHANGED_PATHS" ]]; then echo "CHANGE_DETECTED=true" >> "$GITHUB_OUTPUT" From bac39a8f5c08eddf9f6acb741b034b032f259f4a Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 22:08:16 +0100 Subject: [PATCH 6/9] fix workflow --- .github/workflows/validate-openapi.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validate-openapi.yml b/.github/workflows/validate-openapi.yml index 3ae0a4a..32a5d28 100644 --- a/.github/workflows/validate-openapi.yml +++ b/.github/workflows/validate-openapi.yml @@ -26,10 +26,15 @@ jobs: with: fetch-depth: 0 + - name: Fetch all branches + run: | + git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }} + git fetch origin ${{ github.head_ref }}:refs/remotes/origin/${{ github.head_ref }} + - name: Check for changes in specified paths id: check_changes run: | - CHANGED_PATHS=$(git diff --name-only origin/main ${{ github.head_ref }} | grep -E "^($(echo "$PATHS_TO_CHECK" | tr '\n' '|'))") + CHANGED_PATHS=$(git diff --name-only origin/${{ github.base_ref }} origin/${{ github.head_ref }} | grep -E "^($(echo "$PATHS_TO_CHECK" | tr '\n' '|'))") if [[ -z "$CHANGED_PATHS" ]]; then echo "CHANGE_DETECTED=true" >> "$GITHUB_OUTPUT" From b150540be3059a4e6bbc9b9f38cc444e32c4c5b3 Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 22:11:15 +0100 Subject: [PATCH 7/9] add updated client --- .../app/core/modules/openapi/.openapi-generator/FILES | 1 - .../modules/openapi/api/status-controller.service.ts | 10 +++++----- openapitools.json | 7 +++++++ 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 openapitools.json diff --git a/client/src/app/core/modules/openapi/.openapi-generator/FILES b/client/src/app/core/modules/openapi/.openapi-generator/FILES index 0e30f14..fa537d7 100644 --- a/client/src/app/core/modules/openapi/.openapi-generator/FILES +++ b/client/src/app/core/modules/openapi/.openapi-generator/FILES @@ -1,5 +1,4 @@ .gitignore -.openapi-generator-ignore README.md api.module.ts api/api.ts diff --git a/client/src/app/core/modules/openapi/api/status-controller.service.ts b/client/src/app/core/modules/openapi/api/status-controller.service.ts index 626b01f..7dcfcc7 100644 --- a/client/src/app/core/modules/openapi/api/status-controller.service.ts +++ b/client/src/app/core/modules/openapi/api/status-controller.service.ts @@ -95,10 +95,10 @@ export class StatusControllerService implements StatusControllerServiceInterface * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public healthCheck(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: '*/*', context?: HttpContext, transferCache?: boolean}): Observable; - public healthCheck(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: '*/*', context?: HttpContext, transferCache?: boolean}): Observable>; - public healthCheck(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: '*/*', context?: HttpContext, transferCache?: boolean}): Observable>; - public healthCheck(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: '*/*', context?: HttpContext, transferCache?: boolean}): Observable { + public healthCheck(observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable; + public healthCheck(observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public healthCheck(observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable>; + public healthCheck(observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext, transferCache?: boolean}): Observable { let localVarHeaders = this.defaultHeaders; @@ -106,7 +106,7 @@ export class StatusControllerService implements StatusControllerServiceInterface if (localVarHttpHeaderAcceptSelected === undefined) { // to determine the Accept header const httpHeaderAccepts: string[] = [ - '*/*' + 'application/json' ]; localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); } diff --git a/openapitools.json b/openapitools.json new file mode 100644 index 0000000..f80faaa --- /dev/null +++ b/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.9.0" + } +} From db3b52e6e0e35d3c8f0ed50b9116ddd6a0a35e29 Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 22:13:25 +0100 Subject: [PATCH 8/9] test --- .../src/main/java/de/tum/cit/aet/helios/StatusController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java b/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java index bd8d791..47a8031 100644 --- a/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java +++ b/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java @@ -16,3 +16,4 @@ public String healthCheck() { return "ok"; } } + From 0aecc02e579959b8017e92125590521e72aeb72d Mon Sep 17 00:00:00 2001 From: Ege Kocabas Date: Sun, 17 Nov 2024 22:15:08 +0100 Subject: [PATCH 9/9] test --- .../src/main/java/de/tum/cit/aet/helios/StatusController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java b/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java index 47a8031..bd8d791 100644 --- a/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java +++ b/server/application-server/src/main/java/de/tum/cit/aet/helios/StatusController.java @@ -16,4 +16,3 @@ public String healthCheck() { return "ok"; } } -