├── .gitattributes ├── .github ├── CODEOWNERS ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── jenkins-security-scan.yml │ └── release-drafter.yml ├── .gitignore ├── .mvn ├── extensions.xml ├── maven.config └── wrapper │ └── maven-wrapper.properties ├── .travis.yml ├── CONTRIBUTING.md ├── Jenkinsfile ├── LICENSE ├── NOTICE.md ├── README.md ├── codecov.yml ├── docs └── images │ ├── changes-2.png │ ├── changes.png │ ├── ghserver-config.png │ ├── help_16.svg │ ├── manage-token.png │ └── secret-text.png ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ ├── com │ │ ├── cloudbees │ │ │ └── jenkins │ │ │ │ ├── Cleaner.java │ │ │ │ ├── Credential.java │ │ │ │ ├── GitHubCommitNotifier.java │ │ │ │ ├── GitHubPushCause.java │ │ │ │ ├── GitHubPushTrigger.java │ │ │ │ ├── GitHubRepositoryName.java │ │ │ │ ├── GitHubRepositoryNameContributor.java │ │ │ │ ├── GitHubSetCommitStatusBuilder.java │ │ │ │ ├── GitHubTrigger.java │ │ │ │ ├── GitHubTriggerEvent.java │ │ │ │ ├── GitHubWebHook.java │ │ │ │ └── GitHubWebHookCrumbExclusion.java │ │ └── coravy │ │ │ └── hudson │ │ │ └── plugins │ │ │ └── github │ │ │ ├── GithubLinkAction.java │ │ │ ├── GithubLinkAnnotator.java │ │ │ ├── GithubProjectProperty.java │ │ │ └── GithubUrl.java │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── github │ │ ├── GitHubPlugin.java │ │ ├── admin │ │ ├── GHRepoName.java │ │ ├── GitHubDuplicateEventsMonitor.java │ │ ├── GitHubHookRegisterProblemMonitor.java │ │ ├── RequireAdminRights.java │ │ ├── RespondWithRedirect.java │ │ └── ValidateRepoName.java │ │ ├── common │ │ ├── CombineErrorHandler.java │ │ ├── ErrorHandler.java │ │ └── ExpandableMessage.java │ │ ├── config │ │ ├── GitHubPluginConfig.java │ │ ├── GitHubServerConfig.java │ │ ├── GitHubTokenCredentialsCreator.java │ │ └── HookSecretConfig.java │ │ ├── extension │ │ ├── GHEventsSubscriber.java │ │ ├── GHSubscriberEvent.java │ │ └── status │ │ │ ├── GitHubCommitShaSource.java │ │ │ ├── GitHubReposSource.java │ │ │ ├── GitHubStatusBackrefSource.java │ │ │ ├── GitHubStatusContextSource.java │ │ │ ├── GitHubStatusResultSource.java │ │ │ ├── StatusErrorHandler.java │ │ │ └── misc │ │ │ └── ConditionalResult.java │ │ ├── internal │ │ ├── GHPluginConfigException.java │ │ ├── GitHubClientCacheOps.java │ │ └── GitHubLoginFunction.java │ │ ├── migration │ │ └── Migrator.java │ │ ├── status │ │ ├── GitHubCommitStatusSetter.java │ │ ├── err │ │ │ ├── ChangingBuildStatusErrorHandler.java │ │ │ └── ShallowAnyErrorHandler.java │ │ └── sources │ │ │ ├── AnyDefinedRepositorySource.java │ │ │ ├── BuildDataRevisionShaSource.java │ │ │ ├── BuildRefBackrefSource.java │ │ │ ├── ConditionalStatusResultSource.java │ │ │ ├── DefaultCommitContextSource.java │ │ │ ├── DefaultStatusResultSource.java │ │ │ ├── ManuallyEnteredBackrefSource.java │ │ │ ├── ManuallyEnteredCommitContextSource.java │ │ │ ├── ManuallyEnteredRepositorySource.java │ │ │ ├── ManuallyEnteredShaSource.java │ │ │ └── misc │ │ │ ├── AnyBuildResult.java │ │ │ └── BetterThanOrEqualBuildResult.java │ │ ├── util │ │ ├── BuildDataHelper.java │ │ ├── FluentIterableWrapper.java │ │ ├── JobInfoHelpers.java │ │ ├── XSSApi.java │ │ └── misc │ │ │ ├── NullSafeFunction.java │ │ │ └── NullSafePredicate.java │ │ └── webhook │ │ ├── GHEventHeader.java │ │ ├── GHEventPayload.java │ │ ├── GHWebhookSignature.java │ │ ├── RequirePostWithGHHookPayload.java │ │ ├── WebhookManager.java │ │ └── subscriber │ │ ├── DefaultPushGHEventSubscriber.java │ │ └── PingGHEventSubscriber.java ├── resources │ ├── com │ │ ├── cloudbees │ │ │ └── jenkins │ │ │ │ ├── GitHubCommitNotifier │ │ │ │ ├── config.groovy │ │ │ │ ├── config_zh_CN.properties │ │ │ │ └── help.html │ │ │ │ ├── GitHubPushTrigger │ │ │ │ ├── GitHubWebHookPollingAction │ │ │ │ │ └── index.jelly │ │ │ │ ├── config.groovy │ │ │ │ └── help.html │ │ │ │ ├── GitHubSetCommitStatusBuilder │ │ │ │ └── config.groovy │ │ │ │ └── Messages.properties │ │ └── coravy │ │ │ └── hudson │ │ │ └── plugins │ │ │ └── github │ │ │ └── GithubProjectProperty │ │ │ ├── config.groovy │ │ │ ├── config.properties │ │ │ ├── config_de.properties │ │ │ ├── config_zh_CN.properties │ │ │ ├── help-displayName.html │ │ │ ├── help-projectUrlStr.html │ │ │ └── help-projectUrlStr_de.html │ ├── images │ │ └── symbols │ │ │ └── logo-github.svg │ ├── index.jelly │ ├── lib │ │ └── github │ │ │ └── blockWrapper.jelly │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── github │ │ ├── Messages.properties │ │ ├── admin │ │ ├── GitHubDuplicateEventsMonitor │ │ │ ├── description.jelly │ │ │ └── message.jelly │ │ └── GitHubHookRegisterProblemMonitor │ │ │ ├── index.groovy │ │ │ ├── index.properties │ │ │ ├── message.groovy │ │ │ └── message.properties │ │ ├── common │ │ └── ExpandableMessage │ │ │ ├── config.groovy │ │ │ └── help-content.html │ │ ├── config │ │ ├── GitHubPluginConfig │ │ │ ├── config.groovy │ │ │ ├── config_zh_CN.properties │ │ │ ├── help-additional.html │ │ │ ├── help-overrideHookUrl.jelly │ │ │ └── help.jelly │ │ ├── GitHubServerConfig │ │ │ ├── config.groovy │ │ │ ├── config_zh_CN.properties │ │ │ ├── help-apiUrl.html │ │ │ ├── help-clientCacheSize.html │ │ │ ├── help-credentialsId.html │ │ │ ├── help-manageHooks.html │ │ │ ├── help-name.html │ │ │ └── help.html │ │ ├── GitHubTokenCredentialsCreator │ │ │ ├── config.groovy │ │ │ ├── config_zh_CN.properties │ │ │ └── help.html │ │ ├── HookSecretConfig │ │ │ ├── config.groovy │ │ │ ├── config_zh_CN.properties │ │ │ └── help-sharedSecret.html │ │ └── Messages.properties │ │ ├── extension │ │ └── status │ │ │ └── misc │ │ │ └── ConditionalResult │ │ │ ├── config.groovy │ │ │ └── config_zh_CN.properties │ │ ├── status │ │ ├── GitHubCommitStatusSetter │ │ │ ├── config.groovy │ │ │ ├── config_zh_CN.properties │ │ │ └── help.html │ │ ├── err │ │ │ ├── ChangingBuildStatusErrorHandler │ │ │ │ ├── config.groovy │ │ │ │ └── config_zh_CN.properties │ │ │ └── ShallowAnyErrorHandler │ │ │ │ └── config.groovy │ │ └── sources │ │ │ ├── AnyDefinedRepositorySource │ │ │ ├── config.groovy │ │ │ └── help.html │ │ │ ├── BuildDataRevisionShaSource │ │ │ ├── config.groovy │ │ │ └── help.html │ │ │ ├── BuildRefBackrefSource │ │ │ ├── config.groovy │ │ │ └── help.html │ │ │ ├── ConditionalStatusResultSource │ │ │ ├── config.groovy │ │ │ └── help.html │ │ │ ├── DefaultCommitContextSource │ │ │ ├── config.groovy │ │ │ └── help.html │ │ │ ├── DefaultStatusResultSource │ │ │ ├── config.groovy │ │ │ └── help.html │ │ │ ├── ManuallyEnteredBackrefSource │ │ │ ├── config.groovy │ │ │ ├── help-backref.html │ │ │ └── help.html │ │ │ ├── ManuallyEnteredCommitContextSource │ │ │ ├── config.groovy │ │ │ ├── help-context.html │ │ │ └── help.html │ │ │ ├── ManuallyEnteredRepositorySource │ │ │ ├── config.groovy │ │ │ ├── help-url.html │ │ │ └── help.html │ │ │ ├── ManuallyEnteredShaSource │ │ │ ├── config.groovy │ │ │ ├── help-sha.html │ │ │ └── help.html │ │ │ └── misc │ │ │ └── BetterThanOrEqualBuildResult │ │ │ ├── config.groovy │ │ │ ├── config_zh_CN.properties │ │ │ └── help-message.html │ │ └── util │ │ └── Messages.properties ├── sass │ └── monitor.scss └── webapp │ └── js │ └── warning.js └── test ├── java ├── com │ ├── cloudbees │ │ └── jenkins │ │ │ ├── GitHubCommitNotifierTest.java │ │ │ ├── GitHubPushTriggerTest.java │ │ │ ├── GitHubSetCommitStatusBuilderTest.java │ │ │ ├── GitHubWebHookCrumbExclusionTest.java │ │ │ ├── GitHubWebHookFullTest.java │ │ │ ├── GitHubWebHookTest.java │ │ │ └── GlobalConfigSubmitTest.java │ └── coravy │ │ └── hudson │ │ └── plugins │ │ └── github │ │ ├── GitHubRepositoryNameTest.java │ │ ├── GithubLinkActionFactoryTest.java │ │ ├── GithubLinkAnnotatorTest.java │ │ ├── GithubProjectPropertyTest.java │ │ └── GithubUrlTest.java └── org │ └── jenkinsci │ └── plugins │ └── github │ ├── admin │ ├── GHRepoNameTest.java │ ├── GitHubDuplicateEventsMonitorTest.java │ ├── GitHubDuplicateEventsMonitorUnitTest.java │ ├── GitHubHookRegisterProblemMonitorTest.java │ └── ValidateRepoNameTest.java │ ├── common │ ├── CombineErrorHandlerTest.java │ ├── ExpandableMessageTest.java │ └── ParametersActionHelper.java │ ├── config │ ├── ConfigAsCodeTest.java │ ├── GitHubPluginConfigTest.java │ ├── GitHubServerConfigIntegrationTest.java │ ├── GitHubServerConfigTest.java │ └── HookSecretConfigTest.java │ ├── extension │ ├── CryptoUtilTest.java │ └── GHEventsSubscriberTest.java │ ├── internal │ ├── GitHubClientCacheCleanupTest.java │ └── GitHubClientCacheOpsTest.java │ ├── migration │ └── MigratorTest.java │ ├── status │ ├── GitHubCommitStatusSetterTest.java │ ├── err │ │ └── ErrorHandlersTest.java │ └── sources │ │ ├── BuildRefBackrefSourceTest.java │ │ ├── ConditionalStatusResultSourceTest.java │ │ ├── DefaultStatusResultSourceTest.java │ │ ├── ManuallyEnteredRepositorySourceTest.java │ │ ├── ManuallyEnteredSourcesTest.java │ │ └── misc │ │ ├── AnyBuildResultTest.java │ │ └── BetterThanOrEqualBuildResultTest.java │ ├── test │ ├── GHMockRule.java │ ├── GitHubRepoNameMatchers.java │ ├── GitHubServerConfigMatcher.java │ ├── HookSecretHelper.java │ └── InjectJenkinsMembersRule.java │ ├── util │ ├── BuildDataHelperTest.java │ ├── JobInfoHelpersTest.java │ └── XSSApiTest.java │ └── webhook │ ├── GHEventHeaderTest.java │ ├── GHEventPayloadTest.java │ ├── RequirePostWithGHHookPayloadTest.java │ ├── WebhookManagerTest.java │ └── subscriber │ ├── DefaultPushGHEventListenerTest.java │ └── PingGHEventSubscriberTest.java └── resources ├── checkstyle ├── checkstyle-config.xml └── checkstyle-suppressions.xml ├── com └── cloudbees │ └── jenkins │ ├── GitHubSetCommitStatusBuilderTest │ └── shouldLoadNullStatusMessage │ │ ├── config.xml │ │ └── jobs │ │ └── step │ │ └── config.xml │ └── GitHubWebHookFullTest │ └── payloads │ ├── orgping.json │ ├── ping.json │ ├── ping_hash_355e155fc3d10c4e5f2c6086a01281d2e947d932_secret_123.json │ └── push.json ├── log4j.properties └── org └── jenkinsci └── plugins └── github ├── admin └── GitHubHookRegisterProblemMonitorTest │ └── shouldLoadIgnoredList │ ├── config.xml │ └── org.jenkinsci.plugins.github.admin.GitHubHookRegisterProblemMonitor.xml ├── config └── configuration-as-code.yml ├── migration └── MigratorTest │ ├── shouldLoadDataAfterStart │ ├── com.cloudbees.jenkins.GitHubPushTrigger.xml │ ├── config.xml │ └── github-plugin-configuration.xml │ ├── shouldMigrateCredentials │ ├── com.cloudbees.jenkins.GitHubPushTrigger.xml │ └── config.xml │ ├── shouldMigrateHookUrl │ ├── com.cloudbees.jenkins.GitHubPushTrigger.xml │ └── config.xml │ └── shouldNotThrowExcMalformedHookUrlInOldConfig │ ├── com.cloudbees.jenkins.GitHubPushTrigger.xml │ └── config.xml ├── test └── GHMockRule │ ├── repos-repo.json │ └── user.json └── webhook └── subscriber └── DefaultPushGHEventListenerTest └── workflow-definition.groovy /.gitattributes: -------------------------------------------------------------------------------- 1 | # From https://github.com/Danimoth/gitattributes/blob/master/Java.gitattributes 2 | # Handle line endings automatically for files detected as text 3 | # and leave all files detected as binary untouched. 4 | * text=auto 5 | 6 | # 7 | # The above will handle all files NOT found below 8 | # 9 | # These files are text and should be normalized (Convert crlf => lf) 10 | *.css text 11 | *.df text 12 | *.htm text 13 | *.html text 14 | *.java text 15 | *.js text 16 | *.json text 17 | *.jsp text 18 | *.jspf text 19 | *.properties text 20 | *.sh text 21 | *.svg text 22 | *.tld text 23 | *.txt text 24 | *.xml text 25 | 26 | # These files are binary and should be left untouched 27 | # (binary is a macro for -text -diff) 28 | *.class binary 29 | *.dll binary 30 | *.ear binary 31 | *.gif binary 32 | *.ico binary 33 | *.jar binary 34 | *.jpg binary 35 | *.jpeg binary 36 | *.png binary 37 | *.so binary 38 | *.war binary 39 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/github-plugin-developers 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 10 8 | target-branch: master 9 | labels: 10 | - dependencies 11 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 2 | _extends: .github 3 | version-template: $MAJOR.$MINOR.$PATCH 4 | tag-template: v$NEXT_PATCH_VERSION 5 | name-template: v$NEXT_PATCH_VERSION 6 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ opened, synchronize, reopened ] 9 | workflow_dispatch: 10 | 11 | permissions: 12 | security-events: write 13 | contents: read 14 | actions: read 15 | 16 | jobs: 17 | security-scan: 18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 19 | with: 20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 22 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 2 | 3 | name: Release Drafter 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into the default branch 15 | - uses: release-drafter/release-drafter@v6 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | work 3 | target 4 | .classpath 5 | .project 6 | .settings 7 | *.iml 8 | *.ipr 9 | *.iws 10 | .idea/ 11 | 12 | # autogenerated resources 13 | src/main/webapp/css/* 14 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.8 6 | 7 | 8 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: oraclejdk8 3 | before_install: 4 | - pip install --user codecov 5 | install: travis_wait mvn install 6 | after_success: 7 | - codecov 8 | cache: 9 | directories: 10 | - $HOME/.m2 11 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | buildPlugin(useContainerAgent: true, configurations: [ 2 | [platform: 'linux', jdk: 21], 3 | [platform: 'windows', jdk: 17], 4 | ]) 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009-2014 Jenkins contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | ## License notes 2 | 3 | This plugin uses part of Guava's code in class named `org.jenkinsci.plugins.github.util.FluentIterableWrapper` 4 | licensed under **Apache 2.0** license 5 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | token: secret:eB8EFoOdXjvV5BGCkR+nCxMxNWJZqjpnfqPhrzFs6skp+IqoITDObS95TQwCvpUDISWyi3SeoJSrbbPubPUPWtgHjVIDg86fXQARSadlv5E= 3 | -------------------------------------------------------------------------------- /docs/images/changes-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/github-plugin/0c86f968d0aa157c74fcd8b6477095ab1aab0883/docs/images/changes-2.png -------------------------------------------------------------------------------- /docs/images/changes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/github-plugin/0c86f968d0aa157c74fcd8b6477095ab1aab0883/docs/images/changes.png -------------------------------------------------------------------------------- /docs/images/ghserver-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/github-plugin/0c86f968d0aa157c74fcd8b6477095ab1aab0883/docs/images/ghserver-config.png -------------------------------------------------------------------------------- /docs/images/help_16.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/manage-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/github-plugin/0c86f968d0aa157c74fcd8b6477095ab1aab0883/docs/images/manage-token.png -------------------------------------------------------------------------------- /docs/images/secret-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/github-plugin/0c86f968d0aa157c74fcd8b6477095ab1aab0883/docs/images/secret-text.png -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/Cleaner.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Item; 5 | import hudson.model.PeriodicWork; 6 | import jenkins.model.Jenkins; 7 | import org.jenkinsci.plugins.github.GitHubPlugin; 8 | import org.jenkinsci.plugins.github.webhook.WebhookManager; 9 | 10 | import java.net.URL; 11 | import java.util.List; 12 | import java.util.Queue; 13 | import java.util.concurrent.ConcurrentLinkedQueue; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; 17 | import static org.jenkinsci.plugins.github.util.JobInfoHelpers.associatedNames; 18 | import static org.jenkinsci.plugins.github.util.JobInfoHelpers.isAlive; 19 | 20 | /** 21 | * Removes post-commit hooks from repositories that we no longer care. 22 | * 23 | * This runs periodically in a delayed fashion to avoid hitting GitHub too often. 24 | * 25 | * @author Kohsuke Kawaguchi 26 | */ 27 | @Extension 28 | public class Cleaner extends PeriodicWork { 29 | /** 30 | * Queue contains repo names prepared to cleanup. 31 | * After configure method on job, trigger calls {@link #onStop(Item)} 32 | * which converts to repo names with help of contributors. 33 | * 34 | * This queue is thread-safe, so any thread can write or 35 | * fetch names to this queue without additional sync 36 | */ 37 | private final Queue cleanQueue = new ConcurrentLinkedQueue<>(); 38 | 39 | /** 40 | * Called when a {@link GitHubPushTrigger} is about to be removed. 41 | */ 42 | /* package */ void onStop(Item item) { 43 | cleanQueue.addAll(GitHubRepositoryNameContributor.parseAssociatedNames(item)); 44 | } 45 | 46 | @Override 47 | public long getRecurrencePeriod() { 48 | return TimeUnit.MINUTES.toMillis(3); 49 | } 50 | 51 | /** 52 | * Each run this work fetches alive repo names (which has trigger for it) 53 | * then if names queue is not empty (any job was reconfigured with GH trigger change), 54 | * next name passed to {@link WebhookManager} with list of active names to check and unregister old hooks 55 | */ 56 | @Override 57 | protected void doRun() throws Exception { 58 | if (!GitHubPlugin.configuration().isManageHooks()) { 59 | return; 60 | } 61 | 62 | URL url = GitHubPlugin.configuration().getHookUrl(); 63 | 64 | List aliveRepos = from(Jenkins.get().allItems(Item.class)) 65 | .filter(isAlive()) // live repos 66 | .transformAndConcat(associatedNames()).toList(); 67 | 68 | while (!cleanQueue.isEmpty()) { 69 | GitHubRepositoryName name = cleanQueue.poll(); 70 | 71 | WebhookManager.forHookUrl(url).unregisterFor(name, aliveRepos); 72 | } 73 | } 74 | 75 | public static Cleaner get() { 76 | return PeriodicWork.all().get(Cleaner.class); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/Credential.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import com.google.common.base.Predicate; 4 | import com.google.common.base.Predicates; 5 | import org.jenkinsci.plugins.github.GitHubPlugin; 6 | import org.jenkinsci.plugins.github.config.GitHubServerConfig; 7 | import org.kohsuke.github.GitHub; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | 10 | import edu.umd.cs.findbugs.annotations.CheckForNull; 11 | import java.io.IOException; 12 | 13 | import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; 14 | 15 | /** 16 | * Credential to access GitHub. 17 | * Used only for migration. 18 | * 19 | * @author Kohsuke Kawaguchi 20 | * @see org.jenkinsci.plugins.github.config.GitHubPluginConfig 21 | * @see GitHubServerConfig 22 | * @deprecated since 1.13.0 plugin uses credentials-plugin to manage tokens. All configuration moved to 23 | * {@link org.jenkinsci.plugins.github.config.GitHubPluginConfig} which can be fetched via 24 | * {@link GitHubPlugin#configuration()}. You can fetch corresponding config with creds by 25 | * {@link org.jenkinsci.plugins.github.config.GitHubPluginConfig#findGithubConfig(Predicate)} which returns 26 | * iterable over authorized nonnull {@link GitHub}s matched your predicate 27 | */ 28 | @Deprecated 29 | public class Credential { 30 | @SuppressWarnings("visibilitymodifier") 31 | public final transient String username; 32 | @SuppressWarnings("visibilitymodifier") 33 | public final transient String apiUrl; 34 | @SuppressWarnings("visibilitymodifier") 35 | public final transient String oauthAccessToken; 36 | 37 | @DataBoundConstructor 38 | public Credential(String username, String apiUrl, String oauthAccessToken) { 39 | this.username = username; 40 | this.apiUrl = apiUrl; 41 | this.oauthAccessToken = oauthAccessToken; 42 | } 43 | 44 | public String getUsername() { 45 | return username; 46 | } 47 | 48 | public String getApiUrl() { 49 | return apiUrl; 50 | } 51 | 52 | public String getOauthAccessToken() { 53 | return oauthAccessToken; 54 | } 55 | 56 | /** 57 | * @return authorized first {@link GitHub} from global config or null if no any 58 | * @throws IOException never thrown, but in signature for backward compatibility 59 | * @deprecated see class javadoc. Now any instance return same GH. Please use new api to fetch another 60 | */ 61 | @CheckForNull 62 | @Deprecated 63 | public GitHub login() throws IOException { 64 | return from(GitHubPlugin.configuration().findGithubConfig(Predicates.alwaysTrue())) 65 | .first().orNull(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/GitHubPushCause.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import hudson.triggers.SCMTrigger.SCMTriggerCause; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.Objects; 8 | 9 | import static java.lang.String.format; 10 | import static org.apache.commons.lang3.StringUtils.trimToEmpty; 11 | 12 | /** 13 | * UI object that says a build is started by GitHub post-commit hook. 14 | * 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | public class GitHubPushCause extends SCMTriggerCause { 18 | /** 19 | * The name of the user who pushed to GitHub. 20 | */ 21 | private String pushedBy; 22 | 23 | public GitHubPushCause(String pusher) { 24 | this("", pusher); 25 | } 26 | 27 | public GitHubPushCause(String pollingLog, String pusher) { 28 | super(pollingLog); 29 | pushedBy = pusher; 30 | } 31 | 32 | public GitHubPushCause(File pollingLog, String pusher) throws IOException { 33 | super(pollingLog); 34 | pushedBy = pusher; 35 | } 36 | 37 | @Override 38 | public String getShortDescription() { 39 | return format("Started by GitHub push by %s", trimToEmpty(pushedBy)); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | return o instanceof GitHubPushCause 45 | && Objects.equals(this.pushedBy, ((GitHubPushCause) o).pushedBy) 46 | && super.equals(o); 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | int hash = super.hashCode(); 52 | hash = 89 * hash + Objects.hash(this.pushedBy); 53 | return hash; 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/GitHubTrigger.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import hudson.Extension; 4 | import hudson.Util; 5 | import hudson.model.AbstractProject; 6 | import hudson.model.Item; 7 | import hudson.triggers.Trigger; 8 | import jenkins.model.ParameterizedJobMixIn; 9 | 10 | import java.util.Collection; 11 | import java.util.Set; 12 | 13 | /** 14 | * Optional interface that can be implemented by {@link Trigger} that watches out for a change in GitHub 15 | * and triggers a build. 16 | * 17 | * @author aaronwalker 18 | * @deprecated not used any more 19 | */ 20 | public interface GitHubTrigger { 21 | 22 | @Deprecated 23 | void onPost(); 24 | 25 | // TODO: document me 26 | void onPost(String triggeredByUser); 27 | 28 | /** 29 | * Obtains the list of the repositories that this trigger is looking at. 30 | * 31 | * If the implementation of this class maintain its own list of GitHub repositories, it should 32 | * continue to implement this method for backward compatibility, and it gets picked up by 33 | * {@link GitHubRepositoryNameContributor#parseAssociatedNames(AbstractProject)}. 34 | * 35 | *

