Tải phần mềm lên Nexus mà không có Maven


102

Tôi có một dự án không phải Java tạo ra một cấu phần phần mềm xây dựng có phiên bản và tôi muốn tải nó lên kho lưu trữ Nexus. Vì dự án không phải là Java nên nó không sử dụng Maven cho các bản dựng. Và tôi không muốn giới thiệu tệp Maven / POM chỉ để đưa tệp vào Nexus.

Tất cả các liên kết trên blog tới API REST của Nexus đều kết thúc ở một bức tường đăng nhập, không có liên kết "tạo người dùng" nào mà tôi có thể nhìn thấy.

Vì vậy, cách tốt nhất (hoặc bất kỳ cách hợp lý nào) để tải các tạo tác bản dựng lên kho lưu trữ Nexus mà không có Maven là gì? "bash + curl" sẽ rất tuyệt, hoặc thậm chí là một tập lệnh Python.


Lưu ý, hãy đảm bảo rằng bạn có settings.xml trong ~ / .m2 với các máy chủ & auth thích hợp được xác định.
Adam Vandenberg

Câu trả lời:


98

Bạn đã cân nhắc sử dụng dòng lệnh Maven để tải tệp lên chưa?

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

Điều này sẽ tự động tạo Maven POM cho hiện vật.

Cập nhật

Bài viết Sonatype sau đây nói rằng plugin maven "tệp tin triển khai" là giải pháp dễ dàng nhất, nhưng nó cũng cung cấp một số ví dụ sử dụng curl:

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


Giá như điều này sẽ cho phép chúng tôi tải xuống các tệp từ bên trong tệp zip này trực tiếp nhưng có vẻ như không thể nếu bạn tải nó lên như thế này.
sorin

@sorin Không thể tải tệp xuống từ tệp zip bằng Maven. Đây là một yêu cầu không bình thường và người quản lý phụ thuộc duy nhất tôi biết rằng có thể làm điều đó là ivy (và nó không phải đơn giản) xem ví dụ sau: stackoverflow.com/questions/3445696/...
Đánh dấu O'Connor

Tôi đã cài đặt Nexus để làm cho mọi thứ trở nên đơn giản hơn, nhưng điều gì xảy ra với điều này? .. Điều gì sẽ xảy ra nếu tôi có một số JAR sản xuất tại nhà mà không biết về các phụ thuộc của nó? IDE của tôi liên tục phàn nàn về việc thiếu * .pom. Tôi hy vọng rằng Nexus đã xử lý điều đó cho tôi, nhưng KHÔNG CÓ GÌ ...
vintproykt

66

Sử dụng cuộn tóc:

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

Bạn có thể xem ý nghĩa của các thông số tại đây: https://support.sonatype.com/entries/22189106-How-can-I-programatically-upload-an-artifact-into-Nexus-

Để thực hiện các quyền cho công việc này, tôi đã tạo một vai trò mới trong GUI quản trị và tôi đã thêm hai đặc quyền vào vai trò đó: Tải xuống phần mềm và Tải lên phần mềm. Tiêu chuẩn "Repo: All Maven Repositories (Full Control)" - vai trò là không đủ. Bạn sẽ không tìm thấy điều này trong tài liệu REST API đi kèm với máy chủ Nexus, vì vậy các thông số này có thể thay đổi trong tương lai.

Về vấn đề Sonatype JIRA , người ta đã đề cập rằng họ "sẽ đại tu API REST (và cách tạo tài liệu của nó) trong một bản phát hành sắp tới, rất có thể là vào cuối năm nay".


giả sử chúng tôi xuất bản từ Jenkins và chỉ cho phép người dùng bản dựng xuất bản lên Nexus, làm cách nào để bạn quản lý vấn đề mật khẩu đơn giản? Jenkins có plugin để tải lên để chúng tôi có thể sử dụng thông tin đăng nhập Jenkins không?
Jirong Hu

8

Không cần sử dụng các lệnh này .. bạn có thể trực tiếp sử dụng Giao diện web nexus để tải lên JAR của mình bằng các tham số GAV.

nhập mô tả hình ảnh ở đây

Vì vậy, nó là rất đơn giản.


24
GUI không giúp ích được gì; Tôi cần có thể tải lên thông qua tập lệnh dòng lệnh được sử dụng như một phần của quy trình xây dựng.
Adam Vandenberg

Chà, nó chuyển thành một yêu cầu HTTP POST, bạn có nghĩ vậy không?
Yngve Sneen Lindal

5
@YngveSneenLindal Chắc chắn rồi, nhưng điều đó không có nghĩa là các đối số POST đó là một API được xác định rõ để sử dụng công khai.
Ken Williams

@KenWilliams Chắc chắn, tôi cũng không khẳng định điều đó. Nhưng chúng sẽ hoạt động và đại diện cho một giải pháp, đó là quan điểm của tôi.
Yngve Sneen Lindal

Ít nhất, đối với Sonatype Nexus ™ 2.11.1-01 của chúng tôi, tôi đã phải cấp đặc quyền cho người dùng Artifact Upload. Thật không may, tôi không thể tìm thấy bất kỳ điều gì trong tài liệu đề cập đến điều này ... (Chỉnh sửa: Tôi hiểu rồi, Ed Tôi đã chỉ ra điều này )
Alberto

8

Bạn có thể TUYỆT ĐỐI làm điều này mà không cần sử dụng bất cứ thứ gì liên quan đến MAVEN. Cá nhân tôi sử dụng NING HttpClient (v1.8.16, để hỗ trợ java6).

