From ef1e4124de8a270d0507b1d3d7363801023f5970 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Thu, 21 Oct 2021 12:00:38 +0200
Subject: [PATCH] Allow release and Docker multiarch building

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 .gitlab-ci.yml              | 96 +++++++++++++++++++++++++++++++------
 docker/multiarch/Dockerfile | 44 +++++++++++++++++
 docker/multiarch/README.md  |  1 +
 docker/tests/README.md      |  1 +
 4 files changed, 128 insertions(+), 14 deletions(-)
 create mode 100644 docker/multiarch/Dockerfile
 create mode 100644 docker/multiarch/README.md
 create mode 100644 docker/tests/README.md

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 29804622f..c52c3bde4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,6 +29,9 @@ variables:
   PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${CI_PROJECT_NAME}"
   ARCH: "amd64"
   EXPORT_FORMATS: "csv,ods,pdf"
+  APP_VERSION: "${CI_COMMIT_REF_NAME}"
+  APP_ASSET: "${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_${ARCH}.tar.gz"
+  CYPRESS_INSTALL_BINARY: 0
 
 cache:
   key: "${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}"
@@ -177,15 +180,40 @@ pages:
 
 .docker: &docker
   stage: docker
+  image: docker:stable
+  variables:
+    DOCKER_TLS_CERTDIR: "/certs"
+    DOCKER_HOST: tcp://docker:2376
+    DOCKER_TLS_VERIFY: 1
+    DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
+    DOCKER_DRIVER: overlay2
+  services:
+    - docker:stable-dind
   cache: {}
-  image:
-    name: gcr.io/kaniko-project/executor:debug
-    entrypoint: [""]
   before_script:
-    - mkdir -p /kaniko/.docker
-    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$CI_REGISTRY_AUTH\",\"email\":\"$CI_REGISTRY_EMAIL\"}}}" > /kaniko/.docker/config.json
+    # Install buildx
+    - wget https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64
+    - mkdir -p ~/.docker/cli-plugins/
+    - mv buildx-v0.6.3.linux-amd64 ~/.docker/cli-plugins/docker-buildx
+    - chmod a+x ~/.docker/cli-plugins/docker-buildx
+    # Create env
+    - docker context create tls-environment
+    - docker buildx create --use tls-environment
+    # Install qemu/binfmt
+    - docker pull tonistiigi/binfmt:latest
+    - docker run --rm --privileged tonistiigi/binfmt:latest --install all
+    # Login to DockerHub
+    - mkdir -p ~/.docker
+    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$CI_REGISTRY_AUTH\",\"email\":\"$CI_REGISTRY_EMAIL\"}}}" > ~/.docker/config.json
   script:
-    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/docker/production/Dockerfile --destination $DOCKER_IMAGE_NAME --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP
+    - >
+      docker buildx build
+      --push
+      --platform linux/amd64,linux/arm64,linux/arm
+      -t framasoft/mobilizon:multiarch
+      -f docker/production/Dockerfile .
+  tags:
+    - "privileged"
 
 build-docker-master:
   <<: *docker
@@ -205,12 +233,11 @@ build-docker-tag:
   variables:
     DOCKER_IMAGE_NAME: framasoft/mobilizon:$CI_COMMIT_TAG
 
+# Packaging app for amd64
 package-app:
   stage: package
   variables: &release-variables
     MIX_ENV: "prod"
-    APP_VERSION: "${CI_COMMIT_TAG}"
-    APP_ASSET: "${CI_PROJECT_NAME}_${APP_VERSION}_${ARCH}.tar.gz"
   script: &release-script
     - mix local.hex --force
     - mix local.rebar --force
@@ -240,17 +267,60 @@ package-app-dev:
     paths:
       - ${APP_ASSET}
 
+# Packaging app for multi-arch
+multi-arch-release:
+  stage: package
+  image: docker:stable
+  variables:
+    DOCKER_TLS_CERTDIR: "/certs"
+    DOCKER_HOST: tcp://docker:2376
+    DOCKER_TLS_VERIFY: 1
+    DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
+    DOCKER_DRIVER: overlay2
+    APP_ASSET: "${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}_${ARCH}.tar.gz"
+  services:
+    - docker:stable-dind
+  cache: {}
+  before_script:
+    # Install buildx
+    - wget https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64
+    - mkdir -p ~/.docker/cli-plugins/
+    - mv buildx-v0.6.3.linux-amd64 ~/.docker/cli-plugins/docker-buildx
+    - chmod a+x ~/.docker/cli-plugins/docker-buildx
+    # Create env
+    - docker context create tls-environment
+    - docker buildx create --use tls-environment
+    # Install qemu/binfmt
+    - docker pull tonistiigi/binfmt:latest
+    - docker run --rm --privileged tonistiigi/binfmt:latest --install all
+  script:
+    - docker buildx build --platform linux/${ARCH} --output type=local,dest=releases --build-arg APP_ASSET=${APP_ASSET} -f docker/multiarch/Dockerfile .
+    - ls -alh releases/mobilizon/
+    - du -sh releases/mobilizon/${APP_ASSET}
+  tags:
+    - "privileged"
+  artifacts:
+    expire_in: 30 days
+    paths:
+      - releases/mobilizon/${APP_ASSET}
+  parallel:
+    matrix:
+      - ARCH: ["arm", "arm64"]
+  rules:
+    - if: '$CI_PROJECT_NAMESPACE != "framasoft"'
+      when: never
+    - if: '$CI_PIPELINE_SOURCE == "schedule"'
+    - if: $CI_COMMIT_TAG
+
+# Release
 release-upload:
   stage: upload
   image: framasoft/yakforms-assets-deploy:latest
   rules: *tag-rules
