Завантажте артефакти на Nexus, без Maven


102

У мене є проект, який не є Java, який створює артефакт збірки версій, і я хочу завантажити його в сховище Nexus. Оскільки проект не є Java, він не використовує Maven для збірок. І я б краще не вводив файли Maven / POM лише для отримання файлів у Nexus.

Посилання в блогах на Nexus REST API закінчуються на стіні для входу, без я бачу посилання "створити користувача".

Отже, який найкращий (або будь-який розумний) спосіб завантаження збірних артефактів у сховище Nexus без Maven? "bash + curl" буде чудовим, або навіть сценарієм Python.


Зверніть увагу, переконайтеся, що у вас налаштування.xml в ~ / .m2 з відповідними серверами та авторами визначено.
Адам Ванденберг

Відповіді:


98

Чи плануєте ви використовувати командний рядок 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 "розгорнути-файл" є найпростішим рішенням, але він також містить кілька прикладів з використанням curl:

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


Якщо тільки це дозволить нам безпосередньо завантажувати файли з цього поштового індексу, але, здається, це неможливо, якщо ви завантажуєте його так.
sorin

@sorin Неможливо завантажувати файли зсередини в zip за допомогою Maven. Це незвична вимога, і єдиний менеджер залежностей, який я знаю, що це може зробити, - це плющ (і це не просто), дивіться наступний приклад: stackoverflow.com/questions/3445696/…
Марк О'Коннор

Я встановив Nexus, щоб зробити це все простішим, але що в цьому криється? .. Що робити, якщо у мене є домашній JAR без знання його залежностей? Мій IDE продовжує скаржитися на відсутність * .pom. Я сподівався, що Nexus вже вирішив це для мене, але NOOOOO sh ...
vintproykt

66

Використання завитка:

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-programatic-upload-an-artifact-into-Nexus-

Щоб зробити дозволи для цієї роботи, я створив нову роль у адміністративному інтерфейсі адміністратора та додав до неї дві привілеї: Завантаження артефактів та Завантаження артефактів. Стандартного "Repo: Усі Maven Repositories (Повний контроль)" - ролі недостатньо. Ви не знайдете цього в документації API REST, яка постачається в комплекті з сервером Nexus, тому ці параметри можуть змінитися в майбутньому.

У питанні Sonatype JIRA було зазначено, що вони "збираються капітально переглянути API REST (і спосіб його створення документації) у майбутньому випуску, швидше за все, пізніше цього року".


скажімо, ми публікуємо від Jenkins і дозволяємо лише користувачам збирати публікувати в Nexus, як ви керуєте простою паролем? Чи має Дженкінс плагін для завантаження, щоб ми могли використовувати облікові дані Дженкінса?
Jirong Hu

8

Не потрібно використовувати ці команди. Ви можете безпосередньо використовувати веб-інтерфейс nexus, щоб завантажити свій JAR за допомогою параметрів GAV.

введіть тут опис зображення

Так що це дуже просто.


24
GUI не допомагає; Мені потрібно мати можливість завантажувати за допомогою скрипту командного рядка, що використовується як частина процесу збирання.
Адам Ванденберг

Ну, це перекладається на HTTP POST-запит, ви не думаєте?
Yngve Sneen Lindal

5
@YngveSneenLindal Звичайно, але це не означає, що ці аргументи POST - це чітко визначений API, який слід публічно використовувати.
Кен Вільямс

@KenWilliams Впевнений, я теж цього не стверджував. Але вони працюватимуть і представлятимуть рішення, це моя суть.
Yngve Sneen Lindal

Принаймні, для нашого Sonatype Nexus ™ 2.11.1-01 я повинен був надати користувачеві привілей Artifact Upload. На жаль, я не зміг знайти нічого в документах, що згадують про це ... (Редагувати: Я бачу, Ед, я це вже вказав )
Альберто

8

Ви можете АБСОЛЮТНО це зробити, не використовуючи нічого, що МАТЕ. Я особисто використовую NING HttpClient (v1.8.16, щоб підтримати java6).