36 | * Alternatively, if the implementation doesn't worry about the backward compatibility, it can 37 | * implement this method to return an empty collection, then just implement {@link GitHubRepositoryNameContributor}. 38 | * 39 | * @deprecated Call {@link GitHubRepositoryNameContributor#parseAssociatedNames(AbstractProject)} instead. 40 | */ 41 | Set getGitHubRepositories(); 42 | 43 | /** 44 | * Contributes {@link GitHubRepositoryName} from {@link GitHubTrigger#getGitHubRepositories()} 45 | * for backward compatibility 46 | */ 47 | @Extension 48 | class GitHubRepositoryNameContributorImpl extends GitHubRepositoryNameContributor { 49 | @Override 50 | public void parseAssociatedNames(Item item, Collection result) { 51 | if (item instanceof ParameterizedJobMixIn.ParameterizedJob) { 52 | ParameterizedJobMixIn.ParameterizedJob p = (ParameterizedJobMixIn.ParameterizedJob) item; 53 | // TODO use standard method in 1.621+ 54 | for (GitHubTrigger ght : Util.filter(p.getTriggers().values(), GitHubTrigger.class)) { 55 | result.addAll(ght.getGitHubRepositories()); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/cloudbees/jenkins/GitHubWebHookCrumbExclusion.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import hudson.Extension; 4 | import hudson.security.csrf.CrumbExclusion; 5 | 6 | import jakarta.servlet.FilterChain; 7 | import jakarta.servlet.ServletException; 8 | import jakarta.servlet.http.HttpServletRequest; 9 | import jakarta.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | import static org.apache.commons.lang3.StringUtils.isEmpty; 13 | 14 | @Extension 15 | public class GitHubWebHookCrumbExclusion extends CrumbExclusion { 16 | 17 | @Override 18 | public boolean process(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) 19 | throws IOException, ServletException { 20 | String pathInfo = req.getPathInfo(); 21 | if (isEmpty(pathInfo)) { 22 | return false; 23 | } 24 | // GitHub will not follow redirects https://github.com/isaacs/github/issues/574 25 | pathInfo = pathInfo.endsWith("/") ? pathInfo : pathInfo + '/'; 26 | if (!pathInfo.equals(getExclusionPath())) { 27 | return false; 28 | } 29 | chain.doFilter(req, resp); 30 | return true; 31 | } 32 | 33 | public String getExclusionPath() { 34 | return "/" + GitHubWebHook.URLNAME + "/"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/coravy/hudson/plugins/github/GithubLinkAction.java: -------------------------------------------------------------------------------- 1 | package com.coravy.hudson.plugins.github; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Action; 5 | import hudson.model.Job; 6 | import jenkins.model.TransientActionFactory; 7 | import org.jenkinsci.plugins.github.util.XSSApi; 8 | 9 | import java.util.Collection; 10 | import java.util.Collections; 11 | 12 | /** 13 | * Add the GitHub Logo/Icon to the sidebar. 14 | * 15 | * @author Stefan Saasen 16 | */ 17 | public final class GithubLinkAction implements Action { 18 | 19 | private final transient GithubProjectProperty projectProperty; 20 | 21 | public GithubLinkAction(GithubProjectProperty githubProjectProperty) { 22 | this.projectProperty = githubProjectProperty; 23 | } 24 | 25 | @Override 26 | public String getDisplayName() { 27 | return "GitHub"; 28 | } 29 | 30 | @Override 31 | public String getIconFileName() { 32 | return "symbol-logo-github plugin-github"; 33 | } 34 | 35 | @Override 36 | public String getUrlName() { 37 | return XSSApi.asValidHref(projectProperty.getProjectUrl().baseUrl()); 38 | } 39 | 40 | @SuppressWarnings("rawtypes") 41 | @Extension 42 | public static class GithubLinkActionFactory extends TransientActionFactory { 43 | @Override 44 | public Class type() { 45 | return Job.class; 46 | } 47 | 48 | @Override 49 | public Collection createFor(Job j) { 50 | GithubProjectProperty prop = ((Job) j).getProperty(GithubProjectProperty.class); 51 | 52 | if (prop == null) { 53 | return Collections.emptySet(); 54 | } else { 55 | return Collections.singleton(new GithubLinkAction(prop)); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/coravy/hudson/plugins/github/GithubUrl.java: -------------------------------------------------------------------------------- 1 | package com.coravy.hudson.plugins.github; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | /** 6 | * @author Stefan Saasen 7 | */ 8 | public final class GithubUrl { 9 | 10 | /** 11 | * Normalizes the github URL. 12 | *

