2010-10-27 13 views
86

Mam projekt inny niż Java, który tworzy wersjonowany artefakt kompilacji i chcę go przesłać do repozytorium Nexusa. Ponieważ projekt nie jest Java, nie używa Mavenu do kompilacji. I wolałbym nie wprowadzać plików Maven/POM tylko po to, żeby dostać pliki do Nexusa.Prześlij artefakty do Nexusa, bez Mavena

Linki na blogach do Nexusa REST API kończą się na ścianie logowania, bez widocznego linku "utwórz użytkownika".

Jaki jest najlepszy (lub jakakolwiek rozsądna) metoda przesyłania artefaktów do repozytorium Nexusa bez Mavena? "bash + curl" byłoby świetne, a nawet skrypt w języku Python.

+0

Uwaga, upewnij się, że masz plik settings.xml w ~/.m2 z odpowiednimi serwerami i zdefiniowanym auth. –

Odpowiedz

90

Czy rozważasz użycie linii poleceń Maven do przesyłania plików?

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

To automatycznie wygeneruje Maven POM dla artefaktu.

Aktualizacja

Poniższy artykuł Sonatype stwierdza, że ​​"wdrażanie-file" plugin Maven jest najprostszym rozwiązaniem, ale również zapewnia kilka przykładów korzystania curl:

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

+0

Jeśli tylko to pozwoliłoby nam pobierać pliki bezpośrednio z tego pliku ZIP, ale wydaje się, że nie jest to możliwe, jeśli prześlesz go w ten sposób. – sorin

+0

@sorin Nie można pobrać plików z wnętrza za pomocą suwaka przy użyciu Maven. Jest to niezwykłe wymaganie i jedynym menedżerem zależności, który wiem, że może to zrobić, jest bluszcz (i to nie jest proste). Zobacz poniższy przykład: http://stackoverflow.com/questions/3445696/gradle-how-to-declare-a- zależność-od-a-jar-in-a-jar/ –

8

Nie ma potrzeby korzystania te polecenia .. możesz bezpośrednio użyć interfejsu sieciowego nexus, aby przesłać plik JAR przy użyciu parametrów GAV.

enter image description here

Więc to jest bardzo proste.

+19

GUI nie pomaga; Muszę być w stanie przesłać za pomocą skryptu wiersza polecenia używanego jako część procesu kompilacji. –

+0

Cóż, przekłada się na żądanie HTTP POST, nie sądzisz? –

+4

@YngveSneenLindal Oczywiście, ale to nie znaczy, że te argumenty POST to dobrze zdefiniowany interfejs API do publicznego użytku. –

6

Połączenia, które należy wykonać z Nexusem, to wywołania REST api.

Wtyczka maven-nexus to wtyczka Maven, której można użyć do wykonywania tych połączeń. Możesz stworzyć manekina z niezbędnymi właściwościami i wykonywać połączenia za pośrednictwem wtyczki Maven.

coś takiego:

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

Założone rzeczy:

  1. zdefiniowaniu serwera w katalogu ~/.m2/settings.xml nazwie sonatype-nexus-inscenizacja z użytkownikiem sonatype i hasło skonfigurować - prawdopodobnie już to zrobiłeś, jeśli wdrażasz migawki. Ale możesz znaleźć więcej informacji here.
  2. Twój lokalny plik settings.xml zawiera wtyczki nexus zgodne z podaną here.
  3. Pom.xml siedzący w bieżącym katalogu ma prawidłowe definicje Maven w swojej definicji. Jeśli nie, możesz określić groupId, artifactId i wersję w wierszu poleceń.
  4. Funkcja -Dauto = true wyłączy interaktywne monity, dzięki czemu można skryptować to.

Ostatecznie wszystko to tworzy połączenia REST z Nexusem. Jest pełny interfejs API REST Nexusa, ale nie miałem zbyt wiele szczęścia przy znajdowaniu dokumentacji, która nie jest za zaporą. Możesz włączyć tryb debugowania wtyczki powyżej i wymyślić go jednak za pomocą -Dnexus.verboseDebug=true -X.

