├── Jenkinsfile ├── images ├── setting-screenshot.png ├── pgyer-app-upload-backdata.png └── pgyer-app-upload-running-log.png ├── .gitignore ├── src ├── main │ ├── resources │ │ ├── index.jelly │ │ └── ren │ │ │ └── helloworld │ │ │ └── upload2pgyer │ │ │ ├── UploadBuilderV2 │ │ │ ├── help-buildType.html │ │ │ ├── help-buildUpdateDescription.html │ │ │ ├── help.html │ │ │ ├── help-buildInstallType.html │ │ │ ├── help-buildChannelShortcut.html │ │ │ ├── help-buildPassword.html │ │ │ ├── help-apiKey.html │ │ │ ├── help-wildcard.html │ │ │ ├── help-scanDir.html │ │ │ └── config.jelly │ │ │ └── UploadPublisherV2 │ │ │ ├── help-buildType.html │ │ │ ├── help-buildUpdateDescription.html │ │ │ ├── help.html │ │ │ ├── help-buildChannelShortcut.html │ │ │ ├── help-buildInstallType.html │ │ │ ├── help-buildPassword.html │ │ │ ├── help-apiKey.html │ │ │ ├── help-wildcard.html │ │ │ ├── help-scanDir.html │ │ │ └── config.jelly │ └── java │ │ └── ren │ │ └── helloworld │ │ └── upload2pgyer │ │ ├── impl │ │ └── Message.java │ │ ├── helper │ │ ├── PublishEnvVarAction.java │ │ ├── ProgressRequestBody.java │ │ ├── PgyerV2Helper.java │ │ └── CommonUtil.java │ │ ├── apiv2 │ │ ├── ParamsBeanV2.java │ │ ├── PgyerTokenBeanV2.java │ │ ├── PgyerBeanV2.java │ │ └── PgyerUploadV2.java │ │ ├── ValidationParameters.java │ │ ├── UploadBuilderV2.java │ │ └── UploadPublisherV2.java └── test │ └── java │ └── ren │ └── helloworld │ └── upload2pgyer │ ├── UploadBuilderV2Test.java │ └── UploadPublisherV2Test.java ├── pom.xml ├── README_cn.md └── README.md /Jenkinsfile: -------------------------------------------------------------------------------- 1 | buildPlugin() -------------------------------------------------------------------------------- /images/setting-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/upload-pgyer-plugin/HEAD/images/setting-screenshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea 3 | target 4 | *.iml 5 | pom.xml.releaseBackup 6 | release.properties -------------------------------------------------------------------------------- /images/pgyer-app-upload-backdata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/upload-pgyer-plugin/HEAD/images/pgyer-app-upload-backdata.png -------------------------------------------------------------------------------- /images/pgyer-app-upload-running-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/upload-pgyer-plugin/HEAD/images/pgyer-app-upload-running-log.png -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This plug-in upload the apk/ipa file to pgyer 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-buildType.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional) App Type is android or ios 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-buildType.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional) App Type is android or ios 3 |
4 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/impl/Message.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.impl; 2 | 3 | public interface Message { 4 | void message(boolean needTag, String mesage); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-buildUpdateDescription.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional) Version updated description, please pass on an empty string or do not pass anything.
3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-buildUpdateDescription.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional) Version updated description, please pass on an empty string or do not pass anything.
3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | click to get 4 | the documents 5 |

6 |
-------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | click to get 4 | the documents 5 |

