From a77ac6f2cf0dab035a316e33ef264f86a05492a0 Mon Sep 17 00:00:00 2001 From: rubo77 <github@r.z11.de> Date: Mon, 24 Dec 2018 00:13:27 +0100 Subject: [PATCH] add ci files for gitlab --- .gitlab-ci.yml | 74 ++++++ .gitlab-ci/build-container/Dockerfile | 39 +++ .gitlab-ci/build.sh | 360 ++++++++++++++++++++++++++ .gitlab-ci/update-git.sh | 46 ++++ release | 1 + 5 files changed, 520 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 .gitlab-ci/build-container/Dockerfile create mode 100755 .gitlab-ci/build.sh create mode 100755 .gitlab-ci/update-git.sh create mode 100644 release diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..ea09e9d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,74 @@ +variables: + GIT_SUBMODULE_STRATEGY: recursive + GIT_SSL_CAPATH: /etc/ssl/certs/ + CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/build + GLUON_GIT: https://github.com/freifunk-gluon/gluon.git/ + GLUON_BRANCH: master + BROKEN: BROKEN=1 + +cache: + key: $CI_COMMIT_REF_SLUG-$GLUON_GIT-$GLUON_BRANCH + paths: + - gluon + +stages: + - prepare + - build + - upload + +# Preparation + +prepare: + stage: prepare + image: docker:latest + services: + - docker:dind + script: + - docker info + - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY + - docker pull $CONTAINER_IMAGE:latest || true + - docker build --cache-from $CONTAINER_IMAGE:latest -t $CONTAINER_IMAGE:$CI_COMMIT_SHA -t $CONTAINER_IMAGE:latest .gitlab-ci/build-container + - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA + - docker push $CONTAINER_IMAGE:latest + cache: {} + +# Actual building +build: + stage: build + image: $CI_REGISTRY_IMAGE/build + script: + - export FORCE_UNSAFE_CONFIGURE=1 + # former clone step + - ./.gitlab-ci/update-git.sh | tee -a debug.log + - ./.gitlab-ci/build.sh -c update -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log + # We should never need this, should we? + - ./.gitlab-ci/build.sh -c clean -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log + # In the past this build step repeatedly broke + # - ./.gitlab-ci/build.sh -c download -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) V=s" | tee -a debug.log + - ./.gitlab-ci/build.sh -c build -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log + # Bring gluon repo to cacheable state + - ./.gitlab-ci/build.sh -c clean -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID -m "-j $(nproc --all) $BROKEN" | tee -a debug.log + # Sign + - echo $SIGNING_KEY > signing_key + - ./.gitlab-ci/build.sh -c sign -b $CI_COMMIT_REF_NAME -s $(pwd)/signing_key + artifacts: + untracked: false + paths: + - debug.log + - output + expire_in: 1 day + when: always + dependencies: [] + +upload: + stage: upload + image: $CI_REGISTRY_IMAGE/build + script: + - eval $(ssh-agent -s) + - ssh-add <(echo "$SSH_KEY") + # create fake gluon dir to satisfy build script + - mkdir -p gluon + - ./.gitlab-ci/build.sh -c upload -b $CI_COMMIT_REF_NAME -n $CI_PIPELINE_ID + dependencies: + - build + cache: {} diff --git a/.gitlab-ci/build-container/Dockerfile b/.gitlab-ci/build-container/Dockerfile new file mode 100644 index 0000000..bec64bd --- /dev/null +++ b/.gitlab-ci/build-container/Dockerfile @@ -0,0 +1,39 @@ +FROM debian:stretch + +RUN apt-get update && apt-get install -y \ + git \ + subversion \ + python \ + build-essential \ + gawk \ + unzip \ + time \ + libncurses5-dev \ + zlib1g-dev \ + libssl1.0-dev \ + wget \ + curl \ + openssh-client +RUN apt-get update && apt-get install -y \ + cmake \ + make \ + pkg-config && \ + cd ~ && \ + git clone http://git.universe-factory.net/libuecc && \ + cd libuecc && \ + cmake ./ && \ + make && \ + make install && \ + ldconfig && \ + cd ~ && \ + git clone https://github.com/tcatm/ecdsautils.git && \ + cd ecdsautils && \ + git checkout tags/v0.3.2 && \ + mkdir build && \ + cd build/ && \ + cmake ../ && \ + make && \ + make install && \ + cd ~ && \ + rm -rf ~/libuecc && \ + rm -rf ~/ecdsautils diff --git a/.gitlab-ci/build.sh b/.gitlab-ci/build.sh new file mode 100755 index 0000000..9a3bdfd --- /dev/null +++ b/.gitlab-ci/build.sh @@ -0,0 +1,360 @@ +#!/bin/bash -e +# ===================================================================== +# Build script for Freifunk Nord firmware +# +# Source: +# Contact: +# Web: +# +# Credits: +# - Freifunk Darmstadt for your great support +# - Freifunk Fulda for the base of the gitlab-ci support +# ===================================================================== + +# Default make options +MAKEOPTS="V=s -j 4" + +# Default to build all Gluon targets if parameter -t is not set +TARGETS="ar71xx-tiny ar71xx-generic x86-64 ar71xx-nand x86-generic x86-64" +TARGETS=$TARGETS" mpc85xx-generic" # (tp-link-tl-wdr4900-v1) + +# BROKEN: +TARGETS=$TARGETS" ramips-mt76x8" # BROKEN: unstable WiFi (tp-link 841 v13 und archer c50) +TARGETS=$TARGETS" ar71xx-mikrotik" # BROKEN: no sysupgrade support (mikrotik-nand) +TARGETS=$TARGETS" brcm2708-bcm2710" # BROKEN: Untested (raspberry-pi-3) +TARGETS=$TARGETS" ipq806x" # BROKEN: unstable wifi drivers (tp-link-archer-c2600) +TARGETS=$TARGETS" mvebu-cortexa9" # BROKEN: No AP+IBSS or 11s support (linksys-wrt1200ac) + +# Default is set to use current work directory +SITEDIR="$(pwd)" + +# Default build identifier set to snapshot +BUILD="snapshot" + +# Specify deployment server and user +DEPLOYMENT_SERVER="10.116.250.1" +DEPLOYMENT_USER="rsync" +DEPLOYMENT_PATH="/opt/firmware/nord" + +# Path to signing key +SIGNKEY="" + +# Error codes +E_ILLEGAL_ARGS=126 + +# Help function used in error messages and -h option +usage() { + echo "" + echo "Build script for Freifunk-Fulda gluon firmware." + echo "" + echo "-b: Firmware branch name (e.g. development)" + echo " Default: current git branch" + echo "-c: Build command: update | clean | download | build | sign | upload | prepare" + echo "-d: Enable bash debug output" + echo "-h: Show this help" + echo "-m: Setting for make options (optional)" + echo " Default: \"${MAKEOPTS}\"" + echo "-n: Build identifier (optional)" + echo " Default: \"${BUILD}\"" + echo "-t: Gluon targets architectures to build" + echo " Default: \"${TARGETS}\"" + echo "-r: Release number (optional)" + echo " Default: fetched from release file" + echo "-w: Path to site directory" + echo " Default: current working directory" + echo "-s: Path to signing key" + echo " Default: empty" +} + +# Evaluate arguments for build script. +if [[ "${#}" == 0 ]]; then + usage + exit ${E_ILLEGAL_ARGS} +fi + +# Evaluate arguments for build script. +while getopts b:c:dhm:n:t:w:s: flag; do + case ${flag} in + b) + BRANCH="${OPTARG}" + ;; + c) + case "${OPTARG}" in + update) + COMMAND="${OPTARG}" + ;; + clean) + COMMAND="${OPTARG}" + ;; + download) + COMMAND="${OPTARG}" + ;; + build) + COMMAND="${OPTARG}" + ;; + sign) + COMMAND="${OPTARG}" + ;; + upload) + COMMAND="${OPTARG}" + ;; + prepare) + COMMAND="${OPTARG}" + ;; + *) + echo "Error: Invalid build command set." + usage + exit ${E_ILLEGAL_ARGS} + ;; + esac + ;; + d) + set -x + ;; + h) + usage + exit + ;; + m) + MAKEOPTS="${OPTARG}" + ;; + n) + BUILD="${OPTARG}" + ;; + t) + TARGETS="${OPTARG}" + ;; + r) + RELEASE="${OPTARG}" + ;; + w) + # Use the root project as site-config for make commands below + SITEDIR="${OPTARG}" + ;; + s) + SIGNKEY="${OPTARG}" + ;; + *) + usage + exit ${E_ILLEGAL_ARGS} + ;; + esac +done + +# Strip of all remaining arguments +shift $((OPTIND - 1)); + +# Check if there are remaining arguments +if [[ "${#}" > 0 ]]; then + echo "Error: To many arguments: ${*}" + usage + exit ${E_ILLEGAL_ARGS} +fi + +# Set branch name +if [[ -z "${BRANCH}" ]]; then + BRANCH=$(git symbolic-ref -q HEAD) + BRANCH=${BRANCH##refs/heads/} + BRANCH=${BRANCH:-HEAD} +fi + +# Set command +if [[ -z "${COMMAND}" ]]; then + echo "Error: Build command missing." + usage + exit ${E_ILLEGAL_ARGS} +fi + +# Set release number +if [[ -z "${RELEASE}" ]]; then + RELEASE=$(cat "${SITEDIR}/release") +fi + +# Normalize the branch name +BRANCH="${BRANCH#origin/}" # Use the current git branch as autoupdate branch +BRANCH="${BRANCH//\//-}" # Replace all slashes with dashes + +# Get the GIT commit description +COMMIT="$(git describe --always --dirty)" + +# Number of days that may pass between releasing an updating +PRIORITY=1 + +update() { + echo "--- Update Gluon Dependencies" + make ${MAKEOPTS} \ + GLUON_SITEDIR="${SITEDIR}" \ + GLUON_OUTPUTDIR="${SITEDIR}/output" \ + GLUON_RELEASE="${RELEASE}-${BUILD}" \ + GLUON_BRANCH="${BRANCH}" \ + GLUON_PRIORITY="${PRIORITY}" \ + update +} + +clean() { + for TARGET in ${TARGETS}; do + echo "--- Clean Gluon Build Artifacts for target: ${TARGET}" + make ${MAKEOPTS} \ + GLUON_SITEDIR="${SITEDIR}" \ + GLUON_OUTPUTDIR="${SITEDIR}/output" \ + GLUON_RELEASE="${RELEASE}-${BUILD}" \ + GLUON_BRANCH="${BRANCH}" \ + GLUON_PRIORITY="${PRIORITY}" \ + GLUON_TARGET="${TARGET}" \ + clean + done +} + +download() { + for TARGET in ${TARGETS}; do + echo "--- Download Gluon Dependencies for target: ${TARGET}" + make ${MAKEOPTS} \ + GLUON_SITEDIR="${SITEDIR}" \ + GLUON_OUTPUTDIR="${SITEDIR}/output" \ + GLUON_RELEASE="${RELEASE}-${BUILD}" \ + GLUON_BRANCH="${BRANCH}" \ + GLUON_PRIORITY="${PRIORITY}" \ + GLUON_TARGET="${TARGET}" \ + download + done +} + +build() { + for TARGET in ${TARGETS}; do + echo "--- Build Gluon Images for target: ${TARGET}" + case "${BRANCH}" in + stable| \ + testing| \ + development) + make ${MAKEOPTS} \ + GLUON_SITEDIR="${SITEDIR}" \ + GLUON_OUTPUTDIR="${SITEDIR}/output" \ + GLUON_RELEASE="${RELEASE}-${BUILD}" \ + GLUON_BRANCH="${BRANCH}" \ + GLUON_PRIORITY="${PRIORITY}" \ + GLUON_TARGET="${TARGET}" + ;; + + *) + make ${MAKEOPTS} \ + GLUON_SITEDIR="${SITEDIR}" \ + GLUON_OUTPUTDIR="${SITEDIR}/output" \ + GLUON_RELEASE="${RELEASE}-${BUILD}" \ + GLUON_BRANCH="${BRANCH}" \ + GLUON_TARGET="${TARGET}" + ;; + esac + done + + echo "--- Build Gluon Manifest" + make ${MAKEOPTS} \ + GLUON_SITEDIR="${SITEDIR}" \ + GLUON_OUTPUTDIR="${SITEDIR}/output" \ + GLUON_RELEASE="${RELEASE}-${BUILD}" \ + GLUON_BRANCH="${BRANCH}" \ + GLUON_PRIORITY="${PRIORITY}" \ + manifest + + echo "--- Write Build file" + cat > "${SITEDIR}/output/images/build" <<EOF +DATE=$(date '+%Y-%m-%d %H:%M:%S') +VERSION=$(cat "${SITEDIR}/release") +RELEASE=${RELEASE} +BUILD=${BUILD} +BRANCH=${BRANCH} +COMMIT=${COMMIT} +HOST=$(uname -n) +EOF +} + +sign() { + echo "--- Sign Gluon Firmware Build" + + # Add the signature to the local manifest + contrib/sign.sh \ + "${SIGNKEY}" \ + "${SITEDIR}/output/images/sysupgrade/${BRANCH}.manifest" +} + +upload() { + echo "--- Upload Gluon Firmware Images and Manifest" + + # Build the ssh command to use + SSH="ssh" + SSH="${SSH} -o stricthostkeychecking=no -v" + + # Determine upload target prefix + TARGET="${BRANCH}" + + # Create the target directory on server + ${SSH} \ + ${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER} \ + -- \ + mkdir \ + --parents \ + --verbose \ + "${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}" + + # Add site metadata + tar -czf "${SITEDIR}/output/images/site.tgz" --exclude='gluon' --exclude='output' "${SITEDIR}" + + # Copy images to server + rsync \ + --verbose \ + --recursive \ + --compress \ + --progress \ + --links \ + --chmod=ugo=rwX \ + --rsh="${SSH}" \ + "${SITEDIR}/output/images/" \ + "${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER}:${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}" + ${SSH} \ + ${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER} \ + -- \ + ln -sf \ + "${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}/sysupgrade" \ + "${DEPLOYMENT_PATH}/${TARGET}/" + ${SSH} \ + ${DEPLOYMENT_USER}@${DEPLOYMENT_SERVER} \ + -- \ + ln -sf \ + "${DEPLOYMENT_PATH}/${TARGET}/${RELEASE}-${BUILD}/factory" \ + "${DEPLOYMENT_PATH}/${TARGET}/" +} + +prepare() { + echo "--- Prepare directory for upload" + + # Determine upload target prefix + TARGET="${BRANCH}" + + # Create the target directory on server + mkdir \ + --parents \ + --verbose \ + "${SITEDIR}/output/firmware/${TARGET}" + + # Copy images to directory + mv \ + --verbose \ + "${SITEDIR}/output/images" \ + "${SITEDIR}/output/firmware/${TARGET}/${RELEASE}-${BUILD}" + + # Link latest upload in target to 'current' + cd "${SITEDIR}/output" + ln \ + --symbolic \ + --force \ + --no-target-directory \ + "${RELEASE}-${BUILD}" \ + "firmware/${TARGET}/current" +} + +( + # Change working directory to gluon tree + cd "${SITEDIR}/gluon" + + # Execute the selected command + ${COMMAND} +) diff --git a/.gitlab-ci/update-git.sh b/.gitlab-ci/update-git.sh new file mode 100755 index 0000000..48a78f8 --- /dev/null +++ b/.gitlab-ci/update-git.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +function update() { + # Try ff first + git -C gluon fetch --all && git -C gluon checkout "$GLUON_BRANCH" && git -C gluon pull --ff-only || { + # Kill it with fire + echo "Fast-Forward failed, killing it with fire" + rm -rf gluon + git clone "$GLUON_GIT" -b "$GLUON_BRANCH" gluon + } +} + +( + if ! [[ -e gluon ]]; then + echo "gluon dir nonexistent, updating" + update + exit 0 + fi + + REMOTE_REFS="$(git ls-remote -qht "$GLUON_GIT" | grep "$GLUON_BRANCH" | cut -f1)" + + set +e + LOCAL_REF=$(git -C gluon rev-parse HEAD) + GIT_EXIT=$? + set -e + + if [[ $GIT_EXIT -ne 0 ]]; then + echo "Local repo damaged, forcing update" + update + exit 0 + fi + + # There can be multiple objects describing the same state, we need to check them all + for ref in $REMOTE_REFS; do + echo "Checking $ref == $LOCAL_REF" + if [[ "$ref" == "$LOCAL_REF" ]]; then + echo "Local repo is up to date" + exit 0 + fi + done + + echo "Local state does not reflect latest remote state, updating" + update +) diff --git a/release b/release new file mode 100644 index 0000000..1ba54c6 --- /dev/null +++ b/release @@ -0,0 +1 @@ +2018.2.0.0~exp -- GitLab