Vì bất cứ lý do gì, Sonatype khiến việc tìm ra URL, tiêu đề và trọng tải chính xác được cho là vô cùng khó khăn; và tôi phải đánh hơi lưu lượng truy cập và đoán ... Có một số blog / tài liệu hầu như không hữu ích ở đó, tuy nhiên nó không liên quan oss.sonatype.orghoặc nó dựa trên XML (và tôi phát hiện ra nó thậm chí không hoạt động). Tài liệu tào lao về phía họ, IMHO, và hy vọng những người tìm kiếm trong tương lai có thể thấy câu trả lời này hữu ích. Rất cảm ơn https://stackoverflow.com/a/33414423/2101812 cho bài đăng của họ, vì nó đã giúp ích rất nhiều.

Nếu bạn phát hành ở một nơi khác oss.sonatype.org, chỉ cần thay thế nó bằng bất kỳ máy chủ lưu trữ chính xác là.

Đây là mã (được cấp phép CC0) tôi đã viết để thực hiện điều này. Trong trường hợp profileđược sonatype bạn / nexus profileID (như 4364f3bbaf163) và repo(như comdorkbox-1003) đều được phân tích từ các phản ứng khi bạn tải lên POM ban đầu của bạn / Jar.

Đóng 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);
}

Quảng cáo 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);
}

Thả 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);
}

Xóa các lượt thay đổi chữ ký:

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

Tải lên tệp:

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

CHỈNH SỬA1:

Cách nhận hoạt động / trạng thái cho một 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);
}

6

Các cuộc gọi bạn cần thực hiện đối với Nexus là các cuộc gọi REST api.

Maven-nexus-plugin là một plugin Maven mà bạn có thể sử dụng để thực hiện các cuộc gọi này. Bạn có thể tạo một pom giả với các thuộc tính cần thiết và thực hiện các lệnh gọi đó thông qua plugin Maven.

Cái gì đó như:

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

Những điều giả định:

  1. Bạn đã xác định một máy chủ trong ~ / .m2 / settings.xml của mình có tên là sonatype-nexus-staging với người dùng sonatype và mật khẩu được thiết lập - bạn có thể đã thực hiện việc này nếu bạn đang triển khai ảnh chụp nhanh. Nhưng bạn có thể tìm thêm thông tin ở đây .
  2. Local settings.xml của bạn bao gồm các plugin nexus như được chỉ định tại đây .
  3. Pom.xml nằm trong thư mục hiện tại của bạn có tọa độ Maven chính xác trong định nghĩa của nó. Nếu không, bạn có thể chỉ định groupId, tạo tác và phiên bản trên dòng lệnh.
  4. -Dauto = true sẽ tắt các lời nhắc tương tác để bạn có thể viết kịch bản này.

Cuối cùng, tất cả những gì đang làm là tạo các cuộc gọi REST vào Nexus. Có một api Nexus REST đầy đủ nhưng tôi đã gặp chút may mắn khi tìm thấy tài liệu về nó không có tường phí. Bạn có thể bật chế độ gỡ lỗi cho plugin ở trên và tìm ra nó bằng cách sử dụng -Dnexus.verboseDebug=true -X.

Về mặt lý thuyết, bạn cũng có thể truy cập vào giao diện người dùng, bật bảng điều khiển Firebug Net và xem các POST / dịch vụ và suy ra một đường dẫn ở đó.


3

cho những người cần nó trong Java, sử dụng 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;
    }
}

bài viết đầu tiên. Tôi đã thử thêm tính năng nổi bật cho java nhưng không hiểu.
McMosfet

3

Trong https://github.com/RiotGames/nexus_cli Một trình bao bọc CLI xung quanh các cuộc gọi Sonatype Nexus REST.

Ví dụ sử dụng:

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

Cấu hình được thực hiện thông qua .nexus_clitệp.

url:            "http://my-nexus-server/nexus/"
repository:     "my-repository-id"
username:       "username"
password:       "password"

2

Bạn cũng có thể sử dụng phương pháp triển khai trực tiếp bằng cách sử dụng curl. Bạn không cần tệp pom cho tệp của mình nhưng tệp này cũng sẽ không được tạo nên nếu bạn muốn, bạn sẽ phải tải tệp đó lên riêng.

Đây là lệnh:

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

"tạo tác" không phải là đồ tạo tác
Ram

1

Nếu bạn cần một giao diện dòng lệnh thuận tiện hoặc API python, hãy xem kho lưu trữ

Sử dụng nó, bạn có thể tải cấu phần phần mềm lên nexus bằng lệnh

artifact upload foo-1.2.3.ext releases com.fooware

Để làm cho nó hoạt động, bạn cũng sẽ cần đặt một số biến môi trường

export REPOSITORY_URL=https://repo.example.com
export REPOSITORY_USER=admin
export REPOSITORY_PASSWORD=mysecretpassword

0

Bạn có thể tải lên phần mềm theo cách thủ công bằng cách nhấp vào nút tải lên phần mềm trong máy chủ Nexus và cung cấp các thuộc tính GAV cần thiết để tải lên (thường là cấu trúc tệp để lưu trữ phần mềm)


0

Đối với các phiên bản gần đây của Nexus OSS (> = 3.9.0)

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

Ví dụ cho các phiên bản 3.9.0 đến 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"

-1

@Adam Vandenberg Để có mã Java để ĐĂNG lên 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;
    }

}

-2

Thay vào đó bạn có thể dùng thuốc uốn tóc.

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

câu trả lời này không đúng. Với curl, các groupId nên được biểu diễn như org / myorg (thay thế dấu chấm bằng dấu gạch chéo '/' "")
madduci
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.