З будь-якої причини, Sonatype створює неймовірні труднощі з'ясувати, які саме правильні URL-адреси, заголовки та корисні навантаження повинні бути; і мені довелося нюхати трафік і здогадуватися ... Є деякі ледь корисні блоги / документація там, однак це або не має значення oss.sonatype.org, або це на основі XML (і я виявив, що це навіть не працює). Дана документація зі свого боку, ІМХО, і, сподіваємось, майбутні шукачі можуть вважати цю відповідь корисною. Дякую https://stackoverflow.com/a/33414423/2101812 за їх допис, оскільки це дуже допомогло.

Якщо ви випустите десь інше oss.sonatype.org, просто замініть його будь-яким правильним хостом.

Ось (CC0-ліцензований) код, який я написав для цього. Де profileваш профіль sonatype / nexusID (такий як 4364f3bbaf163) та repo(такий як comdorkbox-1003), аналізується з відповіді під час завантаження початкового POM / Jar.

Закрити репо:

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

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

6

Дзвінки, які вам потрібно здійснити проти Nexus, - це дзвінки REST api.

Плагін maven-nexus - це плагін Maven, який можна використовувати для здійснення цих дзвінків. Ви можете створити фіктивну пам’ять з необхідними властивостями і здійснювати ці дзвінки через плагін Maven.

Щось на зразок:

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

Передбачаються речі:

  1. Ви визначили сервер у вашому ~ / .m2 / settings.xml під назвою sonatype-nexus-staging з налаштованим вами користувачем сонатипу та паролем - ви, мабуть, це вже зробили, якщо розгортаєте знімки. Але ви можете знайти більше інформації тут .
  2. Ваші локальні settings.xml включають додатки Nexus, як зазначено тут .
  3. Pom.xml, що знаходиться у вашому поточному каталозі, має правильні координати Maven у своєму визначенні. Якщо ні, ви можете вказати groupId, artifactId та версію в командному рядку.
  4. -Dauto = true вимкне інтерактивні підказки, щоб ви могли це зробити сценарій.

Зрештою, все це - це створення REST-дзвінків у Nexus. Є повний api Nexus REST, але у мене мало шансів знайти документацію для нього, який не знаходиться за платною стіною. Ви можете ввімкнути режим налагодження для плагіна вище та розібратися в ньому, використовуючи -Dnexus.verboseDebug=true -X.

Ви також можете теоретично зайти в інтерфейс користувача, увімкнути панель Firebug Net, спостерігати за / відправляти поштові пошти та виводити також шлях там.


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

перший пост. Я намагався додати підсвічування для Java, але куд не отримав цього.
МакМосфет

3

У рубіні https://github.com/RiotGames/nexus_cli Обгортка CLI навколо дзвінків REST Sonatype Nexus.

Приклад використання:

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"

2

Ви також можете використовувати метод прямого розгортання за допомогою curl. Для цього вам не потрібна пам’ятка для вашого файлу, але він також не буде генерований, тому, якщо ви хочете його, доведеться завантажувати його окремо.

Ось команда:

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

"артефакт" не артефакт
Рам

1

Якщо вам потрібен зручний інтерфейс командного рядка або API python, подивіться репозиторії

Використовуючи його, ви можете завантажувати артефакт до 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

0

Ви можете завантажувати артефакти вручну, натиснувши кнопку завантажувати артефакти на сервері Nexus і надати необхідні властивості GAV для завантаження (це загалом файлова структура для зберігання артефакту)


0

Для останніх версій Nexus OSS (> = 3.9.0)

https://support.sonatype.com/hc/en-us/articles/115006744008-How-can-I-programmatic-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"

-1

@Adam Vandenberg Для коду Java для POST для 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

Ви можете замість цього використовувати curl.

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

ця відповідь невірна. З завитком groupId слід представити як org / myorg (замінити крапку "." З косою рисою "/")
madduci
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.