From 0739ac226d5a3addc58a0ddeda1095b2cd02db7c Mon Sep 17 00:00:00 2001
From: Maxim Cournoyer <maxim.cournoyer@savoirfairelinux.com>
Date: Thu, 9 Dec 2021 10:45:51 -0500
Subject: [PATCH] Jenkinsfile: Publish release artifacts for release branches.

Previously, the Jenkinsfile did not publish anything except for the
repositories: the release tarball would not get copied to
https://dl.jami.net for stable channel, and no commit nor tag would be
published for the release.

This change addresses these shortcomings with the following changes:

1. Tarballs can be published for the stable channel.
2. Release commits/tags can be published to their corresponding
branch (stable/nightly).

The RELEASE_VERSION string is also once again derived in a
deterministic fashion, from the date of the last commit.

* Jenkinsfile (SSH_PRIVATE_KEY): Remove variable.
(RING_PUBLIC_KEY_FINGERPRINT): Rename to...
(JAMI_PUBLIC_KEY_FINGERPRINT): ... this.
(GIT_USER_EMAIL, GIT_USER_NAME, GIT_PUSH_URL)
(JENKINS_SSH_KEY, DL_SSH_KEY): New variables.
(params.DEPLOY): Fix description.
(Checkout channel branch): New stage.
(Generate release tarball): Also commit and tag.
(Publish release artifacts): New stage to publish conditionally based on the
DEPLOY parameter and the selected channel.
(Sign & deploy packages): Use the 'sshagent' step to setup SSH access.
<--remote-ssh-identity-file>: Remove argument.
<--keyid>: Adjust variable name.
* scripts/deploy-packages.sh (package_snap): Simplify.

Change-Id: I9008ecc2a4ef9820dbc96e26c966ae72110d897d
---
 Jenkinsfile                | 112 +++++++++++++++++++++++++++++--------
 Makefile                   |  24 ++------
 scripts/deploy-packages.sh |   4 +-
 3 files changed, 96 insertions(+), 44 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index 09dc15ee..3cbbd6e7 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -26,14 +26,23 @@
 // 2. ws-cleanup plugin
 // 3. ansicolor plugin
 
+// TODO:
+// - GPG-sign release tarballs.
+// - GPG-sign release commits.
+// - Allow publishing from any node, to avoid relying on a single machine.
+
 // Configuration globals.
 def SUBMODULES = ['daemon', 'lrc', 'client-gnome', 'client-qt']
 def TARGETS = [:]
-def SSH_PRIVATE_KEY = '/var/lib/jenkins/.ssh/gplpriv'
 def REMOTE_HOST = env.SSH_HOST_DL_RING_CX
 def REMOTE_BASE_DIR = '/srv/repository/ring'
-def RING_PUBLIC_KEY_FINGERPRINT = 'A295D773307D25A33AE72F2F64CD5FA175348F84'
+def JAMI_PUBLIC_KEY_FINGERPRINT = 'A295D773307D25A33AE72F2F64CD5FA175348F84'
 def SNAPCRAFT_KEY = '/var/lib/jenkins/.snap/key'
+def GIT_USER_EMAIL = 'jenkins@jami.net'
+def GIT_USER_NAME = 'jenkins'
+def GIT_PUSH_URL = 'ssh://jenkins@review.jami.net:29420/jami-project'
+def JENKINS_SSH_KEY = '35cefd32-dd99-41b0-8312-0b386df306ff'
+def DL_SSH_KEY = '5825b39b-dfc6-435f-918e-12acc1f56221'
 
 pipeline {
     agent {
@@ -72,7 +81,10 @@ pipeline {
                      description: 'Whether to build ARM packages.')
         booleanParam(name: 'DEPLOY',
                      defaultValue: false,
-                     description: 'Whether and where to deploy packages.')
+                     description: 'Whether to deploy packages.')
+        booleanParam(name: 'PUBLISH',
+                     defaultValue: false,
+                     description: 'Whether to upload tarball and push to git.')
         choice(name: 'CHANNEL',
                choices: 'internal\nnightly\nstable',
                description: 'The repository channel to deploy to. ' +
@@ -107,6 +119,28 @@ See https://wiki.savoirfairelinux.com/wiki/Jenkins.jami.net#Configuration_client
             }
         }
 
