代码之家  ›  专栏  ›  技术社区  ›  Adam Vandenberg

上传工件到Nexus,不带Maven

  •  91
  • Adam Vandenberg  · 技术社区  · 15 年前

    那么,在没有Maven的情况下,将构建工件上传到Nexus存储库的最佳(或任何合理)方法是什么?”“bash+curl”会很棒,甚至是一个Python脚本。

    12 回复  |  直到 15 年前
        1
  •  97
  •   Mark O'Connor    12 年前

    你考虑过用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。

    更新

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

        2
  •  63
  •   Ed I    10 年前

    使用卷曲:

    curl -v \
        -F "r=releases" \
        -F "g=com.acme.widgets" \
        -F "a=widget" \
        -F "v=0.1-1" \
        -F "p=tar.gz" \
        -F "file=@./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中创建了一个新角色,并向该角色添加了两个权限:工件下载和工件上载。标准的“Repo:All Maven Repositories(Full Control)”-角色是不够的。

    打开 a Sonatype JIRA issue

        3
  •  8
  •   Praneel PIDIKITI    15 年前

    不需要使用这些命令。。为了使用GAV参数上传JAR,可以直接使用nexus web接口。

    enter image description here

    所以很简单。

        4
  •  8
  •   Community Mohan Dere    9 年前

    你可以 绝对的

    不管是什么原因,Sonatype都能做到 很难找出正确的url、头和有效负载应该是什么;我不得不嗅探流量并猜测。。。有一些 有用的博客/文档,但是它与 oss.sonatype.org https://stackoverflow.com/a/33414423/2101812 为了他们的职位,因为这帮了很多忙。

    如果你在别的地方释放 oss.sonatype.org网站 ,只需将其替换为正确的主机。

    这是我为实现这一点而编写的(CC0许可)代码。在哪里? profile 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);
    }
    

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

    编辑1:

    如何获取回购的活动/状态

    /**
     * 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);
    }
    
        5
  •  6
  •   Alex Miller    15 年前

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

    类似于:

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

    假设的事情:

    1. here .
    2. 本地设置.xml包含指定的nexus插件 here
    3. 位于当前目录中的pom.xml在其定义中具有正确的Maven坐标。如果没有,可以在命令行上指定groupId、artifactId和version。
    4. -Dauto=true将关闭交互式提示,以便您可以编写脚本。

    最终,所有这些都是在Nexus中创建REST调用。有一个完整的NexusRESTAPI,但是我很难找到不在付费墙后面的文档。您可以打开上面插件的调试模式,然后使用 -Dnexus.verboseDebug=true -X .

        6
  •  3
  •   McMosfet    10 年前

    对于那些需要Java语言的用户,使用ApacheHttpComponents 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;
        }
    }
    
        7
  •  2
  •   Vadim    7 年前

    红宝石色 https://github.com/RiotGames/nexus_cli

    用法示例:

    nexus-cli push_artifact com.mycompany.artifacts:myartifact:tgz:1.0.0 ~/path/to/file/to/push/myartifact.tgz
    

    .nexus_cli 文件。

    url:            "http://my-nexus-server/nexus/"
    repository:     "my-repository-id"
    username:       "username"
    password:       "password"
    
        8
  •  2
  •   Djidiouf    6 年前

    您还可以使用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
    
        9
  •  1
  •   Vadim    7 年前

    如果您需要一个方便的命令行接口或python API,请查看 repositorytools

    使用它,您可以使用命令将工件上载到nexus

    artifact upload foo-1.2.3.ext releases com.fooware
    

    export REPOSITORY_URL=https://repo.example.com
    export REPOSITORY_USER=admin
    export REPOSITORY_PASSWORD=mysecretpassword
    
        10
  •  0
  •   jijendiran    7 年前

    您可以通过单击Nexus服务器中的upload artifact s按钮手动上传工件,并提供上传所需的GAV属性(通常是存储工件的文件结构)

        11
  •  0
  •   adrianlzt    7 年前

    https://support.sonatype.com/hc/en-us/articles/115006744008-How-can-I-programmatically-upload-files-into-Nexus-3-

    版本3.9.0到3.13.0的示例:

    curl -D - -u user:pass -X POST "https://nexus.domain/nexus/service/rest/beta/components?repository=somerepo" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "raw.directory=/test/" -F "raw.asset1=@test.txt;type=application/json" -F "raw.asset1.filename=test.txt"
    
        12
  •  -1
  •   Mano Anbalagan    6 年前

    @Adam Vandenberg为Java代码发布到Nexus。 https://github.com/manbalagan/nexusuploader

    public class NexusRepository implements RepoTargetFactory {
    
        String DIRECTORY_KEY= "raw.directory";
        String ASSET_KEY= "raw.asset1";
        String FILENAME_KEY= "raw.asset1.filename";
    
        String repoUrl;
        String userName;
        String password;
    
        @Override
        public void setRepoConfigurations(String repoUrl, String userName, String password) {
            this.repoUrl = repoUrl;
            this.userName = userName;
            this.password = password;
        }
    
        public String pushToRepository() {
            HttpClient httpclient = HttpClientBuilder.create().build();
            HttpPost postRequest = new HttpPost(repoUrl) ;
            String auth = userName + ":" + password;
            byte[] encodedAuth = Base64.encodeBase64(
                    auth.getBytes(StandardCharsets.ISO_8859_1));
            String authHeader = "Basic " + new String(encodedAuth);
            postRequest.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
            try
            {
                byte[] packageBytes = "Hello. This is my file content".getBytes();
                MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
                InputStream packageStream = new ByteArrayInputStream(packageBytes);
                InputStreamBody inputStreamBody = new InputStreamBody(packageStream, ContentType.APPLICATION_OCTET_STREAM);
                multipartEntityBuilder.addPart(DIRECTORY_KEY, new StringBody("DIRECTORY"));
                multipartEntityBuilder.addPart(FILENAME_KEY, new StringBody("MyFile.txt"));
                multipartEntityBuilder.addPart(ASSET_KEY, inputStreamBody);
                HttpEntity entity = multipartEntityBuilder.build();
                postRequest.setEntity(entity); ;
    
                HttpResponse response = httpclient.execute(postRequest) ;
                if (response != null)
                {
                    System.out.println(response.getStatusLine().getStatusCode());
                }
            }
            catch (Exception ex)
            {
                ex.printStackTrace() ;
            }
            return null;
        }
    
    }
    
        13
  •  -2
  •   Community Mohan Dere    8 年前

    你可以用卷曲代替。

    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