<?xml version="1.0" encoding="UTF-8"?>
<!--
- Licensed Materials - Property of IBM Corp.
- IBM UrbanCode Build
- (c) Copyright IBM Corporation 2012, 2014. All Rights Reserved.
-
- U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
- GSA ADP Schedule Contract with IBM Corp.
-->
<plugin xmlns="http://www.urbancode.com/PluginXMLSchema_v1"
   xmlns:server="http://www.urbancode.com/PluginServerXMLSchema_v1"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <header>
    <identifier id="com.urbancode.air.plugin.git" name="Git" version="18"/>
    <description>
       The Git Plugin automates cloning a Git repo, tagging source, and publishing source changes to the Changes tab of the BuildLife.
    </description>
    <tag>SCM/Git</tag>
    <server:plugin-type>Source</server:plugin-type>
  </header>

    <!-- ==================================== -->
    <!--   SCM STEPS                          -->
    <!-- ==================================== -->
    <!--
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/httpcore.jar:lib/httpclient.jar:lib/httpclient-cache.jar:lib/httpmime.jar:lib/HttpComponents-Util.jar:lib/commons-logging.jar:lib/commons-codec.jar:lib/log4j.jar:lib/securedata.jar"/>
    -->

    <step-type name="Git Cleanup">
      <description>Perform a cleanup of the Git working directory</description>
      <properties>
        <property name="source">
          <server:property-ui type="sourcePropSheetRef"
                              label="Source Config"
                              hidden="true"/>
        </property>
      </properties>
      <post-processing><![CDATA[
        if (properties.get("exitCode") != 0) {
            properties.put(new java.lang.String("Status"), new java.lang.String("Failure"));
        }
        else {
            properties.put("Status", "Success");
        }
     ]]></post-processing>

      <command program="${GROOVY_HOME}/bin/groovy">
        <arg value="-cp"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/jettison-1.1.jar:lib/commons-codec.jar"/>
        <arg file="cleanup.groovy"/>
        <arg file="${PLUGIN_INPUT_PROPS}"/>
        <arg file="${PLUGIN_OUTPUT_PROPS}"/>
      </command>

      <server:type>SCM_Cleanup</server:type>
      <server:validation language="javascript">
      </server:validation>
    </step-type>

    <step-type name="Git Checkout">
      <description>Perform a Git checkout of the workflow's source</description>
      <properties>
        <property name="cleanWorkspace">
          <server:property-ui type="checkBox"
                              label="Clean Workspace"
                              description="Erase all files from the workspace before performing checkout" />
        </property>
        <property name="date">
          <server:property-ui type="textBox"
                              label="Date"
                              description="Date of sourcecode to checkout ('yyyy-MM-dd HH:mm:ss z' OR
                              'E MMM dd HH:mm:ss zzz yyyy' OR milliseconds since Unix Epoch). Defaults to the current time." />
        </property>
        <property name="source">
          <server:property-ui type="sourcePropSheetRef"
                              label="Source Config"
                              hidden="true"/>
        </property>
      </properties>
      <post-processing><![CDATA[
        if (properties.get("exitCode") != 0) {
            properties.put(new java.lang.String("Status"), new java.lang.String("Failure"));
        }
        else {
            properties.put("Status", "Success");
        }
     ]]></post-processing>

      <command program="${GROOVY_HOME}/bin/groovy">
        <arg value="-cp"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/jettison-1.1.jar:lib/commons-codec.jar"/>
        <arg file="checkout.groovy" />
        <arg file="${PLUGIN_INPUT_PROPS}"/>
        <arg file="${PLUGIN_OUTPUT_PROPS}"/>
      </command>

      <server:type>SCM_Populate</server:type>
      <server:validation language="javascript">
      </server:validation>
    </step-type>

    <step-type name="Git Create Tag">
      <description>Create a tag in Git of the specified working copy.</description>
      <properties>
        <property name="message" required="true">
          <server:property-ui type="textBox"
                              label="Message"
                              description="A message for the commit" />
        </property>
        <property name="label" required="true">
          <server:property-ui type="textBox"
                              label="Tag"
                              description="The tag name to create" />
        </property>
        <property name="source">
          <server:property-ui type="sourcePropSheetRef"
                              label="Source Config"
                              hidden="true"/>
        </property>
      </properties>
      <post-processing><![CDATA[
        if (properties.get("exitCode") != 0) {
            properties.put(new java.lang.String("Status"), new java.lang.String("Failure"));
        }
        else {
            properties.put("Status", "Success");
        }
     ]]></post-processing>

      <command program="${GROOVY_HOME}/bin/groovy">
        <arg value="-cp"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/jettison-1.1.jar:lib/commons-codec.jar"/>
        <arg file="tag.groovy"/>
        <arg file="${PLUGIN_INPUT_PROPS}"/>
        <arg file="${PLUGIN_OUTPUT_PROPS}"/>
      </command>

      <server:type>SCM_Label</server:type>
      <server:validation language="javascript">
      </server:validation>
    </step-type>

    <step-type name="Git Changelog">
      <description>Perform a Git changelog and publish the results.</description>
      <properties>
        <property name="startRevision">
          <server:property-ui type="textBox"
                              label="Start Revision"
                              description="Start changelog at this revision" />
        </property>
        <property name="endRevision">
          <server:property-ui type="textBox"
                              label="End Revision"
                              description="End changelog at this revision" />
        </property>
        <property name="startDate">
          <server:property-ui type="textBox"
                              label="Start Date"
                              description="Start changelog at this date ('yyyy-MM-dd HH:mm:ss z' OR
                              'E MMM dd HH:mm:ss zzz yyyy' OR milliseconds since Unix Epoch)" />
        </property>
        <property name="endDate">
          <server:property-ui type="textBox"
                              label="End Date"
                              description="End changelog at this date ('yyyy-MM-dd HH:mm:ss z' OR
                              'E MMM dd HH:mm:ss zzz yyyy' OR milliseconds since Unix Epoch)" />
        </property>
        <property name="changesUrl">
          <server:property-ui type="textBox"
                              label="Changes URL"
                              hidden="true" />
        </property>
        <property name="source">
          <server:property-ui type="sourcePropSheetRef"
                              label="Source Config"
                              hidden="true"/>
        </property>
      </properties>
      <post-processing><![CDATA[
        if (properties.get("exitCode") != 0) {
            properties.put(new java.lang.String("Status"), new java.lang.String("Failure"));
        }
        else {
            properties.put("Status", "Success");
        }
     ]]></post-processing>

      <command program="${GROOVY_HOME}/bin/groovy">
        <arg value="-cp"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/httpcore.jar:lib/httpclient.jar:lib/httpclient-cache.jar:lib/httpmime.jar:lib/HttpComponents-Util.jar:lib/commons-logging.jar:lib/commons-codec.jar:lib/log4j.jar:lib/securedata.jar:lib/jettison-1.1.jar"/>
        <arg file="changelog.groovy"/>
        <arg file="${PLUGIN_INPUT_PROPS}"/>
        <arg file="${PLUGIN_OUTPUT_PROPS}"/>
      </command>

      <server:type>SCM_Changelog</server:type>
      <server:validation language="javascript">
      </server:validation>
    </step-type>

    <step-type name="Git Quiet Period">
      <description>Perform a Git changelog for quiet period detection and publish most recent change date within the period.</description>
      <properties>
        <property name="startDate">
          <server:property-ui type="textBox"
                              label="Start Date"
                              description="Start changelog at this date ('yyyy-MM-dd HH:mm:ss z' OR
                              'E MMM dd HH:mm:ss zzz yyyy' OR milliseconds since Unix Epoch)" />
        </property>
        <property name="endDate">
          <server:property-ui type="textBox"
                              label="End Date"
                              description="End changelog at this date ('yyyy-MM-dd HH:mm:ss z' OR
                              'E MMM dd HH:mm:ss zzz yyyy' OR milliseconds since Unix Epoch)" />
        </property>
        <property name="source">
          <server:property-ui type="sourcePropSheetRef"
                              label="Source Config"
                              hidden="true"/>
        </property>
      </properties>
      <post-processing><![CDATA[
        if (properties.get("exitCode") != 0) {
            properties.put(new java.lang.String("Status"), new java.lang.String("Failure"));
        }
        else {
            properties.put("Status", "Success");
        }
     ]]></post-processing>

      <command program="${GROOVY_HOME}/bin/groovy">
        <arg value="-cp"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/httpcore.jar:lib/httpclient.jar:lib/httpclient-cache.jar:lib/httpmime.jar:lib/HttpComponents-Util.jar:lib/commons-logging.jar:lib/commons-codec.jar:lib/log4j.jar:lib/securedata.jar:lib/jettison-1.1.jar"/>
        <arg file="quietperiod.groovy"/>
        <arg file="${PLUGIN_INPUT_PROPS}"/>
        <arg file="${PLUGIN_OUTPUT_PROPS}"/>
      </command>

      <server:type>SCM_QuietPeriod</server:type>
      <server:validation language="javascript">
      </server:validation>
    </step-type>

    <step-type name="Create GitHub Status">
      <description>Create a commit status in GitHub or GitHub Enterprise.</description>

      <properties>
        <property name="state" required="true">
          <server:property-ui type="selectBox"
                            label="State"
                            description="The state of the status."/>
          <server:value label="Success">success</server:value>
          <server:value label="Failure">failure</server:value>
          <server:value label="Pending">pending</server:value>
        </property>
        <property name="description">
          <server:property-ui type="textBox"
                            label="Description"
                            description="High level summary of the status update."/>
        </property>
        <property name="context">
          <server:property-ui type="textBox"
                            label="Context"
                            description="The service that is providing the status."/>
        </property>
        <property name="baseRestUrl">
          <server:property-ui type="textBox"
                            label="Base REST URL"
                            description="The base URL of the REST API e.g. https://api.github.com. This value should be left blank to be automatically inferred from GitHub's webhook data, unless a different URL needs be used."/>
        </property>
        <server:property name="revision">
          <server:property-ui type="textBox"
                            label="Revision"
                            description="The commit hash to create a status for. This value should be left blank so that it will be populated from GitHub's webhook data, unless a specific hash value needs to be used."/>
        </server:property>
        <server:property name="apiToken">
          <server:property-ui type="secureBox"
                            label="API Token"
                            description="Use an API token to work with the REST endpoints. If not specified, the repository credentials will be used."/>
        </server:property>
        <property name="source">
          <server:property-ui type="sourcePropSheetRef"
                              label="Source Config"
                              hidden="true"/>
        </property>
      </properties>

      <post-processing>
        <![CDATA[
          if (properties.get("exitCode") != 0) {
              properties.put(new java.lang.String("Status"), new java.lang.String("Failure"));
          }
          else {
              properties.put("Status", "Success");
          }
        ]]>
      </post-processing>

      <command program="${GROOVY_HOME}/bin/groovy">
        <arg value="-cp"/>
        <arg path="classes:lib/securedata.jar:lib/CommonsUtil.jar:lib/SandboxedJSRuntime.jar:lib/httpcore.jar:lib/httpclient.jar:lib/httpclient-cache.jar:lib/httpmime.jar:lib/HttpComponents-Util.jar:lib/commons-logging.jar:lib/commons-codec.jar:lib/log4j.jar:lib/securedata.jar:lib/jettison-1.1.jar"/>
        <arg file="github_createStatus.groovy"/>
        <arg file="${PLUGIN_INPUT_PROPS}"/>
        <arg file="${PLUGIN_OUTPUT_PROPS}"/>
      </command>
    </step-type>

    <!-- ==================================== -->
    <!--   REPOSITORY                         -->
    <!-- ==================================== -->
    <server:property-group type="Repository" name="Git Repository">
      <server:description>Global settings for accessing git repositories.</server:description>
      <server:property name="commandPath">
        <server:property-ui type="textBox"
                            label="Command Path"
                            description="The location of the Git executable (e.g. /usr/bin/git), if it is not specified in the PATH." />
      </server:property>
      <server:property name="repoBaseUrl">
        <server:property-ui type="textBox"
                            label="Repository Base URL"
                            description="A URL prefix for source configurations to specify a relative path to the git repository.
                            (e.g. https://git.example.com/repos or ssh://git.example.com/repos)" />
      </server:property>
      <server:property name="username">
        <server:property-ui type="textBox"
                            label="Repository Username"
                            description="The username to use for http(s) access to repositories" />
      </server:property>
      <server:property name="password">
        <server:property-ui type="secureBox"
                            label="Repository Password"
                            description="The password to use for http(s) access to repositories" />
      </server:property>
      <server:property name="passScript">
        <server:property-ui type="textAreaBox"
                            label="Password Script"
                            description="Enter a script or property lookup to obtain the password. This field will only be effective if the Repository Password field is blank."/>
      </server:property>

      <!-- Trigger script -->
      <server:property name="triggerScript">
        <server:property-ui type="textAreaBox"
                            label="Trigger Script"
                            hidden="true">
          <server:default-value><![CDATA[
            import com.urbancode.ubuild.domain.property.PropertyValue
            import com.urbancode.ubuild.domain.property.PropertyValueMap
            import groovy.json.JsonSlurper

            public String getPrintablePropertyMap(PropertyValueMap propertyMap) {
                StringBuilder propertyStringBuilder = new StringBuilder("[")
                String[] propertyNames = propertyMap.getPropertyNames()
                int numProperties = propertyNames.length
                for (int i = 0; i < numProperties; i++) {
                    String key = propertyNames[i];
                    PropertyValue value = propertyMap.getPropertyValue(key);
                    propertyStringBuilder.append(key).append("=").append(value.getDisplayedValue())
                    if (i < numProperties - 1) {
                        propertyStringBuilder.append(", ")
                    }
                }
                propertyStringBuilder.append("]")
                return propertyStringBuilder.toString()
            }

            String.metaClass.endsWithIgnoreCase = { String suffix ->
                int dl = delegate.length()
                int sl = suffix.length()
                return dl >= sl && delegate.substring(dl - sl, dl).equalsIgnoreCase(suffix)
            };

            // normalize URI-like strings
            String.metaClass.normalize = {
                return delegate.replaceAll('(?<!:)//+', '/')
            };

            def calculateRepositorySource = { String remoteBaseUrl, String remoteUrl ->
                GitRepoSource result = new GitRepoSource(remoteUrl)
                if (!result.host) {
                    result = new GitRepoSource(remoteBaseUrl) + result
                }
                return result
            }

            public class GitRepoSource {
                // the hostname of the git repo server
                String host = ''
                // the path portion of the git repo, does not include "git" extension
                String path = ''
                String branch = ''

                public GitRepoSource() {
                }

                public GitRepoSource(String url) {
                    url = url.normalize()

                    // scp style URL
                    def scpParser = ~'^(?:[a-zA-Z0-9]+@)?([^:]+):(.*)'

                    // ssh/git/http protocol style URL
                    def protocolParser = ~'^[a-zA-Z]+://(?:[^/@]+@)?([^/:]+)(?::\\d*)?(?:/(.*)|$)'

                    def mProto = (url =~ protocolParser)
                    def mScp = (url =~ scpParser)

                    if (mProto.matches()) {
                        this.setHost(mProto.group(1))
                        this.setPath(mProto.group(2))
                    }
                    else if (mScp.matches()) {
                        this.setHost(mScp.group(1))
                        this.setPath(mScp.group(2))
                    }
                    else {
                        this.setPath(url)
                    }
                }

                public void setPath(String path) {
                    // normalize path and remove any trailing .git and/or /
                    this.path = path?.normalize()?.replaceAll('(\\.git)?/?$', '')
                }

                public void setBranch(String branch) {
                    // remove any refs/heads prefix on ref
                    this.branch = branch.replaceAll('refs/heads/', '')
                }

                /**
                 * Append a page-relative repo-source to this repo-source
                 *
                 * @param child a page-relative repo-source
                 * @return
                 */
                public GitRepoSource plus(GitRepoSource child) {
                    if (child.host) {
                        return child
                    }

                    GitRepoSource result = new GitRepoSource();
                    result.host = this.host;
                    if (this.path) {
                        result.path = this.path + '/' + child.path
                    }
                    else {
                        result.path = child.path
                    }

                    result.branch = child.branch

                    return result
                }

                public boolean matches(GitRepoSource repoSource) {
                    // blank host is treated as a wildcard
                    return (this.host == null || repoSource.host == null || this.host == repoSource.host) &&
                        repoSource.path == path && repoSource.branch == branch
                }

                public String toString() {
                    return "host:${this.host}, path:${this.path}, branch:${this.branch}"
                }
            }

            String revision = requestPropertyMap['revision']?.getValue()?.trim()
            String ref = requestPropertyMap['ref']?.getValue()?.trim()

            // GitHub/GitHubEnterprise related
            // Values of interest are: push, pull_request
            String gitHubEvent = requestPropertyMap['gitHubEvent']?.getValue()
            String gitHubEventAction = ''
            // Prior to UCB 6.1.3.2, pull_request events were not supported. Therefore, if the event
            // type is not explicitly set by the gitHubEvent property, we go ahead and check to see
            // if the type is push by checking gitHubEvent property or by checking the ref from JSON
            boolean isPullRequest = "pull_request".equals(gitHubEvent)
            String gitHubStatusesUrl = ''
            String gitHubPRUrl = ''
            String gitHubPRBaseRef = ''
            String gitHubPRHeadRef = ''
            String gitHubPRBaseRepoName = ''

            GitRepoSource triggeredRepoSource = null

            // github + gitlab  webhook compatibility
            String webhookData = requestPropertyMap['payload'] ?: requestPropertyMap['postData']
            // refTypeIsTag should determine whether or not we are dealing with a tag push event
            boolean refTypeIsTag = false
            if (webhookData) {
                def webhookDataJson = new JsonSlurper().parseText(webhookData)
                if (isPullRequest) {
                    log.debug("Trigger webhook received for a GitHub pull_request")
                    gitHubEventAction = webhookDataJson.action
                    if ("synchronize".equals(gitHubEventAction) || "opened".equals(gitHubEventAction)) {
                        gitHubStatusesUrl = webhookDataJson.pull_request.head.repo.statuses_url
                        gitHubPRUrl = webhookDataJson.pull_request.url
                        gitHubPRBaseRef = webhookDataJson.pull_request.base.ref
                        gitHubPRHeadRef = webhookDataJson.pull_request.head.ref
                        gitHubPRBaseRepoName = webhookDataJson.pull_request.base.repo.name
                        revision = webhookDataJson.pull_request.head.sha
                        gitHubPRBaseRepoGitUrl = webhookDataJson.pull_request.base.repo.git_url
                        triggeredRepoSource = new GitRepoSource(gitHubPRBaseRepoGitUrl)
                        triggeredRepoSource.setBranch(gitHubPRBaseRef)

                        if (log.isDebugEnabled()) {
                            log.debug("pull_request event information received from payload sent by GitHub: " +
                                "action=" + gitHubEventAction +
                                ", statuses_url=" + gitHubStatusesUrl +
                                ", pull_request.url=" + gitHubPRUrl +
                                ", pull_request.base.ref=" + gitHubPRBaseRef +
                                ", pull_request.head.ref=" + gitHubPRHeadRef +
                                ", pull_request.head.sha=" + revision +
                                ", pull_request.base.repo.name=" + gitHubPRBaseRepoName +
                                ", pull_request.base.repo.git_url=" + gitHubPRBaseRepoGitUrl)
                        }
                    }
                    else if (log.isDebugEnabled()) {
                        log.debug("pull_request action is neither 'synchronize' nor 'opened': " + gitHubEventAction +
                                ". Not triggering any builds.")
                    }
                }
                // if gitHubEvent is not equal to "push", perhaps this is due to using a server version
                // prior to 6.1.3.2. Therefore, we should fall back to checking the ref property of
                // the JSON webhook data. Presence of ref means this is a push event.
                else if ("push".equals(gitHubEvent) || webhookDataJson.ref) {
                    String triggerRef = webhookDataJson.ref
                    if (triggerRef.startsWith("refs/heads")) {
                        triggeredRepoSource = new GitRepoSource(webhookDataJson.repository.url)
                        triggeredRepoSource.setBranch(triggerRef)
                        revision = webhookDataJson.after
                    }
                    else if (triggerRef.startsWith("refs/tags")) {
                        refTypeIsTag = true
                    }
                    else {
                        log.warn("The value of ref in webhook data for push event is neither refs/heads" +
                            " nor refs/tags. Not triggering any builds.")
                    }
                }
                else if (log.isDebugEnabled()) {
                    log.debug("GitHub trigger event was neither push nor pull_request: " + gitHubEvent +
                            ". Not triggering any builds.")
                }
            }
            // our "normal" git hook post data
            else {
                String triggerRepoPath = requestPropertyMap['repo']?.getValue()?.trim()?.replaceAll(~'[/\\\\]+$', '')
                if (triggerRepoPath) {
                    String triggerRef = requestPropertyMap['branch']?.getValue()?.trim()
                    triggeredRepoSource = new GitRepoSource(triggerRepoPath)
                    triggeredRepoSource.setBranch(triggerRef)
                }
            }

            log.debug("Trigger notified of changes in repo: $triggeredRepoSource")

            if (!refTypeIsTag) {
                if (triggeredRepoSource && triggeredRepoSource.branch) {
                    for (sc in availableSourceConfigSet) {
                        Map<String,String> scProps = sc.flatDereferencedPropMap

                        String scRepoBasePath = ParameterResolver.resolveForSourceConfig(
                                scProps['repo/repoBaseUrl'], sc)?.replaceAll(~'[/\\\\]+$', '')
                        String scRepoPath = ParameterResolver.resolveForSourceConfig(
                                scProps['remoteUrl'], sc)?.replaceAll(~'[/\\\\]+$', '')
                        String scBranch = ParameterResolver.resolveForSourceConfig(scProps['branch'], sc) ?: 'master'

                        GitRepoSource source = calculateRepositorySource(scRepoBasePath, scRepoPath)
                        source.branch = scBranch

                        if (log.isDebugEnabled()) {
                            log.debug("parsed $scRepoBasePath + $scRepoPath into $source")
                        }
                        if (source) {
                            if (triggeredRepoSource.matches(source)) {
                                if (revision) {
                                    requestPropertyMap.setPropertyValue("workspace.revision.${sc.propSheetId}",
                                            new PropertyValue(revision, false))
                                }
                                if (ref) {
                                    requestPropertyMap.setPropertyValue("workspace.ref.${sc.propSheetId}",
                                            new PropertyValue(ref, false))
                                }
                                if (gitHubPRHeadRef) {
                                    requestPropertyMap.setPropertyValue("workspace.branch.${sc.propSheetId}",
                                            new PropertyValue(gitHubPRHeadRef, false))
                                }
                                if (gitHubStatusesUrl) {
                                    requestPropertyMap.setPropertyValue("gitHubStatusesUrl.${sc.propSheetId}",
                                            new PropertyValue(gitHubStatusesUrl, false))
                                }
                                if (gitHubPRUrl) {
                                    requestPropertyMap.setPropertyValue("gitHubPRUrl.${sc.propSheetId}",
                                            new PropertyValue(gitHubPRUrl, false))
                                }
                                // if dealing with a pull request event, we would only want pre-flight builds
                                requestPropertyMap.setPropertyValue("preflight",
                                            new PropertyValue(String.valueOf(isPullRequest), false))

                                matchingSourceConfigSet.add(sc)
                                if (log.isDebugEnabled()) {
                                    String msg = "Triggered repo source [" + triggeredRepoSource.toString() +
                                        "] matches source [" + source.toString() + "]."
                                    if (gitHubPRHeadRef) {
                                        msg += " Note: branch value of the build is overridden with '" +
                                                gitHubPRHeadRef + "' which comes from GitHub's webhook data."
                                    }
                                    log.debug(msg)
                                }
                            }
                            else if (log.isDebugEnabled()) {
                                log.debug("Triggered repo source [" + triggeredRepoSource.toString() +
                                    "] does not match source [" + source.toString() + "]")
                            }
                        }
                    }
                }
                else {
                    log.warn("Could not process Git repo trigger data: ${getPrintablePropertyMap(requestPropertyMap)} - invalid repo and/or branch parameters")
                }
            }
            else if (log.isDebugEnabled()) {
                log.debug("Value for 'ref' attribute of payload data refers to a tag reference. Not triggering any builds")
            }
            ]]>
          </server:default-value>
          <server:description><![CDATA[
          <div>
            <div class="bold">Using GitHub or GitLab ServiceHook Webhooks</div><pre class="code">${triggerUrl}?code=${triggerCode}</pre>
          </div>
<div><span class="bold">Using wget (Unix)</span><pre class="code">
#!/bin/bash

TRIGGER_URL="${triggerUrl}"
CODE="${triggerCode}"
REPO="[insert repo FQN here]"`pwd`
BRANCH=$1
REV="$(git log -n 1 "$BRANCH" --format=%H)"
wget -O /dev/null --quiet --no-check-certificate --post-data="code=$CODE&repo=$REPO&branch=$BRANCH&revision=$REV" "$TRIGGER_URL"

# To use curl instead of wget, use this command
# curl --retry 1 -k -d "code=$CODE&repo=$REPO&branch=$BRANCH&revision=$REV" -o /dev/null "$TRIGGER_URL"</pre>
</div>
<div>
<div class="bold">Gerrit patchset-created hook for preflight builds</div><pre class="code">#!/bin/bash

GERRIT_URL_BASE= # TODO - url used for the base of cloning

BRANCH=
CHANGEURL=
COMMIT=
PATCHSET=
PROJECT=
# PARSE ARGS
while [ $# -gt 0 ]; do
    case "$1" in
        --branch     )  BRANCH="$2";    shift;;
        --change-url )  CHANGEURL="$2"; shift;;
        --commit     )  COMMIT="$2";    shift;;
        --patchset   )  PATCHSET="$2";  shift;;
        --project    )  PROJECT="$2";   shift;;
        --)                             shift; break;; # end of options
    esac
    shift
