Skip to content
Draft
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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.git
server/.gradle
server/build
server/bin
server/upstream
website/node_modules
website/dist
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@

.helm
charts/openvsx/charts
.gradle
build/
bin/
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "server/upstream"]
path = server/upstream
url = https://github.com/gnugomez/openvsx.git
branch = poc/eclipse-extraction
55 changes: 50 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG SERVER_VERSION=1e8f4f6
ARG SERVER_VERSION=poc/eclipse-extraction
ARG SERVER_VERSION_STRING=v1.1.0-dev.3

# Builder image to compile the website
Expand Down Expand Up @@ -26,15 +26,60 @@ RUN cd website \
&& yarn install --immutable \
&& yarn build

# Main image derived from openvsx-server
FROM ghcr.io/eclipse-openvsx/openvsx-server-snapshot:${SERVER_VERSION}
# Upstream server sources at the ref given by SERVER_VERSION, consumed as a library
# by the Gradle build stage below. To build from a local checkout instead of cloning
# (e.g. the 'upstream' submodule or a sibling working copy):
# docker build --build-context server-src=server/upstream .
FROM alpine/git:latest AS server-clone
ARG SERVER_REPO=https://github.com/gnugomez/openvsx.git
ARG SERVER_VERSION
RUN git clone --filter=blob:none ${SERVER_REPO} /src \
&& git -C /src checkout ${SERVER_VERSION}

FROM scratch AS server-src
COPY --from=server-clone /src /

# Build the server application against the upstream library (composite build)
FROM eclipse-temurin:25-jdk AS server-builder

WORKDIR /workdir

COPY --from=server-src / upstream/
COPY server/gradlew server/settings.gradle server/build.gradle ./
COPY server/gradle/ gradle/
COPY server/src/ src/

ENV CI=true

RUN ./gradlew --no-daemon -PopenvsxServerPath=upstream/server bootJar \
&& mkdir exploded \
&& cd exploded \
&& jar -xf ../build/libs/openvsx-server.jar

# Main image: plain JRE plus the exploded server archive, replicating the layout of
# the upstream-derived image this used to build FROM
FROM eclipse-temurin:25-jre
ARG SERVER_VERSION_STRING

# Create user openvsx and set up home directory
RUN groupadd -r openvsx \
&& useradd --no-log-init -r -g openvsx openvsx \
&& mkdir -p /home/openvsx/server \
&& chown -R openvsx:openvsx /home/openvsx

USER openvsx
WORKDIR /home/openvsx/server

COPY --chown=openvsx:openvsx --from=server-builder /workdir/exploded/ ./
COPY --chown=openvsx:openvsx --from=server-src /server/scripts/run-server.sh ./

COPY --from=builder --chown=openvsx:openvsx /workdir/website/dist/ BOOT-INF/classes/static/
COPY --from=builder --chown=openvsx:openvsx /workdir/configuration/application.yml config/
COPY --from=builder --chown=openvsx:openvsx /workdir/configuration/logback-spring.xml BOOT-INF/classes/
COPY --from=builder --chown=openvsx:openvsx /workdir/mail-templates BOOT-INF/classes/mail-templates

# Replace version placeholder with arg value
RUN sed -i "s/<SERVER_VERSION>/${SERVER_VERSION_STRING}/g" config/application.yml
# Replace version placeholder with arg value; make the start script executable
RUN chmod u+x run-server.sh \
&& sed -i "s/<SERVER_VERSION>/${SERVER_VERSION_STRING}/g" config/application.yml

ENTRYPOINT ["./run-server.sh"]
268 changes: 268 additions & 0 deletions server/NOTES.md

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
plugins {
id 'java'
id 'org.springframework.boot'
}

group = 'org.eclipsefdn.openvsx'

java {
sourceCompatibility = gradle.ext.javaVersion
}

repositories {
mavenCentral()
}