13 | * Removes unwanted path elements (e.g. tree/master). 14 | * 15 | * @return URL to the project or null if input is invalid. 16 | */ 17 | private static String normalize(String url) { 18 | if (StringUtils.isBlank(url)) { 19 | return null; 20 | } 21 | // Strip "/tree/..." 22 | if (url.contains("/tree/")) { 23 | url = url.replaceFirst("/tree/.*$", ""); 24 | } 25 | if (!url.endsWith("/")) { 26 | url += '/'; 27 | } 28 | return url; 29 | } 30 | 31 | private final String baseUrl; 32 | 33 | GithubUrl(final String input) { 34 | this.baseUrl = normalize(input); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return this.baseUrl; 40 | } 41 | 42 | public String baseUrl() { 43 | return this.baseUrl; 44 | } 45 | 46 | /** 47 | * Returns the URL to a particular commit. 48 | * 49 | * @param id - the git SHA1 hash 50 | * 51 | * @return URL String (e.g. http://github.com/juretta/github-plugin/commit/5e31203faea681c41577b685818a361089fac1fc) 52 | */ 53 | public String commitId(final String id) { 54 | return new StringBuilder().append(baseUrl).append("commit/").append(id).toString(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/GitHubPlugin.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github; 2 | 3 | import hudson.Plugin; 4 | import hudson.init.InitMilestone; 5 | import hudson.init.Initializer; 6 | import org.jenkinsci.plugins.github.config.GitHubPluginConfig; 7 | import org.jenkinsci.plugins.github.migration.Migrator; 8 | 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | import org.kohsuke.accmod.Restricted; 11 | import org.kohsuke.accmod.restrictions.DoNotUse; 12 | 13 | import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 14 | 15 | /** 16 | * Main entry point for this plugin 17 | *

18 | * Launches migration from old config versions 19 | * Contains helper method to get global plugin configuration - {@link #configuration()} 20 | * 21 | * @author lanwen (Merkushev Kirill) 22 | */ 23 | public class GitHubPlugin extends Plugin { 24 | /** 25 | * Launched before plugin starts 26 | * Adds alias for {@link GitHubPlugin} to simplify resulting xml. 27 | */ 28 | @Initializer(before = InitMilestone.SYSTEM_CONFIG_LOADED) 29 | @Restricted(DoNotUse.class) 30 | public static void addXStreamAliases() { 31 | Migrator.enableCompatibilityAliases(); 32 | Migrator.enableAliases(); 33 | } 34 | 35 | /** 36 | * Launches migration after all extensions have been augmented as we need to ensure that the credentials plugin 37 | * has been initialized. 38 | * We need ensure that migrator will run after xstream aliases will be added. 39 | * @see JENKINS-36446 40 | */ 41 | @Initializer(after = InitMilestone.EXTENSIONS_AUGMENTED, before = InitMilestone.JOB_LOADED) 42 | public static void runMigrator() throws Exception { 43 | new Migrator().migrate(); 44 | } 45 | 46 | /** 47 | * Shortcut method for getting instance of {@link GitHubPluginConfig}. 48 | * 49 | * @return configuration of plugin 50 | */ 51 | @NonNull 52 | public static GitHubPluginConfig configuration() { 53 | return defaultIfNull( 54 | GitHubPluginConfig.all().get(GitHubPluginConfig.class), 55 | GitHubPluginConfig.EMPTY_CONFIG 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/admin/GHRepoName.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import org.kohsuke.stapler.AnnotationHandler; 5 | import org.kohsuke.stapler.InjectedParameter; 6 | import org.kohsuke.stapler.StaplerRequest2; 7 | import org.slf4j.Logger; 8 | 9 | import java.lang.annotation.Documented; 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | 13 | import static java.lang.annotation.ElementType.PARAMETER; 14 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 15 | import static org.apache.commons.lang3.Validate.notNull; 16 | import static org.slf4j.LoggerFactory.getLogger; 17 | 18 | /** 19 | * InjectedParameter annotation to use on WebMethod parameters. 20 | * Converts form submission to {@link GitHubRepositoryName} 21 | * 22 | * @author lanwen (Merkushev Kirill) 23 | * @see Web Method 24 | * @since 1.17.0 25 | */ 26 | @Retention(RUNTIME) 27 | @Target(PARAMETER) 28 | @Documented 29 | @InjectedParameter(GHRepoName.PayloadHandler.class) 30 | public @interface GHRepoName { 31 | class PayloadHandler extends AnnotationHandler { 32 | private static final Logger LOGGER = getLogger(PayloadHandler.class); 33 | 34 | /** 35 | * @param param name of param in form and name of the argument in web-method 36 | * 37 | * @return {@link GitHubRepositoryName} extracted from request or null on any problem 38 | */ 39 | @Override 40 | public GitHubRepositoryName parse(StaplerRequest2 req, GHRepoName a, Class type, String param) { 41 | String repo = notNull(req, "Why StaplerRequest2 is null?").getParameter(param); 42 | LOGGER.trace("Repo url in method {}", repo); 43 | return GitHubRepositoryName.create(repo); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/admin/RequireAdminRights.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin; 2 | 3 | import jenkins.model.Jenkins; 4 | import org.kohsuke.stapler.StaplerRequest2; 5 | import org.kohsuke.stapler.StaplerResponse2; 6 | import org.kohsuke.stapler.interceptor.Interceptor; 7 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 8 | 9 | import jakarta.servlet.ServletException; 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | import java.lang.reflect.InvocationTargetException; 13 | 14 | import static java.lang.annotation.ElementType.FIELD; 15 | import static java.lang.annotation.ElementType.METHOD; 16 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 17 | 18 | /** 19 | * InterceptorAnnotation annotation to use on WebMethod signature. 20 | * Encapsulates preprocess logic of checking for admin rights 21 | * 22 | * @author lanwen (Merkushev Kirill) 23 | * @see Web Method 24 | */ 25 | @Retention(RUNTIME) 26 | @Target({METHOD, FIELD}) 27 | @InterceptorAnnotation(RequireAdminRights.Processor.class) 28 | public @interface RequireAdminRights { 29 | class Processor extends Interceptor { 30 | 31 | @Override 32 | public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) 33 | throws IllegalAccessException, InvocationTargetException, ServletException { 34 | 35 | Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); 36 | return target.invoke(request, response, instance, arguments); 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/admin/RespondWithRedirect.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin; 2 | 3 | import org.kohsuke.stapler.HttpRedirect; 4 | import org.kohsuke.stapler.StaplerRequest2; 5 | import org.kohsuke.stapler.StaplerResponse2; 6 | import org.kohsuke.stapler.interceptor.Interceptor; 7 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 8 | 9 | import jakarta.servlet.ServletException; 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | import java.lang.reflect.InvocationTargetException; 13 | 14 | import static java.lang.annotation.ElementType.FIELD; 15 | import static java.lang.annotation.ElementType.METHOD; 16 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 17 | 18 | /** 19 | * InterceptorAnnotation annotation to use on WebMethod signature. 20 | * Helps to redirect to prev page after web-method invoking. 21 | * WebMethod can return {@code void} 22 | * 23 | * @author lanwen (Merkushev Kirill) 24 | * @see Web Method 25 | */ 26 | @Retention(RUNTIME) 27 | @Target({METHOD, FIELD}) 28 | @InterceptorAnnotation(RespondWithRedirect.Processor.class) 29 | public @interface RespondWithRedirect { 30 | class Processor extends Interceptor { 31 | 32 | @Override 33 | public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) 34 | throws IllegalAccessException, InvocationTargetException, ServletException { 35 | target.invoke(request, response, instance, arguments); 36 | throw new InvocationTargetException(new HttpRedirect(".")); 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/admin/ValidateRepoName.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import org.kohsuke.stapler.StaplerRequest2; 5 | import org.kohsuke.stapler.StaplerResponse2; 6 | import org.kohsuke.stapler.interceptor.Interceptor; 7 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 8 | 9 | import jakarta.servlet.ServletException; 10 | import java.lang.annotation.Retention; 11 | import java.lang.annotation.Target; 12 | import java.lang.reflect.InvocationTargetException; 13 | 14 | import static com.google.common.base.Predicates.instanceOf; 15 | import static com.google.common.collect.Lists.newArrayList; 16 | import static java.lang.annotation.ElementType.FIELD; 17 | import static java.lang.annotation.ElementType.METHOD; 18 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 19 | import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST; 20 | import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; 21 | import static org.kohsuke.stapler.HttpResponses.errorWithoutStack; 22 | 23 | /** 24 | * InterceptorAnnotation annotation to use on WebMethod signature. 25 | * Encapsulates preprocess logic. Checks that arg list contains nonnull repo name object 26 | * 27 | * @author lanwen (Merkushev Kirill) 28 | * @see Web Method 29 | */ 30 | @Retention(RUNTIME) 31 | @Target({METHOD, FIELD}) 32 | @InterceptorAnnotation(ValidateRepoName.Processor.class) 33 | public @interface ValidateRepoName { 34 | class Processor extends Interceptor { 35 | 36 | @Override 37 | public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) 38 | throws IllegalAccessException, InvocationTargetException, ServletException { 39 | 40 | if (!from(newArrayList(arguments)).firstMatch(instanceOf(GitHubRepositoryName.class)).isPresent()) { 41 | throw new InvocationTargetException( 42 | errorWithoutStack(SC_BAD_REQUEST, "Request should contain full repo name") 43 | ); 44 | } 45 | 46 | return target.invoke(request, response, instance, arguments); 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/common/CombineErrorHandler.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.common; 2 | 3 | import hudson.model.Run; 4 | import hudson.model.TaskListener; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import static org.apache.commons.collections.CollectionUtils.isNotEmpty; 13 | 14 | /** 15 | * With help of list of other error handlers handles exception. 16 | * If no one will handle it, exception will be wrapped to {@link ErrorHandlingException} 17 | * and thrown by the handle method 18 | * 19 | * @author lanwen (Merkushev Kirill) 20 | * @since 1.19.0 21 | */ 22 | public class CombineErrorHandler implements ErrorHandler { 23 | private static final Logger LOG = LoggerFactory.getLogger(CombineErrorHandler.class); 24 | 25 | private List handlers = new ArrayList<>(); 26 | 27 | private CombineErrorHandler() { 28 | } 29 | 30 | /** 31 | * Static factory to produce new instance of this handler 32 | * 33 | * @return new instance 34 | */ 35 | public static CombineErrorHandler errorHandling() { 36 | return new CombineErrorHandler(); 37 | } 38 | 39 | public CombineErrorHandler withHandlers(List handlers) { 40 | if (isNotEmpty(handlers)) { 41 | this.handlers.addAll(handlers); 42 | } 43 | return this; 44 | } 45 | 46 | /** 47 | * Handles exception with help of other handlers. If no one will handle it, it will be thrown to the top level 48 | * 49 | * @param e exception to handle (log, ignore, process, rethrow) 50 | * @param run run object from the step 51 | * @param listener listener object from the step 52 | * 53 | * @return true if exception handled or rethrows it 54 | */ 55 | @Override 56 | public boolean handle(Exception e, @NonNull Run run, @NonNull TaskListener listener) { 57 | LOG.debug("Exception in {} will be processed with {} handlers", 58 | run.getParent().getName(), handlers.size(), e); 59 | try { 60 | for (ErrorHandler next : handlers) { 61 | if (next.handle(e, run, listener)) { 62 | LOG.debug("Exception in {} [{}] handled by [{}]", 63 | run.getParent().getName(), 64 | e.getMessage(), 65 | next.getClass()); 66 | return true; 67 | } 68 | } 69 | } catch (Exception unhandled) { 70 | LOG.error("Exception in {} unhandled", run.getParent().getName(), unhandled); 71 | throw new ErrorHandlingException(unhandled); 72 | } 73 | 74 | throw new ErrorHandlingException(e); 75 | } 76 | 77 | /** 78 | * Wrapper for the not handled by this handler exceptions 79 | */ 80 | public static class ErrorHandlingException extends RuntimeException { 81 | public ErrorHandlingException(Throwable cause) { 82 | super(cause); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/common/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.common; 2 | 3 | import hudson.model.Run; 4 | import hudson.model.TaskListener; 5 | 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | 8 | /** 9 | * So you can implement bunch of {@link ErrorHandler}s and log, rethrow, ignore exception. 10 | * Useful to control own step exceptions 11 | * (for example {@link org.jenkinsci.plugins.github.status.GitHubCommitStatusSetter}) 12 | * 13 | * @author lanwen (Merkushev Kirill) 14 | * @since 1.19.0 15 | */ 16 | public interface ErrorHandler { 17 | 18 | /** 19 | * Normally should return true if exception is handled and no other handler should do anything. 20 | * If you will return false, the next error handler should try to handle this exception 21 | * 22 | * @param e exception to handle (log, ignore, process, rethrow) 23 | * @param run run object from the step 24 | * @param listener listener object from the step 25 | * 26 | * @return true if exception handled successfully 27 | * @throws Exception you can rethrow exception of any type 28 | */ 29 | boolean handle(Exception e, @NonNull Run run, @NonNull TaskListener listener) throws Exception; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/GHSubscriberEvent.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jenkins.scm.api.SCMEvent; 5 | import org.kohsuke.github.GHEvent; 6 | 7 | import edu.umd.cs.findbugs.annotations.CheckForNull; 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | 10 | /** 11 | * An event for a {@link GHEventsSubscriber}. 12 | * 13 | * @since 1.26.0 14 | */ 15 | public class GHSubscriberEvent extends SCMEvent { 16 | /** 17 | * The type of event. 18 | */ 19 | private final GHEvent ghEvent; 20 | 21 | private final String eventGuid; 22 | 23 | /** 24 | * @deprecated use {@link #GHSubscriberEvent(String, String, GHEvent, String)} instead. 25 | */ 26 | @Deprecated 27 | public GHSubscriberEvent(@CheckForNull String origin, @NonNull GHEvent ghEvent, @NonNull String payload) { 28 | this(null, origin, ghEvent, payload); 29 | } 30 | 31 | /** 32 | * Constructs a new {@link GHSubscriberEvent}. 33 | * @param eventGuid the globally unique identifier (GUID) to identify the event; value of 34 | * request header {@link com.cloudbees.jenkins.GitHubWebHook#X_GITHUB_DELIVERY}. 35 | * @param origin the origin (see {@link SCMEvent#originOf(HttpServletRequest)}) or {@code null}. 36 | * @param ghEvent the type of event received from GitHub. 37 | * @param payload the event payload. 38 | */ 39 | public GHSubscriberEvent( 40 | @CheckForNull String eventGuid, 41 | @CheckForNull String origin, 42 | @NonNull GHEvent ghEvent, 43 | @NonNull String payload) { 44 | super(Type.UPDATED, payload, origin); 45 | this.ghEvent = ghEvent; 46 | this.eventGuid = eventGuid; 47 | } 48 | 49 | /** 50 | * Gets the type of event received. 51 | * 52 | * @return the type of event received. 53 | */ 54 | public GHEvent getGHEvent() { 55 | return ghEvent; 56 | } 57 | 58 | @CheckForNull 59 | public String getEventGuid() { 60 | return eventGuid; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/GitHubCommitShaSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status; 2 | 3 | import hudson.ExtensionPoint; 4 | import hudson.model.AbstractDescribableImpl; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | import java.io.IOException; 10 | 11 | /** 12 | * Extension point to provide commit sha which will be used to set state 13 | * 14 | * @author lanwen (Merkushev Kirill) 15 | * @since 1.19.0 16 | */ 17 | public abstract class GitHubCommitShaSource extends AbstractDescribableImpl 18 | implements ExtensionPoint { 19 | 20 | /** 21 | * @param run enclosing run 22 | * @param listener listener of the run. Can be used to fetch env vars 23 | * 24 | * @return plain sha to set state 25 | */ 26 | public abstract String get(@NonNull Run run, @NonNull TaskListener listener) 27 | throws IOException, InterruptedException; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/GitHubReposSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status; 2 | 3 | import hudson.ExtensionPoint; 4 | import hudson.model.AbstractDescribableImpl; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.kohsuke.github.GHRepository; 8 | 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | import java.util.List; 11 | 12 | /** 13 | * Extension point to provide list of resolved repositories where commit is located 14 | * 15 | * @author lanwen (Merkushev Kirill) 16 | * @since 1.19.0 17 | */ 18 | public abstract class GitHubReposSource extends AbstractDescribableImpl implements ExtensionPoint { 19 | 20 | /** 21 | * @param run actual run 22 | * @param listener build listener 23 | * 24 | * @return resolved list of GitHub repositories 25 | */ 26 | public abstract List repos(@NonNull Run run, @NonNull TaskListener listener); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/GitHubStatusBackrefSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status; 2 | 3 | import hudson.ExtensionPoint; 4 | import hudson.model.AbstractDescribableImpl; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | 8 | /** 9 | * Extension point to provide backref for the status, i.e. to the build or to the test report. 10 | * 11 | * @author pupssman (Kalinin Ivan) 12 | * @since 1.21.2 13 | */ 14 | public abstract class GitHubStatusBackrefSource extends AbstractDescribableImpl 15 | implements ExtensionPoint { 16 | 17 | /** 18 | * @param run actual run 19 | * @param listener build listener 20 | * 21 | * @return URL that points to the status source, i.e. test result page 22 | */ 23 | public abstract String get(Run run, TaskListener listener); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/GitHubStatusContextSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status; 2 | 3 | import hudson.ExtensionPoint; 4 | import hudson.model.AbstractDescribableImpl; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | 10 | /** 11 | * Extension point to provide context of the state. For example `integration-tests` or `build` 12 | * 13 | * @author lanwen (Merkushev Kirill) 14 | * @since 1.19.0 15 | */ 16 | public abstract class GitHubStatusContextSource extends AbstractDescribableImpl 17 | implements ExtensionPoint { 18 | 19 | /** 20 | * @param run actual run 21 | * @param listener build listener 22 | * 23 | * @return simple short string to represent context of this state 24 | */ 25 | public abstract String context(@NonNull Run run, @NonNull TaskListener listener); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/GitHubStatusResultSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status; 2 | 3 | import hudson.ExtensionPoint; 4 | import hudson.model.AbstractDescribableImpl; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.kohsuke.github.GHCommitState; 8 | 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | import java.io.IOException; 11 | 12 | /** 13 | * Extension point to provide exact state and message for the commit 14 | * 15 | * @author lanwen (Merkushev Kirill) 16 | * @since 1.19.0 17 | */ 18 | public abstract class GitHubStatusResultSource extends AbstractDescribableImpl 19 | implements ExtensionPoint { 20 | 21 | /** 22 | * @param run actual run 23 | * @param listener run listener 24 | * 25 | * @return bean with state and already expanded message 26 | */ 27 | public abstract StatusResult get(@NonNull Run run, @NonNull TaskListener listener) 28 | throws IOException, InterruptedException; 29 | 30 | /** 31 | * Bean with state and msg info 32 | */ 33 | public static class StatusResult { 34 | private GHCommitState state; 35 | private String msg; 36 | 37 | public StatusResult(GHCommitState state, String msg) { 38 | this.state = state; 39 | this.msg = msg; 40 | } 41 | 42 | public GHCommitState getState() { 43 | return state; 44 | } 45 | 46 | public String getMsg() { 47 | return msg; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/StatusErrorHandler.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.ExtensionPoint; 5 | import hudson.model.AbstractDescribableImpl; 6 | import hudson.model.Descriptor; 7 | import jenkins.model.Jenkins; 8 | import org.jenkinsci.plugins.github.common.ErrorHandler; 9 | 10 | /** 11 | * Extension point to provide way of how to react on errors in status setter step 12 | * 13 | * @author lanwen (Merkushev Kirill) 14 | * @since 1.19.0 15 | */ 16 | public abstract class StatusErrorHandler extends AbstractDescribableImpl 17 | implements ErrorHandler, ExtensionPoint { 18 | 19 | /** 20 | * Used in view 21 | * 22 | * @return all of the available error handlers. 23 | */ 24 | public static DescriptorExtensionList> all() { 25 | return Jenkins.getInstance().getDescriptorList(StatusErrorHandler.class); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/extension/status/misc/ConditionalResult.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status.misc; 2 | 3 | import hudson.DescriptorExtensionList; 4 | import hudson.ExtensionPoint; 5 | import hudson.model.AbstractDescribableImpl; 6 | import hudson.model.Descriptor; 7 | import hudson.model.Run; 8 | import hudson.util.ListBoxModel; 9 | import jenkins.model.Jenkins; 10 | import org.kohsuke.github.GHCommitState; 11 | import org.kohsuke.stapler.DataBoundSetter; 12 | 13 | import edu.umd.cs.findbugs.annotations.NonNull; 14 | 15 | /** 16 | * This extension point allows to define when and what to send as state and message. 17 | * It will be used as part of {@link org.jenkinsci.plugins.github.status.sources.ConditionalStatusResultSource}. 18 | * 19 | * @author lanwen (Merkushev Kirill) 20 | * @see org.jenkinsci.plugins.github.status.sources.misc.BetterThanOrEqualBuildResult 21 | * @since 1.19.0 22 | */ 23 | public abstract class ConditionalResult extends AbstractDescribableImpl implements ExtensionPoint { 24 | 25 | private String state; 26 | private String message; 27 | 28 | @DataBoundSetter 29 | public void setState(String state) { 30 | this.state = state; 31 | } 32 | 33 | @DataBoundSetter 34 | public void setMessage(String message) { 35 | this.message = message; 36 | } 37 | 38 | /** 39 | * @return State to set. Will be converted to {@link GHCommitState} 40 | */ 41 | public String getState() { 42 | return state; 43 | } 44 | 45 | /** 46 | * @return Message to write. Can contain env vars, will be expanded. 47 | */ 48 | public String getMessage() { 49 | return message; 50 | } 51 | 52 | /** 53 | * If matches, will be used to set state 54 | * 55 | * @param run to check against 56 | * 57 | * @return true if matches 58 | */ 59 | public abstract boolean matches(@NonNull Run run); 60 | 61 | /** 62 | * Should be extended to and marked as {@link hudson.Extension} to be in list 63 | */ 64 | public abstract static class ConditionalResultDescriptor extends Descriptor { 65 | 66 | /** 67 | * Gets all available extensions. Used in view 68 | * 69 | * @return all descriptors of conditional results 70 | */ 71 | public static DescriptorExtensionList> all() { 72 | return Jenkins.getInstance().getDescriptorList(ConditionalResult.class); 73 | } 74 | 75 | /** 76 | * @return options to fill state items in view 77 | */ 78 | public ListBoxModel doFillStateItems() { 79 | ListBoxModel items = new ListBoxModel(); 80 | for (GHCommitState commitState : GHCommitState.values()) { 81 | items.add(commitState.name()); 82 | } 83 | return items; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/internal/GHPluginConfigException.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.internal; 2 | 3 | /** 4 | * @author lanwen (Merkushev Kirill) 5 | */ 6 | public class GHPluginConfigException extends RuntimeException { 7 | public GHPluginConfigException(String message, Object... args) { 8 | super(String.format(message, args)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/err/ChangingBuildStatusErrorHandler.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.err; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Result; 6 | import hudson.model.Run; 7 | import hudson.model.TaskListener; 8 | import hudson.util.ListBoxModel; 9 | import org.jenkinsci.plugins.github.extension.status.StatusErrorHandler; 10 | import org.kohsuke.stapler.DataBoundConstructor; 11 | 12 | import edu.umd.cs.findbugs.annotations.NonNull; 13 | 14 | import static hudson.model.Result.FAILURE; 15 | import static hudson.model.Result.UNSTABLE; 16 | import static org.apache.commons.lang3.StringUtils.trimToEmpty; 17 | 18 | /** 19 | * Can change build status in case of errors 20 | * 21 | * @author lanwen (Merkushev Kirill) 22 | * @since 1.19.0 23 | */ 24 | public class ChangingBuildStatusErrorHandler extends StatusErrorHandler { 25 | 26 | private String result; 27 | 28 | @DataBoundConstructor 29 | public ChangingBuildStatusErrorHandler(String result) { 30 | this.result = result; 31 | } 32 | 33 | public String getResult() { 34 | return result; 35 | } 36 | 37 | /** 38 | * Logs error to build console and changes build result 39 | * 40 | * @return true as of it terminating handler 41 | */ 42 | @Override 43 | public boolean handle(Exception e, @NonNull Run run, @NonNull TaskListener listener) { 44 | Result toSet = Result.fromString(trimToEmpty(result)); 45 | 46 | listener.error("[GitHub Commit Status Setter] - %s, setting build result to %s", e.getMessage(), toSet); 47 | 48 | run.setResult(toSet); 49 | return true; 50 | } 51 | 52 | @Extension 53 | public static class ChangingBuildStatusErrorHandlerDescriptor extends Descriptor { 54 | 55 | private static final Result[] SUPPORTED_RESULTS = {FAILURE, UNSTABLE}; 56 | 57 | @Override 58 | public String getDisplayName() { 59 | return "Change build status"; 60 | } 61 | 62 | @SuppressWarnings("unused") 63 | public ListBoxModel doFillResultItems() { 64 | ListBoxModel items = new ListBoxModel(); 65 | for (Result supported : SUPPORTED_RESULTS) { 66 | items.add(supported.toString()); 67 | } 68 | return items; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/err/ShallowAnyErrorHandler.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.err; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.jenkinsci.plugins.github.extension.status.StatusErrorHandler; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | 10 | import edu.umd.cs.findbugs.annotations.NonNull; 11 | 12 | /** 13 | * Just logs message to the build console and do nothing after it 14 | * 15 | * @author lanwen (Merkushev Kirill) 16 | * @since 1.19.0 17 | */ 18 | public class ShallowAnyErrorHandler extends StatusErrorHandler { 19 | 20 | @DataBoundConstructor 21 | public ShallowAnyErrorHandler() { 22 | } 23 | 24 | /** 25 | * @return true as of its terminating handler 26 | */ 27 | @Override 28 | public boolean handle(Exception e, @NonNull Run run, @NonNull TaskListener listener) { 29 | listener.error("[GitHub Commit Status Setter] Failed to update commit state on GitHub. " 30 | + "Ignoring exception [%s]", e.getMessage()); 31 | return true; 32 | } 33 | 34 | @Extension 35 | public static class ShallowAnyErrorHandlerDescriptor extends Descriptor { 36 | @Override 37 | public String getDisplayName() { 38 | return "Just ignore any errors"; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/AnyDefinedRepositorySource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import com.cloudbees.jenkins.GitHubRepositoryNameContributor; 5 | import hudson.Extension; 6 | import hudson.model.Descriptor; 7 | import hudson.model.Run; 8 | import hudson.model.TaskListener; 9 | import org.jenkinsci.plugins.github.extension.status.GitHubReposSource; 10 | import org.jenkinsci.plugins.github.util.misc.NullSafeFunction; 11 | import org.kohsuke.github.GHRepository; 12 | import org.kohsuke.stapler.DataBoundConstructor; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import edu.umd.cs.findbugs.annotations.NonNull; 17 | import java.util.Collection; 18 | import java.util.List; 19 | 20 | import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; 21 | 22 | /** 23 | * Just uses contributors to get list of resolved repositories 24 | * 25 | * @author lanwen (Merkushev Kirill) 26 | * @since 1.19.0 27 | */ 28 | public class AnyDefinedRepositorySource extends GitHubReposSource { 29 | 30 | private static final Logger LOG = LoggerFactory.getLogger(AnyDefinedRepositorySource.class); 31 | 32 | @DataBoundConstructor 33 | public AnyDefinedRepositorySource() { 34 | } 35 | 36 | /** 37 | * @return all repositories which can be found by repo-contributors 38 | */ 39 | @Override 40 | public List repos(@NonNull Run run, @NonNull TaskListener listener) { 41 | final Collection names = GitHubRepositoryNameContributor 42 | .parseAssociatedNames(run.getParent()); 43 | 44 | LOG.trace("repositories source=repo-name-contributor value={}", names); 45 | 46 | return from(names).transformAndConcat(new NullSafeFunction>() { 47 | @Override 48 | protected Iterable applyNullSafe(@NonNull GitHubRepositoryName name) { 49 | return name.resolve(); 50 | } 51 | }).toList(); 52 | } 53 | 54 | @Extension 55 | public static class AnyDefinedRepoSourceDescriptor extends Descriptor { 56 | @Override 57 | public String getDisplayName() { 58 | return "Any defined in job repository"; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/BuildDataRevisionShaSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.eclipse.jgit.lib.ObjectId; 8 | import org.jenkinsci.plugins.github.extension.status.GitHubCommitShaSource; 9 | import org.jenkinsci.plugins.github.util.BuildDataHelper; 10 | import org.kohsuke.stapler.DataBoundConstructor; 11 | 12 | import edu.umd.cs.findbugs.annotations.NonNull; 13 | import java.io.IOException; 14 | 15 | /** 16 | * Gets sha from build data 17 | * 18 | * @author lanwen (Merkushev Kirill) 19 | * @since 1.19.0 20 | */ 21 | public class BuildDataRevisionShaSource extends GitHubCommitShaSource { 22 | 23 | @DataBoundConstructor 24 | public BuildDataRevisionShaSource() { 25 | } 26 | 27 | /** 28 | * @return sha from git's scm build data action 29 | */ 30 | @Override 31 | public String get(@NonNull Run run, @NonNull TaskListener listener) throws IOException { 32 | return ObjectId.toString(BuildDataHelper.getCommitSHA1(run)); 33 | } 34 | 35 | @Extension 36 | public static class BuildDataRevisionShaSourceDescriptor extends Descriptor { 37 | @Override 38 | public String getDisplayName() { 39 | return "Latest build revision"; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/BuildRefBackrefSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider; 8 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusBackrefSource; 9 | import org.kohsuke.stapler.DataBoundConstructor; 10 | 11 | /** 12 | * Gets backref from Run URL. 13 | * 14 | * @author pupssman (Kalinin Ivan) 15 | * @since 1.22.1 16 | */ 17 | public class BuildRefBackrefSource extends GitHubStatusBackrefSource { 18 | 19 | @DataBoundConstructor 20 | public BuildRefBackrefSource() { 21 | } 22 | 23 | /** 24 | * Returns absolute URL of the Run 25 | */ 26 | @SuppressWarnings("deprecation") 27 | @Override 28 | public String get(Run run, TaskListener listener) { 29 | return DisplayURLProvider.get().getRunURL(run); 30 | } 31 | 32 | @Extension 33 | public static class BuildRefBackrefSourceDescriptor extends Descriptor { 34 | @Override 35 | public String getDisplayName() { 36 | return "Backref to the build"; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/ConditionalStatusResultSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.apache.commons.lang3.EnumUtils; 8 | import org.jenkinsci.plugins.github.common.ExpandableMessage; 9 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusResultSource; 10 | import org.jenkinsci.plugins.github.extension.status.misc.ConditionalResult; 11 | import org.kohsuke.github.GHCommitState; 12 | import org.kohsuke.stapler.DataBoundConstructor; 13 | 14 | import edu.umd.cs.findbugs.annotations.NonNull; 15 | import java.io.IOException; 16 | import java.util.Collections; 17 | import java.util.List; 18 | 19 | import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; 20 | import static org.kohsuke.github.GHCommitState.ERROR; 21 | import static org.kohsuke.github.GHCommitState.PENDING; 22 | 23 | /** 24 | * Allows to define message and state for commit for different run results 25 | * 26 | * @author lanwen (Merkushev Kirill) 27 | */ 28 | public class ConditionalStatusResultSource extends GitHubStatusResultSource { 29 | 30 | private List results; 31 | 32 | @DataBoundConstructor 33 | public ConditionalStatusResultSource(List results) { 34 | this.results = results; 35 | } 36 | 37 | @NonNull 38 | public List getResults() { 39 | return defaultIfNull(results, Collections.emptyList()); 40 | } 41 | 42 | /** 43 | * First matching result win. Or will be used pending state. 44 | * Messages are expanded with token macro and env variables 45 | * 46 | * @return first matched result or pending state with warn msg 47 | */ 48 | @Override 49 | public StatusResult get(@NonNull Run run, @NonNull TaskListener listener) 50 | throws IOException, InterruptedException { 51 | 52 | for (ConditionalResult conditionalResult : getResults()) { 53 | if (conditionalResult.matches(run)) { 54 | return new StatusResult( 55 | defaultIfNull(EnumUtils.getEnum(GHCommitState.class, conditionalResult.getState()), ERROR), 56 | new ExpandableMessage(conditionalResult.getMessage()).expandAll(run, listener) 57 | ); 58 | } 59 | } 60 | 61 | return new StatusResult( 62 | PENDING, 63 | new ExpandableMessage("Can't define which status to set").expandAll(run, listener) 64 | ); 65 | } 66 | 67 | @Extension 68 | public static class ConditionalStatusResultSourceDescriptor extends Descriptor { 69 | @Override 70 | public String getDisplayName() { 71 | return "Based on build result manually defined"; 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/DefaultCommitContextSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusContextSource; 8 | import org.kohsuke.stapler.DataBoundConstructor; 9 | 10 | import edu.umd.cs.findbugs.annotations.NonNull; 11 | 12 | import static com.coravy.hudson.plugins.github.GithubProjectProperty.displayNameFor; 13 | 14 | /** 15 | * Uses job name or defined in prop context name 16 | * 17 | * @author lanwen (Merkushev Kirill) 18 | * @since 1.19.0 19 | */ 20 | public class DefaultCommitContextSource extends GitHubStatusContextSource { 21 | 22 | @DataBoundConstructor 23 | public DefaultCommitContextSource() { 24 | } 25 | 26 | /** 27 | * @return context name 28 | * @see com.coravy.hudson.plugins.github.GithubProjectProperty#displayNameFor(hudson.model.Job) 29 | */ 30 | @Override 31 | public String context(@NonNull Run run, @NonNull TaskListener listener) { 32 | return displayNameFor(run.getParent()); 33 | } 34 | 35 | @Extension 36 | public static class DefaultContextSourceDescriptor extends Descriptor { 37 | @Override 38 | public String getDisplayName() { 39 | return "From GitHub property with fallback to job name"; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/DefaultStatusResultSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import com.cloudbees.jenkins.Messages; 4 | import hudson.Extension; 5 | import hudson.Util; 6 | import hudson.model.Descriptor; 7 | import hudson.model.Run; 8 | import hudson.model.TaskListener; 9 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusResultSource; 10 | import org.kohsuke.github.GHCommitState; 11 | import org.kohsuke.stapler.DataBoundConstructor; 12 | 13 | import edu.umd.cs.findbugs.annotations.NonNull; 14 | import java.io.IOException; 15 | 16 | import static hudson.model.Result.FAILURE; 17 | import static hudson.model.Result.SUCCESS; 18 | import static hudson.model.Result.UNSTABLE; 19 | import static java.util.Arrays.asList; 20 | import static org.jenkinsci.plugins.github.status.sources.misc.AnyBuildResult.onAnyResult; 21 | import static org.jenkinsci.plugins.github.status.sources.misc.BetterThanOrEqualBuildResult.betterThanOrEqualTo; 22 | 23 | /** 24 | * Default way to report about build results. 25 | * Reports about time and build status 26 | * 27 | * @author lanwen (Merkushev Kirill) 28 | * @since 1.19.0 29 | */ 30 | public class DefaultStatusResultSource extends GitHubStatusResultSource { 31 | 32 | @DataBoundConstructor 33 | public DefaultStatusResultSource() { 34 | } 35 | 36 | @Override 37 | public StatusResult get(@NonNull Run run, @NonNull TaskListener listener) throws IOException, 38 | InterruptedException { 39 | 40 | // We do not use `build.getDurationString()` because it appends 'and counting' (build is still running) 41 | String duration = Util.getTimeSpanString(System.currentTimeMillis() - run.getTimeInMillis()); 42 | 43 | return new ConditionalStatusResultSource(asList( 44 | betterThanOrEqualTo(SUCCESS, 45 | GHCommitState.SUCCESS, Messages.CommitNotifier_Success(run.getDisplayName(), duration)), 46 | 47 | betterThanOrEqualTo(UNSTABLE, 48 | GHCommitState.FAILURE, Messages.CommitNotifier_Unstable(run.getDisplayName(), duration)), 49 | 50 | betterThanOrEqualTo(FAILURE, 51 | GHCommitState.ERROR, Messages.CommitNotifier_Failed(run.getDisplayName(), duration)), 52 | 53 | onAnyResult(GHCommitState.PENDING, Messages.CommitNotifier_Pending(run.getDisplayName())) 54 | )).get(run, listener); 55 | } 56 | 57 | @Extension 58 | public static class DefaultResultSourceDescriptor extends Descriptor { 59 | @Override 60 | public String getDisplayName() { 61 | return "One of default messages and statuses"; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredBackrefSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import org.jenkinsci.plugins.github.common.ExpandableMessage; 4 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusBackrefSource; 5 | import org.kohsuke.stapler.DataBoundConstructor; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import hudson.Extension; 10 | import hudson.model.Descriptor; 11 | import hudson.model.Run; 12 | import hudson.model.TaskListener; 13 | 14 | /** 15 | * Allows to manually enter backref, with env/token expansion. 16 | * 17 | * @author pupssman (Kalinin Ivan) 18 | * @since 1.21.2 19 | * 20 | */ 21 | public class ManuallyEnteredBackrefSource extends GitHubStatusBackrefSource { 22 | private static final Logger LOG = LoggerFactory.getLogger(ManuallyEnteredBackrefSource.class); 23 | 24 | private String backref; 25 | 26 | @DataBoundConstructor 27 | public ManuallyEnteredBackrefSource(String backref) { 28 | this.backref = backref; 29 | } 30 | 31 | public String getBackref() { 32 | return backref; 33 | } 34 | 35 | /** 36 | * Just returns what user entered. Expands env vars and token macro 37 | */ 38 | @SuppressWarnings("deprecation") 39 | @Override 40 | public String get(Run run, TaskListener listener) { 41 | try { 42 | return new ExpandableMessage(backref).expandAll(run, listener); 43 | } catch (Exception e) { 44 | LOG.debug("Can't expand backref, returning as is", e); 45 | return backref; 46 | } 47 | } 48 | 49 | @Extension 50 | public static class ManuallyEnteredBackrefSourceDescriptor extends Descriptor { 51 | @Override 52 | public String getDisplayName() { 53 | return "Manually entered backref"; 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredCommitContextSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.jenkinsci.plugins.github.common.ExpandableMessage; 8 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusContextSource; 9 | import org.kohsuke.stapler.DataBoundConstructor; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import edu.umd.cs.findbugs.annotations.NonNull; 14 | 15 | /** 16 | * Allows to manually enter context 17 | * 18 | * @author lanwen (Merkushev Kirill) 19 | * @since 1.19.0 20 | */ 21 | public class ManuallyEnteredCommitContextSource extends GitHubStatusContextSource { 22 | private static final Logger LOG = LoggerFactory.getLogger(ManuallyEnteredCommitContextSource.class); 23 | 24 | private String context; 25 | 26 | @DataBoundConstructor 27 | public ManuallyEnteredCommitContextSource(String context) { 28 | this.context = context; 29 | } 30 | 31 | public String getContext() { 32 | return context; 33 | } 34 | 35 | /** 36 | * Just returns what user entered. Expands env vars and token macro 37 | */ 38 | @Override 39 | public String context(@NonNull Run run, @NonNull TaskListener listener) { 40 | try { 41 | return new ExpandableMessage(context).expandAll(run, listener); 42 | } catch (Exception e) { 43 | LOG.debug("Can't expand context, returning as is", e); 44 | return context; 45 | } 46 | } 47 | 48 | @Extension 49 | public static class ManuallyEnteredCommitContextSourceDescriptor extends Descriptor { 50 | @Override 51 | public String getDisplayName() { 52 | return "Manually entered context name"; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredRepositorySource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import com.google.common.annotations.VisibleForTesting; 5 | import hudson.Extension; 6 | import hudson.model.Descriptor; 7 | import hudson.model.Run; 8 | import hudson.model.TaskListener; 9 | import org.jenkinsci.plugins.github.extension.status.GitHubReposSource; 10 | import org.jenkinsci.plugins.github.util.misc.NullSafeFunction; 11 | import org.kohsuke.github.GHRepository; 12 | import org.kohsuke.stapler.DataBoundConstructor; 13 | 14 | import edu.umd.cs.findbugs.annotations.NonNull; 15 | import java.util.Collections; 16 | import java.util.List; 17 | 18 | import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; 19 | 20 | public class ManuallyEnteredRepositorySource extends GitHubReposSource { 21 | private String url; 22 | 23 | @DataBoundConstructor 24 | public ManuallyEnteredRepositorySource(String url) { 25 | this.url = url; 26 | } 27 | 28 | public String getUrl() { 29 | return url; 30 | } 31 | 32 | @VisibleForTesting 33 | GitHubRepositoryName createName(String url) { 34 | return GitHubRepositoryName.create(url); 35 | } 36 | 37 | @Override 38 | public List repos(@NonNull Run run, @NonNull final TaskListener listener) { 39 | List urls = Collections.singletonList(url); 40 | return from(urls).transformAndConcat(new NullSafeFunction>() { 41 | @Override 42 | protected Iterable applyNullSafe(@NonNull String url) { 43 | GitHubRepositoryName name = createName(url); 44 | if (name != null) { 45 | return name.resolve(); 46 | } else { 47 | listener.getLogger().printf("Unable to match %s with a GitHub repository.%n", url); 48 | return Collections.emptyList(); 49 | } 50 | } 51 | }).toList(); 52 | } 53 | 54 | @Extension 55 | public static class ManuallyEnteredRepositorySourceDescriptor extends Descriptor { 56 | @Override 57 | public String getDisplayName() { 58 | return "Manually entered repository"; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredShaSource.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Descriptor; 5 | import hudson.model.Run; 6 | import hudson.model.TaskListener; 7 | import org.jenkinsci.plugins.github.common.ExpandableMessage; 8 | import org.jenkinsci.plugins.github.extension.status.GitHubCommitShaSource; 9 | import org.kohsuke.stapler.DataBoundConstructor; 10 | 11 | import edu.umd.cs.findbugs.annotations.NonNull; 12 | import java.io.IOException; 13 | 14 | /** 15 | * Allows to enter sha manually 16 | * 17 | * @author lanwen (Merkushev Kirill) 18 | * @since 1.19.0 19 | */ 20 | public class ManuallyEnteredShaSource extends GitHubCommitShaSource { 21 | 22 | private String sha; 23 | 24 | @DataBoundConstructor 25 | public ManuallyEnteredShaSource(String sha) { 26 | this.sha = sha; 27 | } 28 | 29 | public String getSha() { 30 | return sha; 31 | } 32 | 33 | /** 34 | * Expands env vars and token macro in entered sha 35 | */ 36 | @Override 37 | public String get(@NonNull Run run, @NonNull TaskListener listener) throws IOException, InterruptedException { 38 | return new ExpandableMessage(sha).expandAll(run, listener); 39 | } 40 | 41 | @Extension 42 | public static class ManuallyEnteredShaSourceDescriptor extends Descriptor { 43 | @Override 44 | public String getDisplayName() { 45 | return "Manually entered SHA"; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/status/sources/misc/AnyBuildResult.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.misc; 2 | 3 | import hudson.Extension; 4 | import hudson.model.Run; 5 | import org.jenkinsci.plugins.github.extension.status.misc.ConditionalResult; 6 | import org.kohsuke.github.GHCommitState; 7 | import org.kohsuke.stapler.DataBoundConstructor; 8 | 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | 11 | /** 12 | * Allows to set state in any case 13 | * 14 | * @author lanwen (Merkushev Kirill) 15 | * @since 1.19.0 16 | */ 17 | public class AnyBuildResult extends ConditionalResult { 18 | 19 | @DataBoundConstructor 20 | public AnyBuildResult() { 21 | } 22 | 23 | /** 24 | * @return true in any case 25 | */ 26 | @Override 27 | public boolean matches(@NonNull Run run) { 28 | return true; 29 | } 30 | 31 | /** 32 | * @param state state to set 33 | * @param msg message to set. Can contain env vars 34 | * 35 | * @return new instance of this conditional result 36 | */ 37 | public static AnyBuildResult onAnyResult(GHCommitState state, String msg) { 38 | AnyBuildResult cond = new AnyBuildResult(); 39 | cond.setState(state.name()); 40 | cond.setMessage(msg); 41 | return cond; 42 | } 43 | 44 | @Extension 45 | public static class AnyBuildResultDescriptor extends ConditionalResultDescriptor { 46 | @Override 47 | public String getDisplayName() { 48 | return "result ANY"; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/util/XSSApi.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.util; 2 | 3 | import org.kohsuke.accmod.Restricted; 4 | import org.kohsuke.accmod.restrictions.NoExternalUse; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.net.MalformedURLException; 9 | import java.net.URL; 10 | 11 | /** 12 | * @author lanwen (Merkushev Kirill) 13 | */ 14 | @Restricted(NoExternalUse.class) 15 | public final class XSSApi { 16 | private static final Logger LOG = LoggerFactory.getLogger(XSSApi.class); 17 | 18 | private XSSApi() { 19 | } 20 | 21 | /** 22 | * Method to filter invalid url for XSS. This url can be inserted to href safely 23 | * 24 | * @param urlString unsafe url 25 | * 26 | * @return safe url 27 | */ 28 | public static String asValidHref(String urlString) { 29 | try { 30 | return new URL(urlString).toExternalForm(); 31 | } catch (MalformedURLException e) { 32 | LOG.debug("Malformed url - {}, empty string will be returned", urlString); 33 | return ""; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/util/misc/NullSafeFunction.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.util.misc; 2 | 3 | import com.google.common.base.Function; 4 | 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | 7 | import static com.google.common.base.Preconditions.checkNotNull; 8 | 9 | /** 10 | * This abstract class calls {@link #applyNullSafe(Object)} only after success validation of inner object for null 11 | * 12 | * @author lanwen (Merkushev Kirill) 13 | */ 14 | public abstract class NullSafeFunction implements Function { 15 | 16 | @Override 17 | public T apply(F input) { 18 | return applyNullSafe(checkNotNull(input, "This function does not allow using null as argument")); 19 | } 20 | 21 | /** 22 | * This method will be called inside of {@link #apply(Object)} 23 | */ 24 | protected abstract T applyNullSafe(@NonNull F input); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/util/misc/NullSafePredicate.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.util.misc; 2 | 3 | import com.google.common.base.Predicate; 4 | 5 | import edu.umd.cs.findbugs.annotations.NonNull; 6 | 7 | import static com.google.common.base.Preconditions.checkNotNull; 8 | 9 | /** 10 | * This abstract class calls {@link #applyNullSafe(Object)} only after success validation of inner object for null 11 | * 12 | * @author lanwen (Merkushev Kirill) 13 | */ 14 | 15 | public abstract class NullSafePredicate implements Predicate { 16 | 17 | @Override 18 | public boolean apply(T input) { 19 | return applyNullSafe(checkNotNull(input, "Argument for this predicate can't be null")); 20 | } 21 | 22 | /** 23 | * This method will be called inside of {@link #apply(Object)} 24 | */ 25 | protected abstract boolean applyNullSafe(@NonNull T input); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/webhook/GHEventHeader.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.webhook; 2 | 3 | import org.kohsuke.github.GHEvent; 4 | import org.kohsuke.stapler.AnnotationHandler; 5 | import org.kohsuke.stapler.InjectedParameter; 6 | import org.kohsuke.stapler.StaplerRequest2; 7 | import org.slf4j.Logger; 8 | 9 | import jakarta.servlet.ServletException; 10 | import java.lang.annotation.Documented; 11 | import java.lang.annotation.Retention; 12 | import java.lang.annotation.Target; 13 | 14 | import static java.lang.annotation.ElementType.PARAMETER; 15 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 16 | import static org.apache.commons.lang3.StringUtils.upperCase; 17 | import static org.apache.commons.lang3.Validate.isTrue; 18 | import static org.slf4j.LoggerFactory.getLogger; 19 | 20 | /** 21 | * InjectedParameter annotation to use on WebMethod parameters. 22 | * Handles GitHub's X-GitHub-Event header. 23 | * 24 | * @author lanwen (Merkushev Kirill) 25 | * @see Web Method 26 | */ 27 | @Retention(RUNTIME) 28 | @Target(PARAMETER) 29 | @Documented 30 | @InjectedParameter(GHEventHeader.PayloadHandler.class) 31 | public @interface GHEventHeader { 32 | class PayloadHandler extends AnnotationHandler { 33 | /** 34 | * @see Developer manual 35 | */ 36 | public static final String EVENT_HEADER = "X-GitHub-Event"; 37 | private static final Logger LOGGER = getLogger(PayloadHandler.class); 38 | 39 | /** 40 | * @param type should be combined with type of {@link GHEvent} 41 | * 42 | * @return parsed {@link GHEvent} or null on empty header or unknown value 43 | */ 44 | @Override 45 | public Object parse(StaplerRequest2 req, GHEventHeader a, Class type, String param) throws ServletException { 46 | isTrue(GHEvent.class.isAssignableFrom(type), 47 | "Parameter '%s' should has type %s, not %s", param, 48 | GHEvent.class.getName(), 49 | type.getName() 50 | ); 51 | 52 | String header = req.getHeader(EVENT_HEADER); 53 | LOGGER.debug("Header {} -> {}", EVENT_HEADER, header); 54 | 55 | if (header == null) { 56 | return null; 57 | } 58 | 59 | try { 60 | return GHEvent.valueOf(upperCase(header)); 61 | } catch (IllegalArgumentException e) { 62 | LOGGER.debug("Unknown event - {}", e.getMessage()); 63 | return null; 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/github/webhook/subscriber/PingGHEventSubscriber.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.webhook.subscriber; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import hudson.Extension; 5 | import hudson.model.Item; 6 | import java.io.IOException; 7 | import java.io.StringReader; 8 | import java.util.Set; 9 | import jakarta.inject.Inject; 10 | import org.jenkinsci.plugins.github.admin.GitHubHookRegisterProblemMonitor; 11 | import org.jenkinsci.plugins.github.extension.GHEventsSubscriber; 12 | import org.kohsuke.github.GHEvent; 13 | import org.kohsuke.github.GHEventPayload; 14 | import org.kohsuke.github.GHOrganization; 15 | import org.kohsuke.github.GHRepository; 16 | import org.kohsuke.github.GitHub; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import static com.google.common.collect.Sets.immutableEnumSet; 21 | import static org.kohsuke.github.GHEvent.PING; 22 | 23 | /** 24 | * Get ping events to log them 25 | * 26 | * @author lanwen (Merkushev Kirill) 27 | * @since 1.13.0 28 | */ 29 | @Extension 30 | @SuppressWarnings("unused") 31 | public class PingGHEventSubscriber extends GHEventsSubscriber { 32 | private static final Logger LOGGER = LoggerFactory.getLogger(PingGHEventSubscriber.class); 33 | 34 | @Inject 35 | private transient GitHubHookRegisterProblemMonitor monitor; 36 | 37 | /** 38 | * This subscriber is not applicable to any item 39 | * 40 | * @param project ignored 41 | * @return always false 42 | */ 43 | @Override 44 | protected boolean isApplicable(Item project) { 45 | return false; 46 | } 47 | 48 | /** 49 | * @return set with only ping event 50 | */ 51 | @Override 52 | protected Set events() { 53 | return immutableEnumSet(PING); 54 | } 55 | 56 | /** 57 | * Logs repo on ping event 58 | * 59 | * @param event only PING event 60 | * @param payload payload of gh-event. Never blank 61 | */ 62 | @Override 63 | protected void onEvent(GHEvent event, String payload) { 64 | GHEventPayload.Ping ping; 65 | try { 66 | ping = GitHub.offline().parseEventPayload(new StringReader(payload), GHEventPayload.Ping.class); 67 | } catch (IOException e) { 68 | LOGGER.warn("Received malformed PingEvent: " + payload, e); 69 | return; 70 | } 71 | GHRepository repository = ping.getRepository(); 72 | if (repository != null) { 73 | LOGGER.info("{} webhook received from repo <{}>!", event, repository.getHtmlUrl()); 74 | monitor.resolveProblem(GitHubRepositoryName.create(repository.getHtmlUrl().toExternalForm())); 75 | } else { 76 | GHOrganization organization = ping.getOrganization(); 77 | if (organization != null) { 78 | LOGGER.info("{} webhook received from org <{}>!", event, organization.getUrl()); 79 | } else { 80 | LOGGER.warn("{} webhook received with unexpected payload", event); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubCommitNotifier/config.groovy: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.GitHubCommitNotifier 2 | 3 | import com.cloudbees.jenkins.GitHubCommitNotifier 4 | 5 | def f = namespace(lib.FormTagLib); 6 | 7 | // prepare default instance 8 | if (instance == null) { 9 | instance = new GitHubCommitNotifier() 10 | } 11 | 12 | f.advanced() { 13 | f.entry(title: _('Build status message'), field: 'statusMessage') { 14 | f.property() 15 | } 16 | 17 | f.entry(title: _('Result on failure'), field: 'resultOnFailure') { 18 | f.select() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubCommitNotifier/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Build\ status\ message=\u6784\u5EFA\u72B6\u6001\u6D88\u606F 24 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubCommitNotifier/help.html: -------------------------------------------------------------------------------- 1 |

2 | This notifier will set GH commit status. 3 | This step is DEPRECATED and will be migrated to new step in one of the next major plugin releases.
4 | Please refer to new universal step. 5 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/GitHubWebHookPollingAction/index.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 |

${%Last GitHub Push}

30 | 31 | 32 | 33 | ${%Polling has not run yet.} 34 | 35 | 36 |
37 |             
38 |             ${it.writeLogTo(output)}
39 |           
40 |
41 |
42 |
43 |
44 |
-------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/config.groovy: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.GitHubPushTrigger 2 | 3 | import com.cloudbees.jenkins.GitHubPushTrigger 4 | 5 | tr { 6 | td(colspan: 4) { 7 | def url = descriptor.getCheckMethod('hookRegistered').toCheckUrl() 8 | def input = "input[name='${GitHubPushTrigger.class.getName().replace('.', '-')}']" 9 | 10 | div(id: 'gh-hooks-warn', 11 | 'data-url': url, 12 | 'data-input': input 13 | ) 14 | } 15 | } 16 | 17 | script(src:"${rootURL}${h.getResourcePath()}/plugin/github/js/warning.js") 18 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubPushTrigger/help.html: -------------------------------------------------------------------------------- 1 | When Jenkins receives a GitHub push hook, GitHub Plugin checks to see 2 | whether the hook came from a GitHub repository which matches the Git repository defined in SCM/Git section of this job. 3 | If they match and this option is enabled, GitHub Plugin triggers a one-time polling on GITScm. 4 | When GITScm polls GitHub, it finds that there is a change and initiates a build. 5 | The last sentence describes the behavior of Git plugin, 6 | thus the polling and initiating the build is not a part of GitHub plugin. 7 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/GitHubSetCommitStatusBuilder/config.groovy: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins.GitHubSetCommitStatusBuilder 2 | 3 | import com.cloudbees.jenkins.GitHubSetCommitStatusBuilder 4 | 5 | def f = namespace(lib.FormTagLib); 6 | 7 | // prepare default instance 8 | if (instance == null) { 9 | instance = new GitHubSetCommitStatusBuilder() 10 | } 11 | 12 | f.dropdownDescriptorSelector(title: _('Commit context: '), field: 'contextSource') 13 | 14 | f.advanced() { 15 | f.entry(title: _('Build status message'), field: 'statusMessage') { 16 | f.property() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/com/cloudbees/jenkins/Messages.properties: -------------------------------------------------------------------------------- 1 | CommitNotifier.Success=Build {0} succeeded in {1} 2 | CommitNotifier.Unstable=Build {0} found unstable in {1} 3 | CommitNotifier.Failed=Build {0} failed in {1} 4 | CommitNotifier.Pending=Build {0} in progress... 5 | GitHubCommitNotifier.SettingCommitStatus=Setting commit status on GitHub for {0} 6 | GitHubCommitNotifier.DisplayName=Set build status on GitHub commit [deprecated] 7 | GitHubSetCommitStatusBuilder.DisplayName=Set build status to "pending" on GitHub commit 8 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/config.groovy: -------------------------------------------------------------------------------- 1 | package com.coravy.hudson.plugins.github.GithubProjectProperty 2 | 3 | import static com.coravy.hudson.plugins.github.GithubProjectProperty.DescriptorImpl.GITHUB_PROJECT_BLOCK_NAME 4 | 5 | def f = namespace(lib.FormTagLib); 6 | 7 | f.optionalBlock(name: GITHUB_PROJECT_BLOCK_NAME, title: _('github.project'), checked: instance != null) { 8 | f.entry(field: 'projectUrlStr', title: _('github.project.url')) { 9 | f.textbox() 10 | } 11 | 12 | f.advanced() { 13 | f.entry(title: _('github.build.display.name'), field: 'displayName') { 14 | f.textbox() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/config.properties: -------------------------------------------------------------------------------- 1 | github.project=GitHub project 2 | github.project.url=Project url 3 | github.build.display.name=Display name 4 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/config_de.properties: -------------------------------------------------------------------------------- 1 | github.project=GitHub-Projekt 2 | github.project.url=Project url 3 | github.build.display.name=Display name 4 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | github.project=GitHub \u9879\u76EE 2 | github.project.url=\u9879\u76EE URL 3 | github.build.display.name=\u663E\u793A\u540D\u79F0 4 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/help-displayName.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | This value will be used as context name for 4 | commit status if status builder or 5 | status publisher is defined for this project. It should be small and clear. 6 |

7 | 8 |

9 | If you leave it empty, job name will be used for builder and publisher. 10 |

11 |
12 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/help-projectUrlStr.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Enter the URL for the GitHub hosted project (without the tree/master or tree/branch part). 4 |

5 | 6 |

7 | For example: 8 | https://github.com/rails/rails for the Rails project. 9 |

10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/com/coravy/hudson/plugins/github/GithubProjectProperty/help-projectUrlStr_de.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | URL des GitHub-Projektes (ohne den Pfad der den Zweig des Repositories angibt - also ohne tree/master oder tree/branch). 4 |

5 | 6 |

7 | Zum Beispiel https://github.com/rails/rails für das Rails-Projekt. 8 |

9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/images/symbols/logo-github.svg: -------------------------------------------------------------------------------- 1 | GitHub 2 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This plugin integrates GitHub to Jenkins. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/lib/github/blockWrapper.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 |
9 |
10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/Messages.properties: -------------------------------------------------------------------------------- 1 | global.config.url.is.empty=The Jenkins URL is empty. Explicitly set the Jenkins URL in the global configuration \ 2 | or in the GitHub plugin configuration to manage webhooks. 3 | global.config.hook.url.is.malformed=There is a malformed GitHub webhook URL in the global configuration ({0}). \ 4 | Please ensure that the Jenkins URL is valid and ends with a forward slash or use the webhook URL override. 5 | common.expandable.message.title=Expandable message 6 | hooks.problem.administrative.monitor.displayname=GitHub Hooks Problems 7 | hooks.problem.administrative.monitor.description=Some of the webhooks failed to be registered or were removed. \ 8 | You can view a detailed list of them at this page. Also you can manage the list of ignored repos. 9 | github.trigger.check.method.warning.details=The webhook for repo {0}/{1} on {2} failed to be registered \ 10 | or was removed. \ 11 | More info can be found on the global configuration page. This message will be dismissed if Jenkins receives \ 12 | a PING event from repo webhook or if you add the repo to the ignore list in the global configuration. 13 | unknown.error=Unknown error 14 | duplicate.events.administrative.monitor.displayname=GitHub Duplicate Events 15 | duplicate.events.administrative.monitor.description=Warns about duplicate events received from GitHub. 16 | duplicate.events.administrative.monitor.blurb=Duplicate events were received from GitHub, possibly due to \ 17 | misconfiguration (e.g., multiple webhooks targeting the same Jenkins controller at the repository or organization \ 18 | level), potentially causing redundant builds or at least wasted work. \ 19 | Click here to inspect the last tracked duplicate event payload. 20 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/admin/GitHubDuplicateEventsMonitor/description.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/admin/GitHubDuplicateEventsMonitor/message.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 | 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/admin/GitHubHookRegisterProblemMonitor/index.properties: -------------------------------------------------------------------------------- 1 | page.title=GitHub Hooks Problems 2 | ignore=Ignore 3 | disignore=Unignore 4 | ignored.projects=Ignored Projects 5 | project.header=Project 6 | message.header=Message 7 | help.for.problems=This table shows any problems with registering/removing repo webhooks. \ 8 | A message will be dismissed if Jenkins receives a PING event from the corresponding repo webhook, \ 9 | or if you add the repo to the ignore list. These messages will not be saved to disk, \ 10 | so they will all be cleared when Jenkins restarts. 11 | help.for.ignored=This table lists any ignored projects. Any problem with the repos in this list will be declined by \ 12 | administrative monitor. \ 13 | You can remove a repo from this list. This list will be saved on each change and reloaded when Jenkins restarts. 14 | help.for.page.and.debug.shows=This page shows problems with webhooks, and ignored projects. 15 | help.for.page.and.debug.system.pre=A detailed stacktrace for any of the problems can be found in the 16 | help.for.page.and.debug.system.log=system log 17 | help.for.page.and.debug.system.suffix=. 18 | help.for.page.and.debug.log.pre=For improved debugging in the Jenkins interface, 19 | help.for.page.and.debug.log.enable=enable these logs 20 | help.for.page.and.debug.log.suffix=: 21 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/admin/GitHubHookRegisterProblemMonitor/message.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin.GitHubHookRegisterProblemMonitor 2 | 3 | def f = namespace(lib.FormTagLib) 4 | 5 | div(class: 'alert alert-warning') { 6 | form(method: 'post', action: "${rootURL}/${my?.url}/act", name: my?.id) { 7 | f.submit(name: 'yes', value: _('view')) 8 | f.submit(name: 'no', value: _('dismiss')) 9 | } 10 | text(_('hook.registering.problem')) 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/admin/GitHubHookRegisterProblemMonitor/message.properties: -------------------------------------------------------------------------------- 1 | view=View 2 | dismiss=Dismiss 3 | hook.registering.problem=There were some problems while registering or removing one or more GitHub webhooks. \ 4 | Would you like to view the problems? 5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/common/ExpandableMessage/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.common.ExpandableMessage 2 | 3 | def f = namespace(lib.FormTagLib); 4 | 5 | f.entry(title: _('Content'), field: 'content') { 6 | f.expandableTextbox() 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/common/ExpandableMessage/help-content.html: -------------------------------------------------------------------------------- 1 |
2 | Message content that will be expanded using core variable expansion i.e. ${WORKSPACE}
3 | and Token Macro Plugin tokens.
4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubPluginConfig/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.config.GitHubPluginConfig 2 | 3 | import com.cloudbees.jenkins.GitHubPushTrigger 4 | import lib.FormTagLib 5 | 6 | def f = namespace(FormTagLib); 7 | def g = namespace("/lib/github") 8 | 9 | f.section(title: descriptor.displayName) { 10 | f.entry(title: _("GitHub Servers"), 11 | help: descriptor.getHelpFile()) { 12 | 13 | f.repeatableHeteroProperty( 14 | field: "configs", 15 | hasHeader: "true", 16 | addCaption: _("Add GitHub Server")) 17 | } 18 | 19 | f.advanced() { 20 | f.validateButton( 21 | title: _("Re-register hooks for all jobs"), 22 | progress: _("Scanning all items..."), 23 | method: "reRegister" 24 | ) 25 | 26 | if (GitHubPushTrigger.ALLOW_HOOKURL_OVERRIDE) { 27 | f.entry(title: _("Override Hook URL")) { 28 | g.blockWrapper { 29 | f.optionalBlock(title: _("Specify another hook URL for GitHub configuration"), 30 | inline: true, 31 | checked: instance.isOverrideHookUrl()) { 32 | f.entry(field: "hookUrl") { 33 | f.textbox(checkMethod: "post") 34 | } 35 | } 36 | } 37 | } 38 | } 39 | 40 | f.entry(title: _("Shared secrets")) { 41 | f.repeatableProperty( 42 | field: "hookSecretConfigs", 43 | add: _("Add shared secret") 44 | ) { 45 | f.entry(title: "") { 46 | div(align: "right") { 47 | f.repeatableDeleteButton() 48 | } 49 | } 50 | } 51 | } 52 | 53 | f.entry(title: _("Additional actions"), help: descriptor.getHelpFile('additional')) { 54 | f.hetero_list(items: [], 55 | addCaption: _("Manage additional GitHub actions"), 56 | name: "actions", 57 | oneEach: "true", hasHeader: "true", descriptors: instance.actions()) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubPluginConfig/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | GitHub\ Servers=GitHub \u670D\u52A1\u5668 24 | Add\ GitHub\ Server=\u6DFB\u52A0 GitHub \u670D\u52A1\u5668 25 | 26 | Re-register\ hooks\ for\ all\ jobs=\u7ED9\u6240\u6709\u4EFB\u52A1\u91CD\u65B0\u6CE8\u518C hook 27 | Scanning\ all\ items...=\u626B\u63CF\u6240\u6709\u7684\u9879\u76EE... 28 | 29 | Override\ Hook\ URL=\u8986\u76D6 Hook URL 30 | Specify\ another\ hook\ URL\ for\ GitHub\ configuration=\u4E3A GitHub \u6307\u5B9A\u53E6\u5916\u4E00\u4E2A Hook URL 31 | 32 | Additional\ actions=\u9644\u52A0\u52A8\u4F5C 33 | Manage\ additional\ GitHub\ actions=\u7BA1\u7406 GitHub \u9644\u52A0\u52A8\u4F5C 34 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubPluginConfig/help-additional.html: -------------------------------------------------------------------------------- 1 |
2 | Additional actions can help you with some routines. For example, you can convert your existing login + password 3 | (stored in credentials or directly) to a GitHub personal token. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubPluginConfig/help-overrideHookUrl.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | If your Jenkins runs inside a firewall and is not directly reachable from the internet, 6 | set up a reverse proxy, port tunneling, and so on so that GitHub can deliver a POST request 7 | to your Jenkins at ${app.rootUrl}github-webhook/. 8 | Then specify the URL that GitHub should POST to here. 9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubPluginConfig/help.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

By default

6 | 7 |

8 | This plugin doesn't do anything with the GitHub API unless you add a configuration with credentials. 9 | So if you don't want to add any configuration, you can set up hooks for this Jenkins instance manually. 10 |
11 | In this mode, in addition to configuring projects with "GitHub hook trigger for GITScm polling", 12 | you need to ensure that Jenkins gets a POST to its 13 | ${app.rootUrl}github-webhook/. 14 |

15 | 16 |

If you set up credentials

17 |

18 | In this mode, Jenkins will add/remove hook URLs to GitHub based on the project configuration. 19 | Jenkins has a single post-commit hook URL for all the repositories, and this URL will be added 20 | to all the GitHub repositories Jenkins is interested in. You should provide credentials with scope 21 | admin:repo_hook for every repository which should be managed by Jenkins. It needs to read the 22 | current list of hooks, create new hooks and remove old hooks. 23 | 24 |

25 | The Hook URL is 26 | 27 | ${app.rootUrl}github-webhook/ 28 | 29 | , 30 | and it needs to be accessible from the internet. If you have a firewall and such between 31 | GitHub and Jenkins, you can set up a reverse proxy and override the hook URL that Jenkins registers 32 | to GitHub, by checking "override hook URL" in the advanced configuration and specify to which URL 33 | GitHub should POST. 34 |

35 |

36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.config.GitHubServerConfig 2 | 3 | import org.jenkinsci.plugins.github.config.GitHubServerConfig 4 | 5 | def f = namespace(lib.FormTagLib); 6 | def c = namespace(lib.CredentialsTagLib) 7 | 8 | f.entry(title: _("Name"), field: "name") { 9 | f.textbox() 10 | } 11 | 12 | f.entry(title: _("API URL"), field: "apiUrl") { 13 | f.textbox(default: GitHubServerConfig.GITHUB_URL) 14 | } 15 | 16 | f.entry(title: _("Credentials"), field: "credentialsId") { 17 | c.select(context:app, includeUser:false, expressionAllowed:false) 18 | } 19 | 20 | f.block() { 21 | f.validateButton( 22 | title: _("Test connection"), 23 | progress: _("Testing..."), 24 | method: "verifyCredentials", 25 | with: "apiUrl,credentialsId" 26 | ) 27 | } 28 | 29 | f.entry() { 30 | f.checkbox(title: _("Manage hooks"), field: "manageHooks") 31 | } 32 | 33 | f.advanced() { 34 | f.entry(title: _("GitHub client cache size (MB)"), field: "clientCacheSize") { 35 | f.textbox(default: GitHubServerConfig.DEFAULT_CLIENT_CACHE_SIZE_MB) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Name=\u540D\u79F0 24 | Credentials=\u51ED\u636E 25 | Test\ connection=\u8FDE\u63A5\u6D4B\u8BD5 26 | Testing...=\u6D4B\u8BD5\u4E2D... 27 | Manage\ hooks=\u7BA1\u7406 Hook 28 | GitHub\ client\ cache\ size\ (MB)=GitHub \u5BA2\u6237\u7AEF\u7F13\u5B58(MB) 29 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/help-apiUrl.html: -------------------------------------------------------------------------------- 1 |
2 | API endpoint of a GitHub server. 3 | 4 | To use public github.com, leave this field 5 | to the default value of https://api.github.com. 6 | 7 | Otherwise if you use GitHub Enterprise, specify its API endpoint here 8 | (e.g., https://ghe.acme.com/api/v3/). 9 |
10 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/help-clientCacheSize.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Jenkins will use this much space, measured in megabytes, 4 | in $JENKINS_HOME to cache data retrieved from GitHub API calls. 5 | A cache will help improve the performance by avoiding unnecessary data transfer, and by doing so it also 6 | makes it less likely to hit API rate limit 7 | (by the use of conditional GET calls). 8 |

9 |

10 | In the unlikely event that cache is causing a problem, set this to 0 to disable cache altogether. 11 |

12 |
13 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/help-credentialsId.html: -------------------------------------------------------------------------------- 1 |
2 | You can create your own personal access token in your account GitHub settings. 3 |
4 | Token should be registered with scopes: 5 |
    6 |
  • admin:repo_hook - for managing hooks (read, write and delete old ones)
  • 7 |
  • repo - to see private repos
  • 8 |
  • repo:status - to manipulate commit statuses
  • 9 |
10 | 11 |
12 | In Jenkins, create credentials as «Secret Text», provided by 13 | Plain Credentials Plugin.
14 | 15 |

16 | WARNING! Credentials are filtered on changing custom GitHub URL.
17 |

18 | 19 |

20 | If you have an existing GitHub login and password you can convert it to a token automatically with the help of «Manage 21 | additional GitHub actions». 22 |

23 |
24 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/help-manageHooks.html: -------------------------------------------------------------------------------- 1 |
2 | Will this configuration be used to manage credentials for repositories where it has admin rights? 3 | If unchecked, this credentials still can be used to manipulate commit statuses, but will be ignored to manage hooks. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/help-name.html: -------------------------------------------------------------------------------- 1 |
2 | An optional name to help with the disambiguation of API URLs. If you have multiple GitHub Enterprise servers with non-helpful 3 | names such as s21356.example.com and s21368.example.com then giving these names can 4 | help users when they need to select the correct server from a drop-down list. If you do not provide a name, 5 | then a "best guess" will be made from the hostname part of the API URL. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubServerConfig/help.html: -------------------------------------------------------------------------------- 1 |
2 | Pair of GitHub token and server URL. If no custom URL is specified, then the default api.github.com will be used. 3 | If your Jenkins uses multiple repositories that are spread across different 4 | user accounts, you can list them all here as separate configurations. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubTokenCredentialsCreator/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.config.GitHubTokenCredentialsCreator 2 | 3 | import org.jenkinsci.plugins.github.config.GitHubServerConfig 4 | 5 | def f = namespace(lib.FormTagLib); 6 | def c = namespace(lib.CredentialsTagLib) 7 | 8 | f.entry(title: _("GitHub API URL"), field: "apiUrl", 9 | help: app.getDescriptor(GitHubServerConfig.class)?.getHelpFile("customApiUrl")) { 10 | f.textbox(default: GitHubServerConfig.GITHUB_URL) 11 | } 12 | 13 | f.radioBlock(checked: true, name: "creds", value: "plugin", title: "From credentials") { 14 | f.entry(title: _("Credentials"), field: "credentialsId") { 15 | c.select(context: app, includeUser: true, expressionAllowed: false) 16 | } 17 | 18 | f.block() { 19 | f.validateButton( 20 | title: _("Create token credentials"), 21 | progress: _("Creating..."), 22 | method: "createTokenByCredentials", 23 | with: "apiUrl,credentialsId" 24 | ) 25 | } 26 | } 27 | 28 | f.radioBlock(checked: false, name: "creds", value: "manually", title: "From login and password") { 29 | 30 | f.entry(title: _("Login"), field: "login") { 31 | f.textbox() 32 | } 33 | 34 | f.entry(title: _("Password"), field: "password") { 35 | f.password() 36 | } 37 | 38 | f.block() { 39 | f.validateButton( 40 | title: _("Create token credentials"), 41 | progress: _("Creating..."), 42 | method: "createTokenByPassword", 43 | with: "apiUrl,login,password" 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubTokenCredentialsCreator/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | From credentials=\u4ECE\u51ED\u636E 24 | Credentials=\u51ED\u636E 25 | Create\ token\ credentials=\u521B\u5EFA token \u51ED\u636E 26 | Creating...=\u521B\u5EFA\u4E2D... 27 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/GitHubTokenCredentialsCreator/help.html: -------------------------------------------------------------------------------- 1 |
2 | Helper to convert existing username-password credentials or directly login+password to a 3 | GitHub personal token.
4 | 5 | This helper doesn't store any entered data, but only registers a new token with all scopes needed to plugin.
6 | After token registration, it will be stored as «Secret text» credentials with domain requirements corresponding to 7 | given API URL. It will be available after refreshing the Global Confirmation page. 8 |
9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/HookSecretConfig/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.config.HookSecretConfig 2 | 3 | def f = namespace(lib.FormTagLib); 4 | def c = namespace(lib.CredentialsTagLib); 5 | 6 | f.entry(title: _("Shared secret"), field: "credentialsId", help: descriptor.getHelpFile('sharedSecret')) { 7 | c.select(context: app, includeUser: false, expressionAllowed: false) 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/HookSecretConfig/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Shared\ secret=\u5171\u4EAB Secret 24 | 25 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/HookSecretConfig/help-sharedSecret.html: -------------------------------------------------------------------------------- 1 |
2 | A shared secret token GitHub will use to sign requests in order for Jenkins to verify that the request came from GitHub. 3 | If left blank, this feature will not be used. 4 | Please use a different token from the token secret. 5 |
6 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/config/Messages.properties: -------------------------------------------------------------------------------- 1 | GitHubServerConfig.displayName={0} ({1}) 2 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/extension/status/misc/ConditionalResult/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension.status.misc.ConditionalResult 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.entry(title: _('Status'), field: 'state') { 7 | f.select() 8 | } 9 | 10 | f.entry(title: _('Message'), field: 'message') { 11 | f.textbox() 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/extension/status/misc/ConditionalResult/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Status=\u72B6\u6001 24 | Message=\u6D88\u606F 25 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/GitHubCommitStatusSetter/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.GitHubCommitStatusSetter 2 | 3 | import org.apache.commons.collections.CollectionUtils 4 | import org.jenkinsci.plugins.github.extension.status.StatusErrorHandler 5 | 6 | 7 | def f = namespace(lib.FormTagLib); 8 | 9 | f.section(title: _('Where:')) { 10 | f.dropdownDescriptorSelector(title: _('Commit SHA: '), field: 'commitShaSource') 11 | f.dropdownDescriptorSelector(title: _('Repositories: '), field: 'reposSource') 12 | } 13 | 14 | f.section(title: _('What:')) { 15 | f.dropdownDescriptorSelector(title: _('Commit context: '), field: 'contextSource') 16 | f.dropdownDescriptorSelector(title: _('Status result: '), field: 'statusResultSource') 17 | f.dropdownDescriptorSelector(title: _('Status backref: '), field: 'statusBackrefSource') 18 | } 19 | 20 | f.advanced { 21 | f.section(title: _('Advanced:')) { 22 | f.optionalBlock( 23 | checked: CollectionUtils.isNotEmpty(instance?.errorHandlers), 24 | inline: true, 25 | name: 'errorHandling', 26 | title: 'Handle errors') { 27 | f.block { 28 | f.hetero_list(items: CollectionUtils.isEmpty(instance?.errorHandlers) 29 | ? [] 30 | : instance.errorHandlers, 31 | addCaption: 'Add error handler', 32 | name: 'errorHandlers', 33 | oneEach: true, hasHeader: true, descriptors: StatusErrorHandler.all()) 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/GitHubCommitStatusSetter/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Advanced:=\u9AD8\u7EA7\uFF1A 24 | Handle\ errors=\u9519\u8BEF\u5904\u7406 25 | Add\ error\ handler=\u6DFB\u52A0\u9519\u8BEF\u5904\u7406 26 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/GitHubCommitStatusSetter/help.html: -------------------------------------------------------------------------------- 1 |
2 | Using GitHub status api sets status of the commit. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/err/ChangingBuildStatusErrorHandler/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.err.ChangingBuildStatusErrorHandler 2 | 3 | def f = namespace(lib.FormTagLib); 4 | 5 | f.entry(title: _('Result on failure'), field: 'result') { 6 | f.select() 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/err/ChangingBuildStatusErrorHandler/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Result\ on\ failure=\u5931\u8D25\u7ED3\u679C 24 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/err/ShallowAnyErrorHandler/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.err.ShallowAnyErrorHandler 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.helpLink(url: descriptor.getHelpFile()) 7 | f.helpArea() 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/AnyDefinedRepositorySource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.AnyDefinedRepositorySource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.helpLink(url: descriptor.getHelpFile()) 7 | f.helpArea() 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/AnyDefinedRepositorySource/help.html: -------------------------------------------------------------------------------- 1 |
2 | Any repository provided by the programmatic contributors list. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/BuildDataRevisionShaSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.BuildDataRevisionShaSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.helpLink(url: descriptor.getHelpFile()) 7 | f.helpArea() 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/BuildDataRevisionShaSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | Uses data-action (located at ${build.url}/git/) to determine actual SHA. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/BuildRefBackrefSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.BuildRefBackrefSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.helpLink(url: descriptor.getHelpFile()) 7 | f.helpArea() 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/BuildRefBackrefSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | Points commit status backref back to the producing build page. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ConditionalStatusResultSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.ConditionalStatusResultSource 2 | 3 | import org.apache.commons.collections.CollectionUtils 4 | import org.jenkinsci.plugins.github.extension.status.misc.ConditionalResult.ConditionalResultDescriptor; 5 | 6 | def f = namespace(lib.FormTagLib); 7 | 8 | f.helpLink(url: descriptor.getHelpFile()) 9 | f.helpArea() 10 | 11 | f.block { 12 | f.hetero_list(items: CollectionUtils.isEmpty(instance?.results) 13 | ? [] 14 | : instance.results, 15 | addCaption: 'If Run', 16 | name: 'results', 17 | oneEach: false, hasHeader: true, descriptors: ConditionalResultDescriptor.all()) 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ConditionalStatusResultSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | You can define in which cases you want to publish exact state and message for the commit. You can define multiple cases. 3 | First match (starting from top) wins. If no one matches, PENDING status + warn message will be used. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/DefaultCommitContextSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.DefaultCommitContextSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.helpLink(url: descriptor.getHelpFile()) 7 | f.helpArea() 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/DefaultCommitContextSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | Uses display name property defined in "GitHub project property" with fallback to job name. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/DefaultStatusResultSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.DefaultStatusResultSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.helpLink(url: descriptor.getHelpFile()) 7 | f.helpArea() 8 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/DefaultStatusResultSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | Writes simple message about build result and duration. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredBackrefSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.ManuallyEnteredBackrefSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.entry(title: _('Backref URL'), field: 'backref') { 7 | f.textbox() 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredBackrefSource/help-backref.html: -------------------------------------------------------------------------------- 1 |
2 | A backref URL. Allows env vars and token macro. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredBackrefSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | A manually entered backref URL. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredCommitContextSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.ManuallyEnteredCommitContextSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.entry(title: _('Context name'), field: 'context') { 7 | f.textbox() 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredCommitContextSource/help-context.html: -------------------------------------------------------------------------------- 1 |
2 | Allows env vars and token macros. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredCommitContextSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | You can define context name manually. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredRepositorySource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.AnyDefinedRepositorySource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.entry(title: _('Repository URL'), field: 'url') { 7 | f.textbox() 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredRepositorySource/help-url.html: -------------------------------------------------------------------------------- 1 |
2 | A GitHub repository URL. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredRepositorySource/help.html: -------------------------------------------------------------------------------- 1 |
2 | A manually entered repository URL. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredShaSource/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.ManuallyEnteredShaSource 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | f.entry(title: _('SHA'), field: 'sha') { 7 | f.textbox() 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredShaSource/help-sha.html: -------------------------------------------------------------------------------- 1 |
2 | Allows env vars and token macro. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredShaSource/help.html: -------------------------------------------------------------------------------- 1 |
2 | Allows to define commit SHA manually. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/misc/BetterThanOrEqualBuildResult/config.groovy: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.misc.BetterThanOrEqualBuildResult 2 | 3 | 4 | def f = namespace(lib.FormTagLib); 5 | 6 | 7 | f.entry(title: _('Build result better than or equal to'), field: 'result') { 8 | f.select() 9 | } 10 | 11 | f.entry(title: _('Status'), field: 'state') { 12 | f.select() 13 | } 14 | 15 | f.entry(title: _('Message'), field: 'message') { 16 | f.textbox() 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/misc/BetterThanOrEqualBuildResult/config_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # The MIT License 2 | # 3 | # Copyright (c) 2018, suren 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | 23 | Status=\u72B6\u6001 24 | Message=\u6D88\u606F 25 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/status/sources/misc/BetterThanOrEqualBuildResult/help-message.html: -------------------------------------------------------------------------------- 1 |
2 | Allows env vars and token macro. 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/github/util/Messages.properties: -------------------------------------------------------------------------------- 1 | BuildDataHelper.NoBuildDataError=Cannot retrieve Git metadata for the build 2 | BuildDataHelper.NoLastRevisionError=Cannot determine sha1 of the commit. The status cannot be reported 3 | -------------------------------------------------------------------------------- /src/main/sass/monitor.scss: -------------------------------------------------------------------------------- 1 | .gh-page { 2 | td, th { 3 | padding: { 4 | left: 25px; 5 | top: 5px; 6 | bottom: 5px; 7 | } 8 | } 9 | } 10 | 11 | .repo-table__header { 12 | text-transform: uppercase; 13 | } 14 | 15 | .repo-line { 16 | 17 | &__title { 18 | font-weight: bold; 19 | } 20 | 21 | &__msg { 22 | font-family: monospace; 23 | word-break: break-all; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/webapp/js/warning.js: -------------------------------------------------------------------------------- 1 | var InlineWarning = (function () { 2 | 'use strict'; 3 | var exports = {}; 4 | var options = { 5 | id: '', // id of element to bind 6 | url: '', // url of check method 7 | input: '' // checkbox to test for checked 8 | }; 9 | 10 | exports.setup = function (opts) { 11 | options = opts; 12 | 13 | // Check if the URL needs concatenation 14 | if (opts.url.includes("'+'")) { 15 | // Manually concatenate the parts 16 | let parts = opts.url.split("'+'"); 17 | options.url = parts.map(part => part.replace(/'/g, '')).join(''); 18 | } else { 19 | options.url = opts.url; 20 | } 21 | 22 | return exports; 23 | }; 24 | 25 | exports.start = function () { 26 | // Ignore when GH trigger unchecked 27 | if (!document.querySelector(options.input).checked) { 28 | return; 29 | } 30 | var frequency = 10; 31 | var decay = 2; 32 | var lastResponseText; 33 | var fetchData = function () { 34 | fetch(options.url).then((rsp) => { 35 | rsp.text().then((responseText) => { 36 | if (responseText !== lastResponseText) { 37 | document.getElementById(options.id).innerHTML = responseText; 38 | lastResponseText = responseText; 39 | frequency = 10; 40 | } else { 41 | frequency *= decay; 42 | } 43 | setTimeout(fetchData, frequency * 1000); 44 | }); 45 | }); 46 | }; 47 | fetchData(); 48 | }; 49 | 50 | return exports; 51 | })(); 52 | 53 | document.addEventListener('DOMContentLoaded', function() { 54 | var warningElement = document.getElementById('gh-hooks-warn'); 55 | 56 | if (warningElement) { 57 | var url = warningElement.getAttribute('data-url'); 58 | var input = warningElement.getAttribute('data-input'); 59 | 60 | if (url && input) { 61 | InlineWarning.setup({ 62 | id: 'gh-hooks-warn', 63 | url: url, 64 | input: input 65 | }).start(); 66 | } else { 67 | console.error('URL or Input is null'); 68 | } 69 | } else { 70 | console.error('Element with ID "gh-hooks-warn" not found'); 71 | } 72 | }); -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/GitHubWebHookCrumbExclusionTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import jakarta.servlet.FilterChain; 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import jakarta.servlet.http.HttpServletResponse; 9 | 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | import static org.mockito.Mockito.mock; 13 | import static org.mockito.Mockito.never; 14 | import static org.mockito.Mockito.times; 15 | import static org.mockito.Mockito.verify; 16 | import static org.mockito.Mockito.when; 17 | 18 | public class GitHubWebHookCrumbExclusionTest { 19 | 20 | private GitHubWebHookCrumbExclusion exclusion; 21 | private HttpServletRequest req; 22 | private HttpServletResponse resp; 23 | private FilterChain chain; 24 | 25 | @Before 26 | public void before() { 27 | exclusion = new GitHubWebHookCrumbExclusion(); 28 | req = mock(HttpServletRequest.class); 29 | resp = mock(HttpServletResponse.class); 30 | chain = mock(FilterChain.class); 31 | } 32 | 33 | @Test 34 | public void testFullPath() throws Exception { 35 | when(req.getPathInfo()).thenReturn("/github-webhook/"); 36 | assertTrue(exclusion.process(req, resp, chain)); 37 | verify(chain, times(1)).doFilter(req, resp); 38 | } 39 | 40 | @Test 41 | public void testFullPathWithoutSlash() throws Exception { 42 | when(req.getPathInfo()).thenReturn("/github-webhook"); 43 | assertTrue(exclusion.process(req, resp, chain)); 44 | verify(chain, times(1)).doFilter(req, resp); 45 | } 46 | 47 | @Test 48 | public void testInvalidPath() throws Exception { 49 | when(req.getPathInfo()).thenReturn("/some-other-url/"); 50 | assertFalse(exclusion.process(req, resp, chain)); 51 | verify(chain, never()).doFilter(req, resp); 52 | } 53 | 54 | @Test 55 | public void testNullPath() throws Exception { 56 | when(req.getPathInfo()).thenReturn(null); 57 | assertFalse(exclusion.process(req, resp, chain)); 58 | verify(chain, never()).doFilter(req, resp); 59 | } 60 | 61 | @Test 62 | public void testEmptyPath() throws Exception { 63 | when(req.getPathInfo()).thenReturn(""); 64 | assertFalse(exclusion.process(req, resp, chain)); 65 | verify(chain, never()).doFilter(req, resp); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/com/cloudbees/jenkins/GlobalConfigSubmitTest.java: -------------------------------------------------------------------------------- 1 | package com.cloudbees.jenkins; 2 | 3 | import org.htmlunit.html.HtmlForm; 4 | import org.htmlunit.html.HtmlPage; 5 | import org.jenkinsci.plugins.github.GitHubPlugin; 6 | import org.junit.Ignore; 7 | import org.junit.Rule; 8 | import org.junit.Test; 9 | import org.jvnet.hudson.test.JenkinsRule; 10 | import org.xml.sax.SAXException; 11 | 12 | import java.io.IOException; 13 | import java.net.URL; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.equalTo; 17 | 18 | /** 19 | * Test Class for {@link GitHubPushTrigger}. 20 | * 21 | * @author Seiji Sogabe 22 | */ 23 | @Ignore("Have troubles with memory consumption") 24 | public class GlobalConfigSubmitTest { 25 | 26 | public static final String OVERRIDE_HOOK_URL_CHECKBOX = "_.isOverrideHookUrl"; 27 | public static final String HOOK_URL_INPUT = "_.hookUrl"; 28 | 29 | private static final String WEBHOOK_URL = "http://jenkinsci.example.com/jenkins/github-webhook/"; 30 | 31 | @Rule 32 | public JenkinsRule jenkins = new JenkinsRule(); 33 | 34 | @Test 35 | public void shouldSetHookUrl() throws Exception { 36 | HtmlForm form = globalConfig(); 37 | 38 | form.getInputByName(OVERRIDE_HOOK_URL_CHECKBOX).setChecked(true); 39 | form.getInputByName(HOOK_URL_INPUT).setValue(WEBHOOK_URL); 40 | jenkins.submit(form); 41 | 42 | assertThat(GitHubPlugin.configuration().getHookUrl(), equalTo(new URL(WEBHOOK_URL))); 43 | } 44 | 45 | @Test 46 | public void shouldNotSetHookUrl() throws Exception { 47 | GitHubPlugin.configuration().setHookUrl(WEBHOOK_URL); 48 | 49 | HtmlForm form = globalConfig(); 50 | 51 | form.getInputByName(OVERRIDE_HOOK_URL_CHECKBOX).setChecked(false); 52 | form.getInputByName(HOOK_URL_INPUT).setValue("http://foo"); 53 | jenkins.submit(form); 54 | 55 | assertThat(GitHubPlugin.configuration().getHookUrl(), equalTo(new URL(WEBHOOK_URL))); 56 | } 57 | 58 | @Test 59 | public void shouldNotOverrideAPreviousHookUrlIfNotChecked() throws Exception { 60 | GitHubPlugin.configuration().setHookUrl(WEBHOOK_URL); 61 | 62 | HtmlForm form = globalConfig(); 63 | 64 | form.getInputByName(OVERRIDE_HOOK_URL_CHECKBOX).setChecked(false); 65 | form.getInputByName(HOOK_URL_INPUT).setValue(""); 66 | jenkins.submit(form); 67 | 68 | assertThat(GitHubPlugin.configuration().getHookUrl(), equalTo(new URL(WEBHOOK_URL))); 69 | } 70 | 71 | public HtmlForm globalConfig() throws IOException, SAXException { 72 | JenkinsRule.WebClient client = configureWebClient(); 73 | HtmlPage p = client.goTo("configure"); 74 | return p.getFormByName("config"); 75 | } 76 | 77 | private JenkinsRule.WebClient configureWebClient() { 78 | JenkinsRule.WebClient client = jenkins.createWebClient(); 79 | client.setJavaScriptEnabled(true); 80 | return client; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/coravy/hudson/plugins/github/GithubLinkActionFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.coravy.hudson.plugins.github; 2 | 3 | import static org.hamcrest.Matchers.is; 4 | import static org.hamcrest.Matchers.instanceOf; 5 | import static org.hamcrest.Matchers.empty; 6 | import static org.hamcrest.MatcherAssert.assertThat; 7 | 8 | import java.io.IOException; 9 | import java.util.Collection; 10 | 11 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 12 | import org.junit.Rule; 13 | import org.junit.Test; 14 | import org.jvnet.hudson.test.JenkinsRule; 15 | 16 | import com.coravy.hudson.plugins.github.GithubLinkAction.GithubLinkActionFactory; 17 | 18 | import hudson.model.Action; 19 | 20 | public class GithubLinkActionFactoryTest { 21 | @Rule 22 | public final JenkinsRule rule = new JenkinsRule(); 23 | 24 | private final GithubLinkActionFactory factory = new GithubLinkActionFactory(); 25 | 26 | private static final String PROJECT_URL = "https://github.com/jenkinsci/github-plugin/"; 27 | 28 | private WorkflowJob createExampleJob() throws IOException { 29 | return rule.getInstance().createProject(WorkflowJob.class, "example"); 30 | } 31 | 32 | private GithubProjectProperty createExampleProperty() { 33 | return new GithubProjectProperty(PROJECT_URL); 34 | } 35 | 36 | @Test 37 | public void shouldCreateGithubLinkActionForJobWithGithubProjectProperty() throws IOException { 38 | final WorkflowJob job = createExampleJob(); 39 | final GithubProjectProperty property = createExampleProperty(); 40 | job.addProperty(property); 41 | 42 | final Collection actions = factory.createFor(job); 43 | assertThat("factored actions list", actions.size(), is(1)); 44 | 45 | final Action action = actions.iterator().next(); 46 | assertThat("instance check", action, is(instanceOf(GithubLinkAction.class))); 47 | assertThat("url of action", action.getUrlName(), is(property.getProjectUrlStr())); 48 | } 49 | 50 | @Test 51 | public void shouldNotCreateGithubLinkActionForJobWithoutGithubProjectProperty() throws IOException { 52 | final WorkflowJob job = createExampleJob(); 53 | 54 | final Collection actions = factory.createFor(job); 55 | assertThat("factored actions list", actions, is(empty())); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/com/coravy/hudson/plugins/github/GithubProjectPropertyTest.java: -------------------------------------------------------------------------------- 1 | package com.coravy.hudson.plugins.github; 2 | 3 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 4 | import org.jenkinsci.plugins.workflow.structs.DescribableHelper; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertNotNull; 9 | import static org.junit.Assert.assertNull; 10 | import org.junit.Rule; 11 | import org.jvnet.hudson.test.JenkinsRule; 12 | 13 | @Ignore("It failed to instantiate class org.jenkinsci.plugins.workflow.flow.FlowDefinition - dunno how to fix it") 14 | public class GithubProjectPropertyTest { 15 | 16 | @Rule 17 | public JenkinsRule j = new JenkinsRule(); 18 | 19 | @Test 20 | public void configRoundTrip() throws Exception { 21 | WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); 22 | j.configRoundtrip(p); 23 | assertNull(p.getProperty(GithubProjectProperty.class)); 24 | String url = "https://github.com/a/b/"; 25 | p.addProperty(new GithubProjectProperty(url)); 26 | j.configRoundtrip(p); 27 | GithubProjectProperty prop = p.getProperty(GithubProjectProperty.class); 28 | assertNotNull(prop); 29 | assertEquals(url, prop.getProjectUrl().baseUrl()); 30 | prop = DescribableHelper.instantiate(GithubProjectProperty.class, DescribableHelper.uninstantiate(prop)); 31 | assertEquals(url, prop.getProjectUrl().baseUrl()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/coravy/hudson/plugins/github/GithubUrlTest.java: -------------------------------------------------------------------------------- 1 | package com.coravy.hudson.plugins.github; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | public class GithubUrlTest { 10 | 11 | @Before 12 | public void setUp() throws Exception { 13 | } 14 | 15 | @After 16 | public void tearDown() throws Exception { 17 | } 18 | 19 | @Test 20 | public final void testBaseUrlWithTree() { 21 | GithubUrl url = new GithubUrl( 22 | "http://github.com/juretta/iphone-project-tools/tree/master"); 23 | assertEquals("http://github.com/juretta/iphone-project-tools/", url 24 | .baseUrl()); 25 | url = new GithubUrl( 26 | "http://github.com/juretta/iphone-project-tools/tree/unstable"); 27 | assertEquals("http://github.com/juretta/iphone-project-tools/", url 28 | .baseUrl()); 29 | } 30 | 31 | @Test 32 | public final void testBaseUrl() { 33 | GithubUrl url = new GithubUrl( 34 | "http://github.com/juretta/iphone-project-tools"); 35 | assertEquals("http://github.com/juretta/iphone-project-tools/", url 36 | .baseUrl()); 37 | } 38 | 39 | @Test 40 | public final void testCommitId() { 41 | GithubUrl url = new GithubUrl( 42 | "http://github.com/juretta/hudson-github-plugin/tree/master"); 43 | assertEquals( 44 | "http://github.com/juretta/hudson-github-plugin/commit/5e31203faea681c41577b685818a361089fac1fc", 45 | url.commitId("5e31203faea681c41577b685818a361089fac1fc")); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/admin/GHRepoNameTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.kohsuke.stapler.StaplerRequest2; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | import static org.hamcrest.Matchers.is; 11 | import static org.hamcrest.Matchers.nullValue; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.mockito.Mockito.when; 14 | 15 | /** 16 | * @author lanwen (Merkushev Kirill) 17 | */ 18 | @RunWith(MockitoJUnitRunner.class) 19 | public class GHRepoNameTest { 20 | 21 | public static final String REPO_NAME_PARAMETER = "repo"; 22 | private static final String REPO = "https://github.com/user/repo"; 23 | 24 | @Mock 25 | private StaplerRequest2 req; 26 | 27 | @Mock 28 | private GHRepoName anno; 29 | 30 | @Test 31 | public void shouldExtractRepoNameFromForm() throws Exception { 32 | when(req.getParameter(REPO_NAME_PARAMETER)).thenReturn(REPO); 33 | GitHubRepositoryName repo = new GHRepoName.PayloadHandler().parse(req, anno, null, REPO_NAME_PARAMETER); 34 | 35 | assertThat("should parse repo", repo, is(GitHubRepositoryName.create(REPO))); 36 | } 37 | 38 | @Test 39 | public void shouldReturnNullOnNoAnyParam() throws Exception { 40 | GitHubRepositoryName repo = new GHRepoName.PayloadHandler().parse(req, anno, null, REPO_NAME_PARAMETER); 41 | 42 | assertThat("should not parse repo", repo, nullValue()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/admin/ValidateRepoNameTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.admin; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import org.junit.Rule; 5 | import org.junit.Test; 6 | import org.junit.rules.ExpectedException; 7 | import org.junit.runner.RunWith; 8 | import org.kohsuke.stapler.Function; 9 | import org.kohsuke.stapler.StaplerRequest2; 10 | import org.kohsuke.stapler.StaplerResponse2; 11 | import org.mockito.Mock; 12 | import org.mockito.junit.MockitoJUnitRunner; 13 | 14 | import java.lang.reflect.InvocationTargetException; 15 | 16 | /** 17 | * @author lanwen (Merkushev Kirill) 18 | */ 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class ValidateRepoNameTest { 21 | public static final Object ANY_INSTANCE = null; 22 | public static final GitHubRepositoryName VALID_REPO = new GitHubRepositoryName("", "", ""); 23 | 24 | @Mock 25 | private Function target; 26 | 27 | @Mock 28 | private StaplerRequest2 req; 29 | 30 | @Mock 31 | private StaplerResponse2 resp; 32 | 33 | @Rule 34 | public ExpectedException exc = ExpectedException.none(); 35 | 36 | @Test 37 | public void shouldThrowInvocationExcOnNullsInArgs() throws Exception { 38 | ValidateRepoName.Processor processor = new ValidateRepoName.Processor(); 39 | processor.setTarget(target); 40 | 41 | exc.expect(InvocationTargetException.class); 42 | 43 | processor.invoke(req, resp, ANY_INSTANCE, new Object[]{null}); 44 | } 45 | 46 | @Test 47 | public void shouldNotThrowInvocationExcNameInArgs() throws Exception { 48 | ValidateRepoName.Processor processor = new ValidateRepoName.Processor(); 49 | processor.setTarget(target); 50 | 51 | processor.invoke(req, resp, ANY_INSTANCE, new Object[]{VALID_REPO}); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/common/ParametersActionHelper.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.common; 2 | 3 | import hudson.model.ParametersAction; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Modifier; 7 | 8 | /** 9 | * Helper class to check if the environment includes SECURITY-170 fix 10 | * 11 | * @see 12 | */ 13 | public class ParametersActionHelper { 14 | 15 | private static final Class actionClass = ParametersAction.class; 16 | 17 | private boolean hasSafeParameterConfig = false; 18 | private boolean abletoInspect = true; 19 | private static final String UNDEFINED_PARAMETERS_FIELD_NAME = "KEEP_UNDEFINED_PARAMETERS_SYSTEM_PROPERTY_NAME"; 20 | private static final String SAFE_PARAMETERS_FIELD_NAME = "SAFE_PARAMETERS_SYSTEM_PROPERTY_NAME"; 21 | 22 | public ParametersActionHelper() { 23 | try { 24 | for (Field field : actionClass.getDeclaredFields()) { 25 | if (Modifier.isStatic(field.getModifiers()) && isSafeParamsField(field)) { 26 | this.hasSafeParameterConfig = true; 27 | break; 28 | } 29 | } 30 | } catch (Exception e) { 31 | this.abletoInspect = false; 32 | } 33 | } 34 | 35 | /** 36 | * Method to check if the fix for SECURITY-170 is present 37 | * 38 | * @return true if the SECURITY-170 fix is present, false otherwise 39 | */ 40 | public boolean getHasSafeParameterConfig() { 41 | return hasSafeParameterConfig; 42 | } 43 | 44 | /** 45 | * Method to check if this class has been able to determine the existence of SECURITY-170 fix 46 | * 47 | * @return true if the check for SECURITY-170 has been executed (whatever the result) false otherwise 48 | */ 49 | public boolean getAbletoInspect() { 50 | return abletoInspect; 51 | } 52 | 53 | private boolean isSafeParamsField(Field field) { 54 | String fieldName = field.getName(); 55 | return UNDEFINED_PARAMETERS_FIELD_NAME.equals(fieldName) 56 | || SAFE_PARAMETERS_FIELD_NAME.equals(fieldName); 57 | } 58 | 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/config/HookSecretConfigTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.config; 2 | 3 | import org.jenkinsci.plugins.github.GitHubPlugin; 4 | import org.junit.Before; 5 | import org.junit.Rule; 6 | import org.junit.Test; 7 | import org.jvnet.hudson.test.JenkinsRule; 8 | 9 | import static org.jenkinsci.plugins.github.test.HookSecretHelper.storeSecret; 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertNotNull; 12 | import static org.junit.Assert.assertTrue; 13 | 14 | 15 | /** 16 | * Test for storing hook secrets. 17 | */ 18 | @SuppressWarnings("deprecation") 19 | public class HookSecretConfigTest { 20 | 21 | private static final String SECRET_INIT = "test"; 22 | 23 | @Rule 24 | public JenkinsRule jenkinsRule = new JenkinsRule(); 25 | 26 | private HookSecretConfig hookSecretConfig; 27 | 28 | @Before 29 | public void setup() { 30 | storeSecret(SECRET_INIT); 31 | } 32 | 33 | @Test 34 | public void shouldStoreNewSecrets() { 35 | storeSecret(SECRET_INIT); 36 | 37 | hookSecretConfig = GitHubPlugin.configuration().getHookSecretConfig(); 38 | assertNotNull("Secret is persistent", hookSecretConfig.getHookSecret()); 39 | assertEquals("Secret correctly stored", SECRET_INIT, hookSecretConfig.getHookSecret().getPlainText()); 40 | } 41 | 42 | @Test 43 | public void shouldOverwriteExistingSecrets() { 44 | final String newSecret = "test2"; 45 | storeSecret(newSecret); 46 | 47 | hookSecretConfig = GitHubPlugin.configuration().getHookSecretConfig(); 48 | assertNotNull("Secret is persistent", hookSecretConfig.getHookSecret()); 49 | assertEquals("Secret correctly stored", newSecret, hookSecretConfig.getHookSecret().getPlainText()); 50 | } 51 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/extension/CryptoUtilTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension; 2 | 3 | import hudson.util.Secret; 4 | import org.junit.ClassRule; 5 | import org.junit.Test; 6 | import org.jvnet.hudson.test.JenkinsRule; 7 | 8 | import static org.hamcrest.core.IsEqual.equalTo; 9 | import static org.jenkinsci.plugins.github.webhook.GHWebhookSignature.webhookSignature; 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | 12 | /** 13 | * Tests for utility class that deals with crypto/hashing of data. 14 | * 15 | * @author martinmine 16 | */ 17 | public class CryptoUtilTest { 18 | 19 | private static final String SIGNATURE = "85d155c55ed286a300bd1cf124de08d87e914f3a"; 20 | private static final String PAYLOAD = "foo"; 21 | private static final String SECRET = "bar"; 22 | 23 | @ClassRule 24 | public static JenkinsRule jRule = new JenkinsRule(); 25 | 26 | @Test 27 | public void shouldComputeSHA1Signature() throws Exception { 28 | assertThat("signature is valid", webhookSignature( 29 | PAYLOAD, 30 | Secret.fromString(SECRET) 31 | ).sha1(), equalTo(SIGNATURE)); 32 | } 33 | 34 | @Test 35 | public void shouldMatchSignature() throws Exception { 36 | assertThat("signature should match", webhookSignature( 37 | PAYLOAD, 38 | Secret.fromString(SECRET) 39 | ).matches(SIGNATURE), equalTo(true)); 40 | } 41 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/extension/GHEventsSubscriberTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.extension; 2 | 3 | import hudson.model.Item; 4 | import hudson.model.Job; 5 | 6 | import org.junit.Test; 7 | import org.kohsuke.github.GHEvent; 8 | 9 | import java.util.Set; 10 | 11 | import static org.hamcrest.MatcherAssert.assertThat; 12 | import static org.hamcrest.Matchers.hasSize; 13 | import static org.hamcrest.Matchers.is; 14 | 15 | /** 16 | * @author lanwen (Merkushev Kirill) 17 | */ 18 | public class GHEventsSubscriberTest { 19 | 20 | @Test 21 | public void shouldReturnEmptySetInsteadOfNull() throws Exception { 22 | Set set = GHEventsSubscriber.extractEvents().apply(new NullSubscriber()); 23 | assertThat("null should be replaced", set, hasSize(0)); 24 | } 25 | 26 | @Test 27 | public void shouldMatchAgainstEmptySetInsteadOfNull() throws Exception { 28 | boolean result = GHEventsSubscriber.isInterestedIn(GHEvent.PUSH).apply(new NullSubscriber()); 29 | assertThat("null should be replaced", result, is(false)); 30 | } 31 | 32 | public static class NullSubscriber extends GHEventsSubscriber { 33 | @Override 34 | protected boolean isApplicable(Item project) { 35 | return true; 36 | } 37 | 38 | @Override 39 | protected Set events() { 40 | return null; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/err/ErrorHandlersTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.err; 2 | 3 | import hudson.model.Result; 4 | import hudson.model.Run; 5 | import hudson.model.TaskListener; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.Mock; 9 | import org.mockito.Mockito; 10 | import org.mockito.junit.MockitoJUnitRunner; 11 | 12 | import static org.hamcrest.Matchers.is; 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | import static org.mockito.Mockito.verify; 15 | 16 | /** 17 | * @author lanwen (Merkushev Kirill) 18 | */ 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class ErrorHandlersTest { 21 | 22 | @Mock 23 | private Run run; 24 | 25 | @Mock 26 | private TaskListener listener; 27 | 28 | @Test 29 | public void shouldSetFailureResultStatus() throws Exception { 30 | boolean handled = new ChangingBuildStatusErrorHandler(Result.FAILURE.toString()) 31 | .handle(new RuntimeException(), run, listener); 32 | 33 | verify(run).setResult(Result.FAILURE); 34 | assertThat("handling", handled, is(true)); 35 | } 36 | 37 | @Test 38 | public void shouldSetFailureResultStatusOnUnknownSetup() throws Exception { 39 | boolean handled = new ChangingBuildStatusErrorHandler("") 40 | .handle(new RuntimeException(), run, listener); 41 | 42 | verify(run).setResult(Result.FAILURE); 43 | assertThat("handling", handled, is(true)); 44 | } 45 | 46 | @Test 47 | public void shouldHandleAndDoNothing() throws Exception { 48 | boolean handled = new ShallowAnyErrorHandler().handle(new RuntimeException(), run, listener); 49 | assertThat("handling", handled, is(true)); 50 | 51 | Mockito.verifyNoMoreInteractions(run); 52 | } 53 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/sources/BuildRefBackrefSourceTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.model.FreeStyleProject; 4 | import hudson.model.Run; 5 | import hudson.model.TaskListener; 6 | import org.jenkinsci.plugins.displayurlapi.DisplayURLProvider; 7 | import org.junit.Rule; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.jvnet.hudson.test.JenkinsRule; 11 | import org.mockito.Answers; 12 | import org.mockito.Mock; 13 | import org.mockito.junit.MockitoJUnitRunner; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.Matchers.is; 17 | 18 | /** 19 | * @author pupssman (Kalinin Ivan) 20 | */ 21 | @RunWith(MockitoJUnitRunner.class) 22 | public class BuildRefBackrefSourceTest { 23 | 24 | @Rule 25 | public JenkinsRule jenkinsRule = new JenkinsRule(); 26 | 27 | @Mock(answer = Answers.RETURNS_MOCKS) 28 | private TaskListener listener; 29 | 30 | @Test 31 | /** 32 | * @throws Exception 33 | */ 34 | public void shouldReturnRunAbsoluteUrl() throws Exception { 35 | Run run = jenkinsRule.buildAndAssertSuccess(jenkinsRule.createFreeStyleProject()); 36 | 37 | String result = new BuildRefBackrefSource().get(run, listener); 38 | assertThat("state", result, is(DisplayURLProvider.get().getRunURL(run))); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/sources/DefaultStatusResultSourceTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import com.tngtech.java.junit.dataprovider.DataProvider; 4 | import com.tngtech.java.junit.dataprovider.DataProviderRunner; 5 | import com.tngtech.java.junit.dataprovider.UseDataProvider; 6 | import hudson.model.Result; 7 | import hudson.model.Run; 8 | import hudson.model.TaskListener; 9 | import org.jenkinsci.plugins.github.extension.status.GitHubStatusResultSource; 10 | import org.junit.Rule; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.kohsuke.github.GHCommitState; 14 | import org.mockito.Answers; 15 | import org.mockito.Mock; 16 | import org.mockito.junit.MockitoJUnit; 17 | import org.mockito.junit.MockitoRule; 18 | 19 | import static org.hamcrest.MatcherAssert.assertThat; 20 | import static org.hamcrest.Matchers.is; 21 | import static org.mockito.Mockito.when; 22 | 23 | /** 24 | * @author lanwen (Merkushev Kirill) 25 | */ 26 | @RunWith(DataProviderRunner.class) 27 | public class DefaultStatusResultSourceTest { 28 | 29 | @Rule 30 | public MockitoRule mockitoRule = MockitoJUnit.rule(); 31 | 32 | @Mock(answer = Answers.RETURNS_MOCKS) 33 | private Run run; 34 | 35 | @Mock(answer = Answers.RETURNS_MOCKS) 36 | private TaskListener listener; 37 | 38 | @DataProvider 39 | public static Object[][] results() { 40 | return new Object[][]{ 41 | {Result.SUCCESS, GHCommitState.SUCCESS}, 42 | {Result.UNSTABLE, GHCommitState.FAILURE}, 43 | {Result.FAILURE, GHCommitState.ERROR}, 44 | {null, GHCommitState.PENDING}, 45 | }; 46 | } 47 | 48 | @Test 49 | @UseDataProvider("results") 50 | public void shouldReturnConditionalResult(Result actual, GHCommitState expected) throws Exception { 51 | when(run.getResult()).thenReturn(actual); 52 | 53 | GitHubStatusResultSource.StatusResult result = new DefaultStatusResultSource().get(run, listener); 54 | assertThat("state", result.getState(), is(expected)); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredRepositorySourceTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.model.Run; 4 | import hudson.model.TaskListener; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.kohsuke.github.GHRepository; 8 | import org.mockito.Answers; 9 | import org.mockito.Mock; 10 | import org.mockito.junit.MockitoJUnitRunner; 11 | 12 | import java.io.PrintStream; 13 | import java.util.List; 14 | 15 | import static org.hamcrest.MatcherAssert.assertThat; 16 | import static org.hamcrest.collection.IsCollectionWithSize.hasSize; 17 | import static org.mockito.Mockito.doReturn; 18 | import static org.mockito.Mockito.eq; 19 | import static org.mockito.Mockito.spy; 20 | import static org.mockito.Mockito.verify; 21 | 22 | @RunWith(MockitoJUnitRunner.class) 23 | public class ManuallyEnteredRepositorySourceTest { 24 | @Mock(answer = Answers.RETURNS_MOCKS) 25 | private Run run; 26 | 27 | @Mock(answer = Answers.RETURNS_MOCKS) 28 | private TaskListener listener; 29 | 30 | @Mock(answer = Answers.RETURNS_MOCKS) 31 | private PrintStream logger; 32 | 33 | @Test 34 | public void nullName() { 35 | ManuallyEnteredRepositorySource instance = spy(new ManuallyEnteredRepositorySource("a")); 36 | doReturn(logger).when(listener).getLogger(); 37 | List repos = instance.repos(run, listener); 38 | assertThat("size", repos, hasSize(0)); 39 | verify(listener).getLogger(); 40 | verify(logger).printf(eq("Unable to match %s with a GitHub repository.%n"), eq("a")); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/sources/ManuallyEnteredSourcesTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources; 2 | 3 | import hudson.EnvVars; 4 | import hudson.model.Run; 5 | import hudson.model.TaskListener; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.Answers; 9 | import org.mockito.ArgumentMatchers; 10 | import org.mockito.Mock; 11 | import org.mockito.junit.MockitoJUnitRunner; 12 | 13 | import static org.hamcrest.Matchers.equalTo; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | import static org.mockito.Mockito.when; 16 | 17 | /** 18 | * @author lanwen (Merkushev Kirill) 19 | */ 20 | @RunWith(MockitoJUnitRunner.class) 21 | public class ManuallyEnteredSourcesTest { 22 | 23 | public static final String EXPANDED = "expanded"; 24 | @Mock(answer = Answers.RETURNS_MOCKS) 25 | private Run run; 26 | 27 | @Mock(answer = Answers.RETURNS_MOCKS) 28 | private TaskListener listener; 29 | 30 | @Mock(answer = Answers.RETURNS_MOCKS) 31 | private EnvVars env; 32 | 33 | 34 | @Test 35 | public void shouldExpandContext() throws Exception { 36 | when(run.getEnvironment(listener)).thenReturn(env); 37 | when(env.expand(ArgumentMatchers.anyString())).thenReturn(EXPANDED); 38 | 39 | String context = new ManuallyEnteredCommitContextSource("").context(run, listener); 40 | assertThat(context, equalTo(EXPANDED)); 41 | } 42 | 43 | @Test 44 | public void shouldExpandSha() throws Exception { 45 | when(run.getEnvironment(listener)).thenReturn(env); 46 | when(env.expand(ArgumentMatchers.anyString())).thenReturn(EXPANDED); 47 | 48 | String context = new ManuallyEnteredShaSource("").get(run, listener); 49 | assertThat(context, equalTo(EXPANDED)); 50 | } 51 | 52 | @Test 53 | public void shouldExpandBackref() throws Exception { 54 | when(run.getEnvironment(listener)).thenReturn(env); 55 | when(env.expand(ArgumentMatchers.anyString())).thenReturn(EXPANDED); 56 | 57 | String context = new ManuallyEnteredBackrefSource("").get(run, listener); 58 | assertThat(context, equalTo(EXPANDED)); 59 | } 60 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/sources/misc/AnyBuildResultTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.misc; 2 | 3 | import hudson.model.Run; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.kohsuke.github.GHCommitState; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | import static org.junit.Assert.assertTrue; 11 | import static org.mockito.Mockito.verifyNoMoreInteractions; 12 | 13 | /** 14 | * @author lanwen (Merkushev Kirill) 15 | */ 16 | @RunWith(MockitoJUnitRunner.class) 17 | public class AnyBuildResultTest { 18 | 19 | @Mock 20 | private Run run; 21 | 22 | @Test 23 | public void shouldMatchEveryTime() throws Exception { 24 | boolean matches = AnyBuildResult.onAnyResult(GHCommitState.ERROR, "").matches(run); 25 | 26 | assertTrue("matching", matches); 27 | verifyNoMoreInteractions(run); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/status/sources/misc/BetterThanOrEqualBuildResultTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.status.sources.misc; 2 | 3 | import com.tngtech.java.junit.dataprovider.DataProvider; 4 | import com.tngtech.java.junit.dataprovider.DataProviderRunner; 5 | import com.tngtech.java.junit.dataprovider.UseDataProvider; 6 | import hudson.model.Result; 7 | import hudson.model.Run; 8 | import org.junit.Rule; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.kohsuke.github.GHCommitState; 12 | import org.mockito.Mock; 13 | import org.mockito.Mockito; 14 | import org.mockito.junit.MockitoJUnit; 15 | import org.mockito.junit.MockitoRule; 16 | 17 | import static org.hamcrest.Matchers.is; 18 | import static org.jenkinsci.plugins.github.status.sources.misc.BetterThanOrEqualBuildResult.betterThanOrEqualTo; 19 | import static org.hamcrest.MatcherAssert.assertThat; 20 | 21 | /** 22 | * @author lanwen (Merkushev Kirill) 23 | */ 24 | @RunWith(DataProviderRunner.class) 25 | public class BetterThanOrEqualBuildResultTest { 26 | 27 | @Rule 28 | public MockitoRule mockitoRule = MockitoJUnit.rule(); 29 | 30 | @Mock 31 | private Run run; 32 | 33 | @DataProvider 34 | public static Object[][] results() { 35 | return new Object[][]{ 36 | {Result.SUCCESS, Result.SUCCESS, true}, 37 | {Result.UNSTABLE, Result.UNSTABLE, true}, 38 | {Result.FAILURE, Result.FAILURE, true}, 39 | {Result.FAILURE, Result.UNSTABLE, true}, 40 | {Result.FAILURE, Result.SUCCESS, true}, 41 | {Result.SUCCESS, Result.FAILURE, false}, 42 | {Result.SUCCESS, Result.UNSTABLE, false}, 43 | {Result.UNSTABLE, Result.FAILURE, false}, 44 | }; 45 | } 46 | 47 | @Test 48 | @UseDataProvider("results") 49 | public void shouldMatch(Result defined, Result real, boolean expect) throws Exception { 50 | Mockito.when(run.getResult()).thenReturn(real); 51 | 52 | boolean matched = betterThanOrEqualTo(defined, GHCommitState.FAILURE, "").matches(run); 53 | assertThat("matching", matched, is(expect)); 54 | } 55 | } -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/test/GitHubRepoNameMatchers.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.test; 2 | 3 | import com.cloudbees.jenkins.GitHubRepositoryName; 4 | import org.hamcrest.Description; 5 | import org.hamcrest.DiagnosingMatcher; 6 | import org.hamcrest.FeatureMatcher; 7 | import org.hamcrest.Matcher; 8 | 9 | import static org.hamcrest.Matchers.is; 10 | 11 | /** 12 | * @author lanwen (Merkushev Kirill) 13 | */ 14 | public final class GitHubRepoNameMatchers { 15 | private GitHubRepoNameMatchers() { 16 | } 17 | 18 | public static Matcher repo(final Matcher matcher) { 19 | return new DiagnosingMatcher() { 20 | @Override 21 | protected boolean matches(Object url, Description mismatchDescription) { 22 | mismatchDescription.appendText("for url ").appendValue(url).appendText(" instead of expected repo "); 23 | 24 | if (url != null && !(url instanceof String)) { 25 | return false; 26 | } 27 | 28 | GitHubRepositoryName repo = GitHubRepositoryName.create((String) url); 29 | matcher.describeMismatch(repo, mismatchDescription); 30 | return matcher.matches(repo); 31 | } 32 | 33 | @Override 34 | public void describeTo(Description description) { 35 | description.appendText("GitHub full repo ").appendDescriptionOf(matcher); 36 | } 37 | }; 38 | } 39 | 40 | public static Matcher withHost(String host) { 41 | return new FeatureMatcher(is(host), "with host", "host") { 42 | @Override 43 | protected String featureValueOf(GitHubRepositoryName repo) { 44 | return repo.getHost(); 45 | } 46 | }; 47 | } 48 | 49 | public static Matcher withUserName(String username) { 50 | return new FeatureMatcher(is(username), "with username", "username") { 51 | @Override 52 | protected String featureValueOf(GitHubRepositoryName repo) { 53 | return repo.getUserName(); 54 | } 55 | }; 56 | } 57 | 58 | public static Matcher withRepoName(String reponame) { 59 | return new FeatureMatcher(is(reponame), "with reponame", "reponame") { 60 | @Override 61 | protected String featureValueOf(GitHubRepositoryName repo) { 62 | return repo.getRepositoryName(); 63 | } 64 | }; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/test/HookSecretHelper.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.test; 2 | 3 | import com.cloudbees.plugins.credentials.CredentialsScope; 4 | import com.cloudbees.plugins.credentials.SystemCredentialsProvider; 5 | import com.cloudbees.plugins.credentials.domains.Domain; 6 | import hudson.security.ACL; 7 | import hudson.util.Secret; 8 | import jenkins.model.Jenkins; 9 | import org.jenkinsci.plugins.github.config.GitHubPluginConfig; 10 | import org.jenkinsci.plugins.github.config.HookSecretConfig; 11 | import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.io.IOException; 16 | import java.util.Collections; 17 | import java.util.UUID; 18 | 19 | /** 20 | * Helper class for setting the secret text for hooks while testing. 21 | */ 22 | public class HookSecretHelper { 23 | private static final Logger LOGGER = LoggerFactory.getLogger(HookSecretHelper.class); 24 | 25 | private HookSecretHelper() { 26 | } 27 | 28 | /** 29 | * Stores the secret and sets it as the current hook secret. 30 | * 31 | * @param config where to save 32 | * @param secretText The secret/key. 33 | */ 34 | public static void storeSecretIn(GitHubPluginConfig config, final String secretText) { 35 | final StringCredentialsImpl credentials = new StringCredentialsImpl( 36 | CredentialsScope.GLOBAL, 37 | UUID.randomUUID().toString(), 38 | null, 39 | Secret.fromString(secretText) 40 | ); 41 | 42 | ACL.impersonate(ACL.SYSTEM, new Runnable() { 43 | @Override 44 | public void run() { 45 | try { 46 | new SystemCredentialsProvider.StoreImpl().addCredentials( 47 | Domain.global(), 48 | credentials 49 | ); 50 | 51 | } catch (IOException e) { 52 | LOGGER.error("Unable to set hook secret", e); 53 | } 54 | } 55 | }); 56 | 57 | config.setHookSecretConfigs(Collections.singletonList(new HookSecretConfig(credentials.getId()))); 58 | } 59 | 60 | /** 61 | * Stores the secret and sets it as the current hook secret. 62 | * @param secretText The secret/key. 63 | */ 64 | public static void storeSecret(final String secretText) { 65 | storeSecretIn(Jenkins.getInstance().getDescriptorByType(GitHubPluginConfig.class), secretText); 66 | } 67 | 68 | /** 69 | * Unsets the current hook secret. 70 | * 71 | * @param config where to remove 72 | */ 73 | public static void removeSecretIn(GitHubPluginConfig config) { 74 | config.setHookSecretConfigs(null); 75 | } 76 | 77 | /** 78 | * Unsets the current hook secret. 79 | */ 80 | public static void removeSecret() { 81 | removeSecretIn(Jenkins.getInstance().getDescriptorByType(GitHubPluginConfig.class)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/test/InjectJenkinsMembersRule.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.test; 2 | 3 | import org.junit.rules.ExternalResource; 4 | import org.jvnet.hudson.test.JenkinsRule; 5 | 6 | /** 7 | * Helpful class to make possible usage of 8 | * {@code @Inject 9 | * public GitHubPluginConfig config; 10 | * } 11 | * 12 | * in test fields instead of static calls {@link org.jenkinsci.plugins.github.GitHubPlugin#configuration()} 13 | * 14 | * See {@link com.cloudbees.jenkins.GitHubSetCommitStatusBuilderTest} for example 15 | * Should be used after JenkinsRule initialized 16 | * 17 | * {@code public RuleChain chain = RuleChain.outerRule(jRule).around(new InjectJenkinsMembersRule(jRule, this)); } 18 | * 19 | * @author lanwen (Merkushev Kirill) 20 | */ 21 | public class InjectJenkinsMembersRule extends ExternalResource { 22 | 23 | private JenkinsRule jRule; 24 | private Object instance; 25 | 26 | /** 27 | * @param jRule Jenkins rule 28 | * @param instance test class instance 29 | */ 30 | public InjectJenkinsMembersRule(JenkinsRule jRule, Object instance) { 31 | this.jRule = jRule; 32 | this.instance = instance; 33 | } 34 | 35 | @Override 36 | protected void before() throws Throwable { 37 | jRule.getInstance().getInjector().injectMembers(instance); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/util/XSSApiTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.util; 2 | 3 | import com.tngtech.java.junit.dataprovider.DataProvider; 4 | import com.tngtech.java.junit.dataprovider.DataProviderRunner; 5 | import com.tngtech.java.junit.dataprovider.UseDataProvider; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | 9 | import static java.lang.String.format; 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.is; 12 | 13 | /** 14 | * @author lanwen (Merkushev Kirill) 15 | */ 16 | @RunWith(DataProviderRunner.class) 17 | public class XSSApiTest { 18 | 19 | @DataProvider 20 | public static Object[][] links() { 21 | return new Object[][]{ 22 | new Object[]{"javascript:alert(1);//", ""}, 23 | new Object[]{"javascript:alert(1)://", ""}, 24 | new Object[]{"http://abcxyz.com?a=b&c=d';alert(1);//", "http://abcxyz.com?a=b&c=d';alert(1);//"}, 25 | new Object[]{"http://github.com/bla/bla", "http://github.com/bla/bla"}, 26 | new Object[]{"https://github.com/bla/bla", "https://github.com/bla/bla"}, 27 | new Object[]{"https://company.com/bla", "https://company.com/bla"}, 28 | new Object[]{"/company.com/bla", ""}, 29 | new Object[]{"//", ""}, 30 | new Object[]{"//text", ""}, 31 | new Object[]{"//text/", ""}, 32 | new Object[]{"ftp://", "ftp:"}, 33 | new Object[]{"ftp://a", "ftp://a"}, 34 | new Object[]{"text", ""}, 35 | new Object[]{"github.com/bla/bla", ""}, 36 | new Object[]{"http://127.0.0.1/", "http://127.0.0.1/"}, 37 | }; 38 | } 39 | 40 | @Test 41 | @UseDataProvider("links") 42 | public void shouldSanitizeUrl(String url, String expected) throws Exception { 43 | assertThat(format("For %s", url), XSSApi.asValidHref(url), is(expected)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/webhook/GHEventHeaderTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.webhook; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.kohsuke.github.GHEvent; 6 | import org.kohsuke.stapler.StaplerRequest2; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.equalTo; 12 | import static org.hamcrest.Matchers.instanceOf; 13 | import static org.hamcrest.Matchers.nullValue; 14 | import static org.mockito.Mockito.when; 15 | 16 | /** 17 | * @author lanwen (Merkushev Kirill) 18 | */ 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class GHEventHeaderTest { 21 | 22 | public static final String STRING_PUSH_HEADER = "push"; 23 | public static final String PARAM_NAME = "event"; 24 | public static final String UNKNOWN_EVENT = "unkn"; 25 | 26 | @Mock 27 | private StaplerRequest2 req; 28 | 29 | @Mock 30 | private GHEventHeader ann; 31 | 32 | @Test 33 | public void shouldReturnParsedPushHeader() throws Exception { 34 | when(req.getHeader(GHEventHeader.PayloadHandler.EVENT_HEADER)).thenReturn(STRING_PUSH_HEADER); 35 | Object event = new GHEventHeader.PayloadHandler().parse(req, ann, GHEvent.class, PARAM_NAME); 36 | 37 | assertThat("instance of event", event, instanceOf(GHEvent.class)); 38 | assertThat("parsed event", (GHEvent) event, equalTo(GHEvent.PUSH)); 39 | } 40 | 41 | @Test 42 | public void shouldReturnNullOnEmptyHeader() throws Exception { 43 | Object event = new GHEventHeader.PayloadHandler().parse(req, ann, GHEvent.class, PARAM_NAME); 44 | 45 | assertThat("event with empty header", event, nullValue()); 46 | } 47 | 48 | @Test 49 | public void shouldReturnNullOnUnknownEventHeader() throws Exception { 50 | when(req.getHeader(GHEventHeader.PayloadHandler.EVENT_HEADER)).thenReturn(UNKNOWN_EVENT); 51 | Object event = new GHEventHeader.PayloadHandler().parse(req, ann, GHEvent.class, PARAM_NAME); 52 | 53 | assertThat("event with unknown event header", event, nullValue()); 54 | } 55 | 56 | @Test(expected = IllegalArgumentException.class) 57 | public void shouldThrowExcOnWrongTypeOfHeader() throws Exception { 58 | new GHEventHeader.PayloadHandler().parse(req, ann, String.class, PARAM_NAME); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/webhook/GHEventPayloadTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.webhook; 2 | 3 | import com.cloudbees.jenkins.GitHubWebHookFullTest; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.kohsuke.stapler.StaplerRequest2; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | import static org.hamcrest.MatcherAssert.assertThat; 11 | import static org.hamcrest.Matchers.equalTo; 12 | import static org.hamcrest.Matchers.instanceOf; 13 | import static org.hamcrest.Matchers.nullValue; 14 | import static org.mockito.Mockito.when; 15 | 16 | /** 17 | * @author lanwen (Merkushev Kirill) 18 | */ 19 | @RunWith(MockitoJUnitRunner.class) 20 | public class GHEventPayloadTest { 21 | 22 | public static final String NOT_EMPTY_PAYLOAD_CONTENT = "{}"; 23 | public static final String PARAM_NAME = "payload"; 24 | public static final String UNKNOWN_CONTENT_TYPE = "text/plain"; 25 | 26 | @Mock 27 | private StaplerRequest2 req; 28 | 29 | @Mock 30 | private GHEventPayload ann; 31 | 32 | @Test 33 | public void shouldReturnPayloadFromForm() throws Exception { 34 | when(req.getContentType()).thenReturn(GitHubWebHookFullTest.FORM); 35 | when(req.getParameter(PARAM_NAME)).thenReturn(NOT_EMPTY_PAYLOAD_CONTENT); 36 | Object payload = new GHEventPayload.PayloadHandler().parse(req, ann, String.class, PARAM_NAME); 37 | 38 | assertThat("class", payload, instanceOf(String.class)); 39 | assertThat("content", (String) payload, equalTo(NOT_EMPTY_PAYLOAD_CONTENT)); 40 | } 41 | 42 | @Test 43 | public void shouldReturnNullOnUnknownContentType() throws Exception { 44 | when(req.getContentType()).thenReturn(UNKNOWN_CONTENT_TYPE); 45 | Object payload = new GHEventPayload.PayloadHandler().parse(req, ann, String.class, PARAM_NAME); 46 | 47 | assertThat("payload should be null", payload, nullValue()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/github/webhook/subscriber/PingGHEventSubscriberTest.java: -------------------------------------------------------------------------------- 1 | package org.jenkinsci.plugins.github.webhook.subscriber; 2 | 3 | import hudson.model.FreeStyleProject; 4 | import org.junit.Rule; 5 | import org.junit.Test; 6 | import org.jvnet.hudson.test.JenkinsRule; 7 | import org.jvnet.hudson.test.WithoutJenkins; 8 | import org.kohsuke.github.GHEvent; 9 | 10 | import static com.cloudbees.jenkins.GitHubWebHookFullTest.classpath; 11 | import static org.hamcrest.MatcherAssert.assertThat; 12 | import static org.hamcrest.Matchers.is; 13 | import org.jvnet.hudson.test.Issue; 14 | 15 | /** 16 | * @author lanwen (Merkushev Kirill) 17 | */ 18 | public class PingGHEventSubscriberTest { 19 | 20 | @Rule 21 | public JenkinsRule jenkins = new JenkinsRule(); 22 | 23 | @Test 24 | public void shouldBeNotApplicableForProjects() throws Exception { 25 | FreeStyleProject prj = jenkins.createFreeStyleProject(); 26 | assertThat(new PingGHEventSubscriber().isApplicable(prj), is(false)); 27 | } 28 | 29 | @Test 30 | public void shouldParsePingPayload() throws Exception { 31 | injectedPingSubscr().onEvent(GHEvent.PING, classpath("payloads/ping.json")); 32 | } 33 | 34 | @Issue("JENKINS-30626") 35 | @Test 36 | @WithoutJenkins 37 | public void shouldParseOrgPingPayload() throws Exception { 38 | new PingGHEventSubscriber().onEvent(GHEvent.PING, classpath("payloads/orgping.json")); 39 | } 40 | 41 | private PingGHEventSubscriber injectedPingSubscr() { 42 | PingGHEventSubscriber pingSubsc = new PingGHEventSubscriber(); 43 | jenkins.getInstance().getInjector().injectMembers(pingSubsc); 44 | return pingSubsc; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/resources/checkstyle/checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/GitHubSetCommitStatusBuilderTest/shouldLoadNullStatusMessage/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.554.1 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 19 | 5 20 | 0 21 | 22 | 23 | 24 | All 25 | false 26 | false 27 | 28 | 29 | 30 | All 31 | 0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/GitHubSetCommitStatusBuilderTest/shouldLoadNullStatusMessage/jobs/step/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | false 6 | 7 | 8 | 9 | true 10 | false 11 | false 12 | false 13 | 14 | false 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test/resources/com/cloudbees/jenkins/GitHubWebHookFullTest/payloads/orgping.json: -------------------------------------------------------------------------------- 1 | { 2 | "zen": "Mind your words, they are important.", 3 | "hook_id": 5926787, 4 | "hook": { 5 | "url": "https://api.github.com/orgs/cloudbeers/hooks/5926787", 6 | "ping_url": "https://api.github.com/orgs/cloudbeers/hooks/5926787/pings", 7 | "id": 5926787, 8 | "name": "web", 9 | "active": true, 10 | "events": [ 11 | "*" 12 | ], 13 | "config": { 14 | "url": "https://jenkins.ci.cloudbees.com/github-webhook/", 15 | "content_type": "json", 16 | "insecure_ssl": "0", 17 | "secret": "" 18 | }, 19 | "updated_at": "2015-09-24T10:13:54Z", 20 | "created_at": "2015-09-24T10:13:54Z" 21 | }, 22 | "organization": { 23 | "login": "cloudbeers", 24 | "id": 4181899, 25 | "url": "https://api.github.com/orgs/cloudbeers", 26 | "repos_url": "https://api.github.com/orgs/cloudbeers/repos", 27 | "events_url": "https://api.github.com/orgs/cloudbeers/events", 28 | "members_url": "https://api.github.com/orgs/cloudbeers/members{/member}", 29 | "public_members_url": "https://api.github.com/orgs/cloudbeers/public_members{/member}", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/4181899?v=3", 31 | "description": null 32 | }, 33 | "sender": { 34 | "login": "jglick", 35 | "id": 154109, 36 | "avatar_url": "https://avatars.githubusercontent.com/u/154109?v=3", 37 | "gravatar_id": "", 38 | "url": "https://api.github.com/users/jglick", 39 | "html_url": "https://github.com/jglick", 40 | "followers_url": "https://api.github.com/users/jglick/followers", 41 | "following_url": "https://api.github.com/users/jglick/following{/other_user}", 42 | "gists_url": "https://api.github.com/users/jglick/gists{/gist_id}", 43 | "starred_url": "https://api.github.com/users/jglick/starred{/owner}{/repo}", 44 | "subscriptions_url": "https://api.github.com/users/jglick/subscriptions", 45 | "organizations_url": "https://api.github.com/users/jglick/orgs", 46 | "repos_url": "https://api.github.com/users/jglick/repos", 47 | "events_url": "https://api.github.com/users/jglick/events{/privacy}", 48 | "received_events_url": "https://api.github.com/users/jglick/received_events", 49 | "type": "User", 50 | "site_admin": false 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, stdout 3 | 4 | # Direct log messages to stdout 5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 6 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 7 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 8 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/admin/GitHubHookRegisterProblemMonitorTest/shouldLoadIgnoredList/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.554.1 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 19 | 5 20 | 0 21 | 22 | 23 | 24 | All 25 | false 26 | false 27 | 28 | 29 | 30 | All 31 | 0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/admin/GitHubHookRegisterProblemMonitorTest/shouldLoadIgnoredList/org.jenkinsci.plugins.github.admin.GitHubHookRegisterProblemMonitor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GitHubHookRegisterProblemMonitor 4 | 5 | 6 | host 7 | user 8 | repo 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/config/configuration-as-code.yml: -------------------------------------------------------------------------------- 1 | unclassified: 2 | 3 | githubpluginconfig: 4 | hookUrl: "http://some.com/github-webhook/secret-path" 5 | hookSecretConfigs: 6 | - credentialsId: "hook_secret_cred_id" 7 | configs: 8 | - credentialsId: "public_cred_id" 9 | name: "Public GitHub" 10 | apiUrl: "https://api.github.com" 11 | manageHooks: true 12 | clientCacheSize: 20 13 | - credentialsId: "private_cred_id" 14 | name: "Private GitHub" 15 | apiUrl: "https://api.some.com" 16 | manageHooks: false 17 | clientCacheSize: 40 -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldLoadDataAfterStart/com.cloudbees.jenkins.GitHubPushTrigger.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldLoadDataAfterStart/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.565.11 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 19 | 5 20 | 0 21 | 22 | 23 | 24 | All 25 | false 26 | false 27 | 28 | 29 | 30 | All 31 | 0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldLoadDataAfterStart/github-plugin-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | https://api.github.com 6 | true 7 | a06436b7-7862-41fd-b7dc-3fec57c81f14 8 | 9 | 10 | http://custom.github.example.com/api/v3 11 | true 12 | aae86cb0-e6d2-4520-80a9-89ab80129a4f 13 | 14 | 15 | http://some.proxy.example.com/webhook 16 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldMigrateCredentials/com.cloudbees.jenkins.GitHubPushTrigger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | http://some.proxy.example.com/webhook 5 | 6 | 7 | user 8 | 9 | some-oauth-token 10 | 11 | 12 | user2 13 | http://custom.github.example.com/api/v3 14 | some-oauth-token2 15 | 16 | 17 | user3 18 | https://api.github.com 19 | some-oauth-token3 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldMigrateCredentials/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.554.1 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 19 | 5 20 | 0 21 | 22 | 23 | 24 | All 25 | false 26 | false 27 | 28 | 29 | 30 | All 31 | 0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldMigrateHookUrl/com.cloudbees.jenkins.GitHubPushTrigger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://some.proxy.example.com/webhook 4 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldMigrateHookUrl/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.554.1 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 19 | 5 20 | 0 21 | 22 | 23 | 24 | All 25 | false 26 | false 27 | 28 | 29 | 30 | All 31 | 0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldNotThrowExcMalformedHookUrlInOldConfig/com.cloudbees.jenkins.GitHubPushTrigger.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | h 5 | 6 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/migration/MigratorTest/shouldNotThrowExcMalformedHookUrlInOldConfig/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.554.1 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | false 11 | 12 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 13 | ${ITEM_ROOTDIR}/builds 14 | 15 | 16 | 17 | 18 | 19 | 5 20 | 0 21 | 22 | 23 | 24 | All 25 | false 26 | false 27 | 28 | 29 | 30 | All 31 | 0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/test/GHMockRule/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "login", 3 | "id": 2341, 4 | "avatar_url": "", 5 | "gravatar_id": "", 6 | "url": "https://api.github.com/users/login", 7 | "html_url": "https://github.com/login", 8 | "followers_url": "https://api.github.com/users/login/followers", 9 | "following_url": "https://api.github.com/users/login/following{/other_user}", 10 | "gists_url": "https://api.github.com/users/login/gists{/gist_id}", 11 | "starred_url": "https://api.github.com/users/login/starred{/owner}{/repo}", 12 | "subscriptions_url": "https://api.github.com/users/login/subscriptions", 13 | "organizations_url": "https://api.github.com/users/login/orgs", 14 | "repos_url": "https://api.github.com/users/login/repos", 15 | "events_url": "https://api.github.com/users/login/events{/privacy}", 16 | "received_events_url": "https://api.github.com/users/login/received_events", 17 | "type": "User", 18 | "site_admin": false, 19 | "name": "User", 20 | "company": "Company", 21 | "blog": "http://blog.blog", 22 | "location": "Location", 23 | "email": null, 24 | "hireable": null, 25 | "bio": null, 26 | "public_repos": 1, 27 | "public_gists": 1, 28 | "followers": 1, 29 | "following": 1, 30 | "created_at": "2012-07-12T16:12:59Z", 31 | "updated_at": "2015-10-05T08:55:34Z", 32 | "private_gists": 1, 33 | "total_private_repos": 0, 34 | "owned_private_repos": 0, 35 | "disk_usage": 10, 36 | "collaborators": 0, 37 | "plan": { 38 | "name": "free", 39 | "space": 976562499, 40 | "collaborators": 0, 41 | "private_repos": 0 42 | } 43 | } -------------------------------------------------------------------------------- /src/test/resources/org/jenkinsci/plugins/github/webhook/subscriber/DefaultPushGHEventListenerTest/workflow-definition.groovy: -------------------------------------------------------------------------------- 1 | node { 2 | git 'https://github.com/lanwen/test.git' 3 | } --------------------------------------------------------------------------------