From 6f5077fae852b24ff5eccffbecdc14a42cea89f7 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Apr 2026 18:41:58 +0000 Subject: [PATCH 1/2] fix: register package name with jdeploy.com during npm publish NPMPublishDriver.prepare() was not triggering the /register call on jdeploy.com, so an npm-only publish left the server with no bundles row for the package. Subsequent /download requests then failed with "No code found for package X" (PackageCodeService::fetchCode returns null and throws). The GitHub publish driver already had this call in its prepare(). This mirrors it in NPMPublishDriver so every publish path registers the package up front. Adds NPMPublishDriverRegisterTest verifying: - prepare() calls bundleCodeService.fetchJdeployBundleCode with the bare package name for npm targets - failures from the register call surface instead of being swallowed --- .../publishing/npm/NPMPublishDriver.java | 20 ++- .../publishing/MockNetworkPublishingTest.java | 7 +- .../NPMPublishDriverPlatformBundlesTest.java | 4 +- .../npm/NPMPublishDriverRegisterTest.java | 137 ++++++++++++++++++ 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverRegisterTest.java diff --git a/cli/src/main/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriver.java b/cli/src/main/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriver.java index 15a764b9..d781b388 100644 --- a/cli/src/main/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriver.java +++ b/cli/src/main/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriver.java @@ -12,6 +12,8 @@ import ca.weblite.jdeploy.publishing.PublishingContext; import ca.weblite.jdeploy.models.JDeployProject; import ca.weblite.jdeploy.models.Platform; +import ca.weblite.jdeploy.services.BundleCodeService; +import ca.weblite.jdeploy.services.PackageNameService; import ca.weblite.jdeploy.services.PackageSigningService; import ca.weblite.jdeploy.services.PlatformBundleGenerator; import ca.weblite.jdeploy.services.PublishBundleService; @@ -48,6 +50,8 @@ public class NPMPublishDriver implements PublishDriverInterface { private final PublishBundleService publishBundleService; private final BundleUploadRouter bundleUploadRouter; private final BundleChecksumWriter bundleChecksumWriter; + private final BundleCodeService bundleCodeService; + private final PackageNameService packageNameService; @Inject public NPMPublishDriver( @@ -57,7 +61,9 @@ public NPMPublishDriver( JDeployProjectFactory projectFactory, PublishBundleService publishBundleService, BundleUploadRouter bundleUploadRouter, - BundleChecksumWriter bundleChecksumWriter + BundleChecksumWriter bundleChecksumWriter, + BundleCodeService bundleCodeService, + PackageNameService packageNameService ) { this.basePublishDriver = basePublishDriver; this.platformBundleGenerator = platformBundleGenerator; @@ -66,6 +72,8 @@ public NPMPublishDriver( this.publishBundleService = publishBundleService; this.bundleUploadRouter = bundleUploadRouter; this.bundleChecksumWriter = bundleChecksumWriter; + this.bundleCodeService = bundleCodeService; + this.packageNameService = packageNameService; } public void setRegistryUrl(String registryUrl) { @@ -253,6 +261,16 @@ public void prepare(PublishingContext context, PublishTargetInterface target, Bu // Build and upload pre-built bundles if enabled maybePublishBundles(context, target); + + // Register the package name with jdeploy.com so the download page can resolve a + // bundle code. Without this, a fresh npm-only publish leaves jdeploy.com with no + // bundles row for the package and /download fails with "No code found for package". + bundleCodeService.fetchJdeployBundleCode( + packageNameService.getFullPackageName( + target, + context.packagingContext.getName() + ) + ); } /** diff --git a/cli/src/test/java/ca/weblite/jdeploy/publishing/MockNetworkPublishingTest.java b/cli/src/test/java/ca/weblite/jdeploy/publishing/MockNetworkPublishingTest.java index 37d34758..21c73177 100644 --- a/cli/src/test/java/ca/weblite/jdeploy/publishing/MockNetworkPublishingTest.java +++ b/cli/src/test/java/ca/weblite/jdeploy/publishing/MockNetworkPublishingTest.java @@ -346,10 +346,15 @@ void npmPublishDriverVersionCheck() throws Exception { PublishBundleService publishBundleService = mock(PublishBundleService.class); BundleUploadRouter bundleUploadRouter = mock(BundleUploadRouter.class); BundleChecksumWriter bundleChecksumWriter = mock(BundleChecksumWriter.class); + ca.weblite.jdeploy.services.BundleCodeService bundleCodeService = + mock(ca.weblite.jdeploy.services.BundleCodeService.class); + ca.weblite.jdeploy.services.PackageNameService packageNameService = + new ca.weblite.jdeploy.services.PackageNameService(); NPMPublishDriver npmDriver = new NPMPublishDriver( baseDriver, platformBundleGenerator, defaultBundleService, projectFactory, - publishBundleService, bundleUploadRouter, bundleChecksumWriter + publishBundleService, bundleUploadRouter, bundleChecksumWriter, + bundleCodeService, packageNameService ); npmDriver.setRegistryUrl(getNpmRegistry()); diff --git a/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverPlatformBundlesTest.java b/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverPlatformBundlesTest.java index 5dd618a5..d82154e2 100644 --- a/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverPlatformBundlesTest.java +++ b/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverPlatformBundlesTest.java @@ -85,7 +85,9 @@ void setUp() throws IOException { projectFactory, mock(ca.weblite.jdeploy.services.PublishBundleService.class), mock(ca.weblite.jdeploy.publishing.BundleUploadRouter.class), - mock(ca.weblite.jdeploy.publishing.BundleChecksumWriter.class) + mock(ca.weblite.jdeploy.publishing.BundleChecksumWriter.class), + mock(ca.weblite.jdeploy.services.BundleCodeService.class), + new ca.weblite.jdeploy.services.PackageNameService() ); // Set up test directories and files diff --git a/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverRegisterTest.java b/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverRegisterTest.java new file mode 100644 index 00000000..f96b0535 --- /dev/null +++ b/cli/src/test/java/ca/weblite/jdeploy/publishing/npm/NPMPublishDriverRegisterTest.java @@ -0,0 +1,137 @@ +package ca.weblite.jdeploy.publishing.npm; + +import ca.weblite.jdeploy.appbundler.BundlerSettings; +import ca.weblite.jdeploy.factories.JDeployProjectFactory; +import ca.weblite.jdeploy.npm.NPM; +import ca.weblite.jdeploy.packaging.PackagingContext; +import ca.weblite.jdeploy.publishTargets.PublishTargetInterface; +import ca.weblite.jdeploy.publishTargets.PublishTargetType; +import ca.weblite.jdeploy.publishing.BasePublishDriver; +import ca.weblite.jdeploy.publishing.BundleChecksumWriter; +import ca.weblite.jdeploy.publishing.BundleUploadRouter; +import ca.weblite.jdeploy.publishing.PublishingContext; +import ca.weblite.jdeploy.services.BundleCodeService; +import ca.weblite.jdeploy.services.DefaultBundleService; +import ca.weblite.jdeploy.services.PackageNameService; +import ca.weblite.jdeploy.services.PlatformBundleGenerator; +import ca.weblite.jdeploy.services.PublishBundleService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * Verifies that NPMPublishDriver.prepare() registers the package name with jdeploy.com + * so that the download page can resolve a bundle code. See flexganttfxshowcase bug where + * the registration step was missing for npm-only publishes. + */ +@ExtendWith(MockitoExtension.class) +class NPMPublishDriverRegisterTest { + + @TempDir + File tempDir; + + @Mock private BasePublishDriver baseDriver; + @Mock private PlatformBundleGenerator platformBundleGenerator; + @Mock private DefaultBundleService defaultBundleService; + @Mock private JDeployProjectFactory projectFactory; + @Mock private PublishBundleService publishBundleService; + @Mock private BundleUploadRouter bundleUploadRouter; + @Mock private BundleChecksumWriter bundleChecksumWriter; + @Mock private BundleCodeService bundleCodeService; + @Mock private PublishTargetInterface target; + @Mock private BundlerSettings bundlerSettings; + @Mock private NPM npm; + + private NPMPublishDriver driver; + private PublishingContext publishingContext; + + @BeforeEach + void setUp() { + driver = new NPMPublishDriver( + baseDriver, + platformBundleGenerator, + defaultBundleService, + projectFactory, + publishBundleService, + bundleUploadRouter, + bundleChecksumWriter, + bundleCodeService, + new PackageNameService() + ); + + Map packageJsonMap = new HashMap<>(); + packageJsonMap.put("name", "flexganttfxshowcase"); + packageJsonMap.put("version", "11.13.4"); + + PackagingContext packagingContext = new PackagingContext( + tempDir, + packageJsonMap, + new File(tempDir, "package.json"), + false, + false, + null, + null, + null, + null, + new PrintStream(System.out), + new PrintStream(System.err), + System.in, + true, + false + ); + + publishingContext = new PublishingContext( + packagingContext, + false, + npm, + null, + null, + null, + null, + null + ); + } + + @Test + @DisplayName("prepare() registers the package name with jdeploy.com for npm targets") + void prepareRegistersNpmPackageName() throws IOException { + when(target.getType()).thenReturn(PublishTargetType.NPM); + when(publishBundleService.isEnabled(any(PackagingContext.class))).thenReturn(false); + + driver.prepare(publishingContext, target, bundlerSettings); + + verify(baseDriver).prepare(publishingContext, target, bundlerSettings); + // For an npm target PackageNameService returns the bare package name (no source prefix), + // which is exactly what the server-side /register endpoint expects. + verify(bundleCodeService).fetchJdeployBundleCode("flexganttfxshowcase"); + } + + @Test + @DisplayName("prepare() propagates failures from the register call so the publish fails loudly") + void prepareFailsWhenRegisterFails() throws IOException { + when(target.getType()).thenReturn(PublishTargetType.NPM); + when(publishBundleService.isEnabled(any(PackagingContext.class))).thenReturn(false); + doThrow(new IOException("register.php unreachable")) + .when(bundleCodeService).fetchJdeployBundleCode(anyString()); + + IOException ex = assertThrows(IOException.class, + () -> driver.prepare(publishingContext, target, bundlerSettings)); + + // Sanity check: the cause surfaces to the caller so we don't silently skip registration. + verify(bundleCodeService).fetchJdeployBundleCode("flexganttfxshowcase"); + } +} From 17b2ce438702b065ff7755dbe4300d6fa19559f5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 21 Apr 2026 18:54:53 +0000 Subject: [PATCH 2/2] fix: pin openai-gpt3-java to 0.18.2 to unblock dependency resolution shared/pom.xml used LATEST for com.theokanning.openai-gpt3-java:service. Resolution went through the sci-java repo, whose maven-metadata.xml still advertises 0.18.2 as the latest/release version but whose storage now returns 404 for the jar. The build fails even though Maven Central still serves the jar. Pin to 0.18.2. Maven goes directly to Central and the sci-java metadata lookup is bypassed. The LATEST metaversion is deprecated anyway. --- shared/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/pom.xml b/shared/pom.xml index e9a78c79..23698c65 100644 --- a/shared/pom.xml +++ b/shared/pom.xml @@ -50,7 +50,7 @@ com.theokanning.openai-gpt3-java service - LATEST + 0.18.2