Możesz także teoretycznie przejść do interfejsu użytkownika, włączyć panel Firebug Net i obserwować/POST usługi i wydedukować tam również ścieżkę.

2

Zwijanie się jest trudną drogą. Jeśli nie chcesz używać Maven (np niedozwolone)

Spójrz na bluszcz:

Inną opcją Gradle: http://www.gradle.org/docs/current/userguide/artifact_management.html#N14566

58

Korzystanie 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 

można zobaczyć, jakie parametry tu na myśli: https://support.sonatype.com/entries/22189106-How-can-I-programatically-upload-an-artifact-into-Nexus-

Aby uczynić trwała ondulacja dla tej pracy, stworzyłem nową rolę w GUI administratora i dodałem dwa uprawnienia do tej roli: pobieranie artefaktów i przesyłanie artefaktów. Standardowe "Repo: Wszystkie repozytorium Maven (pełna kontrola)" - rola nie wystarczy. Nie znajdziesz tego w dokumentacji interfejsu API REST, która jest dołączona do serwera Nexus, więc te parametry mogą ulec zmianie w przyszłości.

Na a Sonatype JIRA issue wspomniano, że "zamierzają dokonać przeglądu interfejsu API REST (i sposobu, w jaki generowana jest jego dokumentacja) w nadchodzącym wydaniu, najprawdopodobniej w tym roku".

+0

, powiedzmy, że publikujemy w Jenkins i zezwalamy tylko użytkownikom kompilacji na publikowanie na Nexusie , w jaki sposób zarządzasz zwykłym problemem z hasłem? Czy Jenkins ma wtyczkę do przesyłania, abyśmy mogli użyć referencji Jenkins? –

3

dla tych, którzy potrzebują go w Javie, używając httpcomponents apache 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

pierwszy post. Próbowałem dodać higlighting dla java, ale nie mogłem go zdobyć. – McMosfet

7

Można ABSOLUTNIE zrobić bez używania niczego Maven związane. Osobiście używam HttpClient NING (v1.8.16, do obsługi java6).

Bez względu na przyczynę, Sonatype sprawia, że ​​trudno jest uzyskać , jakie są prawidłowe URL-e, nagłówki i ładunki; musiałem obwąchać ruch i zgadnąć ... Jest tam tylko ledwie przydatnych blogów/dokumentacji, jednak nie ma to znaczenia dla oss.sonatype.org, lub jest oparte na XML (i dowiedziałem się, że to nawet nie działa). Bzdury z ich strony, IMHO i miejmy nadzieję, że przyszli poszukiwacze mogą uznać tę odpowiedź za przydatną. Wielkie dzięki dla https://stackoverflow.com/a/33414423/2101812 za ich post, ponieważ bardzo pomogło.

Jeśli zwolnisz plik inny niż oss.sonatype.org, po prostu zastąp go dowolnym właściwym hostem.

Oto kod (licencjonowany CC0), który napisałem, aby to osiągnąć. Gdzie profile to Twój identyfikator profilu sonatype/nexus (taki jak 4364f3bbaf163) i repo (taki jak comdorkbox-1003) są analizowane z odpowiedzi podczas przesyłania początkowego POM/Słoika.

Close repo:

/** 
* 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); 
} 

Promuj repo:

/** 
* 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); 
} 

Kropla repo:

/** 
* 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); 
} 

Usuwanie turds Podpis:

/** 
* 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); 
} 

pliku dodane:

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:

Jak uzyskać aktywność/stan na repo

/** 
* 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

Jeśli potrzebujesz wygodny interfejs wiersza poleceń lub Python API, wygląd pod adresem repositorytools

1

Można również użyć metody bezpośredniego wdrażania za pomocą loków. Nie potrzebujesz do tego pliku pom, ale nie zostanie on wygenerowany, więc jeśli chcesz, musisz go przesłać osobno.

Oto polecenie:

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

Można użyć curl zamiast.

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

ta odpowiedź jest nieprawidłowa. Z curl, groupId powinien być reprezentowany jako org/myorg (zamiast kropki "." Z ukośnikiem "/") – madduci

Powiązane problemy