6 |
-------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-buildInstallType.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional)Type of Install, this value is (1,2,3).
3 | 1:Public,
4 | 2:Password,
5 | 3:Restrict.
6 | The default is Public!
7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-buildChannelShortcut.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional) The download short link of the specified channel that needs to be updated.
3 | Only one channel can be specified, string type, such as: abcd. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-buildChannelShortcut.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional) The download short link of the specified channel that needs to be updated.
3 | Only one channel can be specified, string type, such as: abcd. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-buildInstallType.html: -------------------------------------------------------------------------------- 1 |
2 | (Optional)Type of Install, this value is (1,2,3).
3 | 1:Public,
4 | 2:Password,
5 | 3:Restrict.
6 | The default is Public!
7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-buildPassword.html: -------------------------------------------------------------------------------- 1 |
2 | To be safe, the field needs to be encrypted, so it looks that long.
3 | (Optional) Setting App installation password.
4 | If you do not want to set a password, please pass on an empty string or do not pass anything. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-buildPassword.html: -------------------------------------------------------------------------------- 1 |
2 | To be safe, the field needs to be encrypted, so it looks that long.
3 | (Optional) Setting App installation password.
4 | If you do not want to set a password, please pass on an empty string or do not pass anything. 5 |
6 | -------------------------------------------------------------------------------- /src/test/java/ren/helloworld/upload2pgyer/UploadBuilderV2Test.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.jvnet.hudson.test.JenkinsRule; 6 | 7 | import static org.junit.Assert.assertTrue; 8 | 9 | public class UploadBuilderV2Test { 10 | @Rule 11 | public JenkinsRule j = new JenkinsRule(); 12 | 13 | @Test 14 | public void test() { 15 | assertTrue(true); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/ren/helloworld/upload2pgyer/UploadPublisherV2Test.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.jvnet.hudson.test.JenkinsRule; 6 | 7 | import static org.junit.Assert.assertTrue; 8 | 9 | public class UploadPublisherV2Test { 10 | @Rule 11 | public JenkinsRule j = new JenkinsRule(); 12 | 13 | @Test 14 | public void test() { 15 | assertTrue(true); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-apiKey.html: -------------------------------------------------------------------------------- 1 |
2 | To be safe, the field needs to be encrypted, so it looks that long.
3 | (Required) API Key, used to identify the identity of the API caller,
4 | if not specified, each interface needs to contain this parameter.
5 | For the same pgyer registered users, this value is fixed.
6 | Click to get pgyer api_key 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-apiKey.html: -------------------------------------------------------------------------------- 1 |
2 | To be safe, the field needs to be encrypted, so it looks that long.
3 | (Required) API Key, used to identify the identity of the API caller,
4 | if not specified, each interface needs to contain this parameter.
5 | For the same pgyer registered users, this value is fixed.
6 | Click to get pgyer api_key 7 |
8 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-wildcard.html: -------------------------------------------------------------------------------- 1 |
2 | (Required) need to upload ipa or apk file name, Support wildcards,
3 | like this: **/Test?/*.apk
4 | It is using ant's DirectoryScanner class, click to see DirectoryScanner class
7 | It is equivalent to the parameters of the includes method in the DirectoryScanner class! click to see includes method 10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-wildcard.html: -------------------------------------------------------------------------------- 1 |
2 | (Required) need to upload ipa or apk file name, Support wildcards,
3 | like this: **/Test?/*.apk
4 | It is using ant's DirectoryScanner class, click to see DirectoryScanner class
7 | It is equivalent to the parameters of the includes method in the DirectoryScanner class! click to see includes method 10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/help-scanDir.html: -------------------------------------------------------------------------------- 1 |
2 | (Required) need to upload ipa or apk file base dir path!
3 | The default is ${WORKSPACE}, It means the path of the current project!
4 | It is using ant's DirectoryScanner class, click to see DirectoryScanner class
7 | It is equivalent to the parameters of the basedir method in the DirectoryScanner class! click to see basedir method 10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/help-scanDir.html: -------------------------------------------------------------------------------- 1 |
2 | (Required) need to upload ipa or apk file base dir path!
3 | The default is ${WORKSPACE}, It means the path of the current project!
4 | It is using ant's DirectoryScanner class, click to see DirectoryScanner class
7 | It is equivalent to the parameters of the basedir method in the DirectoryScanner class! click to see basedir method 10 |
11 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/helper/PublishEnvVarAction.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.helper; 2 | 3 | import hudson.EnvVars; 4 | import hudson.model.AbstractBuild; 5 | import hudson.model.EnvironmentContributingAction; 6 | import hudson.model.InvisibleAction; 7 | 8 | public class PublishEnvVarAction extends InvisibleAction implements EnvironmentContributingAction { 9 | /** 10 | * The environment variable key. 11 | */ 12 | private final String key; 13 | 14 | /** 15 | * The environment variable value. 16 | */ 17 | private final String value; 18 | 19 | /** 20 | * Constructor. 21 | * 22 | * @param key the environment variable key 23 | * @param value the environment variable value 24 | */ 25 | public PublishEnvVarAction(String key, String value) { 26 | this.key = key; 27 | this.value = value; 28 | } 29 | 30 | /* (non-Javadoc) 31 | * @see hudson.model.EnvironmentContributingAction#buildEnvVars(hudson.model.AbstractBuild, hudson.EnvVars) 32 | */ 33 | public void buildEnvVars(AbstractBuild build, EnvVars env) { 34 | env.put(key, value); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadPublisherV2/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/resources/ren/helloworld/upload2pgyer/UploadBuilderV2/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/helper/ProgressRequestBody.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.helper; 2 | 3 | import okhttp3.MediaType; 4 | import okhttp3.RequestBody; 5 | import okio.*; 6 | 7 | import java.io.IOException; 8 | 9 | public class ProgressRequestBody extends RequestBody { 10 | 11 | protected Listener listener; 12 | protected RequestBody delegate; 13 | protected CountingSink countingSink; 14 | 15 | public ProgressRequestBody(RequestBody delegate, Listener listener) { 16 | this.delegate = delegate; 17 | this.listener = listener; 18 | } 19 | 20 | @Override 21 | public MediaType contentType() { 22 | return delegate.contentType(); 23 | } 24 | 25 | @Override 26 | public long contentLength() { 27 | try { 28 | return delegate.contentLength(); 29 | } catch (IOException e) { 30 | e.printStackTrace(); 31 | } 32 | return -1; 33 | } 34 | 35 | @Override 36 | public void writeTo(BufferedSink sink) throws IOException { 37 | countingSink = new CountingSink(sink); 38 | BufferedSink bufferedSink = Okio.buffer(countingSink); 39 | delegate.writeTo(bufferedSink); 40 | bufferedSink.flush(); 41 | } 42 | 43 | protected final class CountingSink extends ForwardingSink { 44 | 45 | private long bytesWritten = 0; 46 | 47 | public CountingSink(Sink delegate) { 48 | super(delegate); 49 | } 50 | 51 | @Override 52 | public void write(Buffer source, long byteCount) throws IOException { 53 | super.write(source, byteCount); 54 | 55 | bytesWritten += byteCount; 56 | if(listener != null){ 57 | listener.onRequestProgress(bytesWritten, contentLength()); 58 | } 59 | } 60 | } 61 | 62 | public interface Listener { 63 | void onRequestProgress(long bytesWritten, long contentLength); 64 | } 65 | } -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/apiv2/ParamsBeanV2.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.apiv2; 2 | 3 | public class ParamsBeanV2 { 4 | private String apiKey; 5 | // file start 6 | private String scandir; 7 | private String wildcard; 8 | private String uploadFile; 9 | // file end 10 | private String buildInstallType; 11 | private String buildPassword; 12 | private String buildUpdateDescription; 13 | private String buildType; 14 | private String buildChannelShortcut; 15 | 16 | 17 | public String getApiKey() { 18 | return apiKey; 19 | } 20 | 21 | public void setApiKey(String apiKey) { 22 | this.apiKey = apiKey; 23 | } 24 | 25 | public String getScandir() { 26 | return scandir; 27 | } 28 | 29 | public void setScandir(String scandir) { 30 | this.scandir = scandir; 31 | } 32 | 33 | public String getWildcard() { 34 | return wildcard; 35 | } 36 | 37 | public void setWildcard(String wildcard) { 38 | this.wildcard = wildcard; 39 | } 40 | 41 | public String getUploadFile() { 42 | return uploadFile; 43 | } 44 | 45 | public void setUploadFile(String uploadFile) { 46 | this.uploadFile = uploadFile; 47 | } 48 | 49 | public String getBuildInstallType() { 50 | return buildInstallType; 51 | } 52 | 53 | public void setBuildInstallType(String buildInstallType) { 54 | this.buildInstallType = buildInstallType; 55 | } 56 | 57 | public String getBuildPassword() { 58 | return buildPassword; 59 | } 60 | 61 | public void setBuildPassword(String buildPassword) { 62 | this.buildPassword = buildPassword; 63 | } 64 | 65 | public String getBuildType() { 66 | return buildType; 67 | } 68 | 69 | public void setBuildType(String buildType) { 70 | this.buildType = buildType; 71 | } 72 | 73 | public String getBuildUpdateDescription() { 74 | return buildUpdateDescription; 75 | } 76 | 77 | public void setBuildUpdateDescription(String buildUpdateDescription) { 78 | this.buildUpdateDescription = buildUpdateDescription; 79 | } 80 | 81 | public String getBuildChannelShortcut() { 82 | return buildChannelShortcut; 83 | } 84 | 85 | public void setBuildChannelShortcut(String buildChannelShortcut) { 86 | this.buildChannelShortcut = buildChannelShortcut; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/apiv2/PgyerTokenBeanV2.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.apiv2; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class PgyerTokenBeanV2 { 6 | 7 | private int code; 8 | private String message; 9 | private DataBean data; 10 | 11 | public int getCode() { 12 | return code; 13 | } 14 | 15 | public void setCode(int code) { 16 | this.code = code; 17 | } 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | 27 | public DataBean getData() { 28 | return data; 29 | } 30 | 31 | public void setData(DataBean data) { 32 | this.data = data; 33 | } 34 | 35 | public static class DataBean { 36 | 37 | private String key; 38 | private String endpoint; 39 | private Params params; 40 | 41 | public String getKey() { 42 | return key; 43 | } 44 | 45 | public void setKey(String key) { 46 | this.key = key; 47 | } 48 | 49 | public String getEndpoint() { 50 | return endpoint; 51 | } 52 | 53 | public void setEndpoint(String endpoint) { 54 | this.endpoint = endpoint; 55 | } 56 | 57 | public Params getParams() { 58 | return params; 59 | } 60 | 61 | public void setParams(Params params) { 62 | this.params = params; 63 | } 64 | } 65 | 66 | public static class Params { 67 | private String key; 68 | private String signature; 69 | @SerializedName("x-cos-security-token") 70 | private String x_cos_security_token; 71 | 72 | public String getKey() { 73 | return key; 74 | } 75 | 76 | public void setKey(String key) { 77 | this.key = key; 78 | } 79 | 80 | public String getSignature() { 81 | return signature; 82 | } 83 | 84 | public void setSignature(String signature) { 85 | this.signature = signature; 86 | } 87 | 88 | public String getX_cos_security_token() { 89 | return x_cos_security_token; 90 | } 91 | 92 | public void setX_cos_security_token(String x_cos_security_token) { 93 | this.x_cos_security_token = x_cos_security_token; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/ValidationParameters.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer; 2 | 3 | import hudson.util.FormValidation; 4 | 5 | class ValidationParameters { 6 | 7 | public static FormValidation doCheckApiKey(String value) { 8 | if (value.length() == 0) { 9 | return FormValidation.error("Please set a api_key"); 10 | } 11 | return FormValidation.ok(); 12 | } 13 | 14 | public static FormValidation doCheckScanDir(String value) { 15 | if (value.length() == 0) { 16 | return FormValidation.error("Please set upload ipa or apk file base dir name"); 17 | } 18 | return FormValidation.ok(); 19 | } 20 | 21 | public static FormValidation doCheckWildcard(String value) { 22 | if (value.length() == 0) { 23 | return FormValidation.error("Please set upload ipa or apk file wildcard"); 24 | } 25 | return FormValidation.ok(); 26 | } 27 | 28 | public static FormValidation doCheckBuildType(String value) { 29 | if (value.length() == 0) { 30 | return FormValidation.error("Please set upload ipa or apk file buildType"); 31 | } 32 | return FormValidation.ok(); 33 | } 34 | 35 | public static FormValidation doCheckInstallType(String value) { 36 | try { 37 | int valueInt = Integer.parseInt(value); 38 | if (valueInt < 1 || valueInt > 3) { 39 | return FormValidation.error("application installation, the value is (1,2,3)."); 40 | } 41 | return FormValidation.ok(); 42 | } catch (Exception e) { 43 | return FormValidation.error("application installation, must be number, the value is (1,2,3)."); 44 | } 45 | } 46 | 47 | public static FormValidation doCheckPassword(String installType, String value) { 48 | if (!installType.equals(String.valueOf(2))) { 49 | if (value.length() == 0) { 50 | return FormValidation.ok(); 51 | } 52 | return FormValidation.warning("The value of installType is not 2, so the password will be ignored"); 53 | } else { 54 | if (value.length() == 0) { 55 | return FormValidation.error("Please set a password"); 56 | } 57 | if (value.length() < 6) { 58 | return FormValidation.warning("Isn't the password too short?"); 59 | } 60 | return FormValidation.ok(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | 8 7 | 2.277.1 8 | 9 | 10 | 11 | org.jenkins-ci.plugins 12 | plugin 13 | 4.4 14 | 15 | 16 | 17 | ren.helloworld 18 | upload-pgyer 19 | 2.2-SNAPSHOT 20 | hpi 21 | Upload to pgyer 22 | Upload to pgyer for jenkins plugin 23 | 24 | https://github.com/jenkinsci/upload-pgyer-plugin/blob/master/README.md 25 | 26 | 27 | 28 | MIT License 29 | http://opensource.org/licenses/MIT 30 | repo 31 | 32 | 33 | 34 | 35 | 36 | myroid 37 | fan yang 38 | myroid@foxmail.com 39 | https://iamfan.net 40 | 41 | 42 | 43 | manongxiaoyun 44 | xiaoyun 45 | 562007588@qq.com 46 | 47 | 48 | 49 | 50 | 51 | repo.jenkins-ci.org 52 | https://repo.jenkins-ci.org/public/ 53 | 54 | 55 | 56 | 57 | 58 | repo.jenkins-ci.org 59 | https://repo.jenkins-ci.org/public/ 60 | 61 | 62 | 63 | 64 | 65 | org.jenkins-ci.plugins 66 | structs 67 | 1.20 68 | 69 | 70 | 71 | org.apache.ant 72 | ant 73 | 1.10.12 74 | 75 | 76 | 77 | com.google.code.gson 78 | gson 79 | 2.9.0 80 | 81 | 82 | 83 | com.squareup.okhttp3 84 | okhttp-urlconnection 85 | 4.10.0 86 | 87 | 88 | org.jetbrains.kotlin 89 | kotlin-stdlib-common 90 | 91 | 92 | 93 | 94 | 95 | 96 | scm:git:ssh://github.com/jenkinsci/upload-pgyer-plugin.git 97 | scm:git:ssh://git@github.com/jenkinsci/upload-pgyer-plugin.git 98 | https://github.com/jenkinsci/upload-pgyer-plugin 99 | HEAD 100 | 101 | 102 | -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](http://opensource.org/licenses/MIT) 2 | ![Jenkins Plugins](https://img.shields.io/jenkins/plugin/v/upload-pgyer) 3 | ![Jenkins Plugin installs](https://img.shields.io/jenkins/plugin/i/upload-pgyer) 4 | 5 | ### 简单介绍 6 | 7 | [蒲公英官网文档](https://www.pgyer.com/doc/view/jenkins_plugin) 8 | 9 | 蒲公英平台可以让开发者和企业将应用上传到网站,生成安装链接和二维码用户在手机上打开安装链接,或扫码二维码,即可开始安装! 10 | 11 | 因此,这款upload-pgyer的Jenkins插件可以让开发者将apk/ipa文件上传到蒲公英平台!**并且这款插件可以将蒲公英平台返回的应用信息解析后注入到Jenkins的全局变量中,这样你就可以很方便的在其他构建步骤中使用这些返回的信息**。 12 | 13 | ### 安装插件 14 | 15 | - 推荐的安装方式 16 | 17 | `Manage Jenkins` -> `Manage Plugins` -> `Available` -> `Search ` -> *输入* `Upload to pgyer` -> `install` 18 | 19 | - 备用的安装方式 20 | 21 | 1. 点击 [这里](https://updates.jenkins-ci.org/latest/upload-pgyer.hpi) 下载最新的版本 22 | 23 | 2. `Manage Jenkins` -> `Manage Plugins` -> `Advanced` -> `Upload Plugin` -> `Choose file` -> *选择刚才下载的* `upload-pgyer.hpi` -> `Upload` 24 | 25 | ### 构建参数 26 | 27 | 在2.1版本中删除了两个构建参数,分别是`isUploadPgyer`和`uploadPgyerTimeout`,将构建参数`buildName`更改为`buildType`并且`buildType`为必填项 28 | ### 使用指南 29 | 30 | 你可以在Jenkins的job配置页面的`构建`和`构建后操作`这两个操作中点击添加构建步骤选择`upload to pgyer with apiV2`。然后你就可以看到类似下面图片的操作界面: 31 | 32 | 33 | ![](./images/setting-screenshot.png) 34 | 35 | ### 参数介绍 36 | 需要填写的字段|字段的解释 37 | ----:|:---------- 38 | pgyer api_key|(必填) API Key,用来识别API调用者的身份,
如不特别说明,每个接口中都需要含有此参数。
对于同一个蒲公英的注册用户来说,这个值在固定的。
[点击获取_api_key](https://www.pgyer.com/account/api) 39 | scandir|`(必填)` 需要上传的apk/ipa文件所在的文件夹或者父文件夹,
当前默认路径是`${WORKSPACE}`,它代表了当前项目的绝对路径。
这个功能的实现使用了ant框架的DirectoryScanner类,[点击查看DirectoryScanner类](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html),
这个字段就是DirectoryScanner类中的basedir方法的参数[点击查看basedir方法](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html#basedir) 40 | file wildcard|`(必填)` 需要上传的apk/ipa文件的名字,支持通配符,
就像这样: \*\*/\*.apk
或者像这样: \*\*/Test?/\*_sign.apk,
这个功能的实现使用了ant框架的DirectoryScanner类,[点击查看DirectoryScanner类](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html),
这个字段就是DirectoryScanner类中的includes方法的参数,[点击查看includes方法](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html#includes) 41 | buildType|`(必填)` 需要上传应用程序类型,支持,
如: android
如: ios
默认值是: android 42 | installType|`(选填)` 应用安装方式,值为(1,2,3)。
1:公开,2:密码安装,3:邀请安装。
默认为1公开 43 | password|`(选填)` 设置App安装密码,如果不想设置密码,请传空字符串,或不传。 44 | updateDescription|`(选填)` 版本更新描述,请传空字符串,或不传。 45 | channelShortcut|`(选填)` 所需更新的指定渠道的下载短链接,只可指定一个渠道,字符串型,如:abcd 46 | 47 | ### 运行截图 48 | ![](./images/pgyer-app-upload-running-log.png) 49 | 50 | 当你的应用上传成功后,在Jenkins中你就能看到上面图片中的信息。同时,你就可以在其他构建步骤中使用蒲公英返回来的信息,例如我的经验: 51 | 52 | ![](./images/pgyer-app-upload-backdata.png) 53 | 54 | ### Change Log 55 | 56 | 版本 2.1(2022-10-26) 57 | - **最低兼容Jenkins: [2.277.1](http://mirrors.jenkins.io/war-stable/2.277.1)** 58 | - 移除apiv1的相关配置 59 | - 删除' isUploadPgyer '构建参数 60 | - 删除' uploadPgyerTimeout '构建参数 61 | - 删除' buildName '构建参数 62 | - 添加' buildType '构建参数(必填项) 63 | - api变化 64 | - 升级Gson 2.9.0 65 | - 升级OkHttp3 4.10.0 66 | - 优化代码以提高稳定性 67 | 68 | 69 | 版本 1.34(2020-08-15) 70 | 71 | - **最低兼容Jenkins: [2.164.1](http://mirrors.jenkins.io/war-stable/2.164.1)** 72 | - 添加 `isUploadPgyer` 构建参数 73 | - 添加 `uploadPgyerTimeout` 构建参数 74 | - 升级蒲公英API,添加 `channelShortcut` 参数 75 | - `installType` 默认值设置为1 76 | - 优化参数校验 77 | - 升级Gson 2.8.6 78 | - 升级Ant 1.10.8 79 | - 升级OkHttp3 3.14.9 80 | - 优化代码,提升稳定性 81 | 82 | 版本 1.33(2019-09-07) 83 | 84 | - 修复[SECURITY-1044](https://issues.jenkins-ci.org/browse/SECURITY-1044) 85 | - 升级Gson 2.8.5 86 | 87 | 版本 1.31(2018-05-07) 88 | 89 | - 升级Gson 2.8.4 90 | - 优化上传日志 91 | - 更换readme.md图片地址 92 | 93 | 版本 1.30(2018-04-16) 94 | 95 | - 移除Jsoup,并引入okhttp作为网络库 96 | - 增加文件上传进度 97 | - 增加蒲公英[APIV2](https://www.pgyer.com/doc/view/api#uploadApp) -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/helper/PgyerV2Helper.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.helper; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.reflect.TypeToken; 5 | import hudson.model.AbstractBuild; 6 | import hudson.model.BuildListener; 7 | import ren.helloworld.upload2pgyer.apiv2.ParamsBeanV2; 8 | import ren.helloworld.upload2pgyer.apiv2.PgyerBeanV2; 9 | import ren.helloworld.upload2pgyer.apiv2.PgyerUploadV2; 10 | import ren.helloworld.upload2pgyer.impl.Message; 11 | 12 | import java.io.IOException; 13 | import java.util.Map; 14 | 15 | public class PgyerV2Helper { 16 | /** 17 | * @param build build 18 | * @param listener listener 19 | * @param paramsBeanV2 uploadBean 20 | * @return success or failure 21 | * @throws IOException IOException 22 | * @throws InterruptedException InterruptedException 23 | */ 24 | public static boolean upload(AbstractBuild build, final BuildListener listener, ParamsBeanV2 paramsBeanV2) throws IOException, InterruptedException { 25 | Message message = new Message() { 26 | @Override 27 | public void message(boolean needTag, String mesage) { 28 | listener.getLogger().println((needTag ? CommonUtil.LOG_PREFIX : "") + mesage); 29 | } 30 | }; 31 | 32 | if (CommonUtil.isBuildFailed(build, message)) { 33 | return true; 34 | } 35 | 36 | if (CommonUtil.isSkipUpload(build.getEnvironment(listener), message)) { 37 | return true; 38 | } 39 | 40 | // expand params 41 | paramsBeanV2.setApiKey(build.getEnvironment(listener).expand(paramsBeanV2.getApiKey())); 42 | paramsBeanV2.setScandir(build.getEnvironment(listener).expand(paramsBeanV2.getScandir())); 43 | paramsBeanV2.setWildcard(build.getEnvironment(listener).expand(paramsBeanV2.getWildcard())); 44 | paramsBeanV2.setBuildPassword(build.getEnvironment(listener).expand(paramsBeanV2.getBuildPassword())); 45 | paramsBeanV2.setBuildInstallType(build.getEnvironment(listener).expand(paramsBeanV2.getBuildInstallType())); 46 | paramsBeanV2.setBuildUpdateDescription(build.getEnvironment(listener).expand(paramsBeanV2.getBuildUpdateDescription())); 47 | paramsBeanV2.setBuildType(build.getEnvironment(listener).expand(paramsBeanV2.getBuildType())); 48 | paramsBeanV2.setBuildChannelShortcut(build.getEnvironment(listener).expand(paramsBeanV2.getBuildChannelShortcut())); 49 | 50 | // upload 51 | PgyerBeanV2 pgyerBeanV2 = PgyerUploadV2.upload2Pgyer(build.getEnvironment(listener), true, paramsBeanV2, message); 52 | if (pgyerBeanV2 == null) { 53 | return false; 54 | } 55 | 56 | // http://jenkins-ci.361315.n4.nabble.com/Setting-an-env-var-from-a-build-step-td4657347.html 57 | message.message(true, "The Jenkins environment variable is being set."); 58 | String data = new Gson().toJson(pgyerBeanV2.getData()); 59 | Map maps = new Gson().fromJson(data, new TypeToken>() { 60 | }.getType()); 61 | for (Map.Entry entry : maps.entrySet()) { 62 | String key = entry.getKey(); 63 | build.addAction(new PublishEnvVarAction(key, entry.getValue())); 64 | message.message(true, "The ${" + key + "} set up successfully! You can use it anywhere now!"); 65 | 66 | if (key.equals("buildQRCodeURL")) { 67 | build.addAction(new PublishEnvVarAction("appQRCodeURL", entry.getValue())); 68 | message.message(true, "The ${appQRCodeURL} set up successfully! You can use it anywhere now.!"); 69 | } 70 | } 71 | message.message(true, "congratulations!\n"); 72 | return true; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/UploadBuilderV2.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer; 2 | 3 | import hudson.Extension; 4 | import hudson.Launcher; 5 | import hudson.model.AbstractBuild; 6 | import hudson.model.AbstractProject; 7 | import hudson.model.BuildListener; 8 | import hudson.tasks.BuildStepDescriptor; 9 | import hudson.tasks.Builder; 10 | import hudson.util.FormValidation; 11 | import hudson.util.Secret; 12 | import org.jenkinsci.Symbol; 13 | import org.kohsuke.stapler.DataBoundConstructor; 14 | import org.kohsuke.stapler.QueryParameter; 15 | import ren.helloworld.upload2pgyer.apiv2.ParamsBeanV2; 16 | import ren.helloworld.upload2pgyer.helper.PgyerV2Helper; 17 | 18 | import java.io.IOException; 19 | 20 | /** 21 | * upload to jenkins 22 | * 23 | * @author myroid 24 | */ 25 | public class UploadBuilderV2 extends Builder { 26 | 27 | private final Secret apiKey; 28 | private final String scanDir; 29 | private final String wildcard; 30 | private final String buildInstallType; 31 | private final Secret buildPassword; 32 | private final String buildUpdateDescription; 33 | private final String buildType; 34 | private final String buildChannelShortcut; 35 | 36 | 37 | @DataBoundConstructor 38 | public UploadBuilderV2(String apiKey, String scanDir, String wildcard, String buildType, String buildInstallType, String buildPassword, String buildUpdateDescription, String buildChannelShortcut, String qrcodePath, String envVarsPath) { 39 | this.apiKey = Secret.fromString(apiKey); 40 | this.scanDir = scanDir; 41 | this.wildcard = wildcard; 42 | this.buildType = buildType; 43 | this.buildPassword = Secret.fromString(buildPassword); 44 | this.buildInstallType = buildInstallType; 45 | this.buildUpdateDescription = buildUpdateDescription; 46 | this.buildChannelShortcut = buildChannelShortcut; 47 | } 48 | 49 | public Secret getApiKey() { 50 | return apiKey; 51 | } 52 | 53 | public String getScanDir() { 54 | return scanDir; 55 | } 56 | 57 | public String getWildcard() { 58 | return wildcard; 59 | } 60 | 61 | public String getBuildInstallType() { 62 | return buildInstallType; 63 | } 64 | 65 | public Secret getBuildPassword() { 66 | return buildPassword; 67 | } 68 | 69 | public String getBuildUpdateDescription() { 70 | return buildUpdateDescription; 71 | } 72 | 73 | public String getBuildType() { 74 | return buildType; 75 | } 76 | 77 | public String getBuildChannelShortcut() { 78 | return buildChannelShortcut; 79 | } 80 | 81 | 82 | @Override 83 | public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { 84 | ParamsBeanV2 paramsBeanV2 = new ParamsBeanV2(); 85 | paramsBeanV2.setApiKey(apiKey.getPlainText()); 86 | paramsBeanV2.setScandir(scanDir); 87 | paramsBeanV2.setWildcard(wildcard); 88 | paramsBeanV2.setBuildPassword(buildPassword.getPlainText()); 89 | paramsBeanV2.setBuildInstallType(buildInstallType); 90 | paramsBeanV2.setBuildUpdateDescription(buildUpdateDescription); 91 | paramsBeanV2.setBuildType(buildType); 92 | paramsBeanV2.setBuildChannelShortcut(buildChannelShortcut); 93 | return PgyerV2Helper.upload(build, listener, paramsBeanV2); 94 | } 95 | 96 | @Override 97 | public DescriptorImpl getDescriptor() { 98 | return (DescriptorImpl) super.getDescriptor(); 99 | } 100 | 101 | @Symbol("upload-pgyer-v2") 102 | @Extension 103 | public static final class DescriptorImpl extends BuildStepDescriptor { 104 | private String installType = "1"; 105 | 106 | public DescriptorImpl() { 107 | load(); 108 | } 109 | 110 | public FormValidation doCheckApiKey(@QueryParameter String value) { 111 | return ValidationParameters.doCheckApiKey(value); 112 | } 113 | 114 | public FormValidation doCheckScanDir(@QueryParameter String value) { 115 | return ValidationParameters.doCheckScanDir(value); 116 | } 117 | 118 | public FormValidation doCheckWildcard(@QueryParameter String value) { 119 | return ValidationParameters.doCheckWildcard(value); 120 | } 121 | 122 | public FormValidation doCheckBuildType(@QueryParameter String value) { 123 | return ValidationParameters.doCheckBuildType(value); 124 | } 125 | 126 | public FormValidation doCheckBuildInstallType(@QueryParameter String value) { 127 | installType = value; 128 | return ValidationParameters.doCheckInstallType(value); 129 | } 130 | 131 | public FormValidation doCheckBuildPassword(@QueryParameter String value) { 132 | return ValidationParameters.doCheckPassword(installType, value); 133 | } 134 | 135 | public boolean isApplicable(Class aClass) { 136 | return true; 137 | } 138 | 139 | public String getDisplayName() { 140 | return "Upload to pgyer with apiV2"; 141 | } 142 | } 143 | } 144 | 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](http://opensource.org/licenses/MIT) 2 | ![Jenkins Plugins](https://img.shields.io/jenkins/plugin/v/upload-pgyer) 3 | ![Jenkins Plugin installs](https://img.shields.io/jenkins/plugin/i/upload-pgyer) 4 | 5 | ### A simple introduction 6 | 7 | [中文文档](./README_cn.md) 8 | 9 | [蒲公英官网文档](https://www.pgyer.com/doc/view/jenkins_plugin) 10 | 11 | Pgyer can upload the application to the site, generate installation link and qr code user to open the installation link, or scan code qr code, can start installation. 12 | 13 | ### Install plugin 14 | 15 | - Recommend 16 | 17 | `Manage Jenkins` -> `Manage Plugins` -> `Available` -> `Search ` -> *enter* `Upload to pgyer` -> `install` 18 | 19 | - Alternate 20 | 21 | 1. Click [here](https://updates.jenkins-ci.org/latest/upload-pgyer.hpi) to download the latest version 22 | 23 | 2. `Manage Jenkins` -> `Manage Plugins` -> `Advanced` -> `Upload Plugin` -> `Choose file` -> *choose* `upload-pgyer.hpi` -> `Upload` 24 | 25 | ### Build parameters 26 | 27 | In version 2.1 removed the two build parameters, respectively `isUploadPgyer` and `uploadPgyerTimeout`, changing the build parameter `buildName` to `buildType`, and `buildType` to be required 28 | ### User's guidance 29 | So this plugin can be uploaded to the pgyer platform!**And it can put the fields returned by pgyer into an environment variable, which you can use in other build steps**, You can select `upload to pgyer` by adding build steps or adding post-build steps. 30 | 31 | ![](./images/setting-screenshot.png) 32 | 33 | ### Introduction to parameters 34 | field|explanation 35 | ----:|:---------- 36 | pgyer api_key|`(Required)` API Key, used to identify the identity of the API caller,
if not specified, each interface needs to contain this parameter.
For the same pgyer registered users, this value is fixed.
[Click to get pgyer api_key](https://www.pgyer.com/account/api) 37 | scandir|`(Required)` Need to upload ipa or apk file base dir path!
The default is ${WORKSPACE}, It means the path of the current project!
It is using ant's DirectoryScanner class, [click to see DirectoryScanner class](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html)
**It is equivalent to the parameters of the basedir method in the DirectoryScanner class!** [click to see basedir method](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html#basedir) 38 | file wildcard|`(Required)` Need to upload ipa or apk file name, Support wildcards,
like this: \*\*/\*.apk
like this: \*\*/Test?/\*_sign.apk
It is using ant's DirectoryScanner class, [click to see DirectoryScanner class](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html)
**It is equivalent to the parameters of the includes method in the DirectoryScanner class!** [click to see includes method](https://ant.apache.org/manual/api/org/apache/tools/ant/DirectoryScanner.html#includes) 39 | buildType|`(Required)` Need to upload app type, Support buildType,
like this: android
like this: ios
The default: android! 40 | installType|`(Optional)` Application installation, the value is (1,2,3).
1: public,
2: password installed,
3: invitation to install.
The default is 1 public! 41 | password|(Optional) Set the App installation password, if you do not want to set the password, please pass empty string, or not pass. 42 | updateDescription|`(Optional)` Version update description, please pass empty string, or not pass. 43 | channelShortcut|`(Optional)` The download short link of the specified channel that needs to be updated, only one channel can be specified, string type, such as: abcd. 44 | 45 | ### Running log 46 | ![](./images/pgyer-app-upload-running-log.png) 47 | 48 | When it runs successfully, you can use the environment variables that are used! for example: 49 | 50 | ![](./images/pgyer-app-upload-backdata.png) 51 | 52 | ### Change Log 53 | Version 2.1(2022-10-26) 54 | 55 | - **Minimum Jenkins requirement: [2.277.1](http://mirrors.jenkins.io/war-stable/2.277.1)** 56 | - Example Remove configurations related to apiv1 57 | - removed `isUploadPgyer` build parameter 58 | - removed `uploadPgyerTimeout` build parameter 59 | - removed `buildName` build parameter 60 | - add `buildType` build parameter (required) 61 | - api changes 62 | - Upgrade Gson 2.9.0 63 | - Upgrade OkHttp3 4.10.0 64 | - Optimize code to improve stability 65 | 66 | Version 1.34(2020-08-15) 67 | 68 | - **Minimum Jenkins requirement: [2.164.1](http://mirrors.jenkins.io/war-stable/2.164.1)** 69 | - Add `isUploadPgyer` build parameter 70 | - Add `uploadPgyerTimeout` build parameter 71 | - Upgrade pgyer api, add `channelShortcut` parameter 72 | - Change the default value of `installType` to 1 73 | - Optimize parameters verification 74 | - Upgrade Gson 2.8.6 75 | - Upgrade Ant 1.10.8 76 | - Upgrade OkHttp3 3.14.9 77 | - Optimize code to improve stability 78 | 79 | Version 1.33(2019-09-07) 80 | 81 | - Fixed [SECURITY-1044](https://issues.jenkins-ci.org/browse/SECURITY-1044) 82 | - Upgrade gson 2.8.5 83 | 84 | Version 1.31(2018-05-07) 85 | 86 | - Upgrade gson 2.8.4 87 | - Optimize upload log 88 | - Change the document image address. 89 | 90 | Version 1.30(2018-04-16) 91 | 92 | - Remove jsoup, and import okhttp that be used network 93 | - Add upload file progress 94 | - Add [pgyer api v2](https://www.pgyer.com/doc/view/api#uploadApp) -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/UploadPublisherV2.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer; 2 | 3 | import hudson.Extension; 4 | import hudson.Launcher; 5 | import hudson.model.AbstractBuild; 6 | import hudson.model.AbstractProject; 7 | import hudson.model.BuildListener; 8 | import hudson.tasks.BuildStepDescriptor; 9 | import hudson.tasks.BuildStepMonitor; 10 | import hudson.tasks.Publisher; 11 | import hudson.tasks.Recorder; 12 | import hudson.util.FormValidation; 13 | import hudson.util.Secret; 14 | import org.jenkinsci.Symbol; 15 | import org.kohsuke.stapler.DataBoundConstructor; 16 | import org.kohsuke.stapler.QueryParameter; 17 | import ren.helloworld.upload2pgyer.apiv2.ParamsBeanV2; 18 | import ren.helloworld.upload2pgyer.helper.PgyerV2Helper; 19 | 20 | import java.io.IOException; 21 | 22 | /** 23 | * upload to jenkins 24 | * 25 | * @author myroid 26 | */ 27 | public class UploadPublisherV2 extends Recorder { 28 | 29 | private final Secret apiKey; 30 | private final String scanDir; 31 | private final String wildcard; 32 | private final String buildInstallType; 33 | private final Secret buildPassword; 34 | private final String buildUpdateDescription; 35 | private final String buildType; 36 | private final String buildChannelShortcut; 37 | 38 | 39 | @DataBoundConstructor 40 | public UploadPublisherV2(String apiKey, String scanDir, String wildcard, String buildType, String buildInstallType, String buildPassword, String buildUpdateDescription, String buildChannelShortcut, String qrcodePath, String envVarsPath) { 41 | this.apiKey = Secret.fromString(apiKey); 42 | this.scanDir = scanDir; 43 | this.wildcard = wildcard; 44 | this.buildType = buildType; 45 | this.buildPassword = Secret.fromString(buildPassword); 46 | this.buildInstallType = buildInstallType; 47 | this.buildUpdateDescription = buildUpdateDescription; 48 | this.buildChannelShortcut = buildChannelShortcut; 49 | } 50 | 51 | public Secret getApiKey() { 52 | return apiKey; 53 | } 54 | 55 | public String getScanDir() { 56 | return scanDir; 57 | } 58 | 59 | public String getWildcard() { 60 | return wildcard; 61 | } 62 | 63 | public String getBuildInstallType() { 64 | return buildInstallType; 65 | } 66 | 67 | public Secret getBuildPassword() { 68 | return buildPassword; 69 | } 70 | 71 | public String getBuildUpdateDescription() { 72 | return buildUpdateDescription; 73 | } 74 | 75 | public String getBuildType() { 76 | return buildType; 77 | } 78 | 79 | public String getBuildChannelShortcut() { 80 | return buildChannelShortcut; 81 | } 82 | 83 | 84 | @Override 85 | public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { 86 | ParamsBeanV2 paramsBeanV2 = new ParamsBeanV2(); 87 | paramsBeanV2.setApiKey(apiKey.getPlainText()); 88 | paramsBeanV2.setScandir(scanDir); 89 | paramsBeanV2.setWildcard(wildcard); 90 | paramsBeanV2.setBuildPassword(buildPassword.getPlainText()); 91 | paramsBeanV2.setBuildInstallType(buildInstallType); 92 | paramsBeanV2.setBuildType(buildType); 93 | paramsBeanV2.setBuildUpdateDescription(buildUpdateDescription); 94 | paramsBeanV2.setBuildChannelShortcut(buildChannelShortcut); 95 | return PgyerV2Helper.upload(build, listener, paramsBeanV2); 96 | } 97 | 98 | @Override 99 | public DescriptorImpl getDescriptor() { 100 | return (DescriptorImpl) super.getDescriptor(); 101 | } 102 | 103 | @Symbol("upload-pgyer-v2") 104 | @Extension 105 | public static final class DescriptorImpl extends BuildStepDescriptor { 106 | private String installType = "1"; 107 | 108 | public DescriptorImpl() { 109 | load(); 110 | } 111 | 112 | public FormValidation doCheckApiKey(@QueryParameter String value) { 113 | return ValidationParameters.doCheckApiKey(value); 114 | } 115 | 116 | public FormValidation doCheckScanDir(@QueryParameter String value) { 117 | return ValidationParameters.doCheckScanDir(value); 118 | } 119 | 120 | public FormValidation doCheckWildcard(@QueryParameter String value) { 121 | return ValidationParameters.doCheckWildcard(value); 122 | } 123 | 124 | public FormValidation doCheckBuildType(@QueryParameter String value) { 125 | return ValidationParameters.doCheckBuildType(value); 126 | } 127 | 128 | public FormValidation doCheckBuildInstallType(@QueryParameter String value) { 129 | installType = value; 130 | return ValidationParameters.doCheckInstallType(value); 131 | } 132 | 133 | public FormValidation doCheckBuildPassword(@QueryParameter String value) { 134 | return ValidationParameters.doCheckPassword(installType, value); 135 | } 136 | 137 | public boolean isApplicable(Class aClass) { 138 | return true; 139 | } 140 | 141 | public String getDisplayName() { 142 | return "Upload to pgyer with apiV2"; 143 | } 144 | } 145 | 146 | @Override 147 | public BuildStepMonitor getRequiredMonitorService() { 148 | return BuildStepMonitor.NONE; 149 | } 150 | } 151 | 152 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/apiv2/PgyerBeanV2.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.apiv2; 2 | 3 | public class PgyerBeanV2 { 4 | 5 | private int code; 6 | private String message; 7 | private DataBean data; 8 | 9 | public int getCode() { 10 | return code; 11 | } 12 | 13 | public void setCode(int code) { 14 | this.code = code; 15 | } 16 | 17 | public String getMessage() { 18 | return message; 19 | } 20 | 21 | public void setMessage(String message) { 22 | this.message = message; 23 | } 24 | 25 | public DataBean getData() { 26 | return data; 27 | } 28 | 29 | public void setData(DataBean data) { 30 | this.data = data; 31 | } 32 | 33 | public static class DataBean { 34 | 35 | private String buildKey; 36 | private String buildType; 37 | private String buildIsFirst; 38 | private String buildIsLastest; 39 | private String buildFileKey; 40 | private String buildFileName; 41 | private String buildFileSize; 42 | private String buildName; 43 | private String buildVersion; 44 | private String buildVersionNo; 45 | private String buildBuildVersion; 46 | private String buildIdentifier; 47 | private String buildIcon; 48 | private String buildDescription; 49 | private String buildUpdateDescription; 50 | private String buildScreenshots; 51 | private String buildShortcutUrl; 52 | private String buildCreated; 53 | private String buildUpdated; 54 | private String buildQRCodeURL; 55 | private String appPgyerURL; 56 | private String appBuildURL; 57 | 58 | public String getBuildKey() { 59 | return buildKey; 60 | } 61 | 62 | public void setBuildKey(String buildKey) { 63 | this.buildKey = buildKey; 64 | } 65 | 66 | public String getBuildType() { 67 | return buildType; 68 | } 69 | 70 | public void setBuildType(String buildType) { 71 | this.buildType = buildType; 72 | } 73 | 74 | public String getBuildIsFirst() { 75 | return buildIsFirst; 76 | } 77 | 78 | public void setBuildIsFirst(String buildIsFirst) { 79 | this.buildIsFirst = buildIsFirst; 80 | } 81 | 82 | public String getBuildIsLastest() { 83 | return buildIsLastest; 84 | } 85 | 86 | public void setBuildIsLastest(String buildIsLastest) { 87 | this.buildIsLastest = buildIsLastest; 88 | } 89 | 90 | public String getBuildFileKey() { 91 | return buildFileKey; 92 | } 93 | 94 | public void setBuildFileKey(String buildFileKey) { 95 | this.buildFileKey = buildFileKey; 96 | } 97 | 98 | public String getBuildFileName() { 99 | return buildFileName; 100 | } 101 | 102 | public void setBuildFileName(String buildFileName) { 103 | this.buildFileName = buildFileName; 104 | } 105 | 106 | public String getBuildFileSize() { 107 | return buildFileSize; 108 | } 109 | 110 | public void setBuildFileSize(String buildFileSize) { 111 | this.buildFileSize = buildFileSize; 112 | } 113 | 114 | public String getBuildName() { 115 | return buildName; 116 | } 117 | 118 | public void setBuildName(String buildName) { 119 | this.buildName = buildName; 120 | } 121 | 122 | public String getBuildVersion() { 123 | return buildVersion; 124 | } 125 | 126 | public void setBuildVersion(String buildVersion) { 127 | this.buildVersion = buildVersion; 128 | } 129 | 130 | public String getBuildVersionNo() { 131 | return buildVersionNo; 132 | } 133 | 134 | public void setBuildVersionNo(String buildVersionNo) { 135 | this.buildVersionNo = buildVersionNo; 136 | } 137 | 138 | public String getBuildBuildVersion() { 139 | return buildBuildVersion; 140 | } 141 | 142 | public void setBuildBuildVersion(String buildBuildVersion) { 143 | this.buildBuildVersion = buildBuildVersion; 144 | } 145 | 146 | public String getBuildIdentifier() { 147 | return buildIdentifier; 148 | } 149 | 150 | public void setBuildIdentifier(String buildIdentifier) { 151 | this.buildIdentifier = buildIdentifier; 152 | } 153 | 154 | public String getBuildIcon() { 155 | return buildIcon; 156 | } 157 | 158 | public void setBuildIcon(String buildIcon) { 159 | this.buildIcon = buildIcon; 160 | } 161 | 162 | public String getBuildDescription() { 163 | return buildDescription; 164 | } 165 | 166 | public void setBuildDescription(String buildDescription) { 167 | this.buildDescription = buildDescription; 168 | } 169 | 170 | public String getBuildUpdateDescription() { 171 | return buildUpdateDescription; 172 | } 173 | 174 | public void setBuildUpdateDescription(String buildUpdateDescription) { 175 | this.buildUpdateDescription = buildUpdateDescription; 176 | } 177 | 178 | public String getBuildScreenshots() { 179 | return buildScreenshots; 180 | } 181 | 182 | public void setBuildScreenshots(String buildScreenshots) { 183 | this.buildScreenshots = buildScreenshots; 184 | } 185 | 186 | public String getBuildShortcutUrl() { 187 | return buildShortcutUrl; 188 | } 189 | 190 | public void setBuildShortcutUrl(String buildShortcutUrl) { 191 | this.buildShortcutUrl = buildShortcutUrl; 192 | } 193 | 194 | public String getBuildCreated() { 195 | return buildCreated; 196 | } 197 | 198 | public void setBuildCreated(String buildCreated) { 199 | this.buildCreated = buildCreated; 200 | } 201 | 202 | public String getBuildUpdated() { 203 | return buildUpdated; 204 | } 205 | 206 | public void setBuildUpdated(String buildUpdated) { 207 | this.buildUpdated = buildUpdated; 208 | } 209 | 210 | public String getBuildQRCodeURL() { 211 | return buildQRCodeURL; 212 | } 213 | 214 | public void setBuildQRCodeURL(String buildQRCodeURL) { 215 | this.buildQRCodeURL = buildQRCodeURL; 216 | } 217 | 218 | public String getAppPgyerURL() { 219 | return appPgyerURL; 220 | } 221 | 222 | public void setAppPgyerURL(String appPgyerURL) { 223 | this.appPgyerURL = appPgyerURL; 224 | } 225 | 226 | public String getAppBuildURL() { 227 | return appBuildURL; 228 | } 229 | 230 | public void setAppBuildURL(String appBuildURL) { 231 | this.appBuildURL = appBuildURL; 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/helper/CommonUtil.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.helper; 2 | 3 | import hudson.EnvVars; 4 | import hudson.model.AbstractBuild; 5 | import hudson.model.Result; 6 | import org.apache.tools.ant.DirectoryScanner; 7 | import ren.helloworld.upload2pgyer.impl.Message; 8 | 9 | import java.io.*; 10 | import java.net.URL; 11 | import java.net.URLConnection; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.Comparator; 15 | import java.util.List; 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | public class CommonUtil { 20 | public static final String LOG_PREFIX = "[UPLOAD TO PGYER] - "; 21 | public static final String PGYER_HOST = "https://www.pgyer.com"; 22 | 23 | /** 24 | * Header 25 | * 26 | * @param listener listener 27 | */ 28 | public static void printHeaderInfo(Message listener) { 29 | printMessage(listener, false, ""); 30 | printMessage(listener, false, "**************************************************************************************************"); 31 | printMessage(listener, false, "**************************************************************************************************"); 32 | printMessage(listener, false, "******************************** UPLOAD TO PGYER ********************************"); 33 | printMessage(listener, false, "******************************** https://www.pgyer.com ********************************"); 34 | printMessage(listener, false, "**************************************************************************************************"); 35 | printMessage(listener, false, "**************************************************************************************************"); 36 | printMessage(listener, false, ""); 37 | } 38 | 39 | /** 40 | * print message 41 | * 42 | * @param listener listener 43 | * @param needTag needTag 44 | * @param message message 45 | */ 46 | public static void printMessage(Message listener, boolean needTag, String message) { 47 | if (listener != null) { 48 | listener.message(needTag, message); 49 | } 50 | } 51 | 52 | /** 53 | * skip upload 54 | * 55 | * @param envVars envVars 56 | * @param message message 57 | * @return skip 58 | */ 59 | public static boolean isSkipUpload(EnvVars envVars, Message message) { 60 | try { 61 | String uploadKey = "isUploadPgyer"; 62 | String isUploadPgyerString = envVars.get(uploadKey, "true"); 63 | boolean isUploadPgyer = Boolean.parseBoolean(isUploadPgyerString); 64 | if (!isUploadPgyer) { 65 | message.message(true, "The value of " + uploadKey + " is false, so it is not uploaded."); 66 | } 67 | return !isUploadPgyer; 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | return false; 71 | } 72 | } 73 | 74 | /** 75 | * get upload timeout 76 | * 77 | * @param envVars envVars 78 | * @return timeout 79 | */ 80 | public static int getUploadTimeout(EnvVars envVars) { 81 | int defalut = 300; 82 | if (envVars == null) { 83 | return defalut; 84 | } 85 | try { 86 | String timeoutKey = "uploadPgyerTimeout"; 87 | if (envVars.containsKey(timeoutKey)) { 88 | String uploadPgyerTimeoutString = envVars.get(timeoutKey); 89 | return Integer.parseInt(uploadPgyerTimeoutString); 90 | } else { 91 | return defalut; 92 | } 93 | } catch (Exception e) { 94 | e.printStackTrace(); 95 | return defalut; 96 | } 97 | } 98 | 99 | /** 100 | * check build result 101 | * 102 | * @param build build 103 | * @param message message 104 | * @return failed 105 | */ 106 | public static boolean isBuildFailed(AbstractBuild build, Message message) { 107 | // check build result 108 | Result result = build.getResult(); 109 | boolean unStable = result != null && result.isWorseThan(Result.UNSTABLE); 110 | if (unStable) { 111 | message.message(true, "The build " + result.toString() + ", so the file was not uploaded."); 112 | } 113 | return unStable; 114 | } 115 | 116 | /** 117 | * find file 118 | * 119 | * @param scandir scandir 120 | * @param wildcard wildcard 121 | * @param listener listener 122 | * @return file path 123 | */ 124 | public static String findFile(String scandir, String wildcard, Message listener) { 125 | File dir = new File(scandir); 126 | if (!dir.exists() || !dir.isDirectory()) { 127 | CommonUtil.printMessage(listener, true, "scan dir:" + dir.getAbsolutePath()); 128 | CommonUtil.printMessage(listener, true, "scan dir isn't exist or it's not a directory!"); 129 | return null; 130 | } 131 | 132 | DirectoryScanner scanner = new DirectoryScanner(); 133 | scanner.setBasedir(scandir); 134 | scanner.setIncludes(new String[]{wildcard}); 135 | scanner.setCaseSensitive(true); 136 | scanner.scan(); 137 | String[] uploadFiles = scanner.getIncludedFiles(); 138 | 139 | if (uploadFiles == null || uploadFiles.length == 0) { 140 | return null; 141 | } 142 | if (uploadFiles.length == 1) { 143 | return new File(dir, uploadFiles[0]).getAbsolutePath(); 144 | } 145 | 146 | List strings = Arrays.asList(uploadFiles); 147 | Collections.sort(strings, new CommonUtil.FileComparator(dir)); 148 | String uploadFiltPath = new File(dir, strings.get(0)).getAbsolutePath(); 149 | CommonUtil.printMessage(listener, true, "Found " + uploadFiles.length + " files, the default choice of the latest modified file!"); 150 | CommonUtil.printMessage(listener, true, "The latest modified file is " + uploadFiltPath + "\n"); 151 | return uploadFiltPath; 152 | } 153 | 154 | /** 155 | * string is blank 156 | * 157 | * @param str string 158 | * @return isblank 159 | */ 160 | public static boolean isBlank(String str) { 161 | int strLen; 162 | if (str != null && (strLen = str.length()) != 0) { 163 | for (int i = 0; i < strLen; ++i) { 164 | if (!Character.isWhitespace(str.charAt(i))) { 165 | return false; 166 | } 167 | } 168 | } 169 | return true; 170 | } 171 | 172 | /** 173 | * size convert 174 | * 175 | * @param size file size 176 | * @return convert file size 177 | */ 178 | public static String convertFileSize(long size) { 179 | long kb = 1024; 180 | long mb = kb * 1024; 181 | long gb = mb * 1024; 182 | 183 | if (size >= gb) { 184 | return String.format("%.1f GB", (float) size / gb); 185 | } else if (size >= mb) { 186 | float f = (float) size / mb; 187 | return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f); 188 | } else if (size >= kb) { 189 | float f = (float) size / kb; 190 | return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f); 191 | } else 192 | return String.format("%d B", size); 193 | } 194 | 195 | /** 196 | * 197 | */ 198 | public static class FileUploadProgressListener implements ProgressRequestBody.Listener { 199 | private long last_time = -1L; 200 | private final Message listener; 201 | 202 | public FileUploadProgressListener(Message listener) { 203 | this.listener = listener; 204 | } 205 | 206 | @Override 207 | public void onRequestProgress(long bytesWritten, long contentLength) { 208 | final int progress = (int) (100F * bytesWritten / contentLength); 209 | if (progress == 100) { 210 | last_time = -1L; 211 | if(listener != null){ 212 | listener.message(true, "upload progress: " + progress + " %"); 213 | } 214 | 215 | return; 216 | } 217 | 218 | if (last_time == -1) { 219 | last_time = System.currentTimeMillis(); 220 | if(listener != null){ 221 | listener.message(true, "upload progress: " + progress + " %"); 222 | } 223 | return; 224 | } 225 | 226 | if (System.currentTimeMillis() - last_time > 1000) { 227 | last_time = System.currentTimeMillis(); 228 | listener.message(true, "upload progress: " + progress + " %"); 229 | } 230 | } 231 | } 232 | 233 | /** 234 | * 235 | */ 236 | public static class FileComparator implements Comparator, Serializable { 237 | File dir; 238 | 239 | public FileComparator(File dir) { 240 | this.dir = dir; 241 | } 242 | 243 | @Override 244 | public int compare(String o1, String o2) { 245 | File file1 = new File(dir, o1); 246 | File file2 = new File(dir, o2); 247 | return Long.compare(file2.lastModified(), file1.lastModified()); 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /src/main/java/ren/helloworld/upload2pgyer/apiv2/PgyerUploadV2.java: -------------------------------------------------------------------------------- 1 | package ren.helloworld.upload2pgyer.apiv2; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.reflect.TypeToken; 5 | import hudson.EnvVars; 6 | import okhttp3.*; 7 | import ren.helloworld.upload2pgyer.helper.CommonUtil; 8 | import ren.helloworld.upload2pgyer.helper.ProgressRequestBody; 9 | import ren.helloworld.upload2pgyer.impl.Message; 10 | 11 | import javax.swing.*; 12 | import java.awt.event.ActionEvent; 13 | import java.awt.event.ActionListener; 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | public class PgyerUploadV2 { 21 | private static final String UPLOAD_URL = CommonUtil.PGYER_HOST + "/apiv2/app/getCOSToken"; 22 | public static void main(String[] args) { 23 | 24 | Message listener = new Message() { 25 | @Override 26 | public void message(boolean needTag, String mesage) { 27 | System.out.println((needTag ? CommonUtil.LOG_PREFIX : "") + mesage); 28 | } 29 | }; 30 | 31 | CommonUtil.printHeaderInfo(listener); 32 | ParamsBeanV2 paramsBeanV2 = parseArgs(args, listener); 33 | if (paramsBeanV2 == null) { 34 | return; 35 | } 36 | upload2Pgyer(null, false, paramsBeanV2, listener); 37 | } 38 | 39 | /** 40 | * parse args 41 | * 42 | * @param args 43 | * @param listener 44 | * @return 45 | */ 46 | private static ParamsBeanV2 parseArgs(String[] args, Message listener) { 47 | // check args length 48 | int length = args.length; 49 | 50 | if (length == 0 || length % 2 != 0) { 51 | CommonUtil.printMessage(listener, true, "args length is error!\n"); 52 | return null; 53 | } 54 | 55 | // args to map 56 | Map maps = new HashMap<>(); 57 | for (int i = 0; i < args.length; i += 2) { 58 | maps.put(args[i], args[i + 1]); 59 | } 60 | 61 | // check apiKey 62 | if (!maps.containsKey("-apiKey")) { 63 | CommonUtil.printMessage(listener, true, "apiKey not found!\n"); 64 | return null; 65 | } 66 | // check scanDir 67 | if (!maps.containsKey("-scanDir")) { 68 | CommonUtil.printMessage(listener, true, "scanDir not found!\n"); 69 | return null; 70 | } 71 | // check wildcard 72 | if (!maps.containsKey("-wildcard")) { 73 | CommonUtil.printMessage(listener, true, "wildcard not found!\n"); 74 | return null; 75 | } 76 | if (!maps.containsKey("-buildType")) { 77 | CommonUtil.printMessage(listener, true, "buildType not found!\n"); 78 | return null; 79 | } 80 | 81 | // params to uploadBean 82 | ParamsBeanV2 paramsBeanV2 = new ParamsBeanV2(); 83 | paramsBeanV2.setApiKey(maps.get("-apiKey")); 84 | paramsBeanV2.setScandir(maps.get("-scanDir")); 85 | paramsBeanV2.setWildcard(maps.get("-wildcard")); 86 | paramsBeanV2.setBuildType(maps.containsKey("-buildType") ? maps.get("-buildType") : ""); 87 | paramsBeanV2.setBuildPassword(maps.containsKey("-buildPassword") ? maps.get("-buildPassword") : ""); 88 | paramsBeanV2.setBuildInstallType(maps.containsKey("-buildInstallType") ? maps.get("-buildInstallType") : "1"); 89 | paramsBeanV2.setBuildUpdateDescription(maps.containsKey("-buildUpdateDescription") ? maps.get("-buildUpdateDescription") : ""); 90 | paramsBeanV2.setBuildChannelShortcut(maps.containsKey("-buildChannelShortcut") ? maps.get("-buildChannelShortcut") : ""); 91 | return paramsBeanV2; 92 | } 93 | 94 | /** 95 | * upload 2 pgyer 96 | * 97 | * @param envVars envVars 98 | * @param printHeader printHeader 99 | * @param paramsBeanV2 uploadBean 100 | * @param listener listener 101 | * @return pgyer bean 102 | */ 103 | public static PgyerBeanV2 upload2Pgyer(EnvVars envVars, boolean printHeader, ParamsBeanV2 paramsBeanV2, Message listener) { 104 | // print header info 105 | if (printHeader) { 106 | CommonUtil.printHeaderInfo(listener); 107 | } 108 | 109 | // find upload file 110 | paramsBeanV2.setUploadFile(CommonUtil.findFile(paramsBeanV2.getScandir(), paramsBeanV2.getWildcard(), listener)); 111 | 112 | // check upload file 113 | if (paramsBeanV2.getUploadFile() == null) { 114 | CommonUtil.printMessage(listener, true, "The uploaded file was not found,plase check scandir or wildcard!\n"); 115 | return null; 116 | } 117 | 118 | File uploadFile = new File(paramsBeanV2.getUploadFile()); 119 | if (!uploadFile.exists() || !uploadFile.isFile()) { 120 | CommonUtil.printMessage(listener, true, "The uploaded file was not found,plase check scandir or wildcard!\n"); 121 | return null; 122 | } 123 | 124 | String result = ""; 125 | try { 126 | CommonUtil.printMessage(listener, true, "upload:getToken to " + UPLOAD_URL); 127 | // CommonUtil.printMessage(listener, true, "upload file size: " + CommonUtil.convertFileSize(uploadFile.length())); 128 | 129 | // optimization upload description 130 | if (CommonUtil.isBlank(paramsBeanV2.getBuildUpdateDescription()) 131 | || "${SCM_CHANGELOG}".equals(paramsBeanV2.getBuildUpdateDescription())) { 132 | paramsBeanV2.setBuildUpdateDescription(""); 133 | } 134 | 135 | // MediaType type = MediaType.parse("application/octet-stream"); 136 | // RequestBody fileBody = RequestBody.create(type, uploadFile); 137 | RequestBody requestBody = new MultipartBody.Builder() 138 | .setType(MultipartBody.FORM) 139 | .addFormDataPart("_api_key", paramsBeanV2.getApiKey()) 140 | .addFormDataPart("buildInstallType", paramsBeanV2.getBuildInstallType()) 141 | .addFormDataPart("buildPassword", paramsBeanV2.getBuildPassword()) 142 | .addFormDataPart("buildUpdateDescription", paramsBeanV2.getBuildUpdateDescription()) 143 | .addFormDataPart("buildChannelShortcut", paramsBeanV2.getBuildChannelShortcut()) 144 | .addFormDataPart("buildType", paramsBeanV2.getBuildType()) 145 | .build(); 146 | Request request = new Request.Builder() 147 | .url(UPLOAD_URL) 148 | .post(new ProgressRequestBody(requestBody, null)) 149 | .build(); 150 | int timeout = CommonUtil.getUploadTimeout(envVars); 151 | Response execute = new OkHttpClient().newBuilder() 152 | .retryOnConnectionFailure(true) 153 | .readTimeout(timeout, TimeUnit.SECONDS) 154 | .writeTimeout(timeout, TimeUnit.SECONDS) 155 | .connectTimeout(timeout, TimeUnit.SECONDS) 156 | .build() 157 | .newCall(request).execute(); 158 | 159 | if (execute.body() == null) { 160 | CommonUtil.printMessage(listener, true, "Upload failed with pgyer api v2!"); 161 | CommonUtil.printMessage(listener, true, "upload token result is null."); 162 | return null; 163 | } 164 | ResponseBody responseBody = execute.body(); 165 | if(responseBody == null){ 166 | CommonUtil.printMessage(listener, true, "Upload file result failed with uploadResult"); 167 | CommonUtil.printMessage(listener, true, "upload file result is null."); 168 | return null; 169 | } 170 | result = responseBody.string(); 171 | if (result.contains("\"data\":[]")) { 172 | result = result.replace("\"data\":[]", "\"data\":{}"); 173 | } 174 | 175 | PgyerTokenBeanV2 tokenBean = null; 176 | try { 177 | tokenBean = new Gson().fromJson(result, new TypeToken() { 178 | }.getType()); 179 | 180 | } catch (Exception e) { 181 | e.printStackTrace(); 182 | CommonUtil.printMessage(listener, true, e.getMessage()); 183 | return null; 184 | } 185 | if (tokenBean.getCode() != 0) { 186 | CommonUtil.printMessage(listener, true, "Upload failed with pgyer api v2!"); 187 | CommonUtil.printMessage(listener, true, "error code:" + tokenBean.getCode()); 188 | CommonUtil.printMessage(listener, true, "error message:" + tokenBean.getMessage() + "\n"); 189 | return null; 190 | } 191 | return upload2PgyerFile(envVars,paramsBeanV2,tokenBean,listener); 192 | } catch (IOException e) { 193 | listener.message(true, "pgyer result: " + result); 194 | listener.message(true, "ERROR: " + e.getMessage() + "\n"); 195 | return null; 196 | } 197 | } 198 | 199 | /** 200 | * upload 2 pgyer 201 | * @param envVars envVars 202 | * @param paramsBeanV2 uploadBean 203 | * @param listener listener 204 | * @return pgyer bean 205 | */ 206 | public static PgyerBeanV2 upload2PgyerFile(EnvVars envVars, ParamsBeanV2 paramsBeanV2, PgyerTokenBeanV2 tokenBean, Message listener) { 207 | 208 | // find upload file 209 | paramsBeanV2.setUploadFile(CommonUtil.findFile(paramsBeanV2.getScandir(), paramsBeanV2.getWildcard(), listener)); 210 | 211 | // check upload file 212 | if (paramsBeanV2.getUploadFile() == null) { 213 | CommonUtil.printMessage(listener, true, "The uploaded file was not found,plase check scandir or wildcard!\n"); 214 | return null; 215 | } 216 | 217 | File uploadFile = new File(paramsBeanV2.getUploadFile()); 218 | if (!uploadFile.exists() || !uploadFile.isFile()) { 219 | CommonUtil.printMessage(listener, true, "The uploaded file was not found,plase check scandir or wildcard!\n"); 220 | return null; 221 | } 222 | 223 | String result = ""; 224 | try { 225 | CommonUtil.printMessage(listener, true, "upload:" + uploadFile.getName() + " to Pgyer"); 226 | CommonUtil.printMessage(listener, true, "upload file size: " + CommonUtil.convertFileSize(uploadFile.length())); 227 | 228 | MediaType type = MediaType.parse("application/octet-stream"); 229 | RequestBody fileBody = RequestBody.create(type, uploadFile); 230 | RequestBody requestBody = new MultipartBody.Builder() 231 | .setType(MultipartBody.FORM) 232 | .addFormDataPart("key", tokenBean.getData().getKey()) 233 | .addFormDataPart("signature", tokenBean.getData().getParams().getSignature()) 234 | .addFormDataPart("x-cos-security-token", tokenBean.getData().getParams().getX_cos_security_token()) 235 | .addFormDataPart("file", uploadFile.getName(), fileBody) 236 | .build(); 237 | Request request = new Request.Builder() 238 | .url(tokenBean.getData().getEndpoint()) 239 | .post(new ProgressRequestBody(requestBody, new CommonUtil.FileUploadProgressListener(listener))) 240 | .build(); 241 | int timeout = CommonUtil.getUploadTimeout(envVars); 242 | Response execute = new OkHttpClient().newBuilder() 243 | .retryOnConnectionFailure(true) 244 | .readTimeout(timeout, TimeUnit.SECONDS) 245 | .writeTimeout(timeout, TimeUnit.SECONDS) 246 | .connectTimeout(timeout, TimeUnit.SECONDS) 247 | .build() 248 | .newCall(request).execute(); 249 | 250 | if (execute.body() == null) { 251 | CommonUtil.printMessage(listener, true, "Upload file failed with oss"); 252 | CommonUtil.printMessage(listener, true, "upload file result is null."); 253 | return null; 254 | } 255 | if(execute.code() == 204){ 256 | String url = "https://www.pgyer.com/apiv2/app/buildInfo?_api_key="+paramsBeanV2.getApiKey()+"&buildKey="+tokenBean.getData().getKey(); 257 | times = 0; 258 | return uploadResult(url,paramsBeanV2,listener); 259 | } else { 260 | CommonUtil.printMessage(listener, true, "Upload failed with pgyer api v2!"); 261 | return null; 262 | } 263 | } catch (IOException e) { 264 | listener.message(true, "pgyer result: " + result); 265 | listener.message(true, "ERROR: " + e.getMessage() + "\n"); 266 | return null; 267 | } 268 | } 269 | 270 | static boolean bGo = true; 271 | static Timer timers = null; 272 | static int delay = 5000; 273 | static int times = 0; 274 | /** 275 | * Obtain the result of PGYER synchronizing data upload(获取pgyer 同步上传数据结果) 276 | * @param url 277 | * @param paramsBeanV2 278 | * @param listener 279 | * @return 280 | */ 281 | public static PgyerBeanV2 uploadResult(String url, ParamsBeanV2 paramsBeanV2, Message listener){ 282 | String result = ""; 283 | CommonUtil.printMessage(listener, true, "upload:Wait for the PGYER synchronization result"); 284 | try { 285 | //同步数据需要3~5秒延迟4秒获取最终同步数据 286 | timers = null; 287 | bGo = true; 288 | timers = new Timer(delay, new ActionListener() { 289 | @Override 290 | public void actionPerformed(ActionEvent e) { 291 | if(timers != null){ 292 | bGo = false; 293 | timers.stop(); 294 | timers = null; 295 | 296 | } 297 | } 298 | }); 299 | timers.start(); 300 | int i=0; 301 | while (bGo){ 302 | i++; 303 | if(i % 2000000000 == 0){ 304 | CommonUtil.printMessage(listener, true, "upload:Pgyer is synchronizing data……"); 305 | } 306 | } 307 | Request request = new Request.Builder().url(url).get().build(); 308 | Response execute = new OkHttpClient().newBuilder() 309 | .retryOnConnectionFailure(true) 310 | .readTimeout(300, TimeUnit.SECONDS) 311 | .writeTimeout(300, TimeUnit.SECONDS) 312 | .connectTimeout(300, TimeUnit.SECONDS) 313 | .build() 314 | .newCall(request).execute(); 315 | 316 | if (execute.body() == null) { 317 | CommonUtil.printMessage(listener, true, "Upload file result failed with uploadResult"); 318 | CommonUtil.printMessage(listener, true, "upload file result is null."); 319 | return null; 320 | } 321 | ResponseBody responseBody = execute.body(); 322 | if(responseBody == null){ 323 | CommonUtil.printMessage(listener, true, "Upload file result failed with uploadResult"); 324 | CommonUtil.printMessage(listener, true, "upload file result is null."); 325 | return null; 326 | } 327 | result = responseBody.string(); 328 | if (result.contains("\"data\":[]")) { 329 | result = result.replace("\"data\":[]", "\"data\":{}"); 330 | } 331 | 332 | PgyerBeanV2 pgyerBeanV2 = null; 333 | try { 334 | pgyerBeanV2 = new Gson().fromJson(result, new TypeToken() { 335 | }.getType()); 336 | } catch (Exception e) { 337 | e.printStackTrace(); 338 | CommonUtil.printMessage(listener, true, e.getMessage()); 339 | return null; 340 | } 341 | 342 | if (pgyerBeanV2.getCode() != 0) { 343 | if(pgyerBeanV2.getCode() == 1246 || pgyerBeanV2.getCode() == 1247){ 344 | if(times < 5) { 345 | times++; 346 | CommonUtil.printMessage(listener, true, "upload:Pgyer has not synchronized the results"); 347 | bGo = true; 348 | delay = 2000; 349 | return uploadResult(url, paramsBeanV2, listener); 350 | } 351 | } else { 352 | CommonUtil.printMessage(listener, true, "Upload failed with pgyer api v2!"); 353 | CommonUtil.printMessage(listener, true, "error code:" + pgyerBeanV2.getCode()); 354 | CommonUtil.printMessage(listener, true, "error message:" + pgyerBeanV2.getMessage() + "\n"); 355 | return null; 356 | } 357 | } 358 | 359 | pgyerBeanV2.getData().setAppPgyerURL(CommonUtil.PGYER_HOST + "/" + pgyerBeanV2.getData().getBuildShortcutUrl()); 360 | pgyerBeanV2.getData().setAppBuildURL(CommonUtil.PGYER_HOST + "/" + pgyerBeanV2.getData().getBuildKey()); 361 | pgyerBeanV2.getData().setBuildIcon(CommonUtil.PGYER_HOST + "/image/view/app_icons/" + pgyerBeanV2.getData().getBuildIcon()); 362 | 363 | CommonUtil.printMessage(listener, true, "Uploaded successfully!\n"); 364 | printResultInfo(pgyerBeanV2, listener); 365 | return pgyerBeanV2; 366 | } catch (IOException e) { 367 | e.printStackTrace(); 368 | listener.message(true, "pgyer result: " + result); 369 | listener.message(true, "ERROR: " + e.getMessage() + "\n"); 370 | return null; 371 | } 372 | } 373 | 374 | /** 375 | * Print return log 376 | * 377 | * @param pgyerBeanV2 pgyerBeanV2 378 | * @param listener listener 379 | */ 380 | private static void printResultInfo(PgyerBeanV2 pgyerBeanV2, Message listener) { 381 | PgyerBeanV2.DataBean data = pgyerBeanV2.getData(); 382 | CommonUtil.printMessage(listener, true, "应用名称:" + data.getBuildName()); 383 | CommonUtil.printMessage(listener, true, "应用类型:" + data.getBuildType()); 384 | CommonUtil.printMessage(listener, true, "版本号:" + data.getBuildVersion()); 385 | CommonUtil.printMessage(listener, true, "build号:" + data.getBuildBuildVersion()); 386 | CommonUtil.printMessage(listener, true, "Build Key:" + data.getBuildKey()); 387 | CommonUtil.printMessage(listener, true, "版本编号:" + data.getBuildVersionNo()); 388 | CommonUtil.printMessage(listener, true, "文件大小:" + data.getBuildFileSize()); 389 | CommonUtil.printMessage(listener, true, "应用介绍:" + data.getBuildDescription()); 390 | CommonUtil.printMessage(listener, true, "应用主页:" + data.getAppPgyerURL()); 391 | CommonUtil.printMessage(listener, true, "应用短链接:" + data.getBuildShortcutUrl()); 392 | CommonUtil.printMessage(listener, true, "应用上传时间:" + data.getBuildCreated()); 393 | CommonUtil.printMessage(listener, true, "应用更新时间:" + data.getBuildUpdated()); 394 | CommonUtil.printMessage(listener, true, "应用构建主页:" + data.getAppBuildURL()); 395 | CommonUtil.printMessage(listener, true, "应用更新说明:" + data.getBuildUpdateDescription()); 396 | CommonUtil.printMessage(listener, true, "是否是最新版:" + data.getBuildIsLastest()); 397 | CommonUtil.printMessage(listener, true, "应用程序包名:" + data.getBuildIdentifier()); 398 | CommonUtil.printMessage(listener, true, "应用截图的key:" + data.getBuildScreenshots()); 399 | CommonUtil.printMessage(listener, true, "应用二维码地址:" + data.getBuildQRCodeURL()); 400 | CommonUtil.printMessage(listener, true, "是否是第一个App:" + data.getBuildType()); 401 | CommonUtil.printMessage(listener, true, "应用的Icon图标key:" + data.getBuildIcon()); 402 | CommonUtil.printMessage(listener, false, ""); 403 | } 404 | } 405 | --------------------------------------------------------------------------------