Add a Gitlab CI script that runs Circle CI validation jobs
authorAlp Mestanogullari <alp@well-typed.com>
Wed, 7 Nov 2018 00:21:55 +0000 (01:21 +0100)
committerBen Gamari <ben@smart-cactus.org>
Sat, 1 Dec 2018 03:38:54 +0000 (22:38 -0500)
And put it to use for running i386 and x86_64 linux validate,
x86_64 darwin validate and building with hadrian. For all the validate
jobs, we save the artifacts (bindist + test results for now) in Circle CI
and subsequently grab them in Gitlab. The nice side effect is that merge
requests now show the change in test results from the patches and let you
download or browse the artifacts.

.circleci/config.yml
.gitlab-ci.yml [new file with mode: 0644]
.gitlab/circle-ci-job.sh [new file with mode: 0755]

index 8bb9306..4b8d7a4 100644 (file)
@@ -80,6 +80,11 @@ aliases:
     run:
       name: Push Performance Git Notes
       command: .circleci/push-test-metrics.sh
+  - &store_test_artifacts
+    store_artifacts:
+      # we might want to add the whole output of the test phase
+      # too at some point
+      path: test-results/junit.xml
   - &slowtest
     run:
       name: Full Test
@@ -90,17 +95,13 @@ aliases:
     run:
       name: Create bindist
       # Reduce compression effort to 3
-      command: make binary-dist TAR_COMP_OPTS="-2"
+      command: make binary-dist TAR_COMP_OPTS="-2" && mv ghc*.tar.xz ghc.tar.xz
       # Building bindist takes ~15 minutes without output, account for
       # that.
       no_output_timeout: "30m"
-  - &storeartifacts
-    run:
-      name: Store artifacts
-      command: |
-        curl https://ghc-artifacts.s3.amazonaws.com/tools/ghc-artifact-collector-$GHC_COLLECTOR_FLAVOR --output ghc-artifact-collector
-        chmod +x ghc-artifact-collector
-        ./ghc-artifact-collector ghc*.tar.xz
+  - &store_bindist
+    store_artifacts:
+      path: ghc.tar.xz
   - &trigger_on_tags
     filters:
       tags:
@@ -124,9 +125,10 @@ jobs:
       - *configure_unix
       - *make
       - *bindist
-      - *storeartifacts
+      - *store_bindist
       - *test
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   "validate-x86_64-freebsd":
@@ -147,9 +149,10 @@ jobs:
       - *configure_bsd
       - *make
       - *bindist
-      - *storeartifacts
+      - *store_bindist
       - *test
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   "validate-x86_64-darwin":
@@ -173,9 +176,10 @@ jobs:
       - *configure_unix
       - *make
       - *bindist
-      - *storeartifacts
+      - *store_bindist
       - *test
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   "validate-hadrian-x86_64-linux":
@@ -211,6 +215,7 @@ jobs:
       - *test
       - *store_test_results
       - *push_perf_note
+      - *store_test_artifacts
 
   "validate-x86_64-linux-llvm":
     resource_class: xlarge
@@ -237,6 +242,8 @@ jobs:
       - *configure_unix
       - *make
       - *test
+      - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   # Nightly build with -DDEBUG using devel2 flavour
@@ -259,6 +266,7 @@ jobs:
       - *make
       - *test
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   "validate-i386-linux":
@@ -278,9 +286,10 @@ jobs:
       - *configure_unix_32
       - *make
       - *bindist
-      - *storeartifacts
+      - *store_bindist
       - *test
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   "validate-x86_64-fedora":
@@ -300,9 +309,10 @@ jobs:
       - *configure_unix
       - *make
       - *bindist
-      - *storeartifacts
+      - *store_bindist
       - *test
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
   "slow-validate-x86_64-linux":
@@ -321,6 +331,7 @@ jobs:
       - *make
       - *slowtest
       - *store_test_results
+      - *store_test_artifacts
       - *push_perf_note
 
 workflows:
@@ -340,6 +351,9 @@ workflows:
     - validate-x86_64-fedora:
         *trigger_on_tags
 
+    branches:
+      ignore: /gitlab\/.*/
+
   nightly:
     triggers:
       - schedule:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..52ee2f2
