2010-10-27 177 views
86

Tengo un proyecto que no es Java que produce un artefacto de construcción versionado, y quiero subirlo a un repositorio de Nexus. Como el proyecto no es Java, no usa Maven para compilaciones. Y prefiero no presentar archivos Maven/POM solo para obtener archivos en Nexus.Carga de artefactos a Nexus, sin Maven

Los enlaces en los blogs a la API de REST de Nexus terminan en un muro de inicio de sesión, sin ningún vínculo de "crear usuario" que pueda ver.

Entonces, ¿cuál es la mejor (o cualquier otra forma razonable) de cargar artefactos de construcción a un repositorio Nexus sin Maven? "bash + curl" sería genial, o incluso una secuencia de comandos de Python.

+0

Nota, asegúrese de tener un settings.xml en ~/.m2 con los servidores adecuados y auth definidos. –

Respuesta

90

¿Está considerando utilizar la línea de comandos de Maven para cargar archivos?

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

Esto generará automáticamente el POM de Maven para el artefacto.

actualización

El siguiente artículo Sonatype establece que el plugin Maven "desplegar-archivo" es la solución más fácil, sino que también proporciona algunos ejemplos utilizando rizo:

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

+0

Si solo esto nos permitiera descargar archivos desde este zip directamente, parece que no es posible si lo carga así. – sorin

+0

@sorin No es posible descargar archivos desde dentro en un zip usando Maven. Es un requisito inusual y el único administrador de dependencias que sé que puede hacerlo es ivy (y no es simple) vea el siguiente ejemplo: http://stackoverflow.com/questions/3445696/gradle-how-to-declare-a- dependency-of-a-jar-in-a-jar/ –

8

No hay necesidad de usar estos comandos ... puede usar directamente la interfaz web nexus para cargar su JAR utilizando los parámetros de GAV.

enter image description here

lo que es muy sencillo.

+19

Una GUI no ayuda; Necesito poder subir a través de un script de línea de comandos utilizado como parte de un proceso de compilación. –

+0

Bueno, se traduce en una solicitud HTTP POST, ¿no crees? –

+4

@YngveSneenLindal Claro, pero eso no significa que esos argumentos POST sean una API bien definida para usar públicamente. –

6

Las llamadas que debe realizar contra Nexus son llamadas REST api.

El plugin maven-nexus es un plugin Maven que puede usar para realizar estas llamadas. Podrías crear un pom ficticio con las propiedades necesarias y hacer esas llamadas a través del plugin Maven.

algo como:

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

cosas asumidas:

  1. ha definido un servidor en su ~/.m2/settings.xml llamado Sonatype-Nexus-puesta en escena con su usuario y contraseña Sonatype configurar - probablemente ya habrá hecho esto si está implementando instantáneas. Pero puedes encontrar más información here.
  2. Su configuración local.xml incluye los complementos nexus como se especifica here.
  3. El pom.xml que se encuentra en su directorio actual tiene las coordenadas Maven correctas en su definición. De lo contrario, puede especificar groupId, artifactId y version en la línea de comando.
  4. El -Dauto = true desactivará las indicaciones interactivas para que pueda crear una secuencia de comandos.

En última instancia, todo esto es crear llamadas REST en Nexus. Hay una API completa de REST de Nexus, pero he tenido poca suerte para encontrar documentación que no esté detrás de un muro de pago. Puede activar el modo de depuración para el complemento anterior y resolverlo utilizando -Dnexus.verboseDebug=true -X.

En teoría, también podría entrar en la interfaz de usuario, activar el panel Firebug Net y buscar/realizar POST y deducir una ruta allí también.

2

Curl es el camino más difícil. Si no desea utilizar experto (por ejemplo: no autorizado)

Tome un vistazo a la hiedra :

Otra opción Gradle: http://www.gradle.org/docs/current/userguide/artifact_management.html#N14566

58

El uso de rizo:

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 

Se puede ver cuáles son los parámetros significan aquí: https://support.sonatype.com/entries/22189106-How-can-I-programatically-upload-an-artifact-into-Nexus-

Para hacer el permanente Para este trabajo, creé un nuevo rol en la GUI de administración y agregué dos privilegios a esa función: descarga de artefactos y carga de artefactos. El estándar "Repo: todos los repositorios Maven (control total)": el rol no es suficiente. No encontrará esto en la documentación de la API REST que viene incluida con el servidor Nexus, por lo que estos parámetros podrían cambiar en el futuro.

En a Sonatype JIRA issue, se mencionó que "van a revisar la API REST (y la forma en que se genera la documentación) en una próxima versión, muy probablemente a finales de este año".

+0

digamos que publicamos desde Jenkins, y solo permitimos que los usuarios de compilación publiquen en Nexus , ¿cómo gestionas el problema de la contraseña simple? ¿Jenkins tiene un complemento para la carga para que podamos usar las credenciales de Jenkins? –

3

para aquellos que lo necesitan en Java, utilizando 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

primera publicación. He intentado agregar iluminación en relieve para Java pero no pude conseguirlo. – McMosfet

7

Usted puede ABSOLUTAMENTE hacer esto sin usar MAVEN todo lo relacionado. Yo personalmente uso el NING HttpClient (v1.8.16, para admitir java6).

Por alguna razón, Sonatype lo hace increíblemente dificultad para descubrir cuáles son las URL, los encabezados y las cargas útiles correctos; y tuve que olfatear el tráfico y adivinar ... Hay algunos apenas blogs/documentación útil allí, sin embargo es irrelevante para oss.sonatype.org, o está basado en XML (y descubrí que ni siquiera funciona). La documentación de mierda por su parte, en mi humilde opinión, y con suerte los futuros buscadores pueden encontrar esta respuesta útil. Muchas gracias a https://stackoverflow.com/a/33414423/2101812 por su publicación, ya que ayudó mucho.

Si libera en algún lugar que no sea oss.sonatype.org, simplemente reemplácelo con el host correcto.

Aquí está el código (con licencia CC0) que escribí para lograr esto. Donde profile es su sonatype/nexus profileID (como 4364f3bbaf163) y repo (como comdorkbox-1003) se analizan desde la respuesta cuando carga su POM/Jar inicial.

Cerrar 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); 
} 

Promover 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); 
} 

gota 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); 
} 

Eliminar turds firma:

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

La carga de archivos:

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:

¿Cómo obtener la actividad/estado de un acuerdo de recompra

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

Si necesita una interfaz de línea de comandos conveniente o API Python, mire en repositorytools

1

También puede usar el método de despliegue directo usando curl. No necesita un pom para su archivo, pero tampoco se generará así que si quiere uno, tendrá que cargarlo por separado.

Este es el comando:

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

Puede utilizar rizo en su lugar.

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

esta respuesta no es correcta. Con curl, el ID de grupo debe representarse como org/myorg (sustituya el punto "." Con barra "/") – madduci

Cuestiones relacionadas