+        stage('Configure Git') {
+            steps {
+                sh """git config user.name ${GIT_USER_NAME}
+                      git config user.email ${GIT_USER_EMAIL}
+                   """
+            }
+        }
+
+        stage('Checkout channel branch') {
+            when {
+                expression {
+                    params.CHANNEL != 'internal'
+                }
+            }
+
+            steps {
+                sh """git checkout ${params.CHANNEL}
+                      git merge --no-commit FETCH_HEAD
+                   """
+            }
+        }
+
         stage('Fetch submodules') {
             steps {
                 echo 'Initializing submodules ' + SUBMODULES.join(', ') +
@@ -119,14 +153,43 @@ See https://wiki.savoirfairelinux.com/wiki/Jenkins.jami.net#Configuration_client
 
         stage('Generate release tarball') {
             steps {
-                sh '''#!/usr/bin/env -S bash -l
-                   make portable-release-tarball .tarball-version
-                   '''
+                sh """\
+#!/usr/bin/env -S bash -l
+git commit -am 'New release.'
+make portable-release-tarball .tarball-version
+git tag \$(cat .tarball-version) -am "Jami \$(cat .tarball-version)"
+"""
                 stash(includes: '*.tar.gz, .tarball-version',
                       name: 'release-tarball')
             }
         }
 
+        stage('Publish release artifacts') {
+            when {
+                expression {
+                    params.PUBLISH && params.CHANNEL != 'internal'
+                }
+            }
+
+            steps {
+                sshagent(credentials: [JENKINS_SSH_KEY, DL_SSH_KEY]) {
+                    echo "Publishing to git repository..."
+                    script {
+                        if (params.CHANNEL == 'stable') {
+                            // Only stables releases get tarballs and a tag.
+                            sh 'git push --tags'
+                            echo "Publishing release tarball..."
+                            sh 'rsync --verbose jami*.tar.gz ' +
+                                "${REMOTE_HOST}:${REMOTE_BASE_DIR}" +
+                                "/release/tarballs/"
+                        } else {
+                            sh 'git push'
+                        }
+                    }
+                }
+            }
+        }
+
         stage('Build packages') {
             environment {
                 DISABLE_CONTRIB_DOWNLOADS = 'TRUE'
@@ -185,32 +248,33 @@ See https://wiki.savoirfairelinux.com/wiki/Jenkins.jami.net#Configuration_client
             }
 
             steps {
-                script {
-                    TARGETS.each { target ->
-                        try {
-                            unstash target
-                        } catch (err) {
-                            echo "Failed to unstash ${target}, skipping..."
-                            return
+                sshagent(credentials: [DL_SSH_KEY]) {
+                    script {
+                        TARGETS.each { target ->
+                            try {
+                                unstash target
+                            } catch (err) {
+                                echo "Failed to unstash ${target}, skipping..."
+                                return
+                            }
                         }
-                    }
 
-                    def distributionsText = sh(
-                        script: 'find packages/* -maxdepth 1 -type d -print0 ' +
-                            '| xargs -0 -n1 basename -z',
-                        returnStdout: true).trim()
-                    def distributions = distributionsText.split("\0")
+                        def distributionsText = sh(
+                            script: 'find packages/* -maxdepth 1 -type d -print0 ' +
+                                '| xargs -0 -n1 basename -z',
+                            returnStdout: true).trim()
+                        def distributions = distributionsText.split("\0")
 
-                    distributions.each { distribution ->
-                        echo "Deploying ${distribution} packages..."
-                        sh """scripts/deploy-packages.sh \
+                        distributions.each { distribution ->
+                            echo "Deploying ${distribution} packages..."
+                            sh """scripts/deploy-packages.sh \
   --distribution=${distribution} \
-  --keyid="${RING_PUBLIC_KEY_FINGERPRINT}" \
+  --keyid="${JAMI_PUBLIC_KEY_FINGERPRINT}" \
   --snapcraft-login="${SNAPCRAFT_KEY}" \
-  --remote-ssh-identity-file="${SSH_PRIVATE_KEY}" \
   --remote-repository-location="${REMOTE_HOST}:${REMOTE_BASE_DIR}/${params.CHANNEL}" \
   --remote-manual-download-location="${REMOTE_HOST}:${REMOTE_BASE_DIR}/manual-${params.CHANNEL}"
 """
+                        }
                     }
                 }
             }
diff --git a/Makefile b/Makefile
index 53c8e351..71589db6 100644
--- a/Makefile
+++ b/Makefile
@@ -27,24 +27,12 @@ export TARBALLS ?= /var/cache/jami
 TARBALL_VERSION := $(shell cat $(CURDIR)/.tarball-version 2> /dev/null)
 
 ifeq ($(TARBALL_VERSION),)
-# YYYY-MM-DD
-LAST_COMMIT_DATE:=$(shell git log -1 --format=%cd --date=short)
-CURRENT_DATE:=$(shell date +"%Y-%m-%d")
-
-# number of commits that day
-NUMBER_OF_COMMITS:=$(shell git log --format=%cd --date=short | grep -c $(LAST_COMMIT_DATE))
-
-# YYMMDD
-CURRENT_DATE_SHORT:=$(shell echo $(CURRENT_DATE) | sed -s 's/-//g')
-
-# last commit id
-COMMIT_ID:=$(shell git rev-parse --short HEAD)
-
-RELEASE_VERSION:=$(CURRENT_DATE_SHORT).$(NUMBER_OF_COMMITS).$(COMMIT_ID)
-
+LAST_COMMIT_DATE := $(shell git log -1 --format=%cd --date=format:'%Y%m%d.%H%M')
+COMMIT_ID := $(shell git rev-parse --short HEAD)
+RELEASE_VERSION := $(LAST_COMMIT_DATE).$(COMMIT_ID)
 else
 $(warning Using version from the .tarball-version file: $(TARBALL_VERSION))
-RELEASE_VERSION:=$(TARBALL_VERSION)
+RELEASE_VERSION := $(TARBALL_VERSION)
 endif
 RELEASE_TARBALL_FILENAME := jami_$(RELEASE_VERSION).tar.gz
 
@@ -53,8 +41,8 @@ export RELEASE_VERSION
 export RELEASE_TARBALL_FILENAME
 
 # Debian versions
-DEBIAN_VERSION:=$(RELEASE_VERSION)~dfsg1-1
-DEBIAN_DSC_FILENAME:=jami_$(DEBIAN_VERSION).dsc
+DEBIAN_VERSION := $(RELEASE_VERSION)~dfsg1-1
+DEBIAN_DSC_FILENAME := jami_$(DEBIAN_VERSION).dsc
 
 # Qt versions
 QT_MAJOR := 6
diff --git a/scripts/deploy-packages.sh b/scripts/deploy-packages.sh
index 596e11c6..644c5dc0 100755
--- a/scripts/deploy-packages.sh
+++ b/scripts/deploy-packages.sh
@@ -225,10 +225,10 @@ function package_snap()
         mkdir -p ${DISTRIBUTION_REPOSITORY_FOLDER}
         ls packages/${DISTRIBUTION}*
         cp packages/${DISTRIBUTION}*/*.snap ${DISTRIBUTION_REPOSITORY_FOLDER}/
-    elif [[ "${CHANNEL:0:7}" == "nightly" ]]; then
+    elif [[ $CHANNEL =~ nightly ]]; then
         snapcraft login --with ${SNAPCRAFT_LOGIN}
         snapcraft push packages/${DISTRIBUTION}*/*.snap --release edge
-    elif [[ "${CHANNEL:0:6}" == "stable" ]]; then
+    elif [[ $CHANNEL =~ stable ]]; then
         snapcraft login --with ${SNAPCRAFT_LOGIN}
         snapcraft push packages/${DISTRIBUTION}*/*.snap --release stable
     fi
-- 
GitLab