如何确保仅向Nexus仓库上传新版本构件?禁止旧版本上传方案
Great question! I know the "Disable Redeploy" setting stops you from overwriting the same version, but blocking older versions entirely requires a bit more work. Here are the most reliable approaches:
1. Nexus Custom Script Hook (Best for Repository-Level Enforcement)
This is the most robust method because it intercepts uploads directly at the Nexus level, regardless of which tool (Maven, Gradle, CLI) is used. You'll need to create a Groovy script that checks the incoming version against the latest existing version for the same GAV.
Step-by-Step:
- Go to Nexus's Script Manager (under System → Scripts)
- Create a new Groovy script with the following logic (adjust for your repository type, e.g., Maven 2):
import org.sonatype.nexus.repository.Repository import org.sonatype.nexus.repository.storage.StorageFacet import org.sonatype.nexus.repository.storage.Query import org.sonatype.nexus.repository.storage.Component def repository = repository as Repository def storageFacet = repository.facet(StorageFacet) def tx = storageFacet.txSupplier().get() try { tx.begin() // Fetch existing component for the same group/name def componentQuery = Query.builder() .where("group = ").param(attributes.component.group) .and("name = ").param(attributes.component.name) .build() def existingComponents = tx.findComponents(componentQuery, repository) if (!existingComponents.isEmpty()) { // Get the highest existing version def latestExistingVersion = existingComponents.collect { it.version() } .sort { v1, v2 -> compareVersions(v2, v1) }[0] def incomingVersion = attributes.component.version // Compare versions - reject if incoming is older if (compareVersions(incomingVersion, latestExistingVersion) < 0) { throw new Exception("Upload rejected: Incoming version ${incomingVersion} is older than the latest repository version ${latestExistingVersion} for GAV ${attributes.component.group}:${attributes.component.name}") } } } finally { tx.close() } // Helper method to compare semantic versions (handles major/minor/patch + pre-releases) int compareVersions(String v1, String v2) { def parts1 = v1.split(/[\.-]/).collect { it.isInteger() ? it.toInteger() : it } def parts2 = v2.split(/[\.-]/).collect { it.isInteger() ? it.toInteger() : it } def minLen = Math.min(parts1.size(), parts2.size()) for (int i = 0; i < minLen; i++) { def part1 = parts1[i] def part2 = parts2[i] if (part1 instanceof Integer && part2 instanceof Integer) { if (part1 != part2) return part1 - part2 } else { // Handle pre-release tags (e.g., 1.0.0-beta vs 1.0.0) def strComp = part1.toString().compareTo(part2.toString()) if (strComp != 0) return strComp } } // Longer version wins if prefixes are identical (e.g., 1.0.0 vs 1.0.0.1) return parts1.size() - parts2.size() } - Save the script, then go to your repository's Settings → Hooks
- Add a new hook, select the script you created, and set the trigger to Before Component Creation (this runs right before the component is stored)
2. Build-Level Check (Maven/Gradle)
If you want to catch old versions early in your pipeline, add a check in your build tool before deploying. This prevents wasted time trying to upload an invalid version.
For Maven:
Add a Groovy plugin execution to your pom.xml that queries Nexus for the latest version and compares it to your project version:
<plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>gmaven-plugin</artifactId> <version>1.5</version> <executions> <execution> <phase>deploy</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> def nexusRestUrl = "http://your-nexus-url/service/rest/v1/search/assets?repository=maven-releases&group=${project.groupId}&name=${project.artifactId}&sort=version&direction=desc&limit=1" def latestVersion = new URL(nexusRestUrl).text.split('"version":"')[1].split('"')[0] def currentVersion = project.version // Reuse version comparison logic int compareVersions(String v1, String v2) { def parts1 = v1.split(/[\.-]/).collect { it.isInteger() ? it.toInteger() : it } def parts2 = v2.split(/[\.-]/).collect { it.isInteger() ? it.toInteger() : it } def minLen = Math.min(parts1.size(), parts2.size()) for (int i = 0; i < minLen; i++) { def p1 = parts1[i], p2 = parts2[i] if (p1 instanceof Integer && p2 instanceof Integer) { if (p1 != p2) return p1 - p2 } else { def comp = p1.toString().compareTo(p2.toString()) if (comp != 0) return comp } } return parts1.size() - parts2.size() } if (compareVersions(currentVersion, latestVersion) < 0) { throw new RuntimeException("Aborting deploy: Current version ${currentVersion} is older than latest Nexus version ${latestVersion}") } </source> </configuration> </execution> </executions> </plugin>
3. Routing Rules (Limited Use Case)
If your versioning follows a strict numeric pattern (e.g., only X.Y.Z), you could use Nexus Content Selectors and Routing Rules to block paths with older versions. However, this is less flexible than scripts because it can't handle complex formats (like pre-releases) or dynamic version comparisons.
Quick Example:
- Create a content selector that matches paths where the version is lower than your current latest (e.g.,
path =~ "/com/example/myapp/1\\.[0-1].*"if latest is 1.2) - Create a routing rule that rejects uploads matching this selector
Final Notes
The custom Nexus script is the gold standard here because it enforces the rule universally, even if someone tries to upload directly via the Nexus UI or CLI. The build-level check is a great complement to catch issues early in your CI/CD pipeline.
内容的提问来源于stack exchange,提问作者Vikdor

