├── .gitignore ├── Jenkinsfile ├── LICENSE ├── README.md ├── doc └── images │ ├── amazon-create-topic-for-queue.png │ ├── jenkins-build-triggers.png │ ├── plugin-queue-configuration-empty.png │ └── plugin-queue-configuration-success.png ├── pom.xml └── src ├── main ├── java │ └── io │ │ └── relution │ │ └── jenkins │ │ └── awssqs │ │ ├── Context.java │ │ ├── SQSTrigger.java │ │ ├── SQSTriggerBuilder.java │ │ ├── SQSTriggerQueue.java │ │ ├── factories │ │ ├── ExecutorFactoryImpl.java │ │ ├── MessageParserFactoryImpl.java │ │ ├── SQSFactoryImpl.java │ │ └── ThreadFactoryImpl.java │ │ ├── interfaces │ │ ├── Event.java │ │ ├── EventTriggerMatcher.java │ │ ├── ExecutorFactory.java │ │ ├── ExecutorProvider.java │ │ ├── MessageParser.java │ │ ├── MessageParserFactory.java │ │ ├── SQSFactory.java │ │ ├── SQSQueue.java │ │ ├── SQSQueueListener.java │ │ ├── SQSQueueMonitor.java │ │ ├── SQSQueueMonitorScheduler.java │ │ └── SQSQueueProvider.java │ │ ├── logging │ │ └── Log.java │ │ ├── model │ │ ├── CodeCommitMessageParser.java │ │ ├── EventTriggerMatcherImpl.java │ │ ├── SQSQueueProviderImpl.java │ │ ├── constants │ │ │ └── ErrorCode.java │ │ ├── entities │ │ │ └── codecommit │ │ │ │ ├── CodeCommit.java │ │ │ │ ├── CodeCommitEvent.java │ │ │ │ ├── ExecuteJenkinsJobEvent.java │ │ │ │ ├── MessageBody.java │ │ │ │ ├── Record.java │ │ │ │ ├── Records.java │ │ │ │ └── Reference.java │ │ └── events │ │ │ ├── ConfigurationChangedEvent.java │ │ │ └── EventBroker.java │ │ ├── net │ │ ├── RequestFactory.java │ │ ├── RequestFactoryImpl.java │ │ ├── SQSChannel.java │ │ └── SQSChannelImpl.java │ │ ├── threading │ │ ├── ExecutorProviderImpl.java │ │ ├── SQSQueueMonitorImpl.java │ │ └── SQSQueueMonitorSchedulerImpl.java │ │ └── util │ │ ├── ErrorType.java │ │ ├── JobInfoHelpers.java │ │ └── ThrowIf.java └── resources │ ├── index.jelly │ └── io │ └── relution │ └── jenkins │ └── awssqs │ ├── SQSTrigger │ ├── config.jelly │ ├── config_de.properties │ ├── config_ru.properties │ ├── global.jelly │ ├── global_de.properties │ ├── global_ru.properties │ ├── help-disableCodeCommit.html │ ├── help-disableCodeCommit_du.html │ ├── help-disableCodeCommit_ru.html │ ├── help-queueUuid.html │ ├── help-queueUuid_de.html │ ├── help-queueUuid_ru.html │ ├── help.html │ ├── help_de.html │ └── help_ru.html │ ├── SQSTriggerQueue │ ├── config.jelly │ ├── config_de.properties │ ├── config_ru.properties │ ├── help-credentialsId.html │ ├── help-credentialsId_de.html │ ├── help-credentialsId_ru.html │ ├── help-keepQueueMessages.html │ ├── help-maxNumberOfJobQueue.html │ ├── help-maxNumberOfMessages.html │ ├── help-maxNumberOfMessages_de.html │ ├── help-maxNumberOfMessages_ru.html │ ├── help-nameOrUrl.html │ ├── help-nameOrUrl_de.html │ ├── help-nameOrUrl_ru.html │ ├── help-uuid.html │ ├── help-uuid_de.html │ ├── help-uuid_ru.html │ ├── help-waitTimeSeconds.html │ ├── help-waitTimeSeconds_de.html │ └── help-waitTimeSeconds_ru.html │ └── i18n │ ├── sqstrigger │ ├── Messages.properties │ ├── Messages_de.properties │ └── Messages_ru.properties │ └── sqstriggerqueue │ ├── Messages.properties │ ├── Messages_de.properties │ └── Messages_ru.properties └── test └── java └── io └── relution └── jenkins └── awssqs ├── SQSTriggerQueueDescriptorImplTest.java ├── SQSTriggerQueueTest.java ├── net └── SQSQueueImplTest.java └── threading ├── SQSQueueMonitorImplTest.java └── SQSQueueMonitorSchedulerImplTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | build/ 3 | gen/ 4 | target/ 5 | work/ 6 | pom.xml.tag 7 | pom.xml.releaseBackup 8 | pom.xml.versionsBackup 9 | pom.xml.next 10 | release.properties 11 | local.properties 12 | dependency-reduced-pom.xml 13 | buildNumber.properties 14 | settings-release.xml 15 | .DS_Store 16 | .mvn/timing.properties 17 | .settings/ 18 | .idea/ 19 | *.iml 20 | *.ipr 21 | *.iws 22 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!groovy 2 | 3 | // https://github.com/jenkins-infra/pipeline-library 4 | buildPlugin( 5 | jdkVersions: [8], 6 | platforms: [ 7 | 'linux', 8 | 'windows', 9 | ], 10 | jenkinsVersions: [ 11 | '2.63' 12 | ], 13 | findbugs: [ 14 | run: false 15 | ], 16 | failFast: true 17 | ) 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2016 M-Way Solutions GmbH 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS SQS Plugin for Jenkins 2 | 3 | A Jenkins plugin that allows using Events sent to Amazon Simple Queue Service (SQS) as a build trigger. 4 | 5 | Allows default IAM access (no access/security keys required). 6 | 7 | To use this plugin you will need to have the following: 8 | 9 | ## N.B. This readme is currently out of date 10 | 11 | 1. An Amazon Web Services (AWS) account 12 | 2. A Git repository that is hosted on CodeCommit 13 | 3. A Simple Notification Service (SNS) topic 14 | 4. A Simple Queue Service (SQS) queue 15 | 5. A user that is allowed to access the queue 16 | 17 | # Table of contents 18 | 1. [Using the plugin](#using-the-plugin) 19 | 1. [Install the plugin](#install-the-plugin-on-jenkins) 20 | 2. [Set up AWS users](#create-a-jenkins-user-on-aws) 21 | 3. [Create a repository](#create-a-codecommit-repository) 22 | 4. [Create an SQS queue](#create-an-sqs-queue-on-aws) 23 | 5. [Test access to the queue](#test-whether-jenkins-can-access-the-queue) 24 | 6. [Create an SNS topic](#create-an-sns-topic-on-aws) 25 | 7. [Link SNS topic and SQS queue](#link-sns-topic-and-sqs-queue) 26 | 8. [Link AWS CodeCommit and SNS topic](#link-aws-codecommit-and-sns-topic) 27 | 9. [Configure Jenkins jobs](#configure-jobs-to-use-the-queue-on-jenkins) 28 | 10. [Test your setup](#test-your-setup) 29 | 2. [Development](#development) 30 | 2. [Release](#release) 31 | 3. [License](#license) 32 | 4. [Maintainers](#maintainers) 33 | 34 | ## Using the plugin 35 | 36 | This setup assumes that you already have an AWS account and that you're able to log in to your AWS account. You must also be able to manage users and groups and you must be able to create a CodeCommit repository, an SNS topic and an SQS queue. If you don't have the necessary permissions find someone who does. 37 | 38 | ### Install the plugin on Jenkins 39 | 40 | 1. Go to `Jenkins > Manage Jenkins > Manage Plugins`. 41 | 2. Go to `Available` and search for `aws-sqs` or `aws sqs`. 42 | 3. Install the plugin and restart your Jenkins. 43 | 44 | If you've built the plugin from source go to `Advanced` and upload the plugin manually. Don't forget to check the plugin's Wiki page on Jenkins-CI.org: https://wiki.jenkins-ci.org/display/JENKINS/AWS+SQS+Plugin. 45 | 46 | After you've successfully installed the plugin you should see a new entry in your global Jenkins configuration. Go to `Jenkins > Manage Jenkins > Configure System` to verify. You should be able to find an entry similar to the one below. 47 | 48 | ![Empty Jenkins configuration](doc/images/plugin-queue-configuration-empty.png) 49 | 50 | ### Create a Jenkins user on AWS 51 | 52 | 1. Log in to your [Amazon Web Services](https://aws.amazon.com/) account. 53 | 2. Go to `Services > Security & Identity > IAM` 54 | 3. **Create** a **new group** called *Jenkins* 55 | 4. Assign the following managed policies to the user: 56 | 57 | * AmazonSQSFullAccess 58 | * AWSCodeCommitReadOnly 59 | 60 | The `AmazonSQSFullAccess` policy is required for Jenkins to be able to read messages from queues and to delete messages from queues once they've been processed. 61 | 62 | The `AWSCodeCommitReadOnly` permission is required for Jenkins to be able to check out code to build. 63 | 64 | 5. **Create** a **new user** called *Jenkins* 65 | 6. Assign the *Jenkins* user to the *Jenkins* group 66 | 7. Go to `IAM > Users > Jenkins > Security Credentials` 67 | 8. **Create** a new **Access Key** for the Jenkins user 68 | 69 | **Important:** You will need the `Access Key ID` and `Secret Key` for Jenkins to be able to access the SQS queue. Make sure to save both values in a secure place. 70 | 71 | ### Create a CodeCommit repository 72 | 73 | Before you start to configure the plugin you should have at least one Git repository on CodeCommit. If you do not already have a repository follow the steps below to create one. 74 | 75 | **Note:** At the time of writing CodeCommit is only available in the [**US East (N. Virginia)** region](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/). AWS will automatically switch to that region when you access CodeCommit. All services (CodeCommit, SNS, SQS) must be created in the same region, so do not switch regions after you've created the repository. 76 | 77 | 1. Go to `Services > Developer Tools > CodeCommit` 78 | 79 | 2. **Create** a **new repository** 80 | 81 | 3. Enter a name and description for the repository 82 | 83 | At the very least you'll need to enter a new name for the repository. For this plugin we would use something like *aws-sqs-plugin*. To be able to work with repositories your user account also needs permission to access CodeCommit: 84 | 85 | 1. Go to `Services > Security & Identity > IAM` 86 | 87 | 2. Find and open your user account 88 | 89 | 3. Go to `Permissions` 90 | 91 | 4. Click on `Attach Policy` 92 | 93 | 5. Find the developer policy for your Git repository 94 | 95 | When you create a repository AWS will automatically create a policy for it. In the example above the policy would be named *aws-sqs-plugin-developer*. Alternatively you could assign the policy *AmazonSQSFullAccess* which will automatically give your user access to all repositories on CodeCommit. 96 | 97 | In addition to the policy your account also needs a public SSH key assigned. Access to repositories on CodeCommit is only possible via SSH. 98 | 99 | 1. Switch to the tab `Security Credentials` 100 | 101 | 2. `Upload` an `SSH public key` 102 | 103 | 3. You will need the `SSH Key ID` to access the repository 104 | 105 | You should now be able to clone the repository and start working with it. The repository URL for our example would be *ssh://`ssh-key-id`@git-codecommit.us-east-1.amazonaws.com/v1/repos/aws_sqs_plugin* 106 | 107 | ### Create an SQS queue on AWS 108 | 109 | **Note:** The SQS queue must be created in the same region as your CodeCommit repository. At the time of writing CodeCommit is only available in the **US East (N. Virginia)** region. This means the SQS queue must also be created in the US East region. 110 | 111 | 1. Go to `Services > Application Services > SQS` 112 | 113 | 2. **Create** a **new queue** 114 | 115 | At the very least you'll need to enter a new name for the queue. If you already have a repository something like **_repository-name_-queue** is a good idea. So for the *aws-sqs-plugin* repository we would use *aws-sqs-plugin-queue*. 116 | 117 | Review the remaining options and adjust them to your needs. If you do not know what these options do just leave them at their defaults. 118 | 119 | 3. Copy the *ARN* of the queue for later 120 | 121 | ### Create a Jenkins credentials object 122 | 123 | Amazon SQS queue use text security credentials pair Access key ID and Access key secret. You can use the pair previously created as described in section **Create a Jenkins user on AWS**. You have to put AWS SQS credentials pair into **Secret text** kind of Jenkins credentials store object, Access key ID as ID and Access key secret as Secret. AWS-SQS-plugin use plain text credentials and only this kind of credentials objects are visible for the plugin. 124 | 125 | **Note:** The Credentials drop down list will show You the Description You wrote to Jenkins credentials store object. 126 | 127 | ### Test whether Jenkins can access the queue 128 | 129 | 1. Go to `Jenkins > Manage Jenkins > Configure System` on your Jenkins 130 | 131 | 2. Go to `Configuration of Amazon SQS queues` 132 | 133 | 3. Configure a queue 134 | 135 | * Enter the name of the queue you just created 136 | * Select the appropriate *Credentials* of the Jenkins user on AWS from drop-down list 137 | 138 | 4. Click on **Test access** 139 | 140 | You should see a success message as in the screenshot below. If you get an error message make sure you entered the credentials correctly. If you still see errors double check the user, group and permissions you set up on Amazon Web Services. 141 | 142 | ![Jenkins configuration test](doc/images/plugin-queue-configuration-success.png) 143 | 144 | ### Create an SNS topic on AWS 145 | 146 | **Note:** The SNS topic must be created in the same region as your CodeCommit repository. At the time of writing CodeCommit is only available in the **US East (N. Virginia)** region. This means the SNS topic must also be created in the US East region. 147 | 148 | 1. Go to `Services > Mobile Services > SNS` 149 | 2. Go to `Topics` 150 | 3. **Create** a **new topic** 151 | 152 | Enter a new *topic name* (the display name is optional in our case). If you already have a repository something like **_repository-name_-topic** is a good idea. So for the *aws-sqs-plugin* repository we would use the *aws-sqs-plugin-topic*. 153 | 154 | The new topic should have an *ARN* similar to `arn:aws:sns:us-east-1:{id}:{topic-name}`. 155 | 156 | ### Link SNS topic and SQS queue 157 | 158 | 1. Click on the new topic you just created 159 | 2. **Create** a new **subcription** 160 | * The *Topic ARN* should be the ARN of the topic you just created. 161 | * Select **Amazon SQS** as the *protocol* 162 | * Use the *ARN* of the queue you created above as the endpoint 163 | 164 | These steps make sure that all notifications that are posted to this topic are placed in our SQS queue we created above. For testing purposes you could create an additional subscription that delivers all messages also to your inbox. 165 | 166 | ![Topic configuration](doc/images/amazon-create-topic-for-queue.png) 167 | 168 | ### Link AWS CodeCommit and SNS topic 169 | 170 | 1. Go to `Services > Developer Tools > CodeCommit` 171 | 2. Select a repository (or create a new one) 172 | 3. Click on the repositry 173 | 4. Go to `Triggers` 174 | 5. **Create** a new **trigger** 175 | * Enter a new for your trigger (e.g. "send-to-sns-on-push") 176 | * Select **Push to existing branch** as *Events* 177 | * Select the branch(es) you want to monitor 178 | * Select *Send to Amazon SNS* 179 | * Select your SNS topic you created above 180 | 6. Click on **Create** 181 | 182 | These steps make sure that whenever someone pushes changes to this repository a message is sent to SNS. The subscription we created on the notification service makes sure the message is fordwared to the SQS queue. The Jenkins plugin uses the Amazon API to monitor this queue for new messages. 183 | 184 | ### Configure jobs to use the queue on Jenkins 185 | 186 | 1. Go to `Jenkins > $job` 187 | 2. Click on `Configure` 188 | 3. Scroll down to `Build Triggers` 189 | 4. Check `Trigger build when a message is published to an Amazon SQS queue` 190 | 5. Select the queue you created previously 191 | 192 | To reduce cost the Jenkins plugin does not start monitoring a queue until at least one job has been configured to listen to messages from a queue. 193 | 194 | You can use the same queue for multiple jobs or you can create a new queue for each job. Keep in mind that monitoring multiple queues will increase the amount of requests your Jenkins will have to send to AWS. Unless you have specific needs reusing the same queue and topic for multiple jobs is completely acceptable. For billing purposes it may be easier to use multiple queues, especially if you're running builds on behalf of a customer. 195 | 196 | ### Test your setup 197 | 198 | If you've set up everything correctly pushing a change to the Git repository on CodeCommit should now trigger a build on Jenkins. If nothing happens, make sure the job has been set to use messages posted to SQS as a build trigger. 199 | 200 | ![Build trigger configuration](doc/images/jenkins-build-triggers.png) 201 | 202 | # Development 203 | 1. Start the local Jenkins instance: 204 | 205 | mvn clean compile hpi:run 206 | 207 | 2. Wait until "Jenkins is fully up and running" is shown in the terminal 208 | (there may be more messages after that) 209 | 210 | 3. Open http://localhost:8080/jenkins/ in the browser 211 | 212 | 213 | # Release 214 | 215 | ## One time settings setup: 216 | 217 | 1. login into artifactory at: https://repo.jenkins-ci.org 218 | 1. browse to repository "releases", and generate settings file using your own credentials 219 | 1. save the file under repo root folder as `settings-release.xml` 220 | 221 | ## Each release: 222 | 223 | ```Shell 224 | mvn \ 225 | -s settings-release.xml \ 226 | release:prepare \ 227 | release:perform 228 | ``` 229 | 230 | # License 231 | Apache License, Version 2.0 232 | ``` 233 | Copyright 2016 M-Way Solutions GmbH 234 | 235 | Licensed under the Apache License, Version 2.0 (the "License"); 236 | you may not use this file except in compliance with the License. 237 | You may obtain a copy of the License at 238 | 239 | http://www.apache.org/licenses/LICENSE-2.0 240 | 241 | Unless required by applicable law or agreed to in writing, software 242 | distributed under the License is distributed on an "AS IS" BASIS, 243 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 244 | See the License for the specific language governing permissions and 245 | limitations under the License. 246 | ``` 247 | 248 | # Maintainers 249 | - [Markus Pfeiffer](https://github.com/mpfeiffermway) (M-Way Solutions GmbH) – 2016 250 | - [Nick Grealy](nickgrealy@gmail.com) 251 | - [Victor Timohin](vvt@opsguru.io) 252 | - [Max Kovgan](max@opsguru.io) -------------------------------------------------------------------------------- /doc/images/amazon-create-topic-for-queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/aws-sqs-plugin/9bd8663a6b7298cad5335d2ed854e5919104a827/doc/images/amazon-create-topic-for-queue.png -------------------------------------------------------------------------------- /doc/images/jenkins-build-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/aws-sqs-plugin/9bd8663a6b7298cad5335d2ed854e5919104a827/doc/images/jenkins-build-triggers.png -------------------------------------------------------------------------------- /doc/images/plugin-queue-configuration-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/aws-sqs-plugin/9bd8663a6b7298cad5335d2ed854e5919104a827/doc/images/plugin-queue-configuration-empty.png -------------------------------------------------------------------------------- /doc/images/plugin-queue-configuration-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/aws-sqs-plugin/9bd8663a6b7298cad5335d2ed854e5919104a827/doc/images/plugin-queue-configuration-success.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | org.jenkins-ci.plugins 8 | plugin 9 | 2.5 10 | 11 | 12 | 13 | io.relution.jenkins 14 | https://wiki.jenkins-ci.org/display/JENKINS/AWS+SQS+Plugin 15 | aws-sqs 16 | 2.0.2-SNAPSHOT 17 | hpi 18 | 19 | AWS SQS Build Trigger Plugin 20 | 21 | This plugin triggers builds based on events received via Amazon Web 22 | Services Simple Queue Service (AWS SQS) on a specified Queue. 23 | 24 | 25 | 26 | scm:git:ssh://github.com/jenkinsci/${project.artifactId}-plugin.git 27 | scm:git:ssh://git@github.com/jenkinsci/${project.artifactId}-plugin.git 28 | 29 | https://github.com/jenkinsci/${project.artifactId}-plugin 30 | HEAD 31 | 32 | 33 | 34 | 2.63 35 | 8 36 | 2.2 37 | 38 | 1.11.233 39 | 4.0 40 | 2.8.2 41 | 3.6.4 42 | 0.6 43 | 3.7 44 | 1.4 45 | 2.20 46 | 2.12.0 47 | 3.8.0 48 | 1.6 49 | 50 | 2.19.1 51 | 1.16 52 | 1.0 53 | 54 | 55 | 56 | 57 | Apache License, Version 2.0 58 | http://www.apache.org/licenses/LICENSE-2.0 59 | 60 | 61 | 62 | 63 | 64 | mwaylabs 65 | M-Way Solutions GmbH 66 | jenkins.ios.bot@mwaysolutions.com 67 | 68 | 69 | nickg 70 | Nick Grealy 71 | nickgrealy@gmail.com 72 | 73 | 74 | j_vvt 75 | Victor Timohin 76 | vvt@opsguru.io 77 | 78 | 79 | mvk 80 | Max Kovgan 81 | max@opsguru.io 82 | 83 | 84 | 85 | 86 | 87 | repo.jenkins-ci.org 88 | https://repo.jenkins-ci.org/public/ 89 | 90 | 91 | 92 | 93 | 94 | repo.jenkins-ci.org 95 | https://repo.jenkins-ci.org/public/ 96 | 97 | 98 | 99 | 100 | 101 | 102 | com.amazonaws 103 | aws-java-sdk-sqs 104 | ${aws-java-sdk-sqs.version} 105 | 106 | 107 | 108 | com.google.inject 109 | guice 110 | ${guice.version} 111 | 112 | 113 | 114 | com.google.code.gson 115 | gson 116 | ${gson.version} 117 | 118 | 119 | 120 | org.jenkins-ci.plugins 121 | git 122 | true 123 | ${git.version} 124 | 125 | 126 | 127 | org.jenkins-ci.plugins 128 | multiple-scms 129 | true 130 | ${multiple-scms.version} 131 | 132 | 133 | 134 | org.apache.commons 135 | commons-lang3 136 | ${commons-lang3.version} 137 | 138 | 139 | 140 | org.jenkins-ci.plugins 141 | plain-credentials 142 | ${plain-credentials.version} 143 | 144 | 145 | 146 | net.sourceforge.htmlunit 147 | htmlunit 148 | ${htmlunit.version} 149 | test 150 | 151 | 152 | 153 | org.mockito 154 | mockito-core 155 | ${mockito-core.version} 156 | test 157 | 158 | 159 | 160 | org.assertj 161 | assertj-core 162 | ${assertj-core.version} 163 | test 164 | 165 | 166 | 167 | org.jenkins-ci.plugins 168 | junit 169 | ${junit.version} 170 | test 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | org.apache.maven.plugins 180 | maven-surefire-plugin 181 | ${maven-surefire-plugin.version} 182 | 183 | false 184 | 185 | 186 | 187 | 188 | org.codehaus.mojo 189 | animal-sniffer-maven-plugin 190 | ${animal-sniffer-maven-plugin.version} 191 | 192 | 193 | org.codehaus.mojo.signature 194 | java18 195 | ${java18.version} 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | only-eclipse 206 | 207 | 208 | m2e.version 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | org.eclipse.m2e 217 | lifecycle-mapping 218 | 1.0.0 219 | 220 | 221 | 222 | 223 | 224 | org.apache.maven.plugins 225 | maven-javadoc-plugin 226 | [2.10.1,) 227 | 228 | javadoc 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/Context.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs; 18 | 19 | import com.google.inject.Guice; 20 | import com.google.inject.Injector; 21 | 22 | import java.util.concurrent.ExecutorService; 23 | import java.util.concurrent.ThreadFactory; 24 | 25 | import io.relution.jenkins.awssqs.factories.MessageParserFactoryImpl; 26 | import io.relution.jenkins.awssqs.factories.SQSFactoryImpl; 27 | import io.relution.jenkins.awssqs.factories.ThreadFactoryImpl; 28 | import io.relution.jenkins.awssqs.interfaces.EventTriggerMatcher; 29 | import io.relution.jenkins.awssqs.interfaces.ExecutorProvider; 30 | import io.relution.jenkins.awssqs.interfaces.MessageParserFactory; 31 | import io.relution.jenkins.awssqs.interfaces.SQSQueueProvider; 32 | import io.relution.jenkins.awssqs.model.EventTriggerMatcherImpl; 33 | import io.relution.jenkins.awssqs.model.SQSQueueProviderImpl; 34 | import io.relution.jenkins.awssqs.net.RequestFactory; 35 | import io.relution.jenkins.awssqs.net.RequestFactoryImpl; 36 | 37 | 38 | public class Context extends com.google.inject.AbstractModule { 39 | 40 | private static Injector injector; 41 | 42 | public synchronized static Injector injector() { 43 | if (injector == null) { 44 | injector = Guice.createInjector(new Context()); 45 | } 46 | return injector; 47 | } 48 | 49 | @Override 50 | protected void configure() { 51 | this.bind(ThreadFactory.class) 52 | .to(ThreadFactoryImpl.class) 53 | .in(com.google.inject.Singleton.class); 54 | 55 | this.bind(io.relution.jenkins.awssqs.interfaces.ExecutorFactory.class) 56 | .to(io.relution.jenkins.awssqs.factories.ExecutorFactoryImpl.class) 57 | .in(com.google.inject.Singleton.class); 58 | 59 | this.bind(ExecutorProvider.class) 60 | .to(io.relution.jenkins.awssqs.threading.ExecutorProviderImpl.class) 61 | .in(com.google.inject.Singleton.class); 62 | 63 | this.bind(ExecutorService.class) 64 | .toProvider(ExecutorProvider.class) 65 | .in(com.google.inject.Singleton.class); 66 | 67 | this.bind(io.relution.jenkins.awssqs.interfaces.SQSFactory.class) 68 | .to(SQSFactoryImpl.class) 69 | .in(com.google.inject.Singleton.class); 70 | 71 | this.bind(RequestFactory.class) 72 | .to(RequestFactoryImpl.class) 73 | .in(com.google.inject.Singleton.class); 74 | 75 | this.bind(SQSQueueProvider.class) 76 | .to(SQSQueueProviderImpl.class) 77 | .in(com.google.inject.Singleton.class); 78 | 79 | this.bind(io.relution.jenkins.awssqs.interfaces.SQSQueueMonitorScheduler.class) 80 | .to(io.relution.jenkins.awssqs.threading.SQSQueueMonitorSchedulerImpl.class) 81 | .in(com.google.inject.Singleton.class); 82 | 83 | this.bind(MessageParserFactory.class) 84 | .to(MessageParserFactoryImpl.class) 85 | .in(com.google.inject.Singleton.class); 86 | 87 | this.bind(EventTriggerMatcher.class) 88 | .to(EventTriggerMatcherImpl.class) 89 | .in(com.google.inject.Singleton.class); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/SQSTriggerBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs; 18 | 19 | import java.io.File; 20 | import java.io.IOException; 21 | import java.io.PrintStream; 22 | import java.text.DateFormat; 23 | import java.util.Date; 24 | 25 | import hudson.Util; 26 | import hudson.model.Cause; 27 | import hudson.model.Job; 28 | import hudson.util.StreamTaskListener; 29 | import jenkins.triggers.SCMTriggerItem; 30 | 31 | import static io.relution.jenkins.awssqs.util.JobInfoHelpers.asParameterizedJobMixIn; 32 | 33 | public class SQSTriggerBuilder implements Runnable { 34 | 35 | private final SQSTrigger trigger; 36 | private final Job job; 37 | 38 | private final DateFormat formatter = DateFormat.getDateTimeInstance(); 39 | 40 | public SQSTriggerBuilder(final SQSTrigger trigger, final Job job) { 41 | this.trigger = trigger; 42 | this.job = job; 43 | } 44 | 45 | @Override 46 | public void run() { 47 | final File log = this.trigger.getLogFile(); 48 | 49 | try (final StreamTaskListener listener = new StreamTaskListener(log)) { 50 | this.buildIfChanged(listener); 51 | 52 | } catch (final IOException e) { 53 | io.relution.jenkins.awssqs.logging.Log.severe(e, "Failed to record SCM polling"); 54 | 55 | } 56 | } 57 | 58 | private void buildIfChanged(final StreamTaskListener listener) { 59 | final PrintStream logger = listener.getLogger(); 60 | final long now = System.currentTimeMillis(); 61 | 62 | logger.format("Started on %s", this.toDateTime(now)); 63 | if (this.trigger.isDisableCodeCommit()) { 64 | logger.println("Changes found without CodeCommit"); 65 | this.build(logger, now); 66 | } else { 67 | SCMTriggerItem scmTriggerItem = SCMTriggerItem.SCMTriggerItems.asSCMTriggerItem(job); 68 | boolean hasChanges = false; 69 | if (scmTriggerItem != null) { 70 | hasChanges = scmTriggerItem.poll(listener).hasChanges(); 71 | } 72 | logger.println("Done. Took " + this.toTimeSpan(now)); 73 | 74 | if (!hasChanges) { 75 | logger.println("No changes"); 76 | } else { 77 | logger.println("Changes found"); 78 | this.build(logger, now); 79 | } 80 | } 81 | } 82 | 83 | private void build(final PrintStream logger, final long now) { 84 | final String note = "SQS poll initiated on " + this.toDateTime(now); 85 | final Cause cause = new Cause.RemoteCause("SQS trigger", note); 86 | 87 | if (asParameterizedJobMixIn(job).scheduleBuild(cause)) { 88 | logger.println("Job queued"); 89 | } else { 90 | logger.println("Job NOT queued - it was determined that this job has been queued already."); 91 | } 92 | } 93 | 94 | private String toDateTime(final long timestamp) { 95 | final Date date = new Date(timestamp); 96 | return this.formatter.format(date); 97 | } 98 | 99 | private String toTimeSpan(final long timestamp) { 100 | final long now = System.currentTimeMillis(); 101 | return Util.getTimeSpanString(now - timestamp); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/factories/ExecutorFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.factories; 18 | 19 | import com.google.inject.Inject; 20 | 21 | import java.util.concurrent.LinkedBlockingQueue; 22 | import java.util.concurrent.ThreadFactory; 23 | import java.util.concurrent.ThreadPoolExecutor; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | 27 | public class ExecutorFactoryImpl implements io.relution.jenkins.awssqs.interfaces.ExecutorFactory { 28 | 29 | /** 30 | * The number of threads to start by default. Cannot exceed the maximum number of threads. 31 | * Beware: If you reduce this number and do not place a limit on the queue no additional 32 | * threads will ever be started. 33 | */ 34 | private final static int CORE_POOL_SIZE = 10; 35 | private final static int MAXIMUM_POOL_SIZE = 50; 36 | 37 | private final static int KEEP_ALIVE_TIME = 5; 38 | private final static TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.MINUTES; 39 | 40 | final ThreadFactory threadFactory; 41 | 42 | @Inject 43 | public ExecutorFactoryImpl(final ThreadFactory threadFactory) { 44 | this.threadFactory = threadFactory; 45 | } 46 | 47 | @Override 48 | public ThreadPoolExecutor createExecutor() { 49 | final ThreadPoolExecutor executor = new ThreadPoolExecutor( 50 | CORE_POOL_SIZE, 51 | MAXIMUM_POOL_SIZE, 52 | KEEP_ALIVE_TIME, 53 | KEEP_ALIVE_TIME_UNIT, 54 | new LinkedBlockingQueue(), 55 | this.threadFactory); 56 | 57 | executor.allowCoreThreadTimeOut(false); 58 | return executor; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/factories/MessageParserFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.factories; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | 21 | import io.relution.jenkins.awssqs.interfaces.MessageParser; 22 | import io.relution.jenkins.awssqs.model.CodeCommitMessageParser; 23 | 24 | 25 | public class MessageParserFactoryImpl implements io.relution.jenkins.awssqs.interfaces.MessageParserFactory { 26 | 27 | @Override 28 | public MessageParser createParser(final Message message) { 29 | return this.createCodeCommitParser(); 30 | } 31 | 32 | @Override 33 | public MessageParser createCodeCommitParser() { 34 | return new CodeCommitMessageParser(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/factories/SQSFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.factories; 18 | 19 | import com.amazonaws.ClientConfiguration; 20 | import com.amazonaws.services.sqs.AmazonSQS; 21 | import com.amazonaws.services.sqs.AmazonSQSAsync; 22 | import com.amazonaws.services.sqs.AmazonSQSAsyncClient; 23 | import com.amazonaws.services.sqs.AmazonSQSClient; 24 | import com.amazonaws.services.sqs.buffered.AmazonSQSBufferedAsyncClient; 25 | import com.amazonaws.services.sqs.buffered.QueueBufferConfig; 26 | import com.google.inject.Inject; 27 | 28 | import hudson.ProxyConfiguration; 29 | import io.relution.jenkins.awssqs.net.SQSChannel; 30 | import jenkins.model.Jenkins; 31 | 32 | import java.net.InetSocketAddress; 33 | import java.net.Proxy; 34 | import java.util.concurrent.ExecutorService; 35 | 36 | import static org.apache.commons.lang3.StringUtils.isNotBlank; 37 | 38 | 39 | public class SQSFactoryImpl implements io.relution.jenkins.awssqs.interfaces.SQSFactory { 40 | 41 | private final ExecutorService executor; 42 | private final io.relution.jenkins.awssqs.net.RequestFactory factory; 43 | 44 | @Inject 45 | public SQSFactoryImpl(final ExecutorService executor, final io.relution.jenkins.awssqs.net.RequestFactory factory) { 46 | this.executor = executor; 47 | this.factory = factory; 48 | } 49 | 50 | @Override 51 | public AmazonSQS createSQS(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 52 | final ClientConfiguration clientConfiguration = this.getClientConfiguration(queue); 53 | boolean hasCredentials = isNotBlank(queue.getAWSAccessKeyId()) && isNotBlank(queue.getAWSSecretKey()); 54 | io.relution.jenkins.awssqs.logging.Log.info("Creating AmazonSQS instance - hasCredentials='%s'", hasCredentials); 55 | final AmazonSQS sqs = hasCredentials ? new AmazonSQSClient(queue, clientConfiguration) : new AmazonSQSClient(clientConfiguration); 56 | 57 | if (queue.getEndpoint() != null) { 58 | sqs.setEndpoint(queue.getEndpoint()); 59 | } 60 | 61 | return sqs; 62 | } 63 | 64 | @Override 65 | public AmazonSQSAsync createSQSAsync(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 66 | final ClientConfiguration clientConfiguration = this.getClientConfiguration(queue); 67 | boolean hasCredentials = isNotBlank(queue.getAWSAccessKeyId()) && isNotBlank(queue.getAWSSecretKey()); 68 | io.relution.jenkins.awssqs.logging.Log.info("Creating AmazonSQS instance - hasCredentials='%s'", hasCredentials); 69 | final AmazonSQSAsyncClient sqsAsync = hasCredentials ? new AmazonSQSAsyncClient(queue, clientConfiguration, this.executor) : new AmazonSQSAsyncClient(clientConfiguration); 70 | 71 | if (queue.getEndpoint() != null) { 72 | sqsAsync.setEndpoint(queue.getEndpoint()); 73 | } 74 | 75 | final QueueBufferConfig queueBufferConfig = this.getQueueBufferConfig(queue); 76 | final AmazonSQSBufferedAsyncClient sqsBufferedAsync = new AmazonSQSBufferedAsyncClient(sqsAsync, queueBufferConfig); 77 | 78 | return sqsBufferedAsync; 79 | } 80 | 81 | @Override 82 | public SQSChannel createChannel(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 83 | final AmazonSQS sqs = this.createSQS(queue); 84 | return new io.relution.jenkins.awssqs.net.SQSChannelImpl(sqs, queue, this.factory); 85 | } 86 | 87 | @Override 88 | public io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor createMonitor(final ExecutorService executor, final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 89 | final SQSChannel channel = this.createChannel(queue); 90 | return new io.relution.jenkins.awssqs.threading.SQSQueueMonitorImpl(executor, queue, channel); 91 | } 92 | 93 | @Override 94 | public io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor createMonitor(final io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor monitor, final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 95 | final SQSChannel channel = this.createChannel(queue); 96 | return monitor.clone(queue, channel); 97 | } 98 | 99 | private ClientConfiguration getClientConfiguration(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 100 | final ClientConfiguration config = new ClientConfiguration(); 101 | 102 | // Check to see if Jenkins is up yet 103 | Jenkins jenkins = Jenkins.getInstance(); 104 | ProxyConfiguration proxyConfig = jenkins.proxy; 105 | Proxy proxy = proxyConfig == null ? Proxy.NO_PROXY : proxyConfig.createProxy(queue.getEndpoint()); 106 | if (!proxy.equals(Proxy.NO_PROXY) && proxy.address() instanceof InetSocketAddress) { 107 | InetSocketAddress address = (InetSocketAddress) proxy.address(); 108 | config.setProxyHost(address.getHostName()); 109 | config.setProxyPort(address.getPort()); 110 | config.setNonProxyHosts("169.254.169.254"); 111 | if (null != proxyConfig.getUserName()) { 112 | config.setProxyUsername(proxyConfig.getUserName()); 113 | config.setProxyPassword(proxyConfig.getPassword()); 114 | } 115 | io.relution.jenkins.awssqs.logging.Log.info( 116 | "Proxy settings for SQS: %s:%s", 117 | config.getProxyHost(), 118 | config.getProxyPort()); 119 | } 120 | return config; 121 | } 122 | 123 | private QueueBufferConfig getQueueBufferConfig(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 124 | final QueueBufferConfig config = new QueueBufferConfig(); 125 | 126 | // TODO Add more options 127 | 128 | config.setLongPollWaitTimeoutSeconds(queue.getWaitTimeSeconds()); 129 | config.setLongPoll(true); 130 | 131 | return config; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/factories/ThreadFactoryImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.factories; 18 | 19 | import java.util.concurrent.ThreadFactory; 20 | 21 | 22 | public class ThreadFactoryImpl implements ThreadFactory { 23 | 24 | @Override 25 | public Thread newThread(final Runnable r) { 26 | final Thread thread = new Thread(r); 27 | thread.setPriority(Thread.MIN_PRIORITY); 28 | 29 | return thread; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/Event.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import org.eclipse.jgit.transport.URIish; 20 | 21 | 22 | /** 23 | * Interface definition for classes that represent source code management (SCM) events posted to an 24 | * Amazon SQS queue. 25 | */ 26 | public interface Event { 27 | 28 | /** 29 | * Returns the host of the repository that raised the event. 30 | * @return The name of the host. 31 | */ 32 | String getHost(); 33 | 34 | /** 35 | * Returns the path of the repository that raised the event. 36 | * @return The path of the repository on {@code host}. 37 | */ 38 | String getPath(); 39 | 40 | /** 41 | * Returns the user that caused the event to be raised. 42 | * @return The name of the user that caused the event to be raised. 43 | */ 44 | String getUser(); 45 | 46 | /** 47 | * Returns the branch affected by the changed the caused the event to be raised. 48 | * @return The name of the branch that caused the event to be raised. 49 | */ 50 | String getBranch(); 51 | 52 | /** 53 | * Returns a value indicating whether the specified URI matches the events host and path 54 | * information. 55 | * @param uri The {@link URIish} to be tested. 56 | * @return {@code true} if the event matches the specified URI; otherwise, {@code false}. 57 | */ 58 | boolean isMatch(URIish uri); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/EventTriggerMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import hudson.model.Job; 20 | import io.relution.jenkins.awssqs.model.entities.codecommit.ExecuteJenkinsJobEvent; 21 | 22 | import java.util.List; 23 | 24 | 25 | /** 26 | * Interface definition for classes that match events to {@link Job}s. If an event 27 | * matches a project its build process should be triggered. 28 | */ 29 | public interface EventTriggerMatcher { 30 | 31 | /** 32 | * Returns a value indicating whether any of the specified events matches the specified job. 33 | * @param events The collection of {@link Event}s to test against the job. 34 | * @param job The {@link Job} to test against. 35 | * @return {@code true} if any of the specified events matches the specified job; otherwise, 36 | * {@code false}. 37 | */ 38 | boolean matches(List events, Job job); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/ExecutorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import java.util.concurrent.ThreadPoolExecutor; 20 | 21 | 22 | /** 23 | * Interface definition for factories that can create a {@link ThreadPoolExecutor}. 24 | */ 25 | public interface ExecutorFactory { 26 | 27 | /** 28 | * Returns a new instance of a {@link ThreadPoolExecutor}. 29 | * @return A new {@link ThreadPoolExecutor}. 30 | */ 31 | public ThreadPoolExecutor createExecutor(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/ExecutorProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.google.inject.Provider; 20 | 21 | import java.util.concurrent.ExecutorService; 22 | 23 | 24 | /** 25 | * Interface definition for classes that provide access to an {@link ExecutorService} instance. 26 | */ 27 | public interface ExecutorProvider extends Provider { 28 | 29 | /** 30 | * Returns the core number of threads. 31 | * @return The core number of threads. 32 | * @see #setCorePoolSize(int) 33 | */ 34 | int getCorePoolSize(); 35 | 36 | /** 37 | * Sets the core number of threads. This overrides any value set in the constructor. If the new 38 | * value is smaller than the current value, excess existing threads will be terminated when they 39 | * next become idle. If larger, new threads will, if needed, be started to execute any queued 40 | * tasks. 41 | * @param corePoolSize The new core size to set. 42 | * @throws IllegalArgumentException If {@code corePoolSize} is less than zero. 43 | * @see #getCorePoolSize() 44 | */ 45 | void setCorePoolSize(int corePoolSize) throws IllegalArgumentException; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/MessageParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | 21 | import java.util.List; 22 | 23 | 24 | /** 25 | * Interface definition for classes that parse {@link Message}s that are returned by a message 26 | * request to an Amazon SQS queue into SCM {@link Event}s. 27 | */ 28 | public interface MessageParser { 29 | 30 | /** 31 | * Parses the specified message into one or more events. 32 | * @param message The {@link Message} to parse. 33 | * @return The collection of {@link Event} items contained in the message. 34 | */ 35 | List parseMessage(Message message); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/MessageParserFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | 21 | 22 | /** 23 | * Interface definition for factories that can create {@link MessageParser}s suitable for parsing 24 | * {@link Message}s returns by an Amazon SQS queue, based on the message type. 25 | */ 26 | public interface MessageParserFactory { 27 | 28 | /** 29 | * Returns a new parser based on the type of the message that is specified. 30 | * @param message The {@link Message} for which to create a parser. 31 | * @return A {@link MessageParser} that can be used to parse the message. 32 | */ 33 | MessageParser createParser(Message message); 34 | 35 | /** 36 | * Returns a new parser that can be used to parse messages created by CodeCommit events. 37 | * @return A {@link MessageParser} suitable for parsing CodeCommit events. 38 | */ 39 | MessageParser createCodeCommitParser(); 40 | } -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/SQSFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.amazonaws.services.sqs.AmazonSQS; 20 | import com.amazonaws.services.sqs.AmazonSQSAsync; 21 | 22 | import java.util.concurrent.ExecutorService; 23 | 24 | import io.relution.jenkins.awssqs.net.SQSChannel; 25 | 26 | 27 | /** 28 | * Interface definition for factories that can create {@link SQSQueueMonitor} instances and related 29 | * classes. The instances returned by a factory implementation can be used to monitor a particular 30 | * {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} by polling the queue for new messages. 31 | */ 32 | public interface SQSFactory { 33 | 34 | /** 35 | * Returns a new Amazon SQS instance that can be used to access the specified queue. 36 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} for which to create a client. 37 | * @return A new instance of an {@link AmazonSQS} that is suitable for synchronous access to 38 | * the specified queue. 39 | */ 40 | AmazonSQS createSQS(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue); 41 | 42 | /** 43 | * Returns a new Amazon SQS instance that can be used to access the specified queue. 44 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} for which to create a client. 45 | * @return A new instance of an {@link AmazonSQSAsync} that is suitable for asynchronous access 46 | * to the specified queue. 47 | */ 48 | AmazonSQSAsync createSQSAsync(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue); 49 | 50 | /** 51 | * Returns a new channel instance that can be used to communicate with the specified queue. 52 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} for which to create the channel. 53 | * @return A new {@link SQSChannel} for the specified queue. 54 | */ 55 | SQSChannel createChannel(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue); 56 | 57 | /** 58 | * Returns a new monitor instance that can be used to poll the specified queue for new 59 | * messages. 60 | * @param executor The {@link ExecutorService} used to execute the monitor. 61 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} for which to create a monitor. 62 | * @return A new {@link SQSQueueMonitor} instance suitable for monitoring the specified queue. 63 | */ 64 | SQSQueueMonitor createMonitor(final ExecutorService executor, final io.relution.jenkins.awssqs.interfaces.SQSQueue queue); 65 | 66 | /** 67 | * Returns a new monitor instance that can be used to poll the specified queue for new 68 | * messages. 69 | *

