2010-10-27 137 views
86

我有一个非Java项目生成版本化构建工件,我想将其上传到Nexus存储库。由于该项目不是Java,因此它不使用Maven进行构建。我宁愿不介绍Maven/POM文件只是为了获取文件到Nexus中。将工件上传到Nexus,无需Maven

博客上的链接到Nexus REST API都在登录墙上结束,没有“创建用户”链接,我可以看到。

那么,什么是最好的(或任何合理的)上传构建工件到没有Maven的Nexus存储库? “bash + curl”会很棒,甚至是Python脚本。

+0

请注意,请确保在〜/ .m2中有一个settings.xml,并定义了相应的服务器&auth。 – 2010-10-27 21:39:37

回答

90

您是否考虑过使用Maven命令行上传文件?

mvn deploy:deploy-file \ 
    -Durl=$REPO_URL \ 
    -DrepositoryId=$REPO_ID \ 
    -DgroupId=org.myorg \ 
    -DartifactId=myproj \ 
    -Dversion=1.2.3 \ 
    -Dpackaging=zip \ 
    -Dfile=myproj.zip 

这会自动生成工件的Maven POM。

更新

以下Sonatype的文章指出,“部署文件” maven插件是最简单的解决方案,但它也使用提供了一些例子卷曲:

https://support.sonatype.com/entries/22189106-How-can-I-programatically-upload-an-artifact-into-Nexus-

+0

如果只有这样才能让我们直接从这个zip文件中下载文件,但是如果你像这样上传它似乎是不可能的。 – sorin 2015-06-29 17:04:31

+0

@sorin使用Maven无法从zip文件中下载文件。这是一个不寻常的要求,我知道唯一可以做到的依赖管理器就是常春藤(而且这不是简单的),请参阅以下示例:http://stackoverflow.com/questions/3445696/gradle-how-to-declare-a-一个jar中的依赖关系/ – 2015-06-30 06:36:05

8

无需使用这些命令..你可以直接使用nexus web Interface来使用GAV参数上传你的JAR。

enter image description here

所以这是非常简单的。

+19

一个GUI不起作用;我需要能够通过作为构建过程一部分的命令行脚本进行上传。 – 2011-02-22 18:51:59

+0

嗯,它转换为HTTP POST请求,你不觉得吗? – 2013-10-10 07:54:35

+4

@YngveSneenLindal当然,但这并不意味着这些POST参数是一个公开使用的定义良好的API。 – 2014-10-01 16:18:55

6

您需要针对Nexus进行的调用是REST API调用。

maven-nexus-plugin是一个Maven插件,您可以使用这些插件进行这些调用。您可以创建一个具有必要属性的虚拟pom,并通过Maven插件进行这些调用。

喜欢的东西:

mvn -DserverAuthId=sonatype-nexus-staging -Dauto=true nexus:staging-close 

假设的东西:你的Sonatype的用户名和密码

  1. 你已经在你的〜/ .m2目录/ settings.xml中定义的服务器名为Sonatype的-NEXUS-分期设置 - 如果您正在部署快照,则可能已经完成了此操作。但是你可以找到更多信息here
  2. 您的本地settings.xml包含指定为here的nexus插件。
  3. 位于当前目录中的pom.xml在其定义中具有正确的Maven坐标。如果没有,您可以在命令行上指定groupId,artifactId和版本。
  4. -Dauto = true将关闭交互式提示,以便您可以编写脚本。

最终,所有这些工作都是将REST调用创建到Nexus中。有一个完整的Nexus REST api,但我没有找到它的付费墙背后的文档。您可以打开上述插件的调试模式,然后使用-Dnexus.verboseDebug=true -X进行计算。

你理论上也可以进入UI,打开Firebug Net面板,并观察/服务POST并在那里推导出一条路径。

58

使用curl:

curl -v \ 
    -F "r=releases" \ 
    -F "g=com.acme.widgets" \ 
    -F "a=widget" \ 
    -F "v=0.1-1" \ 
    -F "p=tar.gz" \ 
    -F "[email protected]/widget-0.1-1.tar.gz" \ 
    -u myuser:mypassword \ 
    http://localhost:8081/nexus/service/local/artifact/maven/content 

你可以看到参数这里指的是:https://support.sonatype.com/entries/22189106-How-can-I-programatically-upload-an-artifact-into-Nexus-

要使烫发为此工作的发布,我在管理GUI中创建了一个新角色,并为该角色添加了两项权限:工件下载和工件上传。标准的“回购:所有Maven仓库(完全控制)” - 角色是不够的。 您不会在随Nexus服务器捆绑的REST API文档中找到它,因此这些参数将来可能会发生变化。

a Sonatype JIRA issue上,有人提到他们“将在即将发布的版本中彻底检查REST API(以及它生成文档的方式),很可能在今年晚些时候”。