done


REPO_URL=$GERRIT_URL_BASE/${PROJECT}.git
URL="${triggerUrl}"
CODE="${triggerCode}"
SET_ID="${CHANGEURL##*/}"
SET_PREFIX="${SET_ID:${#SET_ID} - 2}" # last two chars of string
REF="refs/changes/$SET_PREFIX/$SET_ID/$PATCHSET"

wget -O /dev/null --no-check-certificate --post-data="preflight=true&code=$CODE&repo=$REPO_URL&branch=$BRANCH&revision=$COMMIT&ref=$REF" "$URL" 2>&1

# To use curl instead of wget, use this command
curl --retry 1 -k -d "preflight=true&code=$CODE&repo=$REPO_URL&branch=$BRANCH&revision=$COMMIT&ref=$REF" -o /dev/null "$URL"</pre>
    </div>
        ]]></server:description>
        </server:property-ui>
      </server:property>

      <server:property name="triggerScriptLanguage">
        <server:property-ui type="textBox"
                            label="Trigger Language"
                            hidden="true"
                            default-value="groovy"/>
      </server:property>
    </server:property-group>

    <!-- ==================================== -->
    <!--   SOURCE                             -->
    <!-- ==================================== -->
    <server:property-group type="Source" name="Git Source Repo">
      <server:property name="dirOffset">
        <server:property-ui type="textBox"
                            label="Directory Offset"
                            description="Directory offset from the current job's working directory. (Use '.' to clone into
                            the current working directory)"
                            default-value="." />
      </server:property>
      <server:property name="remoteUrl" required="true">
        <server:property-ui type="textBox"
                            label="Remote URL"
                            description="The path to the project repository e.g. username/project. The value of Remote URL will be appended to the repository's Base URL" />
      </server:property>
      <server:property name="remoteName">
        <server:property-ui type="textBox"
                            label="Remote Name"
                            description="The name to use for the remote (defaults to 'origin')" />
      </server:property>
      <server:property name="branch">
        <server:property-ui type="textBox"
                            label="Branch"
                            description="The remote branch name to check out (defaults to 'master')" />
      </server:property>
      <!--
      <server:property name = "revision">
        <server:property-ui type="textBox"
                            label="Revision"
                            description="The revision of the branch name to check out (defaults to 'HEAD'). Can be a tag.
                            Should be a child of 'branch'" />
      </server:property>
      -->
      <server:property name="excludeUsers">
        <server:property-ui type="textAreaBox"
                            label="Exclude Filters"
                            description="Exclude this list of usernames" />
      </server:property>
      <server:property name="fileFilters">
        <server:property-ui type="textAreaBox"
                            label="File Filters"
                            description="Restrict changelog to files matching these patterns. Lines start with + to include and - to exclude.
                            Wildcards *, **, and ? are allowed." />
      </server:property>
      <server:property name="repo" required="true">
        <server:property-ui type="repoPropSheetRef"
                            label="Repository"
                            description="Select the Git Repository" />
      </server:property>
    </server:property-group>

</plugin>