-  variables:
-    APP_VERSION: "${CI_COMMIT_TAG}"
-    APP_ASSET: "${CI_PROJECT_NAME}_${APP_VERSION}_${ARCH}.tar.gz"
   script:
     - eval `ssh-agent -s`
     - ssh-add <(echo "${DEPLOYEMENT_KEY}" | base64 --decode -i)
-    - echo "put -r ${APP_ASSET}" | sftp -o "VerifyHostKeyDNS yes" ${DEPLOYEMENT_USER}@${DEPLOYEMENT_HOST}:public/
+    - echo "put -r mobilizon_*.tar.gz" | sftp -o "VerifyHostKeyDNS yes" ${DEPLOYEMENT_USER}@${DEPLOYEMENT_HOST}:public/
   artifacts:
     expire_in: 1 day
     when: on_success
@@ -264,8 +334,6 @@ release-create:
   before_script:
     - apk --no-cache add gawk sed grep
   script: |
-    APP_VERSION="${CI_COMMIT_TAG}"
-    APP_ASSET="${CI_PROJECT_NAME}_${APP_VERSION}_${ARCH}.tar.gz"
     CHANGELOG=$(awk -v version="$APP_VERSION" '/^## / { printit = $2 == version }; printit' CHANGELOG.md | grep -v "## $APP_VERSION" | sed '1{/^$/d}')
     ENDPOINT="https://packages.joinmobilizon.org"
 
diff --git a/docker/multiarch/Dockerfile b/docker/multiarch/Dockerfile
new file mode 100644
index 000000000..cb11aaa13
--- /dev/null
+++ b/docker/multiarch/Dockerfile
@@ -0,0 +1,44 @@
+FROM elixir as build
+SHELL ["/bin/bash", "-c"]
+ENV MIX_ENV prod
+# ENV LANG en_US.UTF-8
+ARG APP_ASSET
+
+# Set the right versions
+ENV ELIXIR_VERSION latest
+ENV ERLANG_VERSION latest
+ENV NODE_VERSION 16
+
+# Install system dependencies
+RUN apt-get update -yq && apt-get install -yq build-essential cmake postgresql-client git curl gnupg unzip exiftool webp imagemagick gifsicle
+RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+
+# # Install Node & yarn
+# RUN curl -sL https://deb.nodesource.com/setup_16.x | bash && apt-get install nodejs -yq
+# RUN npm install -g yarn
+
+# Install build tools
+RUN source /root/.bashrc && \
+    mix local.rebar --force && \
+    mix local.hex -if-missing --force
+
+RUN mkdir /mobilizon
+COPY ./ /mobilizon
+WORKDIR /mobilizon
+
+# # Build front-end
+# RUN yarn --cwd "js" install --frozen-lockfile
+# RUN yarn --cwd "js" run build
+
+# Elixir release
+RUN source /root/.bashrc && \
+    mix deps.get --only prod && \
+    mix compile  && \
+    mix phx.digest.clean --all && \
+    mix release --path release/mobilizon && \
+    cd release/mobilizon && \
+    ln -s lib/mobilizon-*/priv priv && \
+    cd ../../
+
+# Make a release archive
+RUN tar -zcf /mobilizon/${APP_ASSET} -C release mobilizon
diff --git a/docker/multiarch/README.md b/docker/multiarch/README.md
new file mode 100644
index 000000000..311bfec6d
--- /dev/null
+++ b/docker/multiarch/README.md
@@ -0,0 +1 @@
+Contains the Dockerfile used to generate multi-arch Elixir releases
\ No newline at end of file
diff --git a/docker/tests/README.md b/docker/tests/README.md
new file mode 100644
index 000000000..5d4f4714e
--- /dev/null
+++ b/docker/tests/README.md
@@ -0,0 +1 @@
+Contains the Dockerfile for the image used to run the tests
\ No newline at end of file