อัปโหลดสิ่งประดิษฐ์ไปยัง Nexus โดยไม่ต้องใช้ Maven


102

ฉันมีโปรเจ็กต์ที่ไม่ใช่ Java ที่สร้างเวอร์ชันของเวอร์ชันอาร์ติแฟกต์และฉันต้องการอัปโหลดไปยังที่เก็บ Nexus เนื่องจากโปรเจ็กต์ไม่ใช่ Java จึงไม่ใช้ Maven ในการสร้าง และฉันไม่อยากแนะนำไฟล์ Maven / POM เพียงเพื่อรับไฟล์เข้าสู่ Nexus

ลิงก์ในบล็อกไปยัง Nexus REST API ทั้งหมดจะสิ้นสุดที่ผนังการลงชื่อเข้าใช้โดยไม่มีลิงก์ "สร้างผู้ใช้" ที่ฉันเห็น

ดังนั้นวิธีที่ดีที่สุด (หรือสมเหตุสมผล) ในการอัปโหลดบิวด์อาร์ติแฟกต์ไปยังที่เก็บ Nexus โดยไม่ใช้ Maven คือวิธีใด "bash + curl" จะดีมากหรือแม้แต่สคริปต์ Python


หมายเหตุตรวจสอบให้แน่ใจว่าคุณมี settings.xml ใน ~ / .m2 พร้อมกับเซิร์ฟเวอร์ที่เหมาะสมและกำหนด auth
Adam Vandenberg

คำตอบ:


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 "deploy-file" เป็นวิธีแก้ปัญหาที่ง่ายที่สุด แต่ยังมีตัวอย่างบางส่วนโดยใช้ curl:

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


หากเพียงแค่นี้จะทำให้เราสามารถดาวน์โหลดไฟล์จากภายใน zip นี้ได้โดยตรง แต่ดูเหมือนจะเป็นไปไม่ได้หากคุณอัปโหลดแบบนี้
sorin

@sorin ไม่สามารถดาวน์โหลดไฟล์จากภายใน zip โดยใช้ Maven มันเป็นข้อกำหนดที่ผิดปกติและตัวจัดการการพึ่งพาเพียงอย่างเดียวที่ฉันรู้ว่าทำได้ก็คือไอวี่ (และไม่ใช่เรื่องง่าย) ดูตัวอย่างต่อไปนี้: stackoverflow.com/questions/3445696/…
Mark O'Connor

ฉันติดตั้ง Nexus เพื่อให้ทุกอย่างง่ายขึ้น แต่สิ่งที่อยู่ใน blazes นี้คืออะไร .. จะเกิดอะไรขึ้นถ้าฉันมี JAR ที่ทำเองที่บ้านโดยไม่มีความรู้เกี่ยวกับการอ้างอิง? IDE ของฉันเอาแต่บ่นว่าหายไป * .pom ฉันหวังว่า Nexus จะจัดการเรื่องนี้ให้ฉันแล้ว แต่ NOOOOO sh ...
vintproykt

66

ใช้ 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 ของผู้ดูแลระบบและฉันได้เพิ่มสิทธิ์สองอย่างให้กับบทบาทนั้น: ดาวน์โหลด Artifact และ Artifact Upload "Repo: All Maven Repositories (Full Control)" มาตรฐาน - บทบาทไม่เพียงพอ คุณจะไม่พบสิ่งนี้ในเอกสาร REST API ที่มาพร้อมกับเซิร์ฟเวอร์ Nexus ดังนั้นพารามิเตอร์เหล่านี้อาจเปลี่ยนแปลงในอนาคต

ในปัญหา Sonatype JIRAมีการกล่าวถึงว่าพวกเขา "กำลังจะยกเครื่อง REST API (และวิธีสร้างเอกสารประกอบ) ในรุ่นที่กำลังจะมาถึงซึ่งน่าจะเป็นไปได้ในปลายปีนี้"


สมมติว่าเราเผยแพร่จาก Jenkins และอนุญาตให้ผู้ใช้บิวด์เผยแพร่ไปยัง Nexus เท่านั้นคุณจะจัดการปัญหารหัสผ่านธรรมดาได้อย่างไร Jenkins มีปลั๊กอินสำหรับการอัปโหลดเพื่อให้เราใช้ข้อมูลประจำตัวของ Jenkins ได้หรือไม่
Jirong Hu

8

ไม่จำเป็นต้องใช้คำสั่งเหล่านี้ .. คุณสามารถใช้เว็บอินเตอร์เฟส nexus โดยตรงเพื่ออัปโหลด JAR ของคุณโดยใช้พารามิเตอร์ GAV

ใส่คำอธิบายภาพที่นี่

ดังนั้นจึงง่ายมาก


24
GUI ไม่ได้ช่วย ฉันต้องสามารถอัปโหลดผ่านสคริปต์บรรทัดคำสั่งที่ใช้เป็นส่วนหนึ่งของกระบวนการสร้าง
Adam Vandenberg

