2010-10-27 144 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

相關問題