Add plugin and its dependencies version pinning

Version pinning will help to always have reproducable docker image
and avoid broken latest versions of plugins.

Change-Id: Idb49c995222c62f262021c6feca19adc60dee675
Related-bug: PROD-24701
diff --git a/Dockerfile b/Dockerfile
index 05a1b54..08d2a93 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -86,50 +86,54 @@
 # from a derived Dockerfile, can use `RUN plugins.sh active.txt` to setup /usr/share/jenkins/ref/plugins from a support bundle
 COPY plugins.sh /usr/local/bin/plugins.sh
 COPY install-plugins.sh /usr/local/bin/install-plugins.sh
+COPY jenkins-plugins-deps /usr/share/jenkins/ref/jenkins-plugins-deps
 COPY theme /usr/share/jenkins/ref/userContent/theme
 
+# list of plugins which should be installed. Doesn't include deps list, which specified in jenkins-plugins-deps file.
 RUN JENKINS_UC_DOWNLOAD=http://archives.jenkins-ci.org /usr/local/bin/install-plugins.sh \
-        antisamy-markup-formatter \
-        artifactory \
-        blueocean \
-        build-blocker-plugin \
-        build-monitor-plugin \
-        build-timeout \
-        build-user-vars-plugin \
-        categorized-view \
-        copyartifact \
-        description-setter \
-        discard-old-build \
-        docker-workflow \
-        email-ext \
-        envinject \
-        extended-choice-parameter \
-        extensible-choice-parameter \
-        gerrit-trigger \
-        git \
-        github \
-        heavy-job \
-        jobConfigHistory \
-        jira \
-        ldap \
-        lockable-resources \
-        matrix-auth \
-        monitoring \
-        multiple-scms \
-        performance \
-        permissive-script-security \
-        pipeline-utility-steps \
-        plot \
-        prometheus \
-        rebuild \
-        simple-theme-plugin \
-        slack \
-        ssh-agent \
-        test-stability \
-        throttle-concurrents \
-        workflow-cps \
-        workflow-remote-loader \
-        workflow-scm-step
+        antisamy-markup-formatter:1.5 \
+        artifactory:2.16.2 \
+        blueocean:1.9.0 \
+        build-blocker-plugin:1.7.3 \
+        build-monitor-plugin:1.12+build.201809061734 \
+        build-timeout:1.19 \
+        build-user-vars-plugin:1.5 \
+        categorized-view:1.10 \
+        command-launcher:1.2 \
+        copyartifact:1.41 \
+        description-setter:1.10 \
+        discard-old-build:1.05 \
+        docker-workflow:1.17 \
+        email-ext:2.63 \
+        envinject:2.1.6 \
+        extended-choice-parameter:0.76 \
+        extensible-choice-parameter:1.6.0 \
+        gerrit-trigger:2.27.7 \
+        git:3.9.1 \
+        github:1.29.3 \
+        heavy-job:1.1 \
+        jdk-tool:1.1 \
+        jobConfigHistory:2.18.2 \
+        jira:3.0.3 \
+        ldap:1.20 \
+        lockable-resources:2.3 \
+        matrix-auth:2.3 \
+        monitoring:1.74.0 \
+        multiple-scms:0.6 \
+        performance:3.12 \
+        permissive-script-security:0.3 \
+        pipeline-utility-steps:2.1.0 \
+        plot:2.1.0 \
+        prometheus:2.0.0 \
+        rebuild:1.29 \
+        simple-theme-plugin:0.5.1 \
+        slack:2.3 \
+        ssh-agent:1.17 \
+        test-stability:2.3 \
+        throttle-concurrents:2.0.1 \
+        workflow-cps:2.58 \
+        workflow-remote-loader:1.4 \
+        workflow-scm-step:2.7
 
 # Switch user for cleanup
 USER root
diff --git a/install-plugins.sh b/install-plugins.sh
index 233b739..12aa7b4 100755
--- a/install-plugins.sh
+++ b/install-plugins.sh
@@ -8,6 +8,7 @@
 set -o pipefail
 
 REF_DIR=${REF:-/usr/share/jenkins/ref/plugins}
+DEPS_PINNING_FILE=${DEPS_PINNING_FILE:-/usr/share/jenkins/ref/jenkins-plugins-deps}
 FAILED="$REF_DIR/failed-plugins.txt"
 
 . /usr/local/bin/jenkins-support
@@ -80,6 +81,16 @@
     return $?
 }
 
