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
152 changes: 152 additions & 0 deletions gradle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,158 @@
cleanGradleTest(t)
}

// TestGradleBuildSharedBuildLogicClassic verifies that a dependency declared only in a
// shared convention plugin living in buildSrc (not in the api module's own build.gradle)
// is correctly present in the published build-info, when using Classic mode (the plugin
// is auto-injected into every project via the init script).
func TestGradleBuildSharedBuildLogicClassic(t *testing.T) {
initGradleTest(t)
buildGradlePath := createGradleProject(t, "buildsrcdependency")
configFilePath := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "buildspecs", tests.GradleConfig)
destPath := filepath.Join(filepath.Dir(buildGradlePath), ".jfrog", "projects")
createConfigFile(destPath, configFilePath, t)
oldHomeDir := changeWD(t, filepath.Dir(buildGradlePath))
defer clientTestUtils.ChangeDirAndAssert(t, oldHomeDir)

buildName := tests.GradleBuildName + "-shared-build-logic-classic"
buildNumber := "1"

// Run from within the project directory (already the cwd via changeWD above) instead of
// passing -b/--build-file: newer Gradle versions reject that flag when combined with
// task-specific command-line options.
runJfrogCli(t, "gradle", "clean", "artifactoryPublish", "--build-name="+buildName, "--build-number="+buildNumber)
assert.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber))

assertSharedConventionDependencyInBuildInfo(t, buildName, buildNumber)
cleanGradleTest(t)
}

// TestGradleBuildSharedBuildLogicFlexPack is the same check as
// TestGradleBuildSharedBuildLogicClassic, but using FlexPack (native) mode instead.
func TestGradleBuildSharedBuildLogicFlexPack(t *testing.T) {
initGradleTest(t)
buildGradlePath := createGradleProject(t, "buildsrcdependency")
oldHomeDir := changeWD(t, filepath.Dir(buildGradlePath))
defer clientTestUtils.ChangeDirAndAssert(t, oldHomeDir)

buildName := tests.GradleBuildName + "-shared-build-logic-flexpack"
buildNumber := "1"
setEnvCallBack := clientTestUtils.SetEnvWithCallbackAndAssert(t, "JFROG_RUN_NATIVE", "true")
defer setEnvCallBack()

// Defensive: ShouldRunNative refuses native mode if any .jfrog/projects/gradle.yaml is
// found (via an upward directory search from cwd). This fixture directory name is reused
// by TestGradleBuildSharedBuildLogicClassic, and if that test's config file isn't fully
// removed by the shared harness cleanup before this test starts (e.g. a lingering Gradle
// daemon file lock), native mode would silently be skipped. Remove it explicitly so this
// test's outcome never depends on that cleanup having completed.
assert.NoError(t, os.RemoveAll(".jfrog"))

err := runJfrogCliWithoutAssertion("gradle", "clean", "build", "--build-name="+buildName, "--build-number="+buildNumber)
assert.NoError(t, err)
assert.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber))

assertSharedConventionDependencyInBuildInfo(t, buildName, buildNumber)
cleanGradleTest(t)
}

// TestGradleBuildSharedBuildLogicBuildLogicClassic is the same check as
// TestGradleBuildSharedBuildLogicClassic, but the shared convention plugin lives in an
// included build-logic build instead of buildSrc.
func TestGradleBuildSharedBuildLogicBuildLogicClassic(t *testing.T) {
initGradleTest(t)
buildGradlePath := createGradleProject(t, "buildlogicdependency")
configFilePath := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "buildspecs", tests.GradleConfig)
destPath := filepath.Join(filepath.Dir(buildGradlePath), ".jfrog", "projects")
createConfigFile(destPath, configFilePath, t)
oldHomeDir := changeWD(t, filepath.Dir(buildGradlePath))
defer clientTestUtils.ChangeDirAndAssert(t, oldHomeDir)

buildName := tests.GradleBuildName + "-shared-build-logic-buildlogic-classic"
buildNumber := "1"

runJfrogCli(t, "gradle", "clean", "artifactoryPublish", "--build-name="+buildName, "--build-number="+buildNumber)
assert.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber))

assertSharedConventionDependencyInBuildInfo(t, buildName, buildNumber)
cleanGradleTest(t)
}

// TestGradleBuildSharedBuildLogicBuildLogicFlexPack is the same check as
// TestGradleBuildSharedBuildLogicFlexPack, but the shared convention plugin lives in an
// included build-logic build instead of buildSrc.
func TestGradleBuildSharedBuildLogicBuildLogicFlexPack(t *testing.T) {
initGradleTest(t)
buildGradlePath := createGradleProject(t, "buildlogicdependency")
oldHomeDir := changeWD(t, filepath.Dir(buildGradlePath))
defer clientTestUtils.ChangeDirAndAssert(t, oldHomeDir)

buildName := tests.GradleBuildName + "-shared-build-logic-buildlogic-flexpack"
buildNumber := "1"
setEnvCallBack := clientTestUtils.SetEnvWithCallbackAndAssert(t, "JFROG_RUN_NATIVE", "true")
defer setEnvCallBack()

// See TestGradleBuildSharedBuildLogicFlexPack for why this is needed.
assert.NoError(t, os.RemoveAll(".jfrog"))

err := runJfrogCliWithoutAssertion("gradle", "clean", "build", "--build-name="+buildName, "--build-number="+buildNumber)
assert.NoError(t, err)
assert.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber))

assertSharedConventionDependencyInBuildInfo(t, buildName, buildNumber)
cleanGradleTest(t)
}