+0

比方说,我们从詹金斯发布,只允许构建用户发布到Nexus ,你如何管理简单的密码问题?詹金斯有上传插件,所以我们可以使用詹金斯凭据? – 2016-01-21 17:45:45

3

对于那些谁需要它在Java中,使用Apache httpcomponents 4.0:

public class PostFile { 
    protected HttpPost httppost ; 
    protected MultipartEntity mpEntity; 
    protected File filePath; 

    public PostFile(final String fullUrl, final String filePath){ 
     this.httppost = new HttpPost(fullUrl); 
     this.filePath = new File(filePath);   
     this.mpEntity = new MultipartEntity(); 
    } 

    public void authenticate(String user, String password){ 
     String encoding = new String(Base64.encodeBase64((user+":"+password).getBytes())); 
     httppost.setHeader("Authorization", "Basic " + encoding); 
    } 
    private void addParts() throws UnsupportedEncodingException{ 
     mpEntity.addPart("r", new StringBody("repository id")); 
     mpEntity.addPart("g", new StringBody("group id")); 
     mpEntity.addPart("a", new StringBody("artifact id")); 
     mpEntity.addPart("v", new StringBody("version")); 
     mpEntity.addPart("p", new StringBody("packaging")); 
     mpEntity.addPart("e", new StringBody("extension")); 

     mpEntity.addPart("file", new FileBody(this.filePath)); 

    } 

    public String post() throws ClientProtocolException, IOException { 
     HttpClient httpclient = new DefaultHttpClient(); 
     httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); 
     addParts(); 
     httppost.setEntity(mpEntity); 
     HttpResponse response = httpclient.execute(httppost); 

     System.out.println("executing request " + httppost.getRequestLine()); 
     System.out.println(httppost.getEntity().getContentLength()); 

     HttpEntity resEntity = response.getEntity(); 

     String statusLine = response.getStatusLine().toString(); 
     System.out.println(statusLine); 
     if (resEntity != null) { 
      System.out.println(EntityUtils.toString(resEntity)); 
     } 
     if (resEntity != null) { 
      resEntity.consumeContent(); 
     } 
     return statusLine; 
    } 
} 
+0

第一篇文章。我已经尝试为java添加higlight,但cound't没有得到它。 – McMosfet 2015-10-29 12:53:31

7

可以ABSOLUTELY做到这一点,而无需使用任何相关MAVEN。我个人使用NING HttpClient(v1.8.16,支持java6)。

无论出于何种原因,Sonatype使其难以置信地难以找出正确的URL,标题和有效载荷应该是什么;我不得不嗅出交通和猜测......有一些勉强有用的博客/文档存在,但它是两种不相干的oss.sonatype.org,或者它是一个基于XML(和我发现它甚至不工作)。垃圾文件,恕我直言,希望未来的求职者可以找到有用的答案。非常感谢https://stackoverflow.com/a/33414423/2101812他们的帖子,因为它帮助了很多。

如果放开地方比其他oss.sonatype.org,只是无论正确的主机是取代它。

这是我写的(CC0许可)代码来完成此操作。其中profile是您在上载初始POM/Jar时从响应中解析出的sonatype/nexus profileID(如4364f3bbaf163)和repo(如comdorkbox-1003)。

关闭回购:

/** 
* Closes the repo and (the server) will verify everything is correct. 
* @throws IOException 
*/ 
private static 
String closeRepo(final String authInfo, final String profile, final String repo, final String nameAndVersion) throws IOException { 

    String repoInfo = "{'data':{'stagedRepositoryId':'" + repo + "','description':'Closing " + nameAndVersion + "'}}"; 
    RequestBuilder builder = new RequestBuilder("POST"); 
    Request request = builder.setUrl("https://oss.sonatype.org/service/local/staging/profiles/" + profile + "/finish") 
          .addHeader("Content-Type", "application/json") 
          .addHeader("Authorization", "Basic " + authInfo) 

          .setBody(repoInfo.getBytes(OS.UTF_8)) 

          .build(); 

    return sendHttpRequest(request); 
} 

推动回购:

/** 
* Promotes (ie: release) the repo. Make sure to drop when done 
* @throws IOException 
*/ 
private static 
String promoteRepo(final String authInfo, final String profile, final String repo, final String nameAndVersion) throws IOException { 

    String repoInfo = "{'data':{'stagedRepositoryId':'" + repo + "','description':'Promoting " + nameAndVersion + "'}}"; 
    RequestBuilder builder = new RequestBuilder("POST"); 
    Request request = builder.setUrl("https://oss.sonatype.org/service/local/staging/profiles/" + profile + "/promote") 
        .addHeader("Content-Type", "application/json") 
        .addHeader("Authorization", "Basic " + authInfo) 

        .setBody(repoInfo.getBytes(OS.UTF_8)) 

        .build(); 
    return sendHttpRequest(request); 
} 