มันแปลเป็นคำขอ HTTP POST คุณไม่คิดเหรอ?
Yngve Sneen Lindal

5
@YngveSneenLindal แน่นอน แต่นั่นไม่ได้หมายความว่าอาร์กิวเมนต์ POST เหล่านั้นเป็น API ที่กำหนดไว้อย่างดีเพื่อใช้แบบสาธารณะ
Ken Williams

@KenWilliams แน่นอนฉันไม่ได้อ้างอย่างนั้น แต่พวกเขาจะทำงานและเป็นตัวแทนของการแก้ปัญหานั่นคือประเด็นของฉัน
Yngve Sneen Lindal

อย่างน้อยสำหรับเราSonatype Nexus ™ 2.11.1-01Artifact Uploadฉันมีที่จะให้ผู้ใช้สิทธิ์ น่าเสียดายที่ฉันไม่พบสิ่งใดในเอกสารที่กล่าวถึงเรื่องนี้ ... (แก้ไข: ฉันเห็นว่าEd ฉันได้ชี้ให้เห็นแล้ว )
Alberto

8

คุณสามารถอย่างทำเช่นนี้โดยไม่ต้องใช้อะไร MAVEN ที่เกี่ยวข้อง ผมเองใช้ NING HttpClient (v1.8.16 เพื่อรองรับ java6)

สำหรับเหตุผลใด Sonatype ทำให้มันไม่น่าเชื่อความยากลำบากที่จะคิดออกสิ่งที่ถูกต้อง URL ที่ส่วนหัวและน้ำหนักบรรทุกที่ควรจะเป็น; และฉันต้องสูดอากาศเข้าและเดา ... มีบล็อก / เอกสารที่แทบจะไม่เป็นประโยชน์อยู่ที่นั่น แต่มันไม่เกี่ยวข้องกับoss.sonatype.orgหรือเป็น XML (และฉันพบว่ามันใช้ไม่ได้) เอกสารอึในส่วนของพวกเขา IMHO และหวังว่าผู้ค้นหาในอนาคตจะพบว่าคำตอบนี้มีประโยชน์ ขอบคุณมากที่https://stackoverflow.com/a/33414423/2101812สำหรับโพสต์ของพวกเขาเพราะมันช่วยได้มาก

หากคุณปล่อยที่อื่นที่ไม่ใช่oss.sonatype.orgให้แทนที่ด้วยโฮสต์ที่ถูกต้อง

นี่คือรหัส (ใบอนุญาต CC0) ที่ฉันเขียนเพื่อทำสิ่งนี้ให้สำเร็จ profilesonatype / nexus profileID ของคุณอยู่ที่ไหน(เช่น4364f3bbaf163) และrepo(เช่นcomdorkbox-1003) จะถูกแยกวิเคราะห์จากการตอบกลับเมื่อคุณอัปโหลด POM / Jar เริ่มต้นของคุณ

ปิด 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);
}

โปรโมต 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);
}

วาง 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);
}

ลบลายเซ็น Turds:

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

วิธีรับกิจกรรม / สถานะสำหรับ 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

การโทรที่คุณต้องใช้กับ Nexus คือการโทร REST api

maven-nexus-plugin คือปลั๊กอิน 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 เต็มรูปแบบ แต่ฉันมีโชคเล็กน้อยในการค้นหาเอกสารที่ไม่ได้อยู่เบื้องหลัง paywall คุณสามารถเปิดโหมดดีบักสำหรับปลั๊กอินด้านบนและคิดออกโดยใช้-Dnexus.verboseDebug=true -X.

คุณสามารถเข้าไปที่ UI ในทางทฤษฎีเปิดแผง Firebug Net และดู / service POSTs และสรุปเส้นทางที่นั่นได้เช่นกัน


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 แต่ coud ไม่ได้รับ
McMosfet

3

ในทับทิมhttps://github.com/RiotGames/nexus_cliเสื้อคลุม CLI รอบ ๆ การโทร Sonatype Nexus REST

ตัวอย่างการใช้งาน:

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 คุณไม่จำเป็นต้องใช้ 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

หากคุณต้องการอินเตอร์เฟสบรรทัดคำสั่งที่สะดวกหรือ 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

0

คุณสามารถอัปโหลดอาร์ติแฟกต์ด้วยตนเองได้โดยคลิกที่ปุ่มอัปโหลดอาร์ติแฟกต์ในเซิร์ฟเวอร์ Nexus และระบุคุณสมบัติ GAV ที่จำเป็นสำหรับการอัปโหลด (โดยทั่วไปจะเป็นโครงสร้างไฟล์สำหรับจัดเก็บอาร์ติแฟกต์)


0

สำหรับ 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"

-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

คำตอบนี้ไม่ถูกต้อง ด้วย curl ควรแสดง groupId เป็น org / myorg (แทนที่จุด "." ด้วยเครื่องหมายทับ "/")
madduci
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.