我有一个非Java项目,它会生成一个带版本的构建产物,并且我想将其上传到Nexus仓库。因为这个项目不是用Maven进行构建的,所以也不想引入Maven/POM文件就能把文件放到Nexus中。
博客中关于Nexus REST API的链接最后都会出现一个登录墙,我没有看到“创建用户”的链接。
那么,有没有一种最好(或任何合理的)方法可以在没有Maven的情况下将构建产物上传到Nexus仓库呢?使用 “bash + curl” 或者 Python脚本都可以。
我有一个非Java项目,它会生成一个带版本的构建产物,并且我想将其上传到Nexus仓库。因为这个项目不是用Maven进行构建的,所以也不想引入Maven/POM文件就能把文件放到Nexus中。
博客中关于Nexus REST API的链接最后都会出现一个登录墙,我没有看到“创建用户”的链接。
那么,有没有一种最好(或任何合理的)方法可以在没有Maven的情况下将构建产物上传到Nexus仓库呢?使用 “bash + curl” 或者 Python脚本都可以。
你有考虑使用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文章指出 "deploy-file" Maven插件是最简单的解决方案,但它也提供了一些使用curl的示例:
使用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 Download和Artifact Upload。标准的“Repo: All Maven Repositories (Full Control)”角色不足以满足需求。这些参数可能会在未来发生改变,但它们并没有包含在Nexus服务器捆绑的REST API文档中。
在Sonatype JIRA问题页面上提到他们“计划在即将发布的版本中彻底改进REST API(以及文档生成方式)”,预计在今年晚些时候发布。
profile
是您的 sonatype/nexus 个人资料 ID(例如 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);
}
不需要使用这些命令... 您可以直接使用nexus web界面,使用GAV参数上传您的JAR文件。
所以非常简单。
Artifact Upload
权限。不幸的是,在文档中我找不到任何提及此事的内容...(编辑:我看到了,Ed I已经指出了这一点) - Alberto你需要对 Nexus 进行的调用是 REST API 调用。
maven-nexus-plugin 是一个可以用来进行这些调用的 Maven 插件。你可以创建一个带有必要属性的虚拟 pom 文件,并通过 Maven 插件来进行这些调用。
例如:
mvn -DserverAuthId=sonatype-nexus-staging -Dauto=true nexus:staging-close
假设以下事项:
最终,所有这些都只是在 Nexus 中创建 REST 调用。Nexus 有一个完整的 REST api,但我很难找到不需要付费才能查看的文档。您可以使用 -Dnexus.verboseDebug=true -X
打开插件的调试模式并自己找出来。
您也可以理论上进入 UI,打开 Firebug Net 面板,并观察 /service POST,从而推断出路径。
您也可以使用curl直接部署的方法。您的文件不需要pom,但是它也不会被生成,所以如果您需要一个,您必须单独上传它。
以下是命令:
version=1.2.3
artifact="myartifact"
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/$artifact/$version/$artifact-$version.tgz
在Ruby中,https://github.com/RiotGames/nexus_cli 是一个围绕Sonatype Nexus REST调用的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"
对于需要在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;
}
}
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
版本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"