70 | * The new monitor has the same listeners as the specified monitor. This should be used to 71 | * create a new monitor instance in case a queue was reconfigured. 72 | * @param monitor The monitor used to initialize internal fields of the new instance. 73 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} for which to create a monitor. 74 | * @return A new {@link SQSQueueMonitor} instance suitable for monitoring the specified queue, 75 | * that has the same listeners as the specified monitor. 76 | */ 77 | SQSQueueMonitor createMonitor(final SQSQueueMonitor monitor, final io.relution.jenkins.awssqs.interfaces.SQSQueue queue); 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/SQSQueue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.amazonaws.auth.AWSCredentials; 20 | 21 | 22 | /** 23 | * Interface definition for classes that represent the necessary configuration that is required to 24 | * access an Amazon SQS queue. 25 | */ 26 | public interface SQSQueue extends AWSCredentials { 27 | 28 | /** 29 | * Returns the identifier used to uniquely identify the queue configuration. 30 | * @return The unique identifier of this configuration. 31 | */ 32 | String getUuid(); 33 | 34 | /** 35 | * Returns the URL of the queue the configuration is associated with. 36 | * @return The URL of a queue. 37 | */ 38 | String getUrl(); 39 | 40 | /** 41 | * Returns the name of the queue the configuration is associated with. 42 | * @return The name of a queue. 43 | */ 44 | String getName(); 45 | 46 | /** 47 | * Returns the endpoint of the queue the configuration is associated with. 48 | * @return The endpoint of a queue. 49 | */ 50 | String getEndpoint(); 51 | 52 | /** 53 | * Returns the time, in seconds, requests should wait for new messages to arrive in the queue. 54 | * @return The wait time, in seconds, before a receive message request should time out. 55 | */ 56 | int getWaitTimeSeconds(); 57 | 58 | /** 59 | * Returns the maximum number of buildable jobs allowed in the build queue. 60 | * @return The maximum number of buildable jobs allowed in the build queue. 61 | */ 62 | int getMaxNumberOfJobQueue(); 63 | 64 | /** 65 | * Returns a value indicating whether SQS messages should be kept after retrieval. 66 | * @return {@code true} if messages should be kept after retrieval; otherwise, {@code false}. 67 | */ 68 | boolean isKeepQueueMessages(); 69 | 70 | /** 71 | * Returns the maximum number of messages that a request should request. 72 | * @return The maximum number of messages a receive message request should request from the 73 | * queue. 74 | */ 75 | int getMaxNumberOfMessages(); 76 | 77 | /** 78 | * Returns a value indicating whether the configuration is valid. 79 | *

80 | * A configuration is considered valid if all information required to access the associated 81 | * queue has been defined. 82 | * @return {@code true} if the configuration is valid; otherwise, {@code false}. 83 | */ 84 | boolean isValid(); 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/SQSQueueListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | 21 | import java.util.List; 22 | 23 | 24 | /** 25 | * Interface definition for classes that listen for {@link Message}s that are returned by a request 26 | * to an Amazon SQS queue. 27 | */ 28 | public interface SQSQueueListener { 29 | 30 | /** 31 | * The unique identifier of an Amazon SQS configuration that identifies the queue 32 | * this listener is associated with. 33 | * @return The unique identifier of the {@link SQSQueue} this listener is associated with. 34 | */ 35 | String getQueueUuid(); 36 | 37 | /** 38 | * The disable flag of Amazon CodeCommit Check for listner 39 | * @return The disable flag of Amazon CodeCommit Check for listner 40 | */ 41 | default boolean isDisableCodeCommit() { 42 | return false; 43 | } 44 | /** 45 | * The method to be invoked when new messages arrive in the SQS queue this listener is 46 | * associated with. 47 | * @param messages The collection of {@link Message} instances that were posted to the queue. 48 | */ 49 | void handleMessages(List messages); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/SQSQueueMonitor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | 21 | import io.relution.jenkins.awssqs.net.SQSChannel; 22 | 23 | 24 | /** 25 | * Interface definition for classes that can be used to monitor an Amazon {@link SQSQueue} for new 26 | * {@link Message}s that arrive in the queue. 27 | */ 28 | public interface SQSQueueMonitor extends Runnable { 29 | 30 | /** 31 | * Returns a new instance for the specified queue and channel that has the same listeners as 32 | * this instance. 33 | * @param queue The {@link SQSQueue} to monitor. 34 | * @param channel The {@link SQSChannel} used to access the queue. 35 | * @return A new {@link SQSQueueMonitor} instance. 36 | */ 37 | SQSQueueMonitor clone(SQSQueue queue, SQSChannel channel); 38 | 39 | /** 40 | * Registers a new listener with the monitor. The listener is notified when new messages arrive 41 | * in the queue. 42 | *

43 | * Note: If a new listener is registered with a monitor that is already processing 44 | * received messages the listener may not be notified until the next time new messages arrive 45 | * in the queue. 46 | * @param listener The {@link SQSQueueListener} to register with the monitor. 47 | * @return {@code true} if the call caused monitoring to be started (i.e. the first listener was 48 | * registered); otherwise, {@code false}. 49 | * @throws IllegalArgumentException The specified listener is {@code null} 50 | * @throws IllegalArgumentException The specified listener is associated with a different 51 | * queue. 52 | */ 53 | boolean add(SQSQueueListener listener); 54 | 55 | /** 56 | * Unregisters a previously registered listener from the monitor. The listener will no longer 57 | * be notified when new messages arrive in the queue. 58 | * @param listener The {@link SQSQueueListener} to unregister from the monitor. 59 | * @return {@code true} if the call caused monitoring to be stopped (i.e. the last listener was 60 | * unregistered); otherwise, {@code false}. 61 | */ 62 | boolean remove(SQSQueueListener listener); 63 | 64 | /** 65 | * Stops the monitor. 66 | *

67 | * Prevents the monitor from making any further requests to the associated queue. Requests that 68 | * are already in flight may not necessarily be cancelled. 69 | */ 70 | void shutDown(); 71 | 72 | /** 73 | * Returns a value indicating whether the monitor is stopped. 74 | * @return {@code true} if the monitor is stopped; otherwise, {@code false}. 75 | */ 76 | boolean isShutDown(); 77 | 78 | /** 79 | * Returns the SQS queue this monitor is associated with. 80 | * @return The {@link SQSQueue} this monitor is associated with. 81 | */ 82 | SQSQueue getQueue(); 83 | 84 | /** 85 | * Returns the SQS channel this monitor is associated with. 86 | * @return The {@link SQSChannel} this monitor is associated with. 87 | */ 88 | SQSChannel getChannel(); 89 | } -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/SQSQueueMonitorScheduler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import com.google.common.eventbus.Subscribe; 20 | 21 | import io.relution.jenkins.awssqs.model.events.ConfigurationChangedEvent; 22 | 23 | 24 | /** 25 | * Interface definition for classes that schedule the execution of {@link SQSQueueMonitor} 26 | * instances. 27 | */ 28 | public interface SQSQueueMonitorScheduler { 29 | 30 | /** 31 | * Registers the specified listener with the scheduler. The listener is notified when new 32 | * messages arrive in the associated queue. 33 | *

34 | * The listener may be registered with a new monitor or an existing instance at the scheduler's 35 | * discretion. 36 | * @param listener The {@link SQSQueueListener} to be registered. 37 | * @return {@code true} if the listener was registered. {@code false} if no queue configuration 38 | * associated with the listener could be found. 39 | * @throws IllegalArgumentException The specified listener is {@code null}. 40 | */ 41 | boolean register(SQSQueueListener listener); 42 | 43 | /** 44 | * Unregisters the specified listener from the scheduler. The listener will no longer 45 | * be notified of new messages. 46 | * @param listener The {@link SQSQueueListener} to be unregistered. 47 | * @return {@code true} if the listener was unregistered. {@code false} if the specified 48 | * listener is not associated with a monitor. 49 | */ 50 | boolean unregister(SQSQueueListener listener); 51 | 52 | /** 53 | * Notifies the scheduler that the global configuration was changed. It should shut down all 54 | * monitors for which the associated queue configuration was removed. 55 | * @param event The configuration changed event. 56 | */ 57 | @Subscribe 58 | void onConfigurationChanged(ConfigurationChangedEvent event); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/interfaces/SQSQueueProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.interfaces; 18 | 19 | import java.util.List; 20 | 21 | 22 | /** 23 | * Interface definition for classes that provide access to a collection of {@link SQSQueue} 24 | * instances. 25 | */ 26 | public interface SQSQueueProvider { 27 | 28 | /** 29 | * Returns the collection of {@link SQSQueue} instances associated with this provider. 30 | * @return A collection of {@link SQSQueue} instances. 31 | */ 32 | List getSqsQueues(); 33 | 34 | /** 35 | * Returns the SQS queue configuration associated with the specified identifier. 36 | * @param uuid The unique identifier of the configuration to get. 37 | * @return The {@link SQSQueue} associated with the specified identifier, or {@code null} if 38 | * no such configuration exists. 39 | */ 40 | SQSQueue getSqsQueue(String uuid); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/logging/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.logging; 18 | 19 | import java.util.logging.Level; 20 | import java.util.logging.Logger; 21 | 22 | 23 | public class Log { 24 | 25 | private static final Logger LOGGER; 26 | 27 | static { 28 | LOGGER = Logger.getLogger(Log.class.getName()); 29 | } 30 | 31 | private static String format(final String message, final Object... args) { 32 | final String formatted = String.format(message, args); 33 | final long id = Thread.currentThread().getId(); 34 | return String.format("%06X %s", id, formatted); 35 | } 36 | 37 | private static void write(final Level level, final String message, final Object... args) { 38 | final String msg = format(message, args); 39 | LOGGER.log(level, msg); 40 | } 41 | 42 | private static void write(final Level level, final Throwable thrown, final String message, final Object... args) { 43 | final String msg = format(message, args); 44 | LOGGER.log(level, msg, thrown); 45 | } 46 | 47 | public static void finest(final String message, final Object... args) { 48 | write(Level.FINEST, message, args); 49 | } 50 | 51 | public static void finer(final String message, final Object... args) { 52 | write(Level.FINER, message, args); 53 | } 54 | 55 | public static void fine(final String message, final Object... args) { 56 | write(Level.FINE, message, args); 57 | } 58 | 59 | public static void info(final String message, final Object... args) { 60 | write(Level.INFO, message, args); 61 | } 62 | 63 | public static void warning(final String message, final Object... args) { 64 | write(Level.WARNING, message, args); 65 | } 66 | 67 | public static void severe(final String message, final Object... args) { 68 | write(Level.SEVERE, message, args); 69 | } 70 | 71 | public static void severe(final Throwable thrown, final String message, final Object... args) { 72 | write(Level.SEVERE, thrown, message, args); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/CodeCommitMessageParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | import com.google.gson.Gson; 21 | import com.google.gson.GsonBuilder; 22 | import io.relution.jenkins.awssqs.interfaces.MessageParser; 23 | import io.relution.jenkins.awssqs.model.entities.codecommit.ExecuteJenkinsJobEvent; 24 | import org.apache.commons.lang3.StringUtils; 25 | 26 | import java.util.Collections; 27 | import java.util.List; 28 | 29 | 30 | public class CodeCommitMessageParser implements MessageParser { 31 | 32 | private static final String EVENT_SOURCE_CODECOMMIT = "aws:codecommit"; 33 | 34 | private final Gson gson; 35 | 36 | public CodeCommitMessageParser() { 37 | this.gson = new GsonBuilder() 38 | .excludeFieldsWithoutExposeAnnotation() 39 | .create(); 40 | } 41 | 42 | @Override 43 | public List parseMessage(final Message message) { 44 | try { 45 | String body = message.getBody(); 46 | io.relution.jenkins.awssqs.logging.Log.info("Found json body: '%s'", body); 47 | return Collections.singletonList(this.gson.fromJson(body, ExecuteJenkinsJobEvent.class)); 48 | // Log.info("Got message with subject: %s", body.getSubject()); 49 | // final String json = body.getMessage(); 50 | // Log.info("Body of the message: %s", json); 51 | // if (StringUtils.isEmpty(json)) { 52 | // Log.warning("Message contains no text"); 53 | // return Collections.emptyList(); 54 | // } 55 | // 56 | // if (!json.startsWith("{") || !json.endsWith("}")) { 57 | // Log.warning("Message text is no JSON"); 58 | // return Collections.emptyList(); 59 | // } 60 | //// return new ArrayList(); 61 | // return this.parseRecords(json); 62 | } catch (final com.google.gson.JsonSyntaxException e) { 63 | io.relution.jenkins.awssqs.logging.Log.warning("JSON syntax exception, cannot parse message: %s", e); 64 | } 65 | return Collections.emptyList(); 66 | } 67 | 68 | private List parseRecords(final String json) { 69 | final ExecuteJenkinsJobEvent records = this.gson.fromJson(json, ExecuteJenkinsJobEvent.class); 70 | return Collections.singletonList(records); 71 | 72 | // for (final Record record : records) { 73 | // this.parseEvents(events, record); 74 | // } 75 | // 76 | // return events; 77 | } 78 | 79 | private void parseEvents(final List events, final io.relution.jenkins.awssqs.model.entities.codecommit.Record record) { 80 | if (!this.isCodeCommitEvent(record)) { 81 | return; 82 | } 83 | 84 | final io.relution.jenkins.awssqs.model.entities.codecommit.CodeCommit codeCommit = record.getCodeCommit(); 85 | 86 | for (final io.relution.jenkins.awssqs.model.entities.codecommit.Reference reference : codeCommit.getReferences()) { 87 | final io.relution.jenkins.awssqs.interfaces.Event event = new io.relution.jenkins.awssqs.model.entities.codecommit.CodeCommitEvent(record, reference); 88 | events.add(event); 89 | } 90 | } 91 | 92 | private boolean isCodeCommitEvent(final io.relution.jenkins.awssqs.model.entities.codecommit.Record record) { 93 | return StringUtils.equals(EVENT_SOURCE_CODECOMMIT, record.getEventSource()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/EventTriggerMatcherImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model; 18 | 19 | import hudson.model.Job; 20 | import hudson.plugins.git.BranchSpec; 21 | import hudson.plugins.git.GitSCM; 22 | import hudson.scm.SCM; 23 | import io.relution.jenkins.awssqs.interfaces.Event; 24 | import io.relution.jenkins.awssqs.interfaces.EventTriggerMatcher; 25 | import io.relution.jenkins.awssqs.model.entities.codecommit.ExecuteJenkinsJobEvent; 26 | import jenkins.model.Jenkins; 27 | import org.eclipse.jgit.transport.RemoteConfig; 28 | import org.eclipse.jgit.transport.URIish; 29 | import org.jenkinsci.plugins.multiplescms.MultiSCM; 30 | 31 | import java.util.List; 32 | 33 | 34 | public class EventTriggerMatcherImpl implements EventTriggerMatcher { 35 | 36 | @Override 37 | public boolean matches(final List events, final Job job) { 38 | if (events == null || job == null) { 39 | return false; 40 | } 41 | 42 | io.relution.jenkins.awssqs.logging.Log.info("Test if any event matches job '%s'...", job.getName()); 43 | 44 | for (final ExecuteJenkinsJobEvent event : events) { 45 | io.relution.jenkins.awssqs.logging.Log.info("Job '%s' matches event jobName '%s'?", job.getName(), event.getJobName()); 46 | if (job.getName().equalsIgnoreCase(event.getJobName())) { 47 | return true; 48 | } 49 | } 50 | 51 | io.relution.jenkins.awssqs.logging.Log.info("Event(s) did not match job."); 52 | return false; 53 | } 54 | 55 | private boolean matches(final Event event, final SCM scm) { 56 | if (event == null || scm == null) { 57 | return false; 58 | } 59 | 60 | if (this.isGitScmAvailable() && this.matchesGitSCM(event, scm)) { 61 | return true; 62 | 63 | } else if (this.isMultiScmAvailable() && this.matchesMultiSCM(event, scm)) { 64 | return true; 65 | 66 | } else { 67 | return false; 68 | 69 | } 70 | } 71 | 72 | private boolean matchesGitSCM(final Event event, final SCM scmProvider) { 73 | if (!(scmProvider instanceof hudson.plugins.git.GitSCM)) { 74 | return false; 75 | } 76 | 77 | final GitSCM git = (GitSCM) scmProvider; 78 | final List configs = git.getRepositories(); 79 | final List branches = git.getBranches(); 80 | 81 | return this.matchesConfigs(event, configs) && this.matchesBranches(event, branches); 82 | } 83 | 84 | private boolean matchesMultiSCM(final Event event, final SCM scmProvider) { 85 | if (!(scmProvider instanceof org.jenkinsci.plugins.multiplescms.MultiSCM)) { 86 | return false; 87 | } 88 | 89 | final MultiSCM multiSCM = (MultiSCM) scmProvider; 90 | final List scms = multiSCM.getConfiguredSCMs(); 91 | 92 | for (final SCM scm : scms) { 93 | if (this.matches(event, scm)) { 94 | return true; 95 | } 96 | } 97 | 98 | return false; 99 | } 100 | 101 | private boolean matchesBranches(final Event event, final List branches) { 102 | for (final BranchSpec branch : branches) { 103 | if (this.matchesBranch(event, branch)) { 104 | return true; 105 | } 106 | } 107 | return false; 108 | } 109 | 110 | private boolean matchesBranch(final Event event, final BranchSpec branch) { 111 | return branch.matches(event.getBranch()); 112 | } 113 | 114 | private boolean matchesConfigs(final Event event, final List configs) { 115 | for (final RemoteConfig config : configs) { 116 | if (this.matchesConfig(event, config)) { 117 | return true; 118 | } 119 | } 120 | return false; 121 | } 122 | 123 | private boolean matchesConfig(final Event event, final RemoteConfig config) { 124 | for (final URIish uri : config.getURIs()) { 125 | if (event.isMatch(uri)) { 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | private boolean isMultiScmAvailable() { 133 | final Jenkins jenkins = Jenkins.getInstance(); 134 | 135 | return jenkins.getPlugin("multiple-scms") != null; 136 | } 137 | 138 | private boolean isGitScmAvailable() { 139 | final Jenkins jenkins = Jenkins.getInstance(); 140 | 141 | return jenkins.getPlugin("git") != null; 142 | } 143 | } -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/SQSQueueProviderImpl.java: -------------------------------------------------------------------------------- 1 | 2 | package io.relution.jenkins.awssqs.model; 3 | 4 | import java.util.List; 5 | 6 | import io.relution.jenkins.awssqs.interfaces.SQSQueueProvider; 7 | 8 | 9 | public class SQSQueueProviderImpl implements SQSQueueProvider { 10 | 11 | @Override 12 | public List getSqsQueues() { 13 | final io.relution.jenkins.awssqs.SQSTrigger.DescriptorImpl descriptor = io.relution.jenkins.awssqs.SQSTrigger.DescriptorImpl.get(); 14 | return descriptor.getSqsQueues(); 15 | } 16 | 17 | @Override 18 | public io.relution.jenkins.awssqs.interfaces.SQSQueue getSqsQueue(final String uuid) { 19 | final io.relution.jenkins.awssqs.SQSTrigger.DescriptorImpl descriptor = io.relution.jenkins.awssqs.SQSTrigger.DescriptorImpl.get(); 20 | return descriptor.getSqsQueue(uuid); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/constants/ErrorCode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.constants; 18 | 19 | /** 20 | * Defines constants for error codes returned by Amazon Web Services (AWS). 21 | */ 22 | public final class ErrorCode { 23 | 24 | /** 25 | * The X.509 certificate or AWS access key ID provided does not exist on AWS. 26 | *

27 | * HTTP Status Code: 403 28 | */ 29 | public static final String INVALID_CLIENT_TOKEN_ID = "InvalidClientTokenId"; 30 | 31 | private ErrorCode() { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/CodeCommit.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import com.google.gson.annotations.Expose; 20 | import com.google.gson.annotations.SerializedName; 21 | 22 | import java.util.List; 23 | 24 | 25 | public class CodeCommit { 26 | 27 | @Expose 28 | @SerializedName("references") 29 | List references; 30 | 31 | public List getReferences() { 32 | return this.references; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/CodeCommitEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import org.apache.commons.lang3.StringUtils; 20 | import org.eclipse.jgit.transport.URIish; 21 | 22 | import io.relution.jenkins.awssqs.interfaces.Event; 23 | 24 | 25 | public class CodeCommitEvent implements Event { 26 | 27 | private final static String HOST = "git-codecommit.%s.amazonaws.com"; 28 | private final static String PATH = "/v1/repos/%s"; 29 | 30 | private final String host; 31 | private final String path; 32 | 33 | private final String branch; 34 | 35 | public CodeCommitEvent(final Record record, final Reference reference) { 36 | final String arn = record.getEventSourceARN(); 37 | final String[] tokens = arn.split(":", 6); 38 | 39 | this.host = String.format(HOST, tokens[3]); 40 | this.path = String.format(PATH, tokens[5]); 41 | 42 | final String name = reference.getName(); 43 | this.branch = StringUtils.stripStart(name, "refs/"); 44 | } 45 | 46 | @Override 47 | public String getHost() { 48 | return this.host; 49 | } 50 | 51 | @Override 52 | public String getPath() { 53 | return this.path; 54 | } 55 | 56 | @Override 57 | public String getUser() { 58 | return null; 59 | } 60 | 61 | @Override 62 | public String getBranch() { 63 | return this.branch; 64 | } 65 | 66 | @Override 67 | public boolean isMatch(final URIish uri) { 68 | if (uri == null) { 69 | return false; 70 | } 71 | 72 | if (!StringUtils.equals(this.host, uri.getHost())) { 73 | return false; 74 | } 75 | 76 | if (!StringUtils.equals(this.path, uri.getPath())) { 77 | return false; 78 | } 79 | 80 | return true; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/ExecuteJenkinsJobEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import com.google.gson.annotations.Expose; 20 | import com.google.gson.annotations.SerializedName; 21 | 22 | 23 | public class ExecuteJenkinsJobEvent { 24 | 25 | @Expose 26 | @SerializedName("jobName") 27 | private String jobName; 28 | 29 | public String getJobName() { 30 | return jobName; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/MessageBody.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import com.google.gson.annotations.Expose; 20 | import com.google.gson.annotations.SerializedName; 21 | 22 | 23 | public class MessageBody { 24 | 25 | @Expose 26 | @SerializedName("Type") 27 | private String type; 28 | 29 | @Expose 30 | @SerializedName("MessageId") 31 | private String messageId; 32 | 33 | @Expose 34 | @SerializedName("TopicArn") 35 | private String topicArn; 36 | 37 | @Expose 38 | @SerializedName("Subject") 39 | private String subject; 40 | 41 | @Expose 42 | @SerializedName("Message") 43 | private String message; 44 | 45 | @Expose 46 | @SerializedName("Timestamp") 47 | private String timestamp; 48 | 49 | @Expose 50 | @SerializedName("SignatureVersion") 51 | private String signatureVersion; 52 | 53 | @Expose 54 | @SerializedName("Signature") 55 | private String signature; 56 | 57 | @Expose 58 | @SerializedName("SigningCertURL") 59 | private String signingCertURL; 60 | 61 | @Expose 62 | @SerializedName("UnsubscribeURL") 63 | private String unsubscribeURL; 64 | 65 | public String getType() { 66 | return this.type; 67 | } 68 | 69 | public String getMessageId() { 70 | return this.messageId; 71 | } 72 | 73 | public String getTopicArn() { 74 | return this.topicArn; 75 | } 76 | 77 | public String getSubject() { 78 | return this.subject; 79 | } 80 | 81 | public String getMessage() { 82 | return this.message; 83 | } 84 | 85 | public String getTimestamp() { 86 | return this.timestamp; 87 | } 88 | 89 | public String getSignatureVersion() { 90 | return this.signatureVersion; 91 | } 92 | 93 | public String getSignature() { 94 | return this.signature; 95 | } 96 | 97 | public String getSigningCertURL() { 98 | return this.signingCertURL; 99 | } 100 | 101 | public String getUnsubscribeURL() { 102 | return this.unsubscribeURL; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/Record.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import com.google.gson.annotations.Expose; 20 | import com.google.gson.annotations.SerializedName; 21 | 22 | 23 | public class Record { 24 | 25 | @Expose 26 | @SerializedName("awsRegion") 27 | private String awsRegion; 28 | 29 | @Expose 30 | @SerializedName("codecommit") 31 | private CodeCommit codeCommit; 32 | 33 | @Expose 34 | @SerializedName("eventId") 35 | private String eventId; 36 | 37 | @Expose 38 | @SerializedName("eventName") 39 | private String eventName; 40 | 41 | @Expose 42 | @SerializedName("eventPartNumber") 43 | private int eventPartNumber; 44 | 45 | @Expose 46 | @SerializedName("eventSource") 47 | private String eventSource; 48 | 49 | @Expose 50 | @SerializedName("eventSourceARN") 51 | private String eventSourceARN; 52 | 53 | @Expose 54 | @SerializedName("eventTime") 55 | private String eventTime; 56 | 57 | @Expose 58 | @SerializedName("eventTotalParts") 59 | private int eventTotalParts; 60 | 61 | @Expose 62 | @SerializedName("eventTriggerConfigId") 63 | private String eventTriggerConfigId; 64 | 65 | @Expose 66 | @SerializedName("eventTriggerName") 67 | private String eventTriggerName; 68 | 69 | @Expose 70 | @SerializedName("eventVersion") 71 | private String eventVersion; 72 | 73 | @Expose 74 | @SerializedName("userIdentityARN") 75 | private String userIdentityARN; 76 | 77 | public String getAwsRegion() { 78 | return this.awsRegion; 79 | } 80 | 81 | public CodeCommit getCodeCommit() { 82 | return this.codeCommit; 83 | } 84 | 85 | public String getEventId() { 86 | return this.eventId; 87 | } 88 | 89 | public String getEventName() { 90 | return this.eventName; 91 | } 92 | 93 | public int getEventPartNumber() { 94 | return this.eventPartNumber; 95 | } 96 | 97 | public String getEventSource() { 98 | return this.eventSource; 99 | } 100 | 101 | public String getEventSourceARN() { 102 | return this.eventSourceARN; 103 | } 104 | 105 | public String getEventTime() { 106 | return this.eventTime; 107 | } 108 | 109 | public int getEventTotalParts() { 110 | return this.eventTotalParts; 111 | } 112 | 113 | public String getEventTriggerConfigId() { 114 | return this.eventTriggerConfigId; 115 | } 116 | 117 | public String getEventTriggerName() { 118 | return this.eventTriggerName; 119 | } 120 | 121 | public String getEventVersion() { 122 | return this.eventVersion; 123 | } 124 | 125 | public String getUserIdentityARN() { 126 | return this.userIdentityARN; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/Records.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import com.google.gson.annotations.Expose; 20 | import com.google.gson.annotations.SerializedName; 21 | 22 | import java.util.Iterator; 23 | import java.util.List; 24 | 25 | 26 | public class Records implements Iterable { 27 | 28 | @Expose 29 | @SerializedName("Records") 30 | private List records; 31 | 32 | @Override 33 | public Iterator iterator() { 34 | return this.records.iterator(); 35 | } 36 | 37 | public int size() { 38 | return this.records.size(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/entities/codecommit/Reference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.model.entities.codecommit; 18 | 19 | import com.google.gson.annotations.Expose; 20 | import com.google.gson.annotations.SerializedName; 21 | 22 | 23 | public class Reference { 24 | 25 | @Expose 26 | @SerializedName("commit") 27 | private String commit; 28 | 29 | @Expose 30 | @SerializedName("ref") 31 | private String reference; 32 | 33 | public String getCommit() { 34 | return this.commit; 35 | } 36 | 37 | public String getName() { 38 | return this.reference; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/events/ConfigurationChangedEvent.java: -------------------------------------------------------------------------------- 1 | 2 | package io.relution.jenkins.awssqs.model.events; 3 | 4 | 5 | /** 6 | * Event that is sent by the {@link io.relution.jenkins.awssqs.SQSTrigger.DescriptorImpl} when its configuration is changed. 7 | */ 8 | public class ConfigurationChangedEvent {} 9 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/model/events/EventBroker.java: -------------------------------------------------------------------------------- 1 | 2 | package io.relution.jenkins.awssqs.model.events; 3 | 4 | import com.google.common.eventbus.EventBus; 5 | 6 | 7 | /** 8 | * Provides a single instance of {@link EventBus}. 9 | */ 10 | public class EventBroker { 11 | 12 | private static EventBroker instance; 13 | 14 | private final EventBus eventBus = new EventBus(); 15 | 16 | public synchronized static EventBroker getInstance() { 17 | if (instance == null) { 18 | instance = new EventBroker(); 19 | } 20 | return instance; 21 | } 22 | 23 | /** 24 | * Registers all handler methods on {@code object} to receive events. 25 | * @param object The object whose handler methods should be registered. 26 | * @see EventBus#register(Object) 27 | */ 28 | public void register(final Object object) { 29 | this.eventBus.register(object); 30 | } 31 | 32 | /** 33 | * Unregisters all handler methods on a registered object. 34 | * @param object The object whose handler methods should be unregistered. 35 | * @throws IllegalArgumentException if the object was not previously registered. 36 | * @see EventBus#unregister(Object) 37 | */ 38 | public void unregister(final Object object) { 39 | this.eventBus.unregister(object); 40 | } 41 | 42 | /** 43 | * Posts an event to all registered handlers. This method will return successfully after the 44 | * event has been posted to all handlers, and regardless of any exceptions thrown by handlers. 45 | * @param event The event to post 46 | * @see EventBus#post(Object) 47 | */ 48 | public void post(final Object event) { 49 | this.eventBus.post(event); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/net/RequestFactory.java: -------------------------------------------------------------------------------- 1 | 2 | package io.relution.jenkins.awssqs.net; 3 | 4 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequest; 5 | import com.amazonaws.services.sqs.model.Message; 6 | import com.amazonaws.services.sqs.model.ReceiveMessageRequest; 7 | 8 | import java.util.List; 9 | 10 | 11 | public interface RequestFactory { 12 | 13 | /** 14 | * Returns a new request that can be used to receive messages from the specified queue. 15 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} for which to create the request. 16 | * @return A {@link ReceiveMessageRequest} that can be used to request messages from the 17 | * specified queue. 18 | */ 19 | ReceiveMessageRequest createReceiveMessageRequest(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue); 20 | 21 | /** 22 | * Returns a new request that can be used to delete previously received messages from the 23 | * specified queue. 24 | *

25 | * The specified messages must have been received by a previous receive message request to 26 | * the same queue. 27 | * @param queue The {@link io.relution.jenkins.awssqs.interfaces.SQSQueue} from which to delete the specified messages. 28 | * @param messages The collection of {@link Message}s to delete. 29 | * @return A {@link DeleteMessageBatchRequest} that can be used to delete messages from the 30 | * specified queue. 31 | */ 32 | DeleteMessageBatchRequest createDeleteMessageBatchRequest(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue, final List messages); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/net/RequestFactoryImpl.java: -------------------------------------------------------------------------------- 1 | 2 | package io.relution.jenkins.awssqs.net; 3 | 4 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequest; 5 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequestEntry; 6 | import com.amazonaws.services.sqs.model.Message; 7 | import com.amazonaws.services.sqs.model.ReceiveMessageRequest; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | 13 | public class RequestFactoryImpl implements RequestFactory { 14 | 15 | @Override 16 | public ReceiveMessageRequest createReceiveMessageRequest(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue) { 17 | final ReceiveMessageRequest request = new ReceiveMessageRequest(queue.getUrl()); 18 | request.setMaxNumberOfMessages(queue.getMaxNumberOfMessages()); 19 | request.setWaitTimeSeconds(queue.getWaitTimeSeconds()); 20 | return request; 21 | } 22 | 23 | @Override 24 | public DeleteMessageBatchRequest createDeleteMessageBatchRequest(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue, final List messages) { 25 | final List entries = new ArrayList<>(messages.size()); 26 | 27 | for (final Message message : messages) { 28 | final DeleteMessageBatchRequestEntry entry = this.createDeleteMessageBatchRequestEntry(message); 29 | entries.add(entry); 30 | } 31 | 32 | final DeleteMessageBatchRequest request = new DeleteMessageBatchRequest(queue.getUrl()); 33 | request.setEntries(entries); 34 | return request; 35 | } 36 | 37 | private DeleteMessageBatchRequestEntry createDeleteMessageBatchRequestEntry(final Message message) { 38 | final DeleteMessageBatchRequestEntry entry = new DeleteMessageBatchRequestEntry(); 39 | entry.setReceiptHandle(message.getReceiptHandle()); 40 | entry.setId(message.getMessageId()); 41 | return entry; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/net/SQSChannel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.net; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | 21 | import java.util.List; 22 | 23 | 24 | public interface SQSChannel { 25 | 26 | List getMessages(); 27 | 28 | void deleteMessages(List messages); 29 | 30 | String getQueueUuid(); 31 | } -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/net/SQSChannelImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.net; 18 | 19 | import com.amazonaws.services.sqs.AmazonSQS; 20 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequest; 21 | import com.amazonaws.services.sqs.model.DeleteMessageBatchResult; 22 | import com.amazonaws.services.sqs.model.Message; 23 | import com.amazonaws.services.sqs.model.ReceiveMessageRequest; 24 | import com.amazonaws.services.sqs.model.ReceiveMessageResult; 25 | 26 | import org.apache.commons.httpclient.HttpStatus; 27 | 28 | import java.util.Collections; 29 | import java.util.List; 30 | 31 | import io.relution.jenkins.awssqs.interfaces.SQSQueue; 32 | import io.relution.jenkins.awssqs.logging.Log; 33 | import io.relution.jenkins.awssqs.model.constants.ErrorCode; 34 | import io.relution.jenkins.awssqs.util.ErrorType; 35 | import io.relution.jenkins.awssqs.util.ThrowIf; 36 | 37 | 38 | public class SQSChannelImpl implements SQSChannel { 39 | 40 | private final AmazonSQS sqs; 41 | private final SQSQueue queue; 42 | private final io.relution.jenkins.awssqs.net.RequestFactory factory; 43 | 44 | /** 45 | * Number of requests that were sent (for logging) 46 | */ 47 | private int requestCount; 48 | 49 | public SQSChannelImpl(final AmazonSQS sqs, final SQSQueue queue, final io.relution.jenkins.awssqs.net.RequestFactory factory) { 50 | ThrowIf.isNull(sqs, "sqs"); 51 | ThrowIf.isNull(queue, "queue"); 52 | ThrowIf.isNull(factory, "factory"); 53 | 54 | this.sqs = sqs; 55 | this.queue = queue; 56 | this.factory = factory; 57 | } 58 | 59 | @Override 60 | public List getMessages() { 61 | try { 62 | this.logRequestCount(); 63 | 64 | final ReceiveMessageRequest request = this.factory.createReceiveMessageRequest(this.queue); 65 | final ReceiveMessageResult result = this.sqs.receiveMessage(request.withMessageAttributeNames("All")); 66 | 67 | if (result == null) { 68 | return Collections.emptyList(); 69 | } 70 | 71 | return result.getMessages(); 72 | 73 | } catch (final com.amazonaws.services.sqs.model.QueueDoesNotExistException e) { 74 | Log.warning("Failed to send receive message request for %s, queue does not exist", this.queue); 75 | throw e; 76 | 77 | } catch (final com.amazonaws.AmazonServiceException e) { 78 | if (ErrorType.is(e, ErrorCode.INVALID_CLIENT_TOKEN_ID, HttpStatus.SC_FORBIDDEN)) { 79 | Log.warning("Failed to send receive message request for %s, %s", this.queue, e.getMessage()); 80 | throw e; 81 | } 82 | 83 | Log.severe(e, "Failed to send receive message request for %s", this.queue); 84 | } 85 | return Collections.emptyList(); 86 | } 87 | 88 | @Override 89 | public void deleteMessages(final List messages) { 90 | if (messages == null || messages.size() == 0) { 91 | return; 92 | } 93 | 94 | final DeleteMessageBatchResult result = this.deleteMessageBatch(messages); 95 | 96 | if (result == null) { 97 | return; 98 | } 99 | 100 | final List failed = result.getFailed(); 101 | final List success = result.getSuccessful(); 102 | Log.info("Deleted %d message(s) (%d failed) from %s", success.size(), failed.size(), this.queue); 103 | } 104 | 105 | @Override 106 | public String getQueueUuid() { 107 | return this.queue.getUuid(); 108 | } 109 | 110 | @Override 111 | public String toString() { 112 | return this.queue.toString(); 113 | } 114 | 115 | private void logRequestCount() { 116 | this.requestCount++; 117 | Log.fine("Send receive message request #%d for %s", this.requestCount, this.queue); 118 | } 119 | 120 | private DeleteMessageBatchResult deleteMessageBatch(final List messages) { 121 | try { 122 | final DeleteMessageBatchRequest request = this.factory.createDeleteMessageBatchRequest(this.queue, messages); 123 | Log.info("Send delete request for %d message(s) to %s", messages.size(), this.queue); 124 | return this.sqs.deleteMessageBatch(request); 125 | 126 | } catch (final com.amazonaws.AmazonServiceException e) { 127 | Log.severe(e, "Delete from %s failed", this.queue); 128 | 129 | } 130 | return null; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/threading/ExecutorProviderImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.threading; 18 | 19 | import com.google.inject.Inject; 20 | 21 | import java.util.concurrent.ExecutorService; 22 | import java.util.concurrent.ThreadPoolExecutor; 23 | 24 | import io.relution.jenkins.awssqs.interfaces.ExecutorProvider; 25 | 26 | 27 | public class ExecutorProviderImpl implements ExecutorProvider { 28 | 29 | private final ThreadPoolExecutor executor; 30 | 31 | @Inject 32 | public ExecutorProviderImpl(final io.relution.jenkins.awssqs.interfaces.ExecutorFactory factory) { 33 | this.executor = factory.createExecutor(); 34 | } 35 | 36 | @Override 37 | public int getCorePoolSize() { 38 | return this.executor.getCorePoolSize(); 39 | } 40 | 41 | @Override 42 | public void setCorePoolSize(final int corePoolSize) throws IllegalArgumentException { 43 | this.executor.setCorePoolSize(corePoolSize); 44 | } 45 | 46 | @Override 47 | public ExecutorService get() { 48 | return this.executor; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/threading/SQSQueueMonitorImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.threading; 18 | 19 | import com.amazonaws.services.sqs.model.Message; 20 | import jenkins.model.Jenkins; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.concurrent.ExecutorService; 25 | import java.util.concurrent.atomic.AtomicBoolean; 26 | 27 | import io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor; 28 | import io.relution.jenkins.awssqs.logging.Log; 29 | import io.relution.jenkins.awssqs.net.SQSChannel; 30 | 31 | 32 | public class SQSQueueMonitorImpl implements SQSQueueMonitor { 33 | 34 | private final static String ERROR_WRONG_QUEUE = "The specified listener is associated with another queue."; 35 | 36 | private final ExecutorService executor; 37 | 38 | private final io.relution.jenkins.awssqs.interfaces.SQSQueue queue; 39 | private final SQSChannel channel; 40 | 41 | private final Object listenersLock = new Object(); 42 | private final List listeners; 43 | 44 | private final AtomicBoolean isRunning = new AtomicBoolean(); 45 | private volatile boolean isShutDown; 46 | private final Jenkins jenkins = Jenkins.getInstance(); 47 | 48 | public SQSQueueMonitorImpl(final ExecutorService executor, final io.relution.jenkins.awssqs.interfaces.SQSQueue queue, final SQSChannel channel) { 49 | io.relution.jenkins.awssqs.util.ThrowIf.isNull(executor, "executor"); 50 | io.relution.jenkins.awssqs.util.ThrowIf.isNull(channel, "channel"); 51 | 52 | this.executor = executor; 53 | 54 | this.queue = queue; 55 | this.channel = channel; 56 | 57 | this.listeners = new ArrayList<>(); 58 | } 59 | 60 | private SQSQueueMonitorImpl(final ExecutorService executor, 61 | final io.relution.jenkins.awssqs.interfaces.SQSQueue queue, 62 | final SQSChannel channel, 63 | final List listeners) { 64 | io.relution.jenkins.awssqs.util.ThrowIf.isNull(executor, "executor"); 65 | io.relution.jenkins.awssqs.util.ThrowIf.isNull(channel, "channel"); 66 | 67 | this.executor = executor; 68 | 69 | this.queue = queue; 70 | this.channel = channel; 71 | 72 | this.listeners = listeners; 73 | } 74 | 75 | @Override 76 | public SQSQueueMonitor clone(final io.relution.jenkins.awssqs.interfaces.SQSQueue queue, final SQSChannel channel) { 77 | synchronized (this.listenersLock) { 78 | return new SQSQueueMonitorImpl(this.executor, queue, channel, this.listeners); 79 | } 80 | } 81 | 82 | @Override 83 | public boolean add(final io.relution.jenkins.awssqs.interfaces.SQSQueueListener listener) { 84 | io.relution.jenkins.awssqs.util.ThrowIf.isNull(listener, "listener"); 85 | io.relution.jenkins.awssqs.util.ThrowIf.notEqual(listener.getQueueUuid(), this.channel.getQueueUuid(), ERROR_WRONG_QUEUE); 86 | 87 | synchronized (this.listenersLock) { 88 | if (this.listeners.add(listener) && this.listeners.size() == 1) { 89 | this.isShutDown = false; 90 | this.execute(); 91 | return true; 92 | } 93 | } 94 | return false; 95 | } 96 | 97 | @Override 98 | public boolean remove(final io.relution.jenkins.awssqs.interfaces.SQSQueueListener listener) { 99 | if (listener == null) { 100 | return false; 101 | } 102 | 103 | synchronized (this.listenersLock) { 104 | if (this.listeners.remove(listener) && this.listeners.isEmpty()) { 105 | this.shutDown(); 106 | return true; 107 | } 108 | } 109 | return false; 110 | } 111 | 112 | @Override 113 | public void run() { 114 | try { 115 | if (this.isShutDown) { 116 | return; 117 | } 118 | 119 | if (!this.isRunning.compareAndSet(false, true)) { 120 | Log.warning("Monitor for %s already started", this.channel); 121 | return; 122 | } 123 | 124 | Log.fine("Start synchronous monitor for %s", this.channel); 125 | 126 | if (this.isQuietingDown()) { 127 | Log.info("Skipping %s since Jenkins is preparing for shutdown", this.channel); 128 | Thread.sleep(15000); 129 | return; 130 | } 131 | 132 | final int currentJobQueueSize = this.countBuildableItems(); 133 | final int maxJobQueueSize = this.queue.getMaxNumberOfJobQueue(); 134 | if (currentJobQueueSize > maxJobQueueSize) { 135 | Log.info("Skipping %s - Jenkins build queue %d is greater than configured %d", this.channel, currentJobQueueSize, maxJobQueueSize); 136 | Thread.sleep(15000); 137 | return; 138 | } 139 | this.processMessages(); 140 | } catch (final com.amazonaws.services.sqs.model.QueueDoesNotExistException e) { 141 | Log.warning("Queue %s does not exist, monitor stopped", this.channel); 142 | this.isShutDown = true; 143 | 144 | } catch (final com.amazonaws.AmazonServiceException e) { 145 | Log.warning("Service error for queue %s, monitor stopped", this.channel); 146 | this.isShutDown = true; 147 | 148 | } catch (final Exception e) { 149 | Log.severe(e, "Unknown error, monitor for queue %s stopped", this.channel); 150 | this.isShutDown = true; 151 | 152 | } finally { 153 | if (!this.isRunning.compareAndSet(true, false)) { 154 | Log.warning("Monitor for %s already stopped", this.channel); 155 | } 156 | this.execute(); 157 | } 158 | } 159 | 160 | @Override 161 | public void shutDown() { 162 | Log.info("Shut down monitor for %s", this.channel); 163 | this.isShutDown = true; 164 | } 165 | 166 | @Override 167 | public boolean isShutDown() { 168 | return this.isShutDown; 169 | } 170 | 171 | @Override 172 | public io.relution.jenkins.awssqs.interfaces.SQSQueue getQueue() { 173 | return this.queue; 174 | } 175 | 176 | @Override 177 | public SQSChannel getChannel() { 178 | return this.channel; 179 | } 180 | 181 | private void execute() { 182 | if (!this.isShutDown) { 183 | this.executor.execute(this); 184 | } 185 | } 186 | 187 | private boolean isQuietingDown() { 188 | return (jenkins != null ? jenkins.isQuietingDown() : false); 189 | } 190 | 191 | private int countBuildableItems() { 192 | return (jenkins != null ? jenkins.getQueue().countBuildableItems() : 0); 193 | } 194 | 195 | private void processMessages() { 196 | final List messages = this.channel.getMessages(); 197 | 198 | if (this.isShutDown) { 199 | return; 200 | } 201 | 202 | if (this.notifyListeners(messages) && !this.queue.isKeepQueueMessages()) { 203 | this.channel.deleteMessages(messages); 204 | } else if (!messages.isEmpty() && this.queue.isKeepQueueMessages()) { 205 | try { 206 | Thread.sleep(2000); 207 | } catch (InterruptedException ex) { 208 | Log.warning("Exception %s occurred while sleeping after message retrieval on %s", ex.toString(), this.channel); 209 | } 210 | } 211 | } 212 | 213 | private boolean notifyListeners(final List messages) { 214 | if (messages.isEmpty()) { 215 | Log.fine("Received no messages from %s", this.channel); 216 | return false; 217 | } 218 | 219 | Log.info("Received %d message(s) from %s", messages.size(), this.channel); 220 | final List listeners = this.getListeners(); 221 | 222 | for (final io.relution.jenkins.awssqs.interfaces.SQSQueueListener listener : listeners) { 223 | listener.handleMessages(messages); 224 | } 225 | 226 | return true; 227 | } 228 | 229 | private List getListeners() { 230 | synchronized (this.listenersLock) { 231 | return new ArrayList<>(this.listeners); 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/threading/SQSQueueMonitorSchedulerImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.threading; 18 | 19 | import com.google.common.eventbus.Subscribe; 20 | import com.google.inject.Inject; 21 | 22 | import org.apache.commons.lang3.StringUtils; 23 | 24 | import java.util.HashMap; 25 | import java.util.Iterator; 26 | import java.util.Map; 27 | import java.util.Map.Entry; 28 | import java.util.concurrent.ExecutorService; 29 | 30 | import io.relution.jenkins.awssqs.interfaces.SQSFactory; 31 | import io.relution.jenkins.awssqs.interfaces.SQSQueue; 32 | import io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor; 33 | import io.relution.jenkins.awssqs.interfaces.SQSQueueMonitorScheduler; 34 | import io.relution.jenkins.awssqs.interfaces.SQSQueueProvider; 35 | import io.relution.jenkins.awssqs.logging.Log; 36 | import io.relution.jenkins.awssqs.model.events.ConfigurationChangedEvent; 37 | import io.relution.jenkins.awssqs.model.events.EventBroker; 38 | import io.relution.jenkins.awssqs.util.ThrowIf; 39 | 40 | 41 | public class SQSQueueMonitorSchedulerImpl implements SQSQueueMonitorScheduler { 42 | 43 | private final ExecutorService executor; 44 | private final SQSQueueProvider provider; 45 | private final SQSFactory factory; 46 | 47 | private final Map monitors = new HashMap<>(); 48 | 49 | @Inject 50 | public SQSQueueMonitorSchedulerImpl(final ExecutorService executor, final SQSQueueProvider provider, final SQSFactory factory) { 51 | this.executor = executor; 52 | this.provider = provider; 53 | this.factory = factory; 54 | 55 | EventBroker.getInstance().register(this); 56 | } 57 | 58 | @Override 59 | public boolean register(final io.relution.jenkins.awssqs.interfaces.SQSQueueListener listener) { 60 | ThrowIf.isNull(listener, "listener"); 61 | 62 | Log.info("Register SQS listener"); 63 | final String uuid = listener.getQueueUuid(); 64 | final SQSQueue queue = this.provider.getSqsQueue(uuid); 65 | 66 | if (queue == null) { 67 | Log.warning("No queue for {%s}, aborted", uuid); 68 | return false; 69 | } 70 | 71 | this.register(listener, uuid, queue); 72 | return true; 73 | } 74 | 75 | @Override 76 | public synchronized boolean unregister(final io.relution.jenkins.awssqs.interfaces.SQSQueueListener listener) { 77 | if (listener == null) { 78 | return false; 79 | } 80 | 81 | Log.info("Unregister SQS listener"); 82 | final String uuid = listener.getQueueUuid(); 83 | final SQSQueueMonitor monitor = this.monitors.get(uuid); 84 | 85 | if (monitor == null) { 86 | Log.warning("No monitor for {%s}, aborted", uuid); 87 | return false; 88 | } 89 | 90 | Log.info("Remove listener from monitor for {%s}", uuid); 91 | if (monitor.remove(listener)) { 92 | monitor.shutDown(); 93 | } 94 | 95 | if (monitor.isShutDown()) { 96 | Log.info("Monitor is shut down, remove monitor for {%s}", uuid); 97 | this.monitors.remove(uuid); 98 | } 99 | 100 | return true; 101 | } 102 | 103 | @Override 104 | @Subscribe 105 | public synchronized void onConfigurationChanged(final ConfigurationChangedEvent event) { 106 | final Iterator> entries = this.monitors.entrySet().iterator(); 107 | 108 | while (entries.hasNext()) { 109 | final Entry entry = entries.next(); 110 | this.reconfigure(entries, entry); 111 | } 112 | } 113 | 114 | private synchronized void register(final io.relution.jenkins.awssqs.interfaces.SQSQueueListener listener, final String uuid, final SQSQueue queue) { 115 | SQSQueueMonitor monitor = this.monitors.get(uuid); 116 | 117 | if (monitor == null) { 118 | Log.info("No monitor exists, creating new monitor for %s", queue); 119 | monitor = this.factory.createMonitor(this.executor, queue); 120 | this.monitors.put(uuid, monitor); 121 | } 122 | 123 | Log.info("Add listener to monitor for %s", queue); 124 | monitor.add(listener); 125 | } 126 | 127 | private void reconfigure(final Iterator> entries, final Entry entry) { 128 | final String uuid = entry.getKey(); 129 | SQSQueueMonitor monitor = entry.getValue(); 130 | final SQSQueue queue = this.provider.getSqsQueue(uuid); 131 | 132 | if (queue == null) { 133 | Log.info("Queue {%s} removed, shut down monitor", uuid); 134 | monitor.shutDown(); 135 | entries.remove(); 136 | } else if (monitor.isShutDown() || this.hasQueueChanged(monitor, queue)) { 137 | Log.info("Queue {%s} changed or monitor stopped, create new monitor", uuid); 138 | monitor = this.factory.createMonitor(monitor, queue); 139 | entry.setValue(monitor).shutDown(); 140 | this.executor.execute(monitor); 141 | } 142 | } 143 | 144 | private boolean hasQueueChanged(final SQSQueueMonitor monitor, final SQSQueue queue) { 145 | try { 146 | final SQSQueue current = monitor.getQueue(); 147 | 148 | if (!StringUtils.equals(current.getUrl(), queue.getUrl())) { 149 | return true; 150 | } 151 | 152 | if (!StringUtils.equals(current.getAWSAccessKeyId(), queue.getAWSAccessKeyId())) { 153 | return true; 154 | } 155 | 156 | if (!StringUtils.equals(current.getAWSSecretKey(), queue.getAWSSecretKey())) { 157 | return true; 158 | } 159 | 160 | if (current.getMaxNumberOfMessages() != queue.getMaxNumberOfMessages()) { 161 | return true; 162 | } 163 | 164 | if (current.getMaxNumberOfJobQueue() != queue.getMaxNumberOfJobQueue()) { 165 | return true; 166 | } 167 | 168 | if (current.isKeepQueueMessages() != queue.isKeepQueueMessages()) { 169 | return true; 170 | } 171 | 172 | if (current.getWaitTimeSeconds() != queue.getWaitTimeSeconds()) { 173 | return true; 174 | } 175 | 176 | return false; 177 | } catch (final com.amazonaws.AmazonServiceException e) { 178 | Log.warning("Cannot compare queues: %s", e.getMessage()); 179 | } catch (final Exception e) { 180 | Log.severe(e, "Cannot compare queues, unknown error"); 181 | } 182 | return true; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/util/ErrorType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.util; 18 | 19 | import com.amazonaws.AmazonServiceException; 20 | 21 | import org.apache.commons.lang3.StringUtils; 22 | 23 | 24 | /** 25 | * Provides static methods that can be used to filter exceptions based on their properties. 26 | */ 27 | public class ErrorType { 28 | 29 | /** 30 | * Returns a value indicating whether the specified service exception has the specified error 31 | * code and HTTP status. 32 | * @param e The {@link AmazonServiceException} to test. 33 | * @param errorCode The error code to match, can be {@code null}. 34 | * @param httpStatus The HTTP status to match. Use {@code -1} to match any HTTP status. 35 | * @return {@code true} if the specified exception has the specified error code and HTTP status; 36 | * otherwise, {@code false}. 37 | */ 38 | public static boolean is(final AmazonServiceException e, final String errorCode, final int httpStatus) { 39 | if (e == null) { 40 | return false; 41 | } 42 | 43 | if (errorCode != null && !StringUtils.equals(errorCode, e.getErrorCode())) { 44 | return false; 45 | } 46 | 47 | if (httpStatus != -1 && e.getStatusCode() != httpStatus) { 48 | return false; 49 | } 50 | 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/util/JobInfoHelpers.java: -------------------------------------------------------------------------------- 1 | package io.relution.jenkins.awssqs.util; 2 | 3 | import hudson.model.AbstractProject; 4 | import hudson.model.Job; 5 | import jenkins.model.ParameterizedJobMixIn; 6 | 7 | /** 8 | * Job utility class. 9 | */ 10 | public class JobInfoHelpers { 11 | 12 | private JobInfoHelpers() { 13 | throw new IllegalAccessError("Do not instantiate it"); 14 | } 15 | 16 | /** 17 | * This method converts any child class of {@link Job} (ie, {@link AbstractProject} 18 | * to {@link ParameterizedJobMixIn} to use it in workflow 19 | * 20 | * @param job to wrap 21 | * @param any child type of Job 22 | * 23 | * @return ParameterizedJobMixIn 24 | */ 25 | public static ParameterizedJobMixIn asParameterizedJobMixIn(final T job) { 26 | return new ParameterizedJobMixIn() { 27 | @Override 28 | protected Job asJob() { 29 | return job; 30 | } 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/relution/jenkins/awssqs/util/ThrowIf.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.util; 18 | 19 | import java.util.Objects; 20 | 21 | 22 | /** 23 | * This class consists of {@code static} utility methods usable for argument validation. 24 | */ 25 | public class ThrowIf { 26 | 27 | private static final String IS_NULL = "The specified argument is null: %s"; 28 | 29 | private static final String NOT_EQUAL = "The specified argument does not match the expected value of \"%s\", actual value: \"%s\""; 30 | 31 | /** 32 | * Throws an {@link IllegalArgumentException} if {@code o} is {@code null}. 33 | * @param o The object to test for {@code null}. 34 | * @param name The name of the argument. 35 | * @throws IllegalArgumentException If {@code o} is {@code null}. 36 | */ 37 | public static void isNull(final Object o, final String name) { 38 | if (o == null) { 39 | final String msg = String.format(IS_NULL, name); 40 | throw new IllegalArgumentException(msg); 41 | } 42 | } 43 | 44 | /** 45 | * Throws an {@link IllegalArgumentException} if {@code argument} is not equal to {@code value}. 46 | * @param argument The argument to test for equality with {@code value}. 47 | * @param value The value {@code argument} needs to be equal to. 48 | * @throws IllegalArgumentException If {@code argument} is not equal to {@code value}. 49 | * @see #notEqual(Object, Object, String, Object...) 50 | */ 51 | public static void notEqual(final Object argument, final Object value) { 52 | notEqual(argument, value, NOT_EQUAL, value, argument); 53 | } 54 | 55 | /** 56 | * Throws an {@link IllegalArgumentException} if {@code argument} is not equal to {@code value}. 57 | * @param argument The argument to test for equality with {@code value}. 58 | * @param value The value {@code argument} needs to be equal to. 59 | * @param format The detail message for the exception. 60 | * @param args Optional arguments supplied to the detail message. 61 | * @throws IllegalArgumentException If {@code argument} is not equal to {@code value}. 62 | * @see #notEqual(Object, Object) 63 | */ 64 | public static void notEqual(final Object argument, final Object value, final String format, final Object... args) { 65 | if (!Objects.equals(argument, value)) { 66 | final String msg = String.format(format, args); 67 | throw new IllegalArgumentException(msg); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 |

19 | This plugin triggers builds on all events received via Amazon Web 20 | Services Simple Queue Service (AWS SQS) on a specified Queue. 21 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/config.jelly: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | 27 | 28 | 29 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/config_de.properties: -------------------------------------------------------------------------------- 1 | SQS\ queue\ to\ monitor=Zu \u00fcberwachende SQS Queue 2 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/config_ru.properties: -------------------------------------------------------------------------------- 1 | SQS\ queue\ to\ monitor=\u041e\u0447\u0435\u0440\u0435\u0434\u044c SQS \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/global.jelly: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | 25 | 26 | 27 | 28 | 32 |
33 | 36 | 37 |
38 | 42 | 47 |
48 |
49 |
50 | 51 | 52 | 53 |
54 |
55 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/global_de.properties: -------------------------------------------------------------------------------- 1 | Configuration\ of\ Amazon\ SQS\ queues=Konfiguration von Amazon SQS Queues 2 | Add=Hinzuf\u00fcgen 3 | Delete=L\u00f6schen 4 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/global_ru.properties: -------------------------------------------------------------------------------- 1 | Configuration\ of\ Amazon\ SQS\ queues=\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 Amazon SQS 2 | Add=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c 3 | Delete=\u0423\u0434\u0430\u043b\u0438\u0442\u044c -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help-disableCodeCommit.html: -------------------------------------------------------------------------------- 1 |
2 | If enable this checkbox then Trigger build without CodeCommit check. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help-disableCodeCommit_du.html: -------------------------------------------------------------------------------- 1 |
2 | Wenn dieses Kontrollkästchen aktiviert ist, wird die Option Build ohne CodeCommit auslösen aktiviert. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help-disableCodeCommit_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Если этот флажок включен, то Trigger build без проверки CodeCommit. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help-queueUuid.html: -------------------------------------------------------------------------------- 1 |
2 | The Amazon SQS queue to monitor for messages. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help-queueUuid_de.html: -------------------------------------------------------------------------------- 1 |
2 | Amazon SQS Queue die auf Nachrichten überwacht werden soll. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help-queueUuid_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Отслеживание очереди SQS сообщений на Amazon. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help.html: -------------------------------------------------------------------------------- 1 |
2 | Configure Jenkins to monitor an Amazon SQS queue for messages. Jenkins will start a new build 3 | if a message is posted to the queue. 4 |

5 | Available queues can be configured in the System Configuration of 6 | Jenkins. 7 |

8 | Further documentation is available in the 9 | AWS SQS Plugin on GitHub. 10 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help_de.html: -------------------------------------------------------------------------------- 1 |
2 | Konfiguriert Jenkins dafür eine Amazon SQS Queue auf Nachrichten zu überwachen. Jenkins wird ein 3 | neues Build starten, wenn eine Nachricht in der Queue abgelegt wurde und der Inhalt der Nachricht 4 | mit dem Repository und dem Branch dieses Jobs übereinstimmt. Das Repository sollte so konfiguriert 5 | sein, dass es bei Änderungen Nachrichten in der Queue ablegt. 6 |

7 | Verfügbare Queues können in der System Konfiguration von Jenkins 8 | konfiguriert werden. 9 |

10 | Weiterführende Dokumentation ist im 11 | AWS SQS Plugin auf GitHub 12 | verfügbar. 13 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTrigger/help_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Настройте Дженкинс отслеживать сообщения из очереди Amazon SQS. 3 | Дженкинс начнет новую сборку после того, как сообщение будет помещено в очередь. 4 |

5 | Доступные очереди можно настроить в разделе Настроить Jenkins 6 |

7 | Дополнительная документация доступна по адресу 8 | AWS SQS Plugin на GitHub. 9 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/config.jelly: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 40 | 41 | 44 | 45 | 46 | 49 | 50 | 51 | 54 | 55 | 56 | 59 | 60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/config_de.properties: -------------------------------------------------------------------------------- 1 | Amazon\ SQS\ queue=Amazon SQS Queue 2 | Queue\ name\ or\ URL=Queue Name oder URL 3 | Credentials=Anmeldeinformationen 4 | Test\ access=Zugang pr\u00fcfen 5 | Advanced=Erweitert 6 | Request\ wait\ time\ [s]=Wartezeit f\u00fcr Requests [s] 7 | Max.\ number\ of\ messages=Max. Anzahl an Nachrichten 8 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/config_ru.properties: -------------------------------------------------------------------------------- 1 | Amazon\ SQS\ queue=\u041e\u0447\u0435\u0440\u0435\u0434\u044c Amazon SQS 2 | Queue\ name\ or\ URL=\u0418\u043c\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0438\u043b\u0438 URL 3 | Credentials=\u041a\u043b\u044e\u0447 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 AWS (Access Key) 4 | Test\ access=\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f 5 | Advanced=\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e 6 | Request\ wait\ time\ [s]=\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 [\u0441\u0435\u043a] 7 | Max.\ number\ of\ messages=\u041c\u0430\u043a\u0441. \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 8 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-credentialsId.html: -------------------------------------------------------------------------------- 1 |
2 | The AWS access key for the message queue. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-credentialsId_de.html: -------------------------------------------------------------------------------- 1 |
2 | AWS Access Key (Zugangsschlüssel) für eine Nachrichtenwarteschlange. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-credentialsId_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Ключ доступа AWS (access key) к очереди сообщений. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-keepQueueMessages.html: -------------------------------------------------------------------------------- 1 |
2 | By default messages will be deleted from SQS after they are retrieved. Enable this setting if you would like messages to not 3 | be removed from SQS after retrieval. Your job configuration will probably want to remove these messages or they will be 4 | retrieved again after the visibility timeout passes. 5 |

6 | The goal is to prevent messages from going unprocessed when something crashes before the Jenkins job completes. 7 |

8 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-maxNumberOfJobQueue.html: -------------------------------------------------------------------------------- 1 |
2 | The maximum number of buildable items in the build job queue before pausing the retrieval of SQS messages. 3 | Values can be from 0 (don't pull messages from SQS when there is a build job queue) to 100,000. Default is 1000. Pause set to 4 | 15 seconds. 5 |

6 | The goal is to prevent overloading a busy Jenkins master that has a build queue with additional work. 7 |

8 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-maxNumberOfMessages.html: -------------------------------------------------------------------------------- 1 |
2 | The maximum number of messages to receive per request. Amazon SQS never returns more messages than 3 | this value but may return fewer. Values can be from 1 to 10. Default is 10. 4 |

5 | All of the messages are not necessarily returned. 6 |

7 | Larger values can reduce the number of requests that need to be sent if multiple messages are 8 | available. It is recommended to use the maximum value. Reduce the value only if you experience 9 | issues and are certain that a smaller number fixes them. 10 |

11 | See also: 12 | 13 | API ReceiveMessage 14 |
15 | See also: 16 | Amazon SQS – Long 17 | Polling and Request Batching / Client-Side Buffering 18 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-maxNumberOfMessages_de.html: -------------------------------------------------------------------------------- 1 |
2 | Die maximale Anzahl an Nachrichten die pro Request empfangen werden soll. Amazon SQS liefert 3 | nie mehr Nachrichten als diesen Wert zurück, kann aber weniger zurückliefern. Zulässige Werte 4 | gehen von 1 bis 10. Standard sind 10. 5 |

6 | Es werden möglicherweise nicht immer alle Nachrichten zurückgeliefert. 7 |

8 | Größere Werte reduzieren die Anzahl an Requests die gesendet werden müssen, wenn mehrere Nachrichten 9 | verfügbar sind. Es wird empfohlen den maximalen Wert zu verwenden. Reduzieren Sie diesen Wert nur, 10 | wenn es zu Problemen kommt und Sie sicher sind, dass diese durch einen kleineren Wert behoben 11 | werden. 12 |

13 | Siehe auch: 14 | 15 | API ReceiveMessage 16 |
17 | Siehe auch: 18 | Amazon SQS – Long 19 | Polling and Request Batching / Client-Side Buffering 20 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-maxNumberOfMessages_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Максимальное количество принятых сообщений за один запрос. 3 | Amazon SQS не вернёт больше сообщений за запрос, но может быть вернёт меньше. Значения могут быть от 1 до 10. По умолчанию стоит 10. 4 |

5 | Нет гарантии что ВСЕ сообщения обязательно вернутся. 6 |

7 | Более высокие значения сокращают количество запросов, которые нужно выслать. Рекомендуется использовать наивысшее значение. Уменьшайте его только если проблемы стабильности действительно решаются меньшими значениями. 8 | 9 |

10 | Смотреть также: 11 | 12 | API ReceiveMessage 13 |
14 | Смотреть также: 15 | Amazon SQS – Долгое ожидание и Дозирование Запросов/Буфферизация со стороны клиента 16 |

17 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-nameOrUrl.html: -------------------------------------------------------------------------------- 1 |
2 | The name or URL of a message queue that exists on the Amazon Simple Queue Service (SQS). The 3 | plugin will trigger builds whenever a message is posted to this queue. 4 |

5 | The queue will not be actively monitored until you have configured at least one job to listen to 6 | messages from this queue. See the build trigger configuration of individual jobs. 7 |

8 | Further documentation is available in the 9 | AWS SQS Plugin on GitHub. 10 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-nameOrUrl_de.html: -------------------------------------------------------------------------------- 1 |
2 | Name oder URL einer Nachrichtenwarteschlange die im Amazon Simple Queue Service (SQS) angelegt 3 | wurde. Das Plugin startet Builds wenn Nachrichten in dieser Queue abgelegt werden. 4 |

5 | Die Queue wird nicht aktiv überwacht, bis mindestens ein Job so konfiguriert wurde, dass er auf 6 | Nachrichten aus dieser Queue horcht. Siehe Build Trigger Konfiguration von Jobs. 7 |

8 | Weiterführende Dokumentation ist im 9 | AWS SQS Plugin auf GitHub 10 | verfügbar. 11 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-nameOrUrl_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Имя или URL-адрес очереди сообщений, существующей в службе Amazon Simple Queue Service (SQS). 3 | Плагин будет запускать сборку, когда сообщение опубликовано в этой очереди. 4 |

5 | Очередь не будет активно отслеживаться до тех пор, пока не будет настроено хотя бы одно задание для прослушивания 6 | сообщений из этой очереди. Смотрите конфигурации триггера сборки отдельных задач. 7 |

8 | Дополнительная документация доступна по адресу 9 | AWS SQS Plugin на GitHub. 10 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-uuid.html: -------------------------------------------------------------------------------- 1 |
2 | The universally unique identifier (UUID) of the Amazon SQS message queue. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-uuid_de.html: -------------------------------------------------------------------------------- 1 |
2 | Der universally unique identifier (UUID) der Amazon SQS-Nachrichten-queue. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-uuid_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Универсальный уникальный идентификатор (UUID) очереди сообщений Amazon SQS. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-waitTimeSeconds.html: -------------------------------------------------------------------------------- 1 |
2 | The time, in seconds, to wait for a message to arrive in the queue (long polling). Values can be 3 | from 1 to 20. Default is 20. 4 |

5 | Larger values reduce the number of requests that need to be sent. It is recommended to use the 6 | maximum value. Reduce the value only if you experience issues and are certain that a shorter 7 | request timeout fixes them. 8 |

9 | See also: 10 | 11 | Amazon SQS Long Polling 12 |
13 | See also: 14 | Amazon SQS – Long 15 | Polling and Request Batching / Client-Side Buffering 16 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-waitTimeSeconds_de.html: -------------------------------------------------------------------------------- 1 |
2 | Zeit, in Sekunden, die auf die Ankunft von Nachrichten in der Queue gewartet werden soll (Long 3 | Polling). Zulässige Werte gehen von 1 bis 20. Standard sind 20. 4 |

5 | Größere Werte reduzieren die Anzahl an Requests die gesendet werden müssen. Es wird empfohlen den 6 | maximalen Wert zu verwenden. Reduzieren Sie diesen Wert nur, wenn es zu Problemen kommt und Sie 7 | sicher sind, dass diese durch einen kleineren Wert behoben werden. 8 |

9 | Siehe auch (Englisch):
10 | 11 | Amazon SQS Long Polling 12 |
13 | See also: 14 | Amazon SQS – Long 15 | Polling and Request Batching / Client-Side Buffering 16 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/SQSTriggerQueue/help-waitTimeSeconds_ru.html: -------------------------------------------------------------------------------- 1 |
2 | Время ожидания прихода сообщения в очереди в секундах (долгое ожидание). Значения могут быть от 1 до 20. Значение по умолчанию - 20. 3 |

4 | Более высокие значения сокращают количество запросов, которые нужно выслать. Рекомендуется использовать наивысшее значение. Уменьшайте его только если проблемы стабильности действительно решаются меньшими значениями. 5 | 6 |

7 | Смотреть также: 8 | Долгое ожидание Amazon SQS 9 |
10 | Смотреть также: 11 | Amazon SQS – Долгое ожидание и дозирование запросов/Буфферизация со стороны клиента 12 |

-------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/i18n/sqstrigger/Messages.properties: -------------------------------------------------------------------------------- 1 | displayName=Trigger build when a message is published to an Amazon SQS queue 2 | 3 | errorQueueUnavailable=No queues have been configured. Add at least one queue to the global \ 4 | Jenkins configuration. 5 | 6 | errorQueueUuidUnknown=The previously selected queue no longer exists. Select a new queue and \ 7 | save the configuration. 8 | 9 | infoQueueDefault=Selected first available queue. Verify the selection and save the configuration. 10 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/i18n/sqstrigger/Messages_de.properties: -------------------------------------------------------------------------------- 1 | displayName=Build starten, wenn eine Nachricht in einer Amazon SQS Queue ver\u00f6ffentlicht wird 2 | 3 | errorQueueUnavailable=Es sind keine Queues konfiguriert. F\u00fcgen Sie der globalen Jenkins \ 4 | Konfiguration mindestens eine Queue hinzu. 5 | 6 | errorQueueUuidUnknown=Die zuletzt ausgew\u00e4hlte Queue existiert nicht mehr. W\u00e4hlen Sie eine neue \ 7 | Queue und speichern Sie die Konfiguration. 8 | 9 | infoQueueDefault=Erste verf\u00fcgbare Queue ausgew\u00e4hlt. Pr\u00fcfen Sie die Auswahl und speichern Sie die \ 10 | Konfiguration. -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/i18n/sqstrigger/Messages_ru.properties: -------------------------------------------------------------------------------- 1 | displayName=\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 Amazon SQS 2 | 3 | errorQueueUnavailable=\u041d\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u043e\u0447\u0435\u0440\u0435\u0434\u0438. \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0434\u043d\u0443 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0432 \n \u041e\u0431\u0449\u0438\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 4 | 5 | errorQueueUuidUnknown=\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0440\u0430\u043d\u0435\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442. \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u0443\u044e \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. 6 | 7 | infoQueueDefault=\u0412\u044b\u0431\u0440\u0430\u043d\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0432\u044b\u0431\u043e\u0440 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. 8 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/i18n/sqstriggerqueue/Messages.properties: -------------------------------------------------------------------------------- 1 | displayName=An Amazon SQS queue configuration 2 | errorWaitTimeSeconds=Wait Time must be a number between 1 and 20 3 | errorMaxNumberOfMessages=Max. number of messages must be a number between 1 and 10 4 | errorMaxNumberOfJobQueue=Max. number of buildable items in the job queue must be a number between 0 and 100000 5 | infoUrlSqs=You can use \"%s\" instead of the full URL 6 | warningUrl=Name or URL of an SQS queue is required 7 | errorUrlCodecommit=This is a CodeCommit URL, please provide a queue name or SQS URL 8 | errorUrlUnknown=This is not an SQS URL, please provide a queue name or SQS URL 9 | errorUuid=UUID is not unique 10 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/i18n/sqstriggerqueue/Messages_de.properties: -------------------------------------------------------------------------------- 1 | displayName=Eine Amazon SQS Queue Konfiguration 2 | errorWaitTimeSeconds=Wartezeit muss eine Zahl zwischen 1 und 20 sein 3 | errorMaxNumberOfMessages=Max. Anzahl an Nachrichten muss eine Zahl zwischen 1 und 10 sein 4 | infoUrlSqs=Sie können \"%s\" anstelle der vollständigen URL verwenden 5 | warningUrl=Name oder URL einer SQS Queue ist erforderlich 6 | errorUrlCodecommit=Dies ist eine CodeCommit URL, bitte Name einer Queue oder SQS URL angeben 7 | errorUrlUnknown=Dies ist keine SQS URL, bitte Name einer Queue oder SQS URL angeben 8 | errorUuid=UUID ist nicht einzigartig 9 | errorMaxNumberOfJobQueue=Max. Anzahl der Build-Aufgaben in der Build-Warteschlange muss eine Zahl zwischen 0 und 100000 sein 10 | -------------------------------------------------------------------------------- /src/main/resources/io/relution/jenkins/awssqs/i18n/sqstriggerqueue/Messages_ru.properties: -------------------------------------------------------------------------------- 1 | displayName=\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 Amazon SQS 2 | errorWaitTimeSeconds=\u0420\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u044b\u0439 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0442\u0430\u0439\u043c\u0430\u0443\u0442\u043e\u0432 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0447\u0438\u0441\u043b\u043e\u043c \u043e\u0442 1 \u0434\u043e 20 3 | errorMaxNumberOfMessages=\u0420\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0447\u0438\u0441\u043b\u043e\u043c \u043e\u0442 1 \u0434\u043e 10 4 | infoUrlSqs=\u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \"%s\" \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0433\u043e URL 5 | warningUrl=\u0418\u043c\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0438\u043b\u0438 \u043f\u043e\u043b\u043d\u044b\u0439 URL \u043e\u0447\u0435\u0440\u0435\u0434\u0438 SQS \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b 6 | errorUrlCodecommit=\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 CodeCommit URL, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430 \u0438\u043c\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 SQS \u0438\u043b\u0438 \u0435\u0435 \u043f\u043e\u043b\u043d\u043e\u0435 URL 7 | errorUrlUnknown=\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 SQS, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430 \u0438\u043c\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u0438 SQS \u0438\u043b\u0438 \u0435\u0435 \u043f\u043e\u043b\u043d\u043e\u0435 URL 8 | errorUuid=\u0412\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0439 UUID \u043d\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u0435\u043d 9 | -------------------------------------------------------------------------------- /src/test/java/io/relution/jenkins/awssqs/SQSTriggerQueueDescriptorImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | import org.junit.Test; 22 | 23 | import hudson.util.FormValidation; 24 | import io.relution.jenkins.awssqs.SQSTriggerQueue.DescriptorImpl; 25 | 26 | 27 | public class SQSTriggerQueueDescriptorImplTest { 28 | 29 | @Test 30 | public void shouldAcceptNameAsNameOrUrl() { 31 | final DescriptorImpl descriptor = new DescriptorImpl(); 32 | final FormValidation validation = descriptor.doCheckNameOrUrl("test-queue"); 33 | 34 | assertThat(validation.kind).isEqualTo(FormValidation.Kind.OK); 35 | } 36 | 37 | @Test 38 | public void shouldAcceptSqsUrlAsNameOrUrl() { 39 | final DescriptorImpl descriptor = new DescriptorImpl(); 40 | final FormValidation validation = descriptor.doCheckNameOrUrl("https://sqs.us-east-1.amazonaws.com/929548749884/relution-queue-mytest7"); 41 | 42 | assertThat(validation.kind).isEqualTo(FormValidation.Kind.OK); 43 | } 44 | 45 | @Test 46 | public void shouldNotAcceptEmptyUrlAsNameOrUrl() { 47 | final DescriptorImpl descriptor = new DescriptorImpl(); 48 | final FormValidation validation = descriptor.doCheckNameOrUrl(null); 49 | 50 | assertThat(validation.kind).isEqualTo(FormValidation.Kind.WARNING); 51 | } 52 | 53 | @Test 54 | public void shouldNotAcceptCodeCommitUrlAsNameOrUrl() { 55 | final DescriptorImpl descriptor = new DescriptorImpl(); 56 | final FormValidation validation = descriptor.doCheckNameOrUrl("https://git-codecommit.us-east-1.amazonaws.com/v1/repos/relution-mytest7"); 57 | 58 | assertThat(validation.kind).isEqualTo(FormValidation.Kind.ERROR); 59 | } 60 | 61 | @Test 62 | public void shouldNotAcceptAnyUrlAsNameOrUrl() { 63 | final DescriptorImpl descriptor = new DescriptorImpl(); 64 | final FormValidation validation = descriptor.doCheckNameOrUrl("http://www.google.de"); 65 | 66 | assertThat(validation.kind).isEqualTo(FormValidation.Kind.ERROR); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/io/relution/jenkins/awssqs/SQSTriggerQueueTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | import com.amazonaws.services.sqs.AmazonSQSAsync; 22 | import com.amazonaws.services.sqs.model.GetQueueUrlResult; 23 | 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.mockito.Matchers; 27 | import org.mockito.Mock; 28 | import org.mockito.Mockito; 29 | import org.mockito.MockitoAnnotations; 30 | 31 | import io.relution.jenkins.awssqs.interfaces.SQSFactory; 32 | import io.relution.jenkins.awssqs.interfaces.SQSQueue; 33 | 34 | 35 | public class SQSTriggerQueueTest { 36 | 37 | @Mock 38 | private SQSFactory sqsFactory; 39 | 40 | @Mock 41 | private AmazonSQSAsync sqs; 42 | 43 | @Mock 44 | private GetQueueUrlResult getQueueUrlResult; 45 | 46 | @Before 47 | public void init() { 48 | MockitoAnnotations.initMocks(this); 49 | 50 | Mockito.when(this.sqsFactory.createSQS(Matchers.any(SQSQueue.class))).thenReturn(this.sqs); 51 | Mockito.when(this.sqsFactory.createSQSAsync(Matchers.any(SQSQueue.class))).thenReturn(this.sqs); 52 | 53 | Mockito.when(this.sqs.getQueueUrl(Matchers.anyString())).thenReturn(this.getQueueUrlResult); 54 | 55 | Mockito.when(this.getQueueUrlResult.getQueueUrl()).thenReturn("mock://sqs.url"); 56 | } 57 | 58 | @Test 59 | public void shouldSetDefaults() { 60 | // Cannot mock or create an instance of final hudson.util.Secret, so null it is 61 | final SQSTriggerQueue queue = new SQSTriggerQueue(null, "name", null, 0, 0, null, false); 62 | queue.setFactory(this.sqsFactory); 63 | 64 | assertThat(queue.getUuid()).isNotEmpty(); 65 | 66 | assertThat(queue.getUrl()).isEqualTo("mock://sqs.url"); 67 | assertThat(queue.getName()).isEqualTo("name"); 68 | assertThat(queue.getEndpoint()).isNull(); 69 | assertThat(queue.getNameOrUrl()).isEqualTo("name"); 70 | 71 | assertThat(queue.getCredentialsId()).isNull(); 72 | 73 | assertThat(queue.getWaitTimeSeconds()).isEqualTo(20); 74 | assertThat(queue.getMaxNumberOfMessages()).isEqualTo(10); 75 | assertThat(queue.getMaxNumberOfJobQueue()).isEqualTo(1000); 76 | assertThat(queue.isKeepQueueMessages()).isFalse(); 77 | } 78 | 79 | @Test 80 | public void shouldHaveNoExplicitEndpoint() { 81 | final SQSTriggerQueue queue = new SQSTriggerQueue(null, "test-queue", null, 0, 0, 0, false); 82 | queue.setFactory(this.sqsFactory); 83 | 84 | assertThat(queue.getUrl()).isEqualTo("mock://sqs.url"); 85 | assertThat(queue.getName()).isEqualTo("test-queue"); 86 | assertThat(queue.getEndpoint()).isNull(); 87 | assertThat(queue.getNameOrUrl()).isEqualTo("test-queue"); 88 | } 89 | 90 | @Test 91 | public void shouldHaveExplicitEndpoint() { 92 | final SQSTriggerQueue queue = new SQSTriggerQueue( 93 | null, 94 | "https://sqs.us-east-1.amazonaws.com/929548749884/test-queue", 95 | null, 96 | 0, 97 | 0, 98 | 0, 99 | false); 100 | queue.setFactory(this.sqsFactory); 101 | 102 | assertThat(queue.getUrl()).isEqualTo("https://sqs.us-east-1.amazonaws.com/929548749884/test-queue"); 103 | assertThat(queue.getName()).isEqualTo("test-queue"); 104 | assertThat(queue.getEndpoint()).isEqualTo("sqs.us-east-1.amazonaws.com"); 105 | assertThat(queue.getNameOrUrl()).isEqualTo("https://sqs.us-east-1.amazonaws.com/929548749884/test-queue"); 106 | } 107 | 108 | @Test 109 | public void shouldAcceptAnyUrl() { 110 | final SQSTriggerQueue queue = new SQSTriggerQueue( 111 | null, 112 | "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test", 113 | null, 114 | 0, 115 | 0, 116 | 0, 117 | false); 118 | queue.setFactory(this.sqsFactory); 119 | 120 | assertThat(queue.getUrl()).isEqualTo("mock://sqs.url"); 121 | assertThat(queue.getName()).isEqualTo("https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test"); 122 | assertThat(queue.getEndpoint()).isNull(); 123 | assertThat(queue.getNameOrUrl()).isEqualTo("https://git-codecommit.us-east-1.amazonaws.com/v1/repos/test"); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/io/relution/jenkins/awssqs/net/SQSQueueImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.net; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | import com.amazonaws.services.sqs.AmazonSQS; 22 | import com.amazonaws.services.sqs.model.BatchResultErrorEntry; 23 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequest; 24 | import com.amazonaws.services.sqs.model.DeleteMessageBatchResult; 25 | import com.amazonaws.services.sqs.model.DeleteMessageBatchResultEntry; 26 | import com.amazonaws.services.sqs.model.Message; 27 | import com.amazonaws.services.sqs.model.ReceiveMessageRequest; 28 | import com.amazonaws.services.sqs.model.ReceiveMessageResult; 29 | 30 | import org.junit.Before; 31 | import org.junit.Test; 32 | import org.mockito.Mock; 33 | import org.mockito.Mockito; 34 | import org.mockito.MockitoAnnotations; 35 | 36 | import java.util.ArrayList; 37 | import java.util.Collections; 38 | import java.util.List; 39 | 40 | import io.relution.jenkins.awssqs.interfaces.SQSQueue; 41 | 42 | 43 | public class SQSQueueImplTest { 44 | 45 | @Mock 46 | private RequestFactory factory; 47 | 48 | @Mock 49 | private AmazonSQS sqs; 50 | 51 | @Mock 52 | private SQSQueue queue; 53 | 54 | private io.relution.jenkins.awssqs.net.SQSChannel channel; 55 | 56 | private final List messages = Collections.singletonList(new Message()); 57 | 58 | @Before 59 | public void init() { 60 | MockitoAnnotations.initMocks(this); 61 | 62 | this.channel = new io.relution.jenkins.awssqs.net.SQSChannelImpl(this.sqs, this.queue, this.factory); 63 | } 64 | 65 | @Test 66 | public void shouldReturnMessages() { 67 | final ReceiveMessageRequest request = Mockito.mock(ReceiveMessageRequest.class); 68 | final ReceiveMessageResult result = Mockito.mock(ReceiveMessageResult.class); 69 | 70 | Mockito.when(this.factory.createReceiveMessageRequest(this.queue)).thenReturn(request); 71 | Mockito.when(this.sqs.receiveMessage(request.withMessageAttributeNames("All"))).thenReturn(result); 72 | Mockito.when(result.getMessages()).thenReturn(this.messages); 73 | 74 | final List messages = this.channel.getMessages(); 75 | 76 | assertThat(messages).isSameAs(this.messages); 77 | } 78 | 79 | @Test 80 | public void shouldDeleteMessages() { 81 | final DeleteMessageBatchRequest request = Mockito.mock(DeleteMessageBatchRequest.class); 82 | final DeleteMessageBatchResult result = Mockito.mock(DeleteMessageBatchResult.class); 83 | 84 | Mockito.when(this.factory.createDeleteMessageBatchRequest(this.queue, this.messages)).thenReturn(request); 85 | Mockito.when(this.sqs.deleteMessageBatch(request)).thenReturn(result); 86 | Mockito.when(result.getSuccessful()).thenReturn(new ArrayList()); 87 | Mockito.when(result.getFailed()).thenReturn(new ArrayList()); 88 | 89 | this.channel.deleteMessages(this.messages); 90 | 91 | Mockito.verify(this.factory).createDeleteMessageBatchRequest(this.queue, this.messages); 92 | Mockito.verify(this.sqs).deleteMessageBatch(request); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/io/relution/jenkins/awssqs/threading/SQSQueueMonitorImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.threading; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 21 | 22 | import com.amazonaws.services.sqs.model.Message; 23 | 24 | import org.assertj.core.api.ThrowableAssert.ThrowingCallable; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.mockito.Mock; 28 | import org.mockito.Mockito; 29 | import org.mockito.MockitoAnnotations; 30 | 31 | import java.util.ArrayList; 32 | import java.util.Collections; 33 | import java.util.List; 34 | import java.util.concurrent.ExecutorService; 35 | 36 | import io.relution.jenkins.awssqs.interfaces.SQSQueue; 37 | import io.relution.jenkins.awssqs.interfaces.SQSQueueListener; 38 | import io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor; 39 | import io.relution.jenkins.awssqs.net.SQSChannel; 40 | 41 | 42 | public class SQSQueueMonitorImplTest { 43 | 44 | private static final String UUID_A = "uuid-a"; 45 | private static final String UUID_B = "uuid-b"; 46 | 47 | @Mock 48 | private ExecutorService executor; 49 | 50 | @Mock 51 | private SQSQueue queue; 52 | 53 | @Mock 54 | private SQSChannel channel; 55 | 56 | @Mock 57 | private SQSQueueListener listener; 58 | 59 | private SQSQueueMonitor monitor; 60 | 61 | private final List messages = new ArrayList<>(); 62 | 63 | @Before 64 | public void init() { 65 | MockitoAnnotations.initMocks(this); 66 | 67 | final Message message = new Message(); 68 | this.messages.add(message); 69 | 70 | Mockito.when(this.channel.getMessages()).thenReturn(this.messages); 71 | 72 | Mockito.when(this.listener.getQueueUuid()).thenReturn(UUID_A); 73 | Mockito.when(this.channel.getQueueUuid()).thenReturn(UUID_A); 74 | 75 | this.monitor = new SQSQueueMonitorImpl(this.executor, this.queue, this.channel); 76 | } 77 | 78 | @Test 79 | public void shouldThrowIfRegisterNullListener() { 80 | assertThatThrownBy(new ThrowingCallable() { 81 | 82 | @Override 83 | public void call() throws Throwable { 84 | SQSQueueMonitorImplTest.this.monitor.add(null); 85 | } 86 | 87 | }).isInstanceOf(IllegalArgumentException.class); 88 | } 89 | 90 | @Test 91 | public void shouldNotThrowIfUnregisterNullListener() { 92 | assertThat(this.monitor.remove(null)).isFalse(); 93 | assertThat(this.monitor.isShutDown()).isFalse(); 94 | } 95 | 96 | @Test 97 | public void shouldNotThrowIfUnregisterUnknown() { 98 | assertThat(this.monitor.remove(this.listener)).isFalse(); 99 | assertThat(this.monitor.isShutDown()).isFalse(); 100 | } 101 | 102 | @Test 103 | public void shouldThrowIfWrongQueue() { 104 | Mockito.when(this.listener.getQueueUuid()).thenReturn(UUID_A); 105 | Mockito.when(this.channel.getQueueUuid()).thenReturn(UUID_B); 106 | 107 | assertThatThrownBy(new ThrowingCallable() { 108 | 109 | @Override 110 | public void call() throws Throwable { 111 | SQSQueueMonitorImplTest.this.monitor.add(SQSQueueMonitorImplTest.this.listener); 112 | } 113 | 114 | }).isInstanceOf(IllegalArgumentException.class); 115 | } 116 | 117 | @Test 118 | public void shouldStartMonitorForFirstListener() { 119 | final boolean result = this.monitor.add(this.listener); 120 | 121 | assertThat(result).isTrue(); 122 | Mockito.verify(this.executor).execute(this.monitor); 123 | assertThat(this.monitor.isShutDown()).isFalse(); 124 | } 125 | 126 | @Test 127 | public void shouldNotStartMultipleTimesForMultipleListeners() { 128 | this.monitor.add(this.listener); 129 | 130 | final boolean result = this.monitor.add(this.listener); 131 | 132 | assertThat(result).isFalse(); 133 | Mockito.verify(this.executor).execute(this.monitor); 134 | assertThat(this.monitor.isShutDown()).isFalse(); 135 | } 136 | 137 | @Test 138 | public void shouldNotStopBeforeLastListenerRemoved() { 139 | this.monitor.add(this.listener); 140 | this.monitor.add(this.listener); 141 | Mockito.verify(this.executor).execute(this.monitor); 142 | 143 | final boolean result = this.monitor.remove(this.listener); 144 | 145 | assertThat(result).isFalse(); 146 | Mockito.verifyNoMoreInteractions(this.executor); 147 | assertThat(this.monitor.isShutDown()).isFalse(); 148 | } 149 | 150 | @Test 151 | public void shouldStopIfLastListenerRemoved() { 152 | this.monitor.add(this.listener); 153 | this.monitor.add(this.listener); 154 | this.monitor.remove(this.listener); 155 | Mockito.verify(this.executor).execute(this.monitor); 156 | 157 | final boolean result = this.monitor.remove(this.listener); 158 | 159 | assertThat(result).isTrue(); 160 | Mockito.verifyNoMoreInteractions(this.executor); 161 | assertThat(this.monitor.isShutDown()).isTrue(); 162 | } 163 | 164 | @Test 165 | public void shouldQueryQueue() { 166 | this.monitor.add(this.listener); 167 | Mockito.verify(this.channel).getQueueUuid(); 168 | Mockito.verify(this.listener).getQueueUuid(); 169 | Mockito.verify(this.executor).execute(this.monitor); 170 | 171 | this.monitor.run(); 172 | 173 | Mockito.verify(this.channel).getMessages(); 174 | Mockito.verify(this.listener).handleMessages(this.messages); 175 | Mockito.verifyNoMoreInteractions(this.listener); 176 | Mockito.verify(this.channel).deleteMessages(this.messages); 177 | Mockito.verifyNoMoreInteractions(this.channel); 178 | Mockito.verify(this.executor, Mockito.times(2)).execute(this.monitor); 179 | } 180 | 181 | @Test 182 | public void shouldNotSendDeleteRequestIfResultIsEmpty() { 183 | final List messages = Collections.emptyList(); 184 | Mockito.when(this.channel.getMessages()).thenReturn(messages); 185 | assertThat(this.monitor.add(this.listener)).isTrue(); 186 | Mockito.verify(this.channel).getQueueUuid(); 187 | Mockito.verify(this.listener).getQueueUuid(); 188 | Mockito.verify(this.executor).execute(this.monitor); 189 | 190 | this.monitor.run(); 191 | 192 | Mockito.verify(this.channel).getMessages(); 193 | Mockito.verifyNoMoreInteractions(this.listener); 194 | Mockito.verifyNoMoreInteractions(this.channel); 195 | Mockito.verify(this.executor, Mockito.times(2)).execute(this.monitor); 196 | } 197 | 198 | @Test 199 | public void shouldNotRunIfAlreadyShutDown() { 200 | this.monitor.add(this.listener); 201 | Mockito.verify(this.channel).getQueueUuid(); 202 | Mockito.verify(this.listener).getQueueUuid(); 203 | Mockito.verify(this.executor).execute(this.monitor); 204 | 205 | this.monitor.shutDown(); 206 | this.monitor.run(); 207 | 208 | assertThat(this.monitor.isShutDown()).isTrue(); 209 | Mockito.verifyNoMoreInteractions(this.channel); 210 | Mockito.verifyNoMoreInteractions(this.listener); 211 | Mockito.verifyNoMoreInteractions(this.executor); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/test/java/io/relution/jenkins/awssqs/threading/SQSQueueMonitorSchedulerImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 M-Way Solutions GmbH 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.relution.jenkins.awssqs.threading; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.assertj.core.api.Assertions.assertThatThrownBy; 21 | import static org.mockito.Mockito.times; 22 | 23 | import org.assertj.core.api.ThrowableAssert.ThrowingCallable; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.mockito.Mock; 27 | import org.mockito.Mockito; 28 | import org.mockito.MockitoAnnotations; 29 | 30 | import java.util.concurrent.ExecutorService; 31 | 32 | import io.relution.jenkins.awssqs.interfaces.SQSFactory; 33 | import io.relution.jenkins.awssqs.interfaces.SQSQueue; 34 | import io.relution.jenkins.awssqs.interfaces.SQSQueueListener; 35 | import io.relution.jenkins.awssqs.interfaces.SQSQueueMonitor; 36 | import io.relution.jenkins.awssqs.interfaces.SQSQueueMonitorScheduler; 37 | import io.relution.jenkins.awssqs.interfaces.SQSQueueProvider; 38 | import io.relution.jenkins.awssqs.model.events.ConfigurationChangedEvent; 39 | 40 | 41 | public class SQSQueueMonitorSchedulerImplTest { 42 | 43 | private static final String UUID_A = "uuid-a"; 44 | private static final String UUID_B = "uuid-b"; 45 | 46 | @Mock 47 | private ExecutorService executor; 48 | 49 | @Mock 50 | private SQSQueueProvider provider; 51 | 52 | @Mock 53 | private SQSFactory factory; 54 | 55 | @Mock 56 | private SQSQueueMonitor monitorA; 57 | 58 | @Mock 59 | private SQSQueueMonitor monitorB; 60 | 61 | @Mock 62 | private SQSQueueListener listenerA1; 63 | 64 | @Mock 65 | private SQSQueueListener listenerA2; 66 | 67 | @Mock 68 | private SQSQueueListener listenerB1; 69 | 70 | @Mock 71 | private SQSQueue queueA; 72 | 73 | @Mock 74 | private SQSQueue queueB; 75 | 76 | private SQSQueueMonitorScheduler scheduler; 77 | 78 | @Before 79 | public void init() { 80 | MockitoAnnotations.initMocks(this); 81 | 82 | Mockito.when(this.factory.createMonitor(this.executor, this.queueA)).thenReturn(this.monitorA); 83 | Mockito.when(this.factory.createMonitor(this.executor, this.queueB)).thenReturn(this.monitorB); 84 | Mockito.when(this.factory.createMonitor(this.monitorA, this.queueA)).thenReturn(this.monitorA); 85 | Mockito.when(this.factory.createMonitor(this.monitorB, this.queueB)).thenReturn(this.monitorB); 86 | 87 | Mockito.when(this.monitorA.getQueue()).thenReturn(this.queueA); 88 | Mockito.when(this.monitorB.getQueue()).thenReturn(this.queueB); 89 | 90 | Mockito.when(this.listenerA1.getQueueUuid()).thenReturn(UUID_A); 91 | Mockito.when(this.listenerA2.getQueueUuid()).thenReturn(UUID_A); 92 | Mockito.when(this.listenerB1.getQueueUuid()).thenReturn(UUID_B); 93 | 94 | Mockito.when(this.queueA.getUuid()).thenReturn(UUID_A); 95 | Mockito.when(this.queueA.getUrl()).thenReturn("url-a"); 96 | Mockito.when(this.queueA.getAWSAccessKeyId()).thenReturn("access-key-a"); 97 | Mockito.when(this.queueA.getAWSSecretKey()).thenReturn("secret-key-a"); 98 | Mockito.when(this.queueA.getMaxNumberOfMessages()).thenReturn(20); 99 | Mockito.when(this.queueA.getWaitTimeSeconds()).thenReturn(10); 100 | 101 | Mockito.when(this.queueB.getUuid()).thenReturn(UUID_B); 102 | Mockito.when(this.queueB.getUrl()).thenReturn("url-b"); 103 | Mockito.when(this.queueB.getAWSAccessKeyId()).thenReturn("access-key-b"); 104 | Mockito.when(this.queueB.getAWSSecretKey()).thenReturn("secret-key-b"); 105 | Mockito.when(this.queueB.getMaxNumberOfMessages()).thenReturn(20); 106 | Mockito.when(this.queueB.getWaitTimeSeconds()).thenReturn(10); 107 | 108 | Mockito.when(this.provider.getSqsQueue(UUID_A)).thenReturn(this.queueA); 109 | Mockito.when(this.provider.getSqsQueue(UUID_B)).thenReturn(this.queueB); 110 | 111 | this.scheduler = new SQSQueueMonitorSchedulerImpl(this.executor, this.provider, this.factory); 112 | } 113 | 114 | @Test 115 | public void shouldThrowIfRegisterNullListener() { 116 | assertThatThrownBy(new ThrowingCallable() { 117 | 118 | @Override 119 | public void call() throws Throwable { 120 | SQSQueueMonitorSchedulerImplTest.this.scheduler.register(null); 121 | } 122 | 123 | }).isInstanceOf(IllegalArgumentException.class); 124 | } 125 | 126 | @Test 127 | public void shouldNotThrowIfUnregisterNullListener() { 128 | assertThat(this.scheduler.unregister(null)).isFalse(); 129 | } 130 | 131 | @Test 132 | public void shouldNotThrowIfUnregisterUnknownListener() { 133 | final SQSQueueListener listener = Mockito.mock(SQSQueueListener.class); 134 | Mockito.when(listener.getQueueUuid()).thenReturn("unknown"); 135 | 136 | final boolean result = this.scheduler.unregister(listener); 137 | 138 | assertThat(result).isFalse(); 139 | } 140 | 141 | @Test 142 | public void shouldStartMonitorForFirstListener() { 143 | final boolean result = this.scheduler.register(this.listenerA1); 144 | 145 | assertThat(result).isTrue(); 146 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_A); 147 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 148 | Mockito.verify(this.monitorA).add(this.listenerA1); 149 | } 150 | 151 | @Test 152 | public void shouldUseSingleMonitorInstancePerQueue() { 153 | this.scheduler.register(this.listenerA1); 154 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_A); 155 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 156 | Mockito.verify(this.monitorA).add(this.listenerA1); 157 | 158 | final boolean result = this.scheduler.register(this.listenerA2); 159 | 160 | assertThat(result).isTrue(); 161 | Mockito.verify(this.provider, times(2)).getSqsQueue(UUID_A); 162 | Mockito.verifyNoMoreInteractions(this.factory); 163 | Mockito.verify(this.monitorA).add(this.listenerA2); 164 | } 165 | 166 | @Test 167 | public void shouldUseSeparateMonitorInstanceForEachQueue() { 168 | this.scheduler.register(this.listenerA1); 169 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_A); 170 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 171 | Mockito.verify(this.monitorA).add(this.listenerA1); 172 | 173 | final boolean result = this.scheduler.register(this.listenerB1); 174 | 175 | assertThat(result).isTrue(); 176 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_B); 177 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueB); 178 | Mockito.verify(this.monitorB).add(this.listenerB1); 179 | Mockito.verifyNoMoreInteractions(this.monitorA); 180 | } 181 | 182 | @Test 183 | public void shouldReuseMonitorInstaceForListenerOfSameQueue() { 184 | this.scheduler.register(this.listenerA1); 185 | this.scheduler.register(this.listenerB1); 186 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_A); 187 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_B); 188 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 189 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueB); 190 | Mockito.verify(this.monitorA).add(this.listenerA1); 191 | Mockito.verify(this.monitorB).add(this.listenerB1); 192 | Mockito.verifyNoMoreInteractions(this.monitorA); 193 | 194 | final boolean result = this.scheduler.register(this.listenerA2); 195 | 196 | assertThat(result).isTrue(); 197 | Mockito.verify(this.provider, times(2)).getSqsQueue(UUID_A); 198 | Mockito.verifyNoMoreInteractions(this.factory); 199 | Mockito.verify(this.monitorA).add(this.listenerA2); 200 | Mockito.verifyNoMoreInteractions(this.monitorB); 201 | } 202 | 203 | @Test 204 | public void shouldNotCreateMonitorForUnknownQueue() { 205 | final SQSQueueListener listener = Mockito.mock(SQSQueueListener.class); 206 | Mockito.when(listener.getQueueUuid()).thenReturn("unknown"); 207 | 208 | final boolean result = this.scheduler.register(listener); 209 | 210 | assertThat(result).isFalse(); 211 | Mockito.verify(this.provider, times(1)).getSqsQueue("unknown"); 212 | Mockito.verifyZeroInteractions(this.factory); 213 | } 214 | 215 | @Test 216 | public void shouldCreateNewMonitorAfterUnregisterLast() { 217 | this.scheduler.register(this.listenerA1); 218 | this.scheduler.unregister(this.listenerA1); 219 | Mockito.verify(this.provider, times(1)).getSqsQueue(UUID_A); 220 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 221 | Mockito.verify(this.monitorA).add(this.listenerA1); 222 | Mockito.verify(this.monitorA).remove(this.listenerA1); 223 | 224 | final boolean result = this.scheduler.register(this.listenerA2); 225 | 226 | assertThat(result).isTrue(); 227 | Mockito.verify(this.provider, times(2)).getSqsQueue(UUID_A); 228 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 229 | Mockito.verify(this.monitorA).add(this.listenerA2); 230 | } 231 | 232 | @Test 233 | public void shouldNotCreateNewMonitorIfMoreListenersOnUnregister() { 234 | this.scheduler.register(this.listenerA1); 235 | this.scheduler.register(this.listenerA2); 236 | this.scheduler.unregister(this.listenerA1); 237 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 238 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA1); 239 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA2); 240 | Mockito.verify(this.monitorA, times(1)).remove(this.listenerA1); 241 | 242 | final boolean result = this.scheduler.register(this.listenerA1); 243 | 244 | assertThat(result).isTrue(); 245 | Mockito.verifyNoMoreInteractions(this.factory); 246 | Mockito.verify(this.monitorA, times(2)).add(this.listenerA1); 247 | } 248 | 249 | @Test 250 | public void shouldDoNothingOnConfigurationChangedIfUnchanged() { 251 | this.scheduler.register(this.listenerA1); 252 | this.scheduler.register(this.listenerB1); 253 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 254 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueB); 255 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA1); 256 | Mockito.verify(this.monitorB, times(1)).add(this.listenerB1); 257 | 258 | this.scheduler.onConfigurationChanged(new ConfigurationChangedEvent()); 259 | 260 | Mockito.verifyNoMoreInteractions(this.factory); 261 | Mockito.verify(this.monitorA).getQueue(); 262 | Mockito.verify(this.monitorB).getQueue(); 263 | Mockito.verify(this.monitorA).isShutDown(); 264 | Mockito.verify(this.monitorB).isShutDown(); 265 | Mockito.verifyNoMoreInteractions(this.monitorA); 266 | Mockito.verifyNoMoreInteractions(this.monitorB); 267 | } 268 | 269 | @Test 270 | public void shouldStartNewMonitorOnConfigurationChangedIfChanged() { 271 | final SQSQueue queueA_ = Mockito.mock(SQSQueue.class); 272 | final SQSQueueMonitor monitorA_ = Mockito.mock(SQSQueueMonitor.class); 273 | this.scheduler.register(this.listenerA1); 274 | this.scheduler.register(this.listenerA2); 275 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 276 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA1); 277 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA2); 278 | Mockito.when(this.monitorA.getQueue()).thenReturn(this.queueA); 279 | Mockito.when(this.provider.getSqsQueue(UUID_A)).thenReturn(queueA_); 280 | Mockito.when(this.factory.createMonitor(this.monitorA, queueA_)).thenReturn(monitorA_); 281 | 282 | this.scheduler.onConfigurationChanged(new ConfigurationChangedEvent()); 283 | 284 | Mockito.verify(this.factory).createMonitor(this.monitorA, queueA_); 285 | Mockito.verify(this.monitorA).getQueue(); 286 | Mockito.verify(this.monitorA).shutDown(); 287 | Mockito.verify(this.monitorA).isShutDown(); 288 | Mockito.verifyNoMoreInteractions(this.monitorA); 289 | Mockito.verifyNoMoreInteractions(monitorA_); 290 | } 291 | 292 | @Test 293 | public void shouldDoNothingOnConfigurationChangedIfPropertiesEqual() { 294 | final SQSQueue queueA_ = Mockito.mock(SQSQueue.class); 295 | final SQSQueueMonitor monitorA_ = Mockito.mock(SQSQueueMonitor.class); 296 | this.scheduler.register(this.listenerA1); 297 | this.scheduler.register(this.listenerA2); 298 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 299 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA1); 300 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA2); 301 | Mockito.when(this.monitorA.getQueue()).thenReturn(this.queueA); 302 | Mockito.when(this.provider.getSqsQueue(UUID_A)).thenReturn(queueA_); 303 | Mockito.when(this.factory.createMonitor(this.monitorA, queueA_)).thenReturn(monitorA_); 304 | Mockito.when(queueA_.getUuid()).thenReturn(UUID_A); 305 | Mockito.when(queueA_.getUrl()).thenReturn("url-a"); 306 | Mockito.when(queueA_.getAWSAccessKeyId()).thenReturn("access-key-a"); 307 | Mockito.when(queueA_.getAWSSecretKey()).thenReturn("secret-key-a"); 308 | Mockito.when(queueA_.getMaxNumberOfMessages()).thenReturn(20); 309 | Mockito.when(queueA_.getWaitTimeSeconds()).thenReturn(10); 310 | 311 | this.scheduler.onConfigurationChanged(new ConfigurationChangedEvent()); 312 | 313 | Mockito.verifyNoMoreInteractions(this.factory); 314 | Mockito.verify(this.monitorA).getQueue(); 315 | Mockito.verify(this.monitorA).isShutDown(); 316 | Mockito.verifyNoMoreInteractions(this.monitorA); 317 | } 318 | 319 | @Test 320 | public void shouldStopMonitorOnConfigurationChangedIfQueueRemoved() { 321 | this.scheduler.register(this.listenerA1); 322 | this.scheduler.register(this.listenerB1); 323 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueA); 324 | Mockito.verify(this.factory).createMonitor(this.executor, this.queueB); 325 | Mockito.verify(this.monitorA, times(1)).add(this.listenerA1); 326 | Mockito.verify(this.monitorB, times(1)).add(this.listenerB1); 327 | Mockito.when(this.provider.getSqsQueue(UUID_B)).thenReturn(null); 328 | 329 | this.scheduler.onConfigurationChanged(new ConfigurationChangedEvent()); 330 | 331 | Mockito.verifyNoMoreInteractions(this.factory); 332 | Mockito.verify(this.monitorA).getQueue(); 333 | Mockito.verify(this.monitorA).isShutDown(); 334 | Mockito.verify(this.monitorB).shutDown(); 335 | Mockito.verifyNoMoreInteractions(this.monitorA); 336 | Mockito.verifyNoMoreInteractions(this.monitorB); 337 | } 338 | } 339 | --------------------------------------------------------------------------------