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
26 changes: 0 additions & 26 deletions .github/workflows/codespell.yml

This file was deleted.

16 changes: 0 additions & 16 deletions .github/workflows/typespec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,3 @@ jobs:
cd typespec
tsp install
tsp compile .

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@67fbcbb121271f7775d2e7715933280b06314838 # v1.7.0
with:
aws-access-key-id: ${{secrets.TOWER_CI_AWS_ACCESS}}
aws-secret-access-key: ${{secrets.TOWER_CI_AWS_SECRET}}
aws-region: eu-west-1

- name : Login to Amazon ECR
id : login-ecr
uses : aws-actions/amazon-ecr-login@5a88a04c91d5c6f97aae0d9be790e64d9b1d47b7 # v1.7.1

- name: Release OpenAPI docs
if: "contains(github.event.head_commit.message, '[release]')"
run: |
bash typespec/tag-and-push-openapi.sh
68 changes: 68 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ dependencies {
// caching deps
implementation 'io.micronaut.cache:micronaut-cache-core'
implementation 'io.micronaut.cache:micronaut-cache-caffeine'
// swagger ui via webjars (served at /webjars/swagger-ui/*)
implementation 'org.webjars:swagger-ui:5.17.14'
implementation 'io.micronaut.aws:micronaut-aws-parameter-store'
implementation 'software.amazon.awssdk:ecr'
implementation 'software.amazon.awssdk:ecrpublic'
Expand Down Expand Up @@ -209,6 +211,72 @@ task buildInfo { doLast {
buildInfo.dependsOn processResources
compileGroovy.dependsOn buildInfo

// ----------------------------------------------------------------------------
// OpenAPI / Swagger UI bundling
//
// Compiles the TypeSpec sources in `typespec/` to `openapi.yaml` and generates
// a Swagger UI page from `src/main/resources/swagger-ui-template.html`.
// Both artifacts are copied into `build/resources/main/public/openapi/` so they
// are bundled into the main Wave application container and served at /openapi/.
//
// This replaces the previous separate `wave/openapi` nginx container.
// ----------------------------------------------------------------------------
def typespecDir = file('typespec')
def typespecOutput = file("${typespecDir}/tsp-output/@typespec/openapi3/openapi.yaml")
def openapiBuildDir = file("${buildDir}/generated/openapi")

tasks.register('installTypeSpec', Exec) {
group = 'documentation'
description = 'Install TypeSpec compiler and dependencies via npm'
workingDir typespecDir
commandLine 'npm', 'install'

inputs.file("${typespecDir}/package.json")
outputs.dir("${typespecDir}/node_modules")
}

tasks.register('generateOpenApi', Exec) {
group = 'documentation'
description = 'Compile TypeSpec sources into openapi.yaml'
dependsOn 'installTypeSpec'
workingDir typespecDir
commandLine 'npx', 'tsp', 'compile', '.'

inputs.files(fileTree(typespecDir) {
include 'main.tsp', 'routes.tsp', 'tspconfig.yaml', 'models/**/*.tsp'
})
outputs.file(typespecOutput)
}

tasks.register('generateSwaggerUI') {
group = 'documentation'
description = 'Stage openapi.yaml and a Swagger UI page under public/openapi'
dependsOn 'generateOpenApi'

inputs.file(typespecOutput)
inputs.file('src/main/resources/swagger-ui-template.html')
outputs.dir(openapiBuildDir)

doLast {
openapiBuildDir.mkdirs()

// Copy spec and substitute the placeholder version (typespec emits `version: 0.0.0`)
def specText = typespecOutput.text.replace('version: 0.0.0', "version: ${version}")
new File(openapiBuildDir, 'openapi.yaml').text = specText

// Render the Swagger UI page with the project version
def template = file('src/main/resources/swagger-ui-template.html').text
new File(openapiBuildDir, 'index.html').text = template.replace('${PROJECT_VERSION}', version.toString())
}
}

processResources {
dependsOn generateSwaggerUI
from(openapiBuildDir) {
into 'public/openapi'
}
}

jacoco {
toolVersion '0.8.12'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ class ServiceInfoController {
: HttpResponse.badRequest()
}

@Get("/openapi")
HttpResponse getOpenAPI() {
HttpResponse.redirect(URI.create("/openapi/"))
}

@Get(uri = "/favicon.ico", produces = MediaType.IMAGE_X_ICON)
HttpResponse getFavicon() {
final inputStream = getClass().getResourceAsStream("/io/seqera/wave/assets/wave.ico");
Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ micronaut:
paths: 'classpath:io/seqera/wave/assets'
mapping: '/assets/**'
enabled: true
openapi:
paths: 'classpath:public/openapi'
mapping: '/openapi/**'
enabled: true
webjars:
paths: 'classpath:META-INF/resources/webjars'
mapping: '/webjars/**'
enabled: true
# http client configuration
# https://docs.micronaut.io/latest/guide/configurationreference.html#io.micronaut.http.client.DefaultHttpClientConfiguration
http:
Expand Down
15 changes: 15 additions & 0 deletions src/main/resources/public/openapi/swagger-ui-init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
window.onload = function () {
window.ui = SwaggerUIBundle({
url: '/openapi/openapi.yaml',
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: 'StandaloneLayout'
});
};
27 changes: 27 additions & 0 deletions src/main/resources/public/openapi/swagger-ui-overrides.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}

*, *:before, *:after {
box-sizing: inherit;
}

body {
margin: 0;
background: #fafafa;
}

/* Hide Swagger branding */
.swagger-ui .topbar {
display: none;
}

.swagger-ui .info hgroup.main a {
display: none;
}

.swagger-ui .info .title small {
display: none;
}
34 changes: 34 additions & 0 deletions src/main/resources/swagger-ui-template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!--
~ Wave, containers provisioning service
~ Copyright (c) 2023-2024, Seqera Labs
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Wave API ${PROJECT_VERSION}</title>
<link rel="stylesheet" type="text/css" href="/webjars/swagger-ui/5.17.14/swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="/openapi/swagger-ui-overrides.css" />
</head>
<body>
<div id="swagger-ui"></div>

<script src="/webjars/swagger-ui/5.17.14/swagger-ui-bundle.js"></script>
<script src="/webjars/swagger-ui/5.17.14/swagger-ui-standalone-preset.js"></script>
<script src="/openapi/swagger-ui-init.js"></script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ import spock.lang.Specification

import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.DefaultHttpClientConfiguration
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.runtime.server.EmbeddedServer
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import jakarta.inject.Inject
/**
Expand All @@ -40,9 +38,6 @@ class ServiceInfoControllerTest extends Specification {
@Client("/")
HttpClient client

@Inject
EmbeddedServer embeddedServer;

def 'should get service info' () {
when:
def request = HttpRequest.GET("/service-info")
Expand All @@ -60,23 +55,6 @@ class ServiceInfoControllerTest extends Specification {
e.status == HttpStatus.METHOD_NOT_ALLOWED
}

def 'should redirect to /openapi/'() {
given:
def uri = embeddedServer.getContextURI()
and:
// Create a new HttpClient with redirects disabled
def config = new DefaultHttpClientConfiguration()
config.setFollowRedirects(false)
def client = HttpClient.create(uri.toURL(), config)
when:
def request = HttpRequest.GET("/openapi")
def resp = client.toBlocking().exchange(request, String)

then:
resp.status == HttpStatus.MOVED_PERMANENTLY // Expect 301
resp.headers.get("Location") == "/openapi/" // Validate redirect location
}

def 'should get favicon' () {
when:
def request = HttpRequest.GET("/favicon.ico")
Expand Down
10 changes: 0 additions & 10 deletions typespec/Dockerfile

This file was deleted.

28 changes: 0 additions & 28 deletions typespec/index.html

This file was deleted.

39 changes: 0 additions & 39 deletions typespec/tag-and-push-openapi.sh

This file was deleted.

Loading