--- /dev/null
@@ -0,0 +1,119 @@
+# image: ghcci/x86_64-linux:0.0.4
+variables:
+  GIT_SSL_NO_VERIFY: "1"
+
+before_script:
+  - mkdir -p ~/.ssh
+  - chmod 700 ~/.ssh
+  #- git config --global user.email "user@example.com"
+  #- git config --global user.name "User name"
+  - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
+  - chmod 644 ~/.ssh/known_hosts
+  #- sudo apt-get update -y
+  #- sudo apt-get install jq wget -y
+  #- 'which ssh-agent || sudo apt-get install openssh-client -y'
+  - eval $(ssh-agent -s)
+  ## Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
+  ## We're using tr to fix line endings which makes ed25519 keys work
+  ## without extra base64 encoding.
+  ## https://gitlab.com/gitlab-examples/ssh-private-key/issues/1#note_48526556
+  ##
+  - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
+
+# All validation jobs keep the bindists and test results are artifacts,
+# when we get far enough to generate them.
+#
+# This requires updating the maximum artifacts size limit in Gitlab to
+# something like 200MB.
+
+validate-x86_64-linux:
+  script: ".gitlab/circle-ci-job.sh validate-x86_64-linux"
+  artifacts:
+    when: always
+    reports:
+      junit: junit.xml
+    paths:
+      - ghc.tar.xz
+      - junit.xml
+
+validate-i386-linux:
+  script: ".gitlab/circle-ci-job.sh validate-i386-linux"
+  artifacts:
+    when: always
+    reports:
+      junit: junit.xml
+    paths:
+      - ghc.tar.xz
+      - junit.xml
+
+# validate-x86_64-freebsd:
+#   script: ".gitlab/circle-ci-job.sh validate-x86_64-freebsd"
+#   artifacts:
+#     when: always
+#     reports:
+#       junit: junit.xml
+#     paths:
+#       - ghc.tar.xz
+#       - junit.xml
+
+validate-x86_64-darwin:
+  script: ".gitlab/circle-ci-job.sh validate-x86_64-darwin"
+  artifacts:
+    when: always
+    reports:
+      junit: junit.xml
+    paths:
+      - ghc.tar.xz
+      - junit.xml
+
+validate-hadrian-x86_64-linux:
+  script: ".gitlab/circle-ci-job.sh validate-hadrian-x86_64-linux"
+  # the testsuite doesn't pass with hadrian yet...
+  #
+  # artifacts:
+  #   when: always
+  #   reports:
+  #     junit: junit.xml
+  #   paths:
+  #     - ghc.tar.xz
+  #     - junit.xml
+
+# validate-x86_64-linux-unreg:
+#   script: ".gitlab/circle-ci-job.sh validate-x86_64-linux-unreg"
+#   artifacts:
+#     when: always
+#     reports:
+#       junit: junit.xml
+#     paths:
+#       - ghc.tar.xz
+#       - junit.xml
+
+# validate-x86_64-linux-llvm:
+#   script: ".gitlab/circle-ci-job.sh validate-x86_64-linux-llvm"
+#   artifacts:
+#     when: always
+#     reports:
+#       junit: junit.xml
+#     paths:
+#       - ghc.tar.xz
+#       - junit.xml
+
+# validate-x86_64-linux-debug:
+#   script: ".gitlab/circle-ci-job.sh validate-x86_64-linux-debug"
+#   artifacts:
+#     when: always
+#     reports:
+#       junit: junit.xml
+#     paths:
+#       - ghc.tar.xz
+#       - junit.xml
+
+# slow-validate-x86_64-linux:
+#   script: ".gitlab/circle-ci-job.sh slow-validate-x86_64-linux"
+#   artifacts:
+#     when: always
+#     reports:
+#       junit: junit.xml
+#     paths:
+#       - ghc.tar.xz
+#       - junit.xml
diff --git a/.gitlab/circle-ci-job.sh b/.gitlab/circle-ci-job.sh
new file mode 100755 (executable)
index 0000000..f629557
--- /dev/null
@@ -0,0 +1,125 @@
+# Circle CI "backend" for Gitlab CI
+# =================================
+#
+# Usage example:
+#   .gitlab/circle-ci-job.sh validate-x86_64-linux
+#
+# It currently requires the following environment variables to
+# be set:
+#
+# - CI_RUNNER_ID, CI_JOB_ID, CI_COMMIT_SHA, set automatically,
+#   as per: https://docs.gitlab.com/ce/ci/variables/
+#
+# - CIRCLECI_TOKEN, which should be set as a Gitlab
+#   CI "variable", as per:
+#   https://docs.gitlab.com/ce/ci/variables/README.html#variables
+#
+# - SSH_PRIVATE_KEY, variable set in the gitlab interface, as per:
+#   https://docs.gitlab.com/ce/ci/ssh_keys/#ssh-keys-when-using-the-docker-executor
+#   This script itself doesn't actually need that one, but it is
+#   needed for the .gitlab-ci.yml script.
+#
+#
+# Finally, there are two other things to configure to get artifacts to be
+# uploaded to gitlab properly:
+#
+# - At https://<gitlab host>/admin/application_settings, expand the
+#   Continuous Integration and Deployment section and set the
+#   "Maximum artifacts size (MB)" field to something large enough
+#   to contain the bindists (the test reports are tiny in comparison).
+#   500MB seems to work fine, but 200MB might be sufficient.
+#
+# - If gitlab is exposed behind some form of proxy (e.g nginx), make sure
+#   the maximum client request body size is large enough to contain all the
+#   artifacts of a build. For nginx, this would be the following configuration
+#   option: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size
+#   (which can be set with services.nginx.clientMaxBodySize on nixos).
+
+#!/usr/bin/env sh
+
+set -e
+
+[ $# -gt 0 ] || (echo You need to pass the Circle CI job type as argument to this script; exit 1)
+[ ${CI_RUNNER_ID:-} ] || (echo "CI_RUNNER_ID is not set"; exit 1)
+[ ${CI_JOB_ID:-} ] || (echo "CI_JOB_ID is not set"; exit 1)
+[ ${CI_COMMIT_SHA:-} ] || (echo "CI_COMMIT_SHA is not set"; exit 1)
+
+GITHUB_ORG="ghc"
+GITHUB_PROJECT="ghc-diffs"
+GITHUB_BRANCH="gitlab/${CI_RUNNER_ID}/${CI_JOB_ID}"
+
+# the first argument to this script is the Circle CI job type:
+# validate-x86_64-linux, validate-i386-linux, ...
+CIRCLE_JOB=$1
+
+git remote add gh git@github.com:${GITHUB_ORG}/${GITHUB_PROJECT} &> /dev/null || echo "gh remote already present"
+git checkout -b ${GITHUB_BRANCH} || true # if we've already done this before
+git push gh ${GITHUB_BRANCH} || true # if we've already done this before
+
+BODY="{ \"revision\": \"${CI_COMMIT_SHA}\", \"build_parameters\": { \"CIRCLE_JOB\": \"${CIRCLE_JOB}\" } }"
+RESP=$(curl -s -X POST -H "Content-Type: application/json" -d "$BODY" \
+           https://circleci.com/api/v1.1/project/github/${GITHUB_ORG}/${GITHUB_PROJECT}/tree/${GITHUB_BRANCH}?circle-token=${CIRCLECI_TOKEN})
+
+if [ $? -eq 0 ]; then
+  build_num=$(echo $RESP | jq '.build_num')
+else
+    echo "Couldn't submit job"
+    echo $RESP
+    exit 1
+fi
+
+echo Circle CI build number: $build_num
+echo Circle CI build page: https://circleci.com/gh/${GITHUB_ORG}/${GITHUB_PROJECT}/$build_num
+
+outcome="null"
+STATUS_URL="https://circleci.com/api/v1.1/project/github/${GITHUB_ORG}/${GITHUB_PROJECT}/${build_num}?circle-token=${CIRCLECI_TOKEN}"
+STATUS_RESP=""
+
+while [ "$outcome" == "null" ]; do
+    sleep 30s
+    STATUS_RESP=$(curl -s $STATUS_URL)
+    if [ $? -eq 0 ]; then
+       new_outcome=$(echo $STATUS_RESP | jq '.outcome')
+       jq_exitcode=$?
+       if [ "$new_outcome" == "null" ] && [ $jq_exitcode -ne 0 ]; then
+           echo "Couldn't read 'outcome' field in JSON:"
+           echo $STATUS_RESP
+           echo "Skipping"
+       else
+           outcome="$new_outcome"
+       fi
+    else
+       echo "curl failed:"
+       echo $STATUS_RESP
+       echo "Skipping"
+    fi
+done
+
+if [ "$outcome" == "\"success\"" ]; then
+    echo The build passed
+    artifactsBody=$(curl -s https://circleci.com/api/v1.1/project/github/${GITHUB_ORG}/${GITHUB_PROJECT}/${build_num}/artifacts?circle-token=${CIRCLECI_TOKEN})
+    (echo $artifactsBody | jq '.[] | .url' | xargs wget -q) || echo "No artifacts"
+    exit 0
+else
+    echo The build failed
+
+    artifactsBody=$(curl -s https://circleci.com/api/v1.1/project/github/${GITHUB_ORG}/${GITHUB_PROJECT}/${build_num}/artifacts?circle-token=${CIRCLECI_TOKEN})
+    (echo $artifactsBody | jq '.[] | .url' | xargs wget -q) || echo "No artifacts"
+
+    failing_step=$(echo $STATUS_RESP | jq '.steps | .[] | .actions | .[] | select(.status != "success")')
+    failing_step_name=$(echo $failing_step | jq '.name' | sed -e 's/^"//' -e 's/"$//' -e 's/\\r\\n/\n/')
+    echo "Failing step: $failing_step_name"
+
+    failing_cmds=$(echo $failing_step | jq '.bash_command' | sed -e 's/^"//' -e 's/"$//' -e 's/\\r\\n/\n/')
+    echo "Failing command(s):"
+    echo $failing_cmds
+
+    log_url=$(echo $failing_step | jq '.output_url' | sed -e 's/^"//' -e 's/"$//' -e 's/\\r\\n/\n/')
+    echo "Log url: $log_url"
+
+    last_log_lines=$(curl -s $log_url | gunzip | jq '.[] | select(.type == "out") | .message' | sed -e 's/^"//' -e 's/"$//' -e 's/\\r\\n/\n/' | tail -50)
+    echo End of the build log:
+    echo $last_log_lines
+
+    exit 1
+fi