Загрузить артефакты в Nexus, без Maven - PullRequest
93 голосов
/ 27 октября 2010

У меня есть не-Java проект, который производит версионный артефакт сборки, и я хочу загрузить его в репозиторий Nexus. Поскольку проект не является Java, он не использует Maven для сборок. И я бы предпочел не вводить файлы Maven / POM только для загрузки файлов в Nexus.

Ссылки в блогах на Nexus REST API все заканчиваются на стене входа без видимой ссылки "создать пользователя".

Итак, каков наилучший (или любой разумный) способ загрузки артефактов сборки в репозиторий Nexus без Maven? "bash + curl" было бы замечательно, или даже скрипт Python.

Ответы [ 12 ]

94 голосов
/ 27 октября 2010

Рассматривали ли вы использование командной строки 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

Это автоматически сгенерирует POM Maven для артефакта.

Обновление

В следующей статье Sonatype говорится, что плагин maven "deploy-file" является самым простым решением, но он также предоставляет некоторые примеры с использованием curl:

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

62 голосов
/ 31 октября 2013

Использование curl:

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 администратора.и я добавил к этой роли две привилегии: загрузка артефакта и загрузка артефакта.Стандарт «Репо: Все репозитории Maven (полный контроль)» - роли недостаточно.Вы не найдете этого в документации REST API, поставляемой в комплекте с сервером Nexus, поэтому в будущем эти параметры могут измениться.они «собираются пересмотреть REST API (и то, как генерируется его документация) в следующем выпуске, скорее всего, позже в этом году».

8 голосов
/ 21 ноября 2015

Вы можете АБСОЛЮТНО сделать это, не используя ничего, связанного с MAVEN.Лично я использую NING HttpClient (v1.8.16, для поддержки java6).

По какой-то причине Sonatype затрудняет невероятно , чтобы выяснить, каковы правильные URL, заголовки и полезные нагрузки.должно быть;и мне пришлось понюхать трафик и угадать ... Есть несколько едва полезных блогов / документации там, однако это либо не имеет отношения к oss.sonatype.org, либо основано на XML (и я обнаружил, что это не так)т даже работать).Дерьмо с их стороны, IMHO, и, надеюсь, будущие искатели найдут этот ответ полезным.Огромное спасибо https://stackoverflow.com/a/33414423/2101812 за их пост, так как это очень помогло.

Если вы выпускаете где-то, кроме oss.sonatype.org, просто замените его на правильный хост.

Вот код (CC0 лицензированный), который я написал для достижения этой цели.Где profile - это ваш ID профиля sonatype / nexus (например, 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);
    }

РЕДАКТИРОВАТЬ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);
}
8 голосов
/ 22 февраля 2011

Нет необходимости использовать эти команды. Вы можете напрямую использовать веб-интерфейс nexus для загрузки JAR-файла с использованием параметров GAV.

enter image description here

Так что это очень просто.

6 голосов
/ 02 июля 2011

Звонки на Nexus - это вызовы REST API.

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

Что-то вроде:

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

Предполагаемые вещи:

  1. ВыВы определили сервер в вашем ~ / .m2 / settings.xml с именем sonatype-nexus-staging, указав имя пользователя и пароль sonatype - вы, вероятно, уже сделали это, если будете развертывать снимки.Но вы можете найти больше информации здесь .
  2. Ваш локальный файл settings.xml включает подключаемые модули nexus, как указано здесь .
  3. Файл pom.xml, расположенный в вашем текущем каталоге, имеет правильные координаты Maven в своем определении.Если нет, вы можете указать groupId, artifactId и версию в командной строке.
  4. Параметр -Dauto = true отключит интерактивные подсказки, поэтому вы можете написать этот сценарий.

В конечном итоге все, что мы делаем, - это создаем вызовы REST в Nexus.Существует полный API-интерфейс Nexus REST, но мне не повезло найти документацию для него, которая не защищена платным доступом.Вы можете включить режим отладки для указанного выше плагина и выяснить это, используя -Dnexus.verboseDebug=true -X.

. Вы также можете теоретически войти в интерфейс, включить панель Firebug Net и посмотреть / service POSTи выведите путь туда.

3 голосов
/ 29 октября 2015

для тех, кому это нужно в 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;
    }
}
2 голосов
/ 29 июля 2016

Вы также можете использовать метод прямого развертывания с помощью 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
1 голос
/ 11 мая 2016

Если вам нужен удобный интерфейс командной строки или Python API, посмотрите на repositorytools

Используя его, вы можете загрузить артефакт в нексус с помощью команды

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
1 голос
/ 01 ноября 2013

В рубине 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"
0 голосов
/ 08 апреля 2019

Для последних версий Nexus OSS (> = 3.9.0)

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"
...