+getPluginDepsPinnedVersion() {
+    local plugin
+    plugin="$1"
+    pinnedPlugin=$(cat $DEPS_PINNING_FILE | grep "^${plugin}:")
+    if [ -n "$pinnedPlugin" ]; then
+        pinnedPluginVersion="$(echo "$pinnedPlugin" | cut -d':' -f2 | tr -d ' ')"
+        printf '%s' "$pinnedPluginVersion"
+    fi
+}
+
 resolveDependencies() {
     local plugin jpi dependencies
     plugin="$1"
@@ -103,18 +114,22 @@
             echo "Skipping optional dependency $plugin"
         else
             local pluginInstalled
+            local pluginVersion; pluginVersion=$(getPluginDepsPinnedVersion "${plugin}")
             if pluginInstalled="$(echo "${bundledPlugins}" | grep "^${plugin}:")"; then
                 pluginInstalled="${pluginInstalled//[$'\r']}"
                 local versionInstalled; versionInstalled=$(versionFromPlugin "${pluginInstalled}")
-                local minVersion; minVersion=$(versionFromPlugin "${d}")
+                local minVersion="$pluginVersion"
+                if [ -z "$minVersion" ]; then
+                    minVersion=$(versionFromPlugin "${d}")
+                fi
                 if versionLT "${versionInstalled}" "${minVersion}"; then
                     echo "Upgrading bundled dependency $d ($minVersion > $versionInstalled)"
-                    download "$plugin" &
+                    download "$plugin" "$pluginVersion" &
                 else
                     echo "Skipping already bundled dependency $d ($minVersion <= $versionInstalled)"
                 fi
             else
-                download "$plugin" &
+                download "$plugin" "$pluginVersion" &
             fi
         fi
     done
diff --git a/jenkins-plugins-deps b/jenkins-plugins-deps
new file mode 100644
index 0000000..b80d143
--- /dev/null
+++ b/jenkins-plugins-deps
@@ -0,0 +1,105 @@
+#############################################################################################
+# This file contains list of plugin's dependencies, installed to Docker image and pinned to #
+# some version, to always have repeatable Jenkins Docker image. Any newly added plugin or   #
+# plugin's update should be aligned with its dependencies list here. Make sure, that plugin #
+# has needed list of dependencies here, before image creation. Otherwise, always will be    #
+# taken latest versions of plugin's dependencies automactically.                            #
+#############################################################################################
+ace-editor:1.1
+ant:1.8
+apache-httpcomponents-client-4-api:4.5.5-3.0
+authentication-tokens:1.3
+blueocean-autofavorite:1.2.2
+blueocean-bitbucket-pipeline:1.9.0
+blueocean-commons:1.9.0
+blueocean-config:1.9.0
+blueocean-core-js:1.9.0
+blueocean-dashboard:1.9.0
+blueocean-display-url:2.2.0
+blueocean-events:1.9.0
+blueocean-git-pipeline:1.9.0
+blueocean-github-pipeline:1.9.0
+blueocean-i18n:1.9.0
+blueocean-jira:1.9.0
+blueocean-jwt:1.9.0
+blueocean-personalization:1.9.0
+blueocean-pipeline-api-impl:1.9.0
+blueocean-pipeline-editor:1.9.0
+blueocean-pipeline-scm-api:1.9.0
+blueocean-rest-impl:1.9.0
+blueocean-rest:1.9.0
+blueocean-web:1.9.0
+bouncycastle-api:2.17
+branch-api:2.0.20
+cloudbees-bitbucket-branch-source:2.2.12
+cloudbees-folder:6.5.1
+command-launcher:1.2
+config-file-provider:3.3
+credentials-binding:1.16
+credentials:2.1.18
+display-url-api:2.2.0
+docker-commons:1.13
+docker-workflow:1.17
+durable-task:1.26
+envinject-api:1.5
+favorite:2.3.2
+git-client:2.7.3
+git-server:1.7
+git:3.9.1
+github-api:1.92
+github-branch-source:2.4.1
+github:1.29.3
+gradle:1.29
+handlebars:1.1.1
+handy-uri-templates-2-api:2.1.6-1.0
+htmlpublisher:1.17
+ivy:1.28
+jackson2-api:2.8.11.3
+javadoc:1.4
+jdk-tool:1.1
+jenkins-design-language:1.9.0
+jira:3.0.3
+jquery-detached:1.2.1
+jquery:1.12.4-0
+jsch:0.1.54.2
+junit:1.26.1
+mailer:1.21
+matrix-project:1.13
+maven-plugin:3.1.2
+mercurial:2.4
+metrics:4.0.2.2
+momentjs:1.1.1
+multiple-scms:0.6
+pipeline-build-step:2.7
+pipeline-graph-analysis:1.7
+pipeline-input-step:2.8
+pipeline-milestone-step:1.3.1
+pipeline-model-api:1.3.2
+pipeline-model-declarative-agent:1.1.1
+pipeline-model-definition:1.3.2
+pipeline-model-extensions:1.3.2
+pipeline-rest-api:2.10
+pipeline-stage-step:2.3
+pipeline-stage-tags-metadata:1.3.2
+pipeline-stage-view:2.10
+plain-credentials:1.4
+pubsub-light:1.12
+rebuild:1.29
+scm-api:2.3.0
+script-security:1.46
+sse-gateway:1.16
+ssh-credentials:1.14
+structs:1.17
+token-macro:2.5
+variant:1.1
+workflow-aggregator:2.5
+workflow-api:2.30
+workflow-basic-steps:2.11
+workflow-cps-global-lib:2.12
+workflow-cps:2.58
+workflow-durable-task-step:2.22
+workflow-job:2.26
+workflow-multibranch:2.20
+workflow-scm-step:2.7
+workflow-step-api:2.16
+workflow-support:2.21
\ No newline at end of file