Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

### External Service Jira (`exterla-service-jira`)
### External Service Jira (`external-service-jira`)
- **New module** for checking project existance in Jira (Server)
- Caching for the client

#### External Service API Module (`external-service-api`)
- **New module** for standardizing external service integrations
Expand All @@ -24,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Updated all external service implementations to extend `ExternalService` interface
- Use of lombok.extern.slf4j.Slf4j to remove boilerplate code.
- Use **io.fabric8** in the `external-service-ocp`
- Add caching to `external-service-ocp` client factory.

### Dependencies
- Updated Spring Boot version
Expand Down Expand Up @@ -140,12 +143,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Technical Stack

#### Frameworks & Libraries
- **Spring Boot**: 3.5.7
- **Spring Boot**: 3.5.11
- **Spring Security**: OAuth2 Resource Server
- **SpringDoc OpenAPI**: 2.8.13
- **OpenTelemetry**: 2.20.1
- **Lombok**: 1.18.42
- **Jackson Databind Nullable**: 0.2.7
- **io.Fabric8**: 7.5.2

#### Build Tools
- **Maven**: 3.x
Expand All @@ -171,11 +175,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
This is the initial release of the DevStack API Service - a stateless, microservices-based platform for managing DevStack project lifecycles. The service provides RESTful APIs for third-party applications and CLI tools, with minimal server-side data storage and integration with external identity providers.

### Key Highlights
- ✅ Production-ready Spring Boot 3.5.7 application
- ✅ Production-ready Spring Boot 3.5.11 application
- ✅ Complete API documentation with OpenAPI/Swagger
- ✅ Multiple deployment options (JAR, Native Binary, Docker)
- ✅ Comprehensive external service integrations
- ✅ CI/CD pipeline with automated releases
- ✅ Observable with OpenTelemetry support
- ✅ Secure with OAuth2 authentication

Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The system will expose RESTful APIs for third-party client applications and futu
Before using the Makefile, ensure you have the following installed:

### Required
- **Java 17+** - The project uses Java 17
- **Java 17+** - The project uses Java 21
- **Maven** - Maven wrapper (`mvnw`) is included in the project
- **Make** - For running Makefile commands

Expand Down Expand Up @@ -265,15 +265,17 @@ Port 8080 was already in use
## 📁 Project Structure

```
devstack-api-service/
├── Makefile # Build automation
├── pom.xml # Parent POM
├── mvnw # Maven wrapper
├── core/ # Main application module
ods-api-service/
├── Makefile # Build automation
├── pom.xml # Parent POM
├── mvnw # Maven wrapper
├── api-xxx # Api module
├── external-service-yyy # External service module
├── core/ # Main application module
│ ├── pom.xml # Core module POM
│ ├── src/ # Source code
│ └── target/ # Build output
└── docker/ # Docker configuration
└── docker/ # Docker configuration
├── Dockerfile # Standard container definition
└── Docker.native # Native container definition
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public String getDefaultInstanceName() throws JiraException {
* @return Configured JiraApiClient
* @throws JiraException if the instance is not configured
*/
@Cacheable(value = "jiraApiClients", key = "#instanceName")
@Cacheable(value = "jiraApiClients", key = "#instanceName", condition = "#instanceName != null && !#instanceName.isBlank()")
public JiraApiClient getClient(String instanceName) throws JiraException {
if (instanceName == null || instanceName.isBlank()) {
throw new JiraException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ void testProjectExists_NonExistentProject() throws JiraException {
log.info("Project '{}' exists on instance '{}': {}", testNonExistentProjectKey, testInstance, exists);
}

@Test
void testProjectExists_nullInstanceName() {
// This should throw a JiraException
assertThrows(JiraException.class, () -> jiraService.projectExists(null, testProjectKey),
"Calling projectExists with null instance name should throw JiraException");
assertThrows(JiraException.class, () -> jiraService.projectExists("", testProjectKey),
"Calling projectExists with blank instance name should throw JiraException");
assertThrows(JiraException.class, () -> jiraService.projectExists(" ", testProjectKey),
"Calling projectExists with whitespace instance name should throw JiraException");

}

// -------------------------------------------------------------------------
// Default-instance tests
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -147,13 +159,4 @@ void testProjectExists_UsingDefaultInstance_NonExistentProject() throws JiraExce
log.info("projectExists('{}') via default instance returned: {}", testNonExistentProjectKey, exists);
}

@Test
void testProjectExists_NullInstance_SameAsDefaultInstance() throws JiraException {
// Passing null explicitly must produce the same result as the no-arg overload
boolean viaNull = jiraService.projectExists(null, testProjectKey);
boolean viaDefault = jiraService.projectExists(testProjectKey);

assertEquals(viaDefault, viaNull,
"Passing null instanceName should behave identically to the default-instance overload");
}
}
20 changes: 4 additions & 16 deletions external-service-ocp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,17 @@
<artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- Spring Boot Web for HTTP clients -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Boot Actuator for health checks -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- Jackson for JSON processing -->
<!-- Fabric8 OpenShift Client -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<groupId>io.fabric8</groupId>
<artifactId>openshift-client</artifactId>
<version>7.5.2</version>
</dependency>

<!-- Lombok for boilerplate code reduction -->
Expand All @@ -58,13 +53,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!-- WireMock for testing HTTP clients -->
<dependency>
<groupId>org.wiremock.integrations</groupId>
<artifactId>wiremock-spring-boot</artifactId>
<version>3.10.0</version>
</dependency>
</dependencies>

<build>
Expand Down
Loading