跌落式回购:

/** 
* Drops the repo 
* @throws IOException 
*/ 
private static 
String dropRepo(final String authInfo, final String profile, final String repo, final String nameAndVersion) throws IOException { 

    String repoInfo = "{'data':{'stagedRepositoryId':'" + repo + "','description':'Dropping " + nameAndVersion + "'}}"; 
    RequestBuilder builder = new RequestBuilder("POST"); 
    Request request = builder.setUrl("https://oss.sonatype.org/service/local/staging/profiles/" + profile + "/drop") 
        .addHeader("Content-Type", "application/json") 
        .addHeader("Authorization", "Basic " + authInfo) 

        .setBody(repoInfo.getBytes(OS.UTF_8)) 

        .build(); 

    return sendHttpRequest(request); 
} 

删除签名turds:

/** 
* Deletes the extra .asc.md5 and .asc.sh1 'turds' that show-up when you upload the signature file. And yes, 'turds' is from sonatype 
* themselves. See: https://issues.sonatype.org/browse/NEXUS-4906 
* @throws IOException 
*/ 
private static 
void deleteSignatureTurds(final String authInfo, final String repo, final String groupId_asPath, final String name, 
          final String version, final File signatureFile) 
       throws IOException { 

    String delURL = "https://oss.sonatype.org/service/local/repositories/" + repo + "/content/" + 
        groupId_asPath + "/" + name + "/" + version + "/" + signatureFile.getName(); 

    RequestBuilder builder; 
    Request request; 

    builder = new RequestBuilder("DELETE"); 
    request = builder.setUrl(delURL + ".sha1") 
        .addHeader("Authorization", "Basic " + authInfo) 
        .build(); 
    sendHttpRequest(request); 

    builder = new RequestBuilder("DELETE"); 
    request = builder.setUrl(delURL + ".md5") 
        .addHeader("Authorization", "Basic " + authInfo) 
        .build(); 
    sendHttpRequest(request); 
} 

文件上传:

public 
    String upload(final File file, final String extension, String classification) throws IOException { 

     final RequestBuilder builder = new RequestBuilder("POST"); 
     final RequestBuilder requestBuilder = builder.setUrl(uploadURL); 
     requestBuilder.addHeader("Authorization", "Basic " + authInfo) 

         .addBodyPart(new StringPart("r", repo)) 
         .addBodyPart(new StringPart("g", groupId)) 
         .addBodyPart(new StringPart("a", name)) 
         .addBodyPart(new StringPart("v", version)) 
         .addBodyPart(new StringPart("p", "jar")) 
         .addBodyPart(new StringPart("e", extension)) 
         .addBodyPart(new StringPart("desc", description)); 


     if (classification != null) { 
      requestBuilder.addBodyPart(new StringPart("c", classification)); 
     } 

     requestBuilder.addBodyPart(new FilePart("file", file)); 
     final Request request = requestBuilder.build(); 

     return sendHttpRequest(request); 
    } 

EDIT1:

如何获得回购活动/状态

/** 
* Gets the activity information for a repo. If there is a failure during verification/finish -- this will provide what it was. 
* @throws IOException 
*/ 
private static 
String activityForRepo(final String authInfo, final String repo) throws IOException { 

    RequestBuilder builder = new RequestBuilder("GET"); 
    Request request = builder.setUrl("https://oss.sonatype.org/service/local/staging/repository/" + repo + "/activity") 
          .addHeader("Content-Type", "application/json") 
          .addHeader("Authorization", "Basic " + authInfo) 

          .build(); 

    return sendHttpRequest(request); 
} 
0

如果你需要一个方便的命令行界面或Python API,看看在repositorytools

1

您也可以使用使用curl的直接部署方法。你不需要为你的文件需要一个pom文件,但它不会生成,所以如果你想要一个,你将不得不单独上传它。

下面是一个命令:

version=1.2.3 
artefact="myartefact" 
repoId=yourrepository 
groupId=org.myorg 
REPO_URL=http://localhost:8081/nexus 

curl -u nexususername:nexuspassword --upload-file filename.tgz $REPO_URL/content/repositories/$repoId/$groupId/$artefact/$version/$artefact-$version.tgz 
-2

您可以使用卷曲来代替。

version=1.2.3 
artifact="artifact" 
repoId=repositoryId 
groupId=org/myorg 
REPO_URL=http://localhost:8081/nexus 

curl -u username:password --upload-file filename.tgz $REPO_URL/content/repositories/$repoId/$groupId/$artefact/$version/$artifact-$version.tgz 
+0

这个答案不正确。使用curl时,groupId应表示为org/myorg(用斜杠“/”替换点“。”) – madduci 2017-09-01 06:25:53

相关问题