diff --git a/README.md b/README.md index 7148a5901221bd56b44f0f626d024fc34a774bb4..e7b126f3ca6f26abc6fdfe94e6b9eabd144a6427 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,62 @@ -# jenkins-aliyun-oss-plugin -jenkins阿里云OSS上传插件 +# jenkins阿里云OSS上传插件 + +## 使用 + +1.增加`构建后操作`,选择`阿里云OSS上传` + +![](https://github.com/raylax/jenkins-aliyun-oss-plugin/raw/master/image/step1.png) + +2.填写阿里云OSS配置信息 + +![](https://github.com/raylax/jenkins-aliyun-oss-plugin/raw/master/image/step2.png) + +> 本地路径为相对于workspace的路径,例如填写为`/abc`,则本地路径为`${WORKSPACE}/abc` +本地路径可以设置为文件或目录 + +## 构建 + +1. 修改`${USER}/.m2/settings.xml`中的maven配置文件 + +在`mirrors`节点中增加 +```xml + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + m.g.o-public + +``` +在`pluginGroups`节点中增加 +```xml +org.jenkins-ci.tools +``` +在`profiles`节点中增加 +```xml + + jenkins + + true + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + + + repo.jenkins-ci.org + https://repo.jenkins-ci.org/public/ + + + +``` + +2. 打包 +```bash +mvn package +``` + +3. 运行 +```bash +mvn hpi:run +``` \ No newline at end of file diff --git a/image/step1.png b/image/step1.png new file mode 100644 index 0000000000000000000000000000000000000000..bd94b15c110df85376bf4efb2f680c6b8677615e Binary files /dev/null and b/image/step1.png differ diff --git a/image/step2.png b/image/step2.png new file mode 100644 index 0000000000000000000000000000000000000000..b781500a77a636e4eeeb90ac19b1dd8a94d1695b Binary files /dev/null and b/image/step2.png differ diff --git a/src/main/java/org/inurl/jenkins/plugin/OSSPublisher.java b/src/main/java/org/inurl/jenkins/plugin/OSSPublisher.java index 9045e7e60a56d24fb95107fd29002a72ed4665a5..cefaceb1fb2d7afe3c130eddea6506b34d677b03 100644 --- a/src/main/java/org/inurl/jenkins/plugin/OSSPublisher.java +++ b/src/main/java/org/inurl/jenkins/plugin/OSSPublisher.java @@ -12,7 +12,9 @@ import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.util.FormValidation; import jenkins.tasks.SimpleBuildStep; +import jnr.ffi.annotations.In; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; @@ -36,6 +38,8 @@ public class OSSPublisher extends Publisher implements SimpleBuildStep { private final String remotePath; + private final String maxRetries; + public String getEndpoint() { return endpoint; @@ -61,14 +65,19 @@ public class OSSPublisher extends Publisher implements SimpleBuildStep { return remotePath; } + public int getMaxRetries() { + return StringUtils.isEmpty(maxRetries) ? 3 : Integer.parseInt(maxRetries); + } + @DataBoundConstructor - public OSSPublisher(String endpoint, String accessKeyId, String accessKeySecret, String bucketName, String localPath, String remotePath) { + public OSSPublisher(String endpoint, String accessKeyId, String accessKeySecret, String bucketName, String localPath, String remotePath, String maxRetries) { this.endpoint = endpoint; this.accessKeyId = accessKeyId; this.accessKeySecret = accessKeySecret; this.bucketName = bucketName; this.localPath = localPath; this.remotePath = remotePath; + this.maxRetries = maxRetries; } @Override @@ -82,15 +91,17 @@ public class OSSPublisher extends Publisher implements SimpleBuildStep { OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret); String local = localPath.substring(1); String remote = remotePath.substring(1); - logger.println("workspace => " + workspace); FilePath p = new FilePath(workspace, local); if (p.isDirectory()) { logger.println("upload dir => " + p); upload(client, logger, remote, p, true); + logger.println("upload dir success"); } else { logger.println("upload file => " + p); uploadFile(client, logger, remote, p); + logger.println("upload file success"); } + } private void upload(OSSClient client, PrintStream logger, String base, FilePath path, boolean root) throws InterruptedException, IOException { @@ -104,6 +115,23 @@ public class OSSPublisher extends Publisher implements SimpleBuildStep { } private void uploadFile(OSSClient client, PrintStream logger, String key, FilePath path) throws InterruptedException, IOException { + int maxRetries = getMaxRetries(); + int retries = 0; + do { + if (retries > 0) { + logger.println("upload retrying (" + retries + "/" + maxRetries +")"); + } + try { + uploadFile0(client, logger, key, path); + return; + } catch (Exception e) { + e.printStackTrace(logger); + } + } while ((++retries) <= maxRetries); + throw new RuntimeException("upload fail, more than the max of retries"); + } + + private void uploadFile0(OSSClient client, PrintStream logger, String key, FilePath path) throws InterruptedException, IOException { String realKey = key; if (realKey.startsWith("/")) { realKey = realKey.substring(1); @@ -118,6 +146,15 @@ public class OSSPublisher extends Publisher implements SimpleBuildStep { @Extension public static final class DescriptorImpl extends BuildStepDescriptor { + public FormValidation doCheckMaxRetries(@QueryParameter String value) { + try { + Integer.parseInt(value); + } catch (Exception e) { + return FormValidation.error(Messages.OSSPublish_MaxRetiesMustBeNumbers()); + } + return FormValidation.ok(); + } + public FormValidation doCheckEndpoint(@QueryParameter(required = true) String value) { return checkValue(value, Messages.OSSPublish_MissingEndpoint()); } diff --git a/src/main/resources/org/inurl/jenkins/plugin/Messages.properties b/src/main/resources/org/inurl/jenkins/plugin/Messages.properties index 0fa2fe0e02fa64cab7b41d9a3d55f8fb416bd362..09d0f314650e98030f90801df37f2a291b4e90fe 100644 --- a/src/main/resources/org/inurl/jenkins/plugin/Messages.properties +++ b/src/main/resources/org/inurl/jenkins/plugin/Messages.properties @@ -5,4 +5,5 @@ OSSPublish.MissingAccessKeyId=Please set AccessKeyId OSSPublish.MissingAccessKeySecret=Please set AccessKeySecret OSSPublish.MissingBucketName=Please set BucketName OSSPublish.MissingLocalPath=Please set LocalPath -OSSPublish.MissingRemotePath=Please set RemotePath \ No newline at end of file +OSSPublish.MissingRemotePath=Please set RemotePath +OSSPublish.MaxRetiesMustBeNumbers=Must be number \ No newline at end of file diff --git a/src/main/resources/org/inurl/jenkins/plugin/Messages_zh.properties b/src/main/resources/org/inurl/jenkins/plugin/Messages_zh.properties index abb1222d175ced7d75164bdb0607a9481d4ac93a..b5df8f6f20b92e0af25b26c3ad6076e4dafa67e8 100644 --- a/src/main/resources/org/inurl/jenkins/plugin/Messages_zh.properties +++ b/src/main/resources/org/inurl/jenkins/plugin/Messages_zh.properties @@ -5,4 +5,5 @@ OSSPublish.MissingAccessKeyId=\u8bf7\u8bbe\u7f6eAccessKeyId OSSPublish.MissingAccessKeySecret=\u8bf7\u8bbe\u7f6eAccessKeySecret OSSPublish.MissingBucketName=\u8bf7\u8bbe\u7f6eBucketName OSSPublish.MissingLocalPath=\u8bf7\u8bbe\u7f6e\u672c\u5730\u8def\u5f84 -OSSPublish.MissingRemotePath=\u8bf7\u8bbe\u7f6e\u8fdc\u7a0b\u8def\u5f84 \ No newline at end of file +OSSPublish.MissingRemotePath=\u8bf7\u8bbe\u7f6e\u8fdc\u7a0b\u8def\u5f84 +OSSPublish.MaxRetiesMustBeNumbers=\u6700\u5927\u91cd\u8bd5\u6b21\u6570\u5fc5\u987b\u4e3a\u6570\u5b57 \ No newline at end of file diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.jelly b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.jelly index c1cd62c6c4059773a7bc55cc3f21f0006c38d744..b439156110774e6511ce73f1a2e3e793f49d0f2a 100644 --- a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.jelly +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.jelly @@ -19,9 +19,8 @@ - - + + diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.properties b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.properties index f4865b91c5643c9b5fe34f7dbb25671c895f27f3..13ce9cd72d6d555505e8f12312c0b348087ea8b9 100644 --- a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.properties +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config.properties @@ -3,4 +3,6 @@ AccessKeyId=AccessKeyId AccessKeySecret=AccessKeySecret BucketName=BucketName LocalPath=Local Path -RemotePath=Remote Path \ No newline at end of file +RemotePath=Remote Path + +MaxRetries=max retries \ No newline at end of file diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config_zh.properties b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config_zh.properties index 598951ef67d8bc935e3a5f9efcff20e1b1a70c65..4e83625ed48a0db8657c63ff4d64c6b0870b24f2 100644 --- a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config_zh.properties +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/config_zh.properties @@ -3,4 +3,6 @@ AccessKeyId=AccessKeyId AccessKeySecret=AccessKeySecret BucketName=BucketName LocalPath=\u672c\u5730\u8def\u5f84 -RemotePath=\u8fdc\u7a0b\u8def\u5f84 \ No newline at end of file +RemotePath=\u8fdc\u7a0b\u8def\u5f84 + +MaxRetries=\u6700\u5927\u91cd\u8bd5\u6b21\u6570 \ No newline at end of file diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-accessKeyId_zh.html b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-accessKeyId_zh.html new file mode 100644 index 0000000000000000000000000000000000000000..56b3890e128753d5f9b53e179cac8a55dbfdedf9 --- /dev/null +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-accessKeyId_zh.html @@ -0,0 +1,4 @@ +
+ 阿里云 AccessKey
+ 去配置 +
diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-accessKeySecret_zh.html b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-accessKeySecret_zh.html new file mode 100644 index 0000000000000000000000000000000000000000..a6b013f723bf3ab26cf459a99e91dd69a40a6748 --- /dev/null +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-accessKeySecret_zh.html @@ -0,0 +1,4 @@ +
+ 阿里云 AccessKeySecret
+ 去配置 +
diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-bucketName_zh.html b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-bucketName_zh.html new file mode 100644 index 0000000000000000000000000000000000000000..7e8878064c0460a57ad687ded2eac0c268d376ba --- /dev/null +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-bucketName_zh.html @@ -0,0 +1,4 @@ +
+ 阿里云 OSS BucketName
+ 去配置 +
diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-endpoint_zh.html b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-endpoint_zh.html new file mode 100644 index 0000000000000000000000000000000000000000..94bd0bf4daf96b9cc8e4b3cadcf8a64331af22af --- /dev/null +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-endpoint_zh.html @@ -0,0 +1,4 @@ +
+ 阿里云 OSS Endpoint
+ 去配置 +
diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-localPath_zh.html b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-localPath_zh.html new file mode 100644 index 0000000000000000000000000000000000000000..974f4d062343a91a40cb97d96aa94c22faf162f5 --- /dev/null +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-localPath_zh.html @@ -0,0 +1,3 @@ +
+ 本地路径,必须以`/`开头 +
\ No newline at end of file diff --git a/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-remotePath_zh.html b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-remotePath_zh.html new file mode 100644 index 0000000000000000000000000000000000000000..f307115e4560b8fac0c65cea91b815df86c69052 --- /dev/null +++ b/src/main/resources/org/inurl/jenkins/plugin/OSSPublisher/help-remotePath_zh.html @@ -0,0 +1,3 @@ +
+ 远程路径,必须以`/`开头 +
\ No newline at end of file diff --git a/src/test/java/org/inurl/jenkins/plugin/OSSPublisherTest.java b/src/test/java/org/inurl/jenkins/plugin/OSSPublisherTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bed631fc095459fc852b80cea431c81e1e6d6543 --- /dev/null +++ b/src/test/java/org/inurl/jenkins/plugin/OSSPublisherTest.java @@ -0,0 +1,90 @@ +package org.inurl.jenkins.plugin; + +import com.aliyun.oss.OSSClient; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import hudson.tasks.Shell; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import static org.junit.Assert.assertTrue; + +public class OSSPublisherTest { + + @Rule + public JenkinsRule jenkins = new JenkinsRule(); + + private final String name = "Test"; + + private final String endpoint = System.getenv("OSS_ENDPOINT"); + private final String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID"); + private final String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET"); + private final String bucketName = System.getenv("OSS_BUCKET_NAME"); + private final String maxRetries = "10"; + + public static void main(String[] args) { + System.out.println(System.getenv("os").contains("Windows")); + } + + @Test + public void testOSS() { + OSSClient client = new OSSClient(endpoint, accessKeyId, accessKeySecret); + client.getBucketInfo(bucketName); + assertTrue(true); + } + + @Test + public void testConfigRoundtrip() throws Exception { + FreeStyleProject project = jenkins.createFreeStyleProject(name); + String localPath = "/"; + String remotePath = "/"; + project.getPublishersList().add(new OSSPublisher(endpoint, accessKeyId, accessKeySecret, bucketName, localPath, remotePath, maxRetries)); + project = jenkins.configRoundtrip(project); + jenkins.assertEqualDataBoundBeans( + new OSSPublisher(endpoint, accessKeyId, accessKeySecret, bucketName, localPath, remotePath, maxRetries), + project.getPublishersList().get(0)); + } + + + @Test + public void testBuildDir() throws Exception { + FreeStyleProject project = jenkins.createFreeStyleProject(name); + Shell shell = createFileShell(); + project.getBuildersList().add(shell); + project.getPublishersList().add(new OSSPublisher(endpoint, accessKeyId, accessKeySecret, bucketName, "/", "/", maxRetries)); + FreeStyleBuild build = jenkins.buildAndAssertSuccess(project); + jenkins.assertLogContains("upload dir success", build); + } + + @Test + public void testBuildFile() throws Exception { + FreeStyleProject project = jenkins.createFreeStyleProject(name); + project.getPublishersList().add(new OSSPublisher(endpoint, accessKeyId, accessKeySecret, bucketName, "/n/3", "/remoteFile", maxRetries)); + FreeStyleBuild build = jenkins.buildAndAssertSuccess(project); + jenkins.assertLogContains("upload file success", build); + } + + private static Shell createFileShell() { + //language=Bash + String del = + "if [[ -e \"a\" ]];then rm -f a fi\n" + + "if [[ -e \"b\" ]];then rm -f b fi\n" + + "if [[ -e \"c\" ]];then rm -f c fi\n" + + "if [[ -e \"n/1\" ]];then rm -f n/1 fi\n" + + "if [[ -e \"n/2\" ]];then rm -f n/2 fi\n" + + "if [[ -e \"n/3\" ]];then rm -f n/3 fi\n"; + //language=Bash + String create = + "echo a > a\n" + + "echo b > b\n" + + "echo c > c\n" + + "mkdir n\n" + + "echo 1 > n/1\n" + + "echo 2 > n/2\n" + + "echo 3 > n/3"; + return new Shell(del + "\n" + create); + } + + +} \ No newline at end of file