// assertSharedConventionDependencyInBuildInfo asserts the published build-info has:
// - an "api" module (applies the shared java-common-conventions plugin) whose
// dependencies include org.slf4j:slf4j-api — a dependency declared only in the
// shared buildSrc convention plugin, never in api's own build.gradle.
// - a "lib" module (does NOT apply the shared convention plugin) whose dependencies
// do NOT include org.slf4j:slf4j-api, proving the shared dependency only reaches
// subprojects that actually apply the convention plugin.
func assertSharedConventionDependencyInBuildInfo(t *testing.T, buildName, buildNumber string) {

Check failure on line 664 in gradle_test.go

View workflow job for this annotation

GitHub Actions / Static Check

assertSharedConventionDependencyInBuildInfo - buildNumber always receives buildNumber ("1") (unparam)
publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, buildName, buildNumber)
if err != nil {
assert.NoError(t, err)
return
}
if !found {
assert.True(t, found, "build info was expected to be found")
return
}
buildInfo := publishedBuildInfo.BuildInfo

apiModule := findModuleByIdSubstring(buildInfo.Modules, "com.example:api")
if assert.NotNil(t, apiModule, "api module missing from build-info") {
assert.True(t, moduleHasDependency(apiModule, "org.slf4j:slf4j-api"),
"shared dependency (org.slf4j:slf4j-api, declared only in the shared convention plugin) missing from api module's dependencies")
}

libModule := findModuleByIdSubstring(buildInfo.Modules, "com.example:lib")
if assert.NotNil(t, libModule, "lib module missing from build-info") {
assert.False(t, moduleHasDependency(libModule, "org.slf4j:slf4j-api"),
"lib does not apply the shared convention plugin, so org.slf4j:slf4j-api must not appear in its dependencies")
}
}

func findModuleByIdSubstring(modules []buildinfo.Module, idSubstring string) *buildinfo.Module {
for i := range modules {
if strings.Contains(modules[i].Id, idSubstring) {
return &modules[i]
}
}
return nil
}

func moduleHasDependency(module *buildinfo.Module, depIdPrefix string) bool {
for _, dep := range module.Dependencies {
if strings.HasPrefix(dep.Id, depIdPrefix) {
return true
}
}
return false
}

func createGradleProject(t *testing.T, projectName string) string {
// Copy the entire project directory including source files
projectSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "gradle", projectName)
Expand Down
15 changes: 15 additions & 0 deletions testdata/gradle/buildlogicdependency/api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id 'java-common-conventions'
id 'maven-publish'
}

group = 'com.example'
version = '1.0.0'

publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.api;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PersonList {
private static final Logger logger = LoggerFactory.getLogger(PersonList.class);

public void log() {
logger.info("PersonList using slf4j-api pulled in only via the shared convention plugin");
}
}
7 changes: 7 additions & 0 deletions testdata/gradle/buildlogicdependency/build-logic/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id 'groovy-gradle-plugin'
}

repositories {
mavenCentral()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = 'build-logic'
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id 'java-library'
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.slf4j:slf4j-api:2.0.9'
}
3 changes: 3 additions & 0 deletions testdata/gradle/buildlogicdependency/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Root build file intentionally left plain. Neither Classic mode (plugin
// auto-injected via init script) nor FlexPack mode requires any plugin
// application here.
22 changes: 22 additions & 0 deletions testdata/gradle/buildlogicdependency/lib/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Intentionally does NOT apply the shared java-common-conventions plugin from
// build-logic, so it must not receive org.slf4j:slf4j-api (or anything else the
// convention plugin declares).
plugins {
id 'java-library'
id 'maven-publish'
}

repositories {
mavenCentral()
}

group = 'com.example'
version = '1.0.0'

publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.lib;

public class Utils {
public static String greet() {
return "hello from lib";
}
}
7 changes: 7 additions & 0 deletions testdata/gradle/buildlogicdependency/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pluginManagement {
includeBuild 'build-logic'
}

rootProject.name = 'buildlogicdependency'
include 'api'
include 'lib'
15 changes: 15 additions & 0 deletions testdata/gradle/buildsrcdependency/api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id 'java-common-conventions'
id 'maven-publish'
}

group = 'com.example'
version = '1.0.0'

publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.api;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PersonList {
private static final Logger logger = LoggerFactory.getLogger(PersonList.class);

public void log() {
logger.info("PersonList using slf4j-api pulled in only via the shared convention plugin");
}
}
3 changes: 3 additions & 0 deletions testdata/gradle/buildsrcdependency/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Root build file intentionally left plain. Neither Classic mode (plugin
// auto-injected via init script) nor FlexPack mode requires any plugin
// application here.
7 changes: 7 additions & 0 deletions testdata/gradle/buildsrcdependency/buildSrc/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id 'groovy-gradle-plugin'
}

repositories {
mavenCentral()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id 'java-library'
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.slf4j:slf4j-api:2.0.9'
}
22 changes: 22 additions & 0 deletions testdata/gradle/buildsrcdependency/lib/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Intentionally does NOT apply the shared java-common-conventions plugin from
// buildSrc, so it must not receive org.slf4j:slf4j-api (or anything else the
// convention plugin declares).
plugins {
id 'java-library'
id 'maven-publish'
}

repositories {
mavenCentral()
}

group = 'com.example'
version = '1.0.0'

publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.lib;

public class Utils {
public static String greet() {
return "hello from lib";
}
}
3 changes: 3 additions & 0 deletions testdata/gradle/buildsrcdependency/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rootProject.name = 'buildsrcdependency'
include 'api'
include 'lib'
Loading