dependencies {
// The upstream registry server, consumed as a library. No version: the composite
// build (settings.gradle) substitutes the included server project.
implementation 'org.eclipse.openvsx:openvsx-server'

// What this module's own sources compile against. No versions: the server
// library publishes its effective managed versions as dependency constraints.
implementation "org.springframework.boot:spring-boot-starter-webmvc"
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
implementation "org.springframework.security:spring-security-oauth2-client"
implementation "org.apache.commons:commons-lang3"
implementation "com.fasterxml.jackson.core:jackson-annotations"
implementation "tools.jackson.core:jackson-databind"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui"

// Mirrors the server's tomcat -> jetty replacement; component module rules are
// project-local upstream and do not propagate to consumers.
modules {
module("org.springframework.boot:spring-boot-starter-tomcat") {
replacedBy("org.springframework.boot:spring-boot-starter-jetty")
}
}

testImplementation "org.springframework.boot:spring-boot-starter-test"
testImplementation "org.springframework.boot:spring-boot-starter-webmvc-test"
testImplementation "org.springframework.boot:spring-boot-testcontainers"
testImplementation "org.testcontainers:testcontainers-junit-jupiter"
testImplementation "org.testcontainers:testcontainers-postgresql"
testImplementation "io.micrometer:micrometer-core"
testImplementation "org.jobrunr:jobrunr-spring-boot-4-starter"
}

// The server's io.spring.dependency-management plugin resolves its graph with
// Maven-like semantics: managed and declared versions beat newer transitive
// requests. That does not travel to consumers, where Gradle picks the highest
// requested version. Force the few modules where the two disagree so this build
// resolves exactly what the upstream bootJar ships (the two ranges are upstream's
// CVE floors). Verified by diffing BOOT-INF/lib against an upstream bootJar; see
// NOTES.md. The mockito/byte-buddy entries only matter on the test classpaths
// (upstream's tests force-downgrade them the same way).
configurations.configureEach {
resolutionStrategy {
force 'com.google.code.gson:gson:2.13.2'
force 'com.fasterxml.woodstox:woodstox-core:6.4.0'
force 'org.apache.commons:commons-compress:[1.26.0,2.0)'
force 'org.eclipse.parsson:parsson:[1.1.8,2.0)'
force 'net.bytebuddy:byte-buddy:1.17.8'
force 'org.mockito:mockito-core:5.20.0'
force 'org.mockito:mockito-junit-jupiter:5.20.0'
}
}

test {
jvmArgs = ['--enable-native-access=ALL-UNNAMED', '-Xmx2048m']
useJUnitPlatform()
}

// Same developer entry point as upstream's `./gradlew runServer`: runs the registry
// on the host JVM with upstream's dev configuration (src/dev/resources), plus this
// module's beans. Expects the dev services from upstream's docker-compose.yml
// (postgres), exactly like the upstream task does.
tasks.register('runServer', JavaExec) {
jvmArgs = [
'-Dorg.jooq.no-logo=true',
'-Dorg.jooq.no-tips=true',
'--enable-native-access=ALL-UNNAMED' // due to https://github.com/netty/netty/issues/15161
]
classpath = sourceSets.main.runtimeClasspath + files(new File(gradle.ext.openvsxServerDir, 'src/dev/resources'))
mainClass = 'org.eclipse.openvsx.RegistryApplication'

// Upstream's one-time dev bootstrap: the dev profile includes the gitignored
// application-ovsx.properties, which developers generate in their checkout.
// Generate it on first run so a fresh submodule works out of the box.
doFirst {
def serverDir = gradle.ext.openvsxServerDir as File
if (!new File(serverDir, 'src/dev/resources/application-ovsx.properties').exists()) {
def generate = new ProcessBuilder('bash', 'scripts/generate-properties.sh')
.directory(serverDir)
.inheritIO()
.start()
if (generate.waitFor() != 0) {
throw new GradleException("${serverDir}/scripts/generate-properties.sh failed")
}
}
}
}

springBoot {
// The application class is upstream's; this module only layers deployment-specific
// beans on top via auto-configuration. Do not add a second @SpringBootApplication.
mainClass = 'org.eclipse.openvsx.RegistryApplication'
}

bootJar {
// Keep the artifact name the Docker image entrypoint expects.
archiveFileName = 'openvsx-server.jar'

// bootJar hoists this module's META-INF resources to the jar root, but the
// image entrypoint launches with -cp BOOT-INF/classes:BOOT-INF/lib/* (no jar
// root on the classpath), which would silently drop the auto-configuration
// registration. Keep a copy under BOOT-INF/classes.
from(sourceSets.main.resources) {
include 'META-INF/spring/**'
into 'BOOT-INF/classes'
}
}
Binary file added server/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
9 changes: 9 additions & 0 deletions server/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading