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"); + } +} 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