From cf6737efb6af4ecb69a6c91e9a469849fd9a4ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= <karel.koci@nic.cz> Date: Mon, 18 Feb 2019 16:11:24 +0100 Subject: [PATCH] Document release and steps for new version branch --- README.asciidoc | 111 +++++++++++------ compile_pkgs | 16 ++- defaults.sh | 8 ++ feeds.conf | 4 + generate_medkit | 3 +- helpers/new_release.sh | 251 ++++++++++++++++++++++++++++++++++++++ turris-build.conf.example | 4 - 7 files changed, 353 insertions(+), 44 deletions(-) create mode 100644 defaults.sh create mode 100755 helpers/new_release.sh diff --git a/README.asciidoc b/README.asciidoc index 37c531104..c685824fb 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -4,16 +4,54 @@ Simple Turris OS building script Getting started --------------- -Create an empty directory you want to build Turris OS in, enter that directory -and from it call `compile_pkgs` script. In most basic use-case, this should be -enough. Be aware - *it will delete all previous content of the current -directory*. You can repeat individual steps of the compilation separately, -check with the following command `compile_pkgs --help` for a list of available commands, generic options, and -their brief descriptions. +Create an empty directory you want to build Turris OS in, enter that directory and +from it call `compile_pkgs` script. In most basic use-case, this should be enough. +Be aware - *it will delete all previous content of the current directory*. You can +repeat individual steps of the compilation separately, check with the following +command `compile_pkgs --help` for a list of available commands, generic options, +and their brief descriptions. + Advanced usage -------------- +Building a single package +~~~~~~~~~~~~~~~~~~~~~~~~ + +To build only one package you have to first prepare build directory. That can be +achieved by running in target directory. +-- + compile_pkgs prepare_tools -t board # <1> +-- + +<1> ~-t~ means `-target`, so only valid values are `turris`, `omnia`, `mox`. + +Be aware *it removes previous content of current directory*! + +Once, you have compiled required tools, you need **enter build directory** and +then run `make menuconfig`, select the package you want to compile and save it. +Then you can build it using this command: + +-- + make package/name/compile # <2> +-- + +<2> ~name~ is package name, which you want to compile. + +You can also clean single package just by replacing `compile` with `clean`. + +The resulting package is placed in directory **bin/packages/~ARCH~/~REPO~** + +;; `ARCH` is target architecture specific string. +;; `REPO` is the name of package's source repository. + +Occasionally, you can meet cases, where you need to run `make +package/name/compile` with parameters `-j1 V=s` or `-j1 V=sc` to be able to see, +what went wrong. + + +Development and maintenance +--------------------------- + Configuration ~~~~~~~~~~~~~ @@ -30,6 +68,37 @@ it lines with new features in the release. This file is used to generate `turris-version` package. `compile_pkgs` script reads it, finds the newest version and from notes underneath it creates the package with release notes. +Releasing new version +~~~~~~~~~~~~~~~~~~~~~ + +When new version is released to Snails (see workflow for explanation) then new +commit with hashes has to be created and pushed. This commit have to be tagged +with appropriate version tag in format `vVERSION` where VERSION is released +version. To make this all simple and to correctly set always all configurations we +have script `helpers/new_release.sh`. Run this script after release from +turris-build project root directory and it is going to automatically detect, +commit and tag new version. You should review commit and tag it created for you +and then push it using `git push --tags`. + +Script `helpers/new_release.sh` can generate various errors and warnings. It is +advised to run it even before release in `verify` mode to review possible problems +with release. + +Forking new release +~~~~~~~~~~~~~~~~~~~ + +According to workflow new releases are forked from parent branch. During this +process care should be taken to tweak defaults to appropriate values. Following +list should be taken as a checklist for new release branch. + +. Set `PUBLISH_BRANCH` in `defaults.sh`. Master branch should always be set to + `hbd` and release branches should be set to `hbs`. +. Set branches in `feeds.conf`. You should append string like this: + `;openwrt-18.06`. This has to be done for all OpenWRT feeds as well for OpenWRT + it self. URL used by `compile_pkgs` is specified as first line in `feeds.conf` + and with exception of first column it has same format as feeds. Note that that + line is intentionally commented out as that is not feed. + Patching ~~~~~~~~ @@ -60,33 +129,3 @@ manually and afterward, we need to call `git add` on newly patched files. Once all conflicts are resolved, `git am --continue` will create real commit that we were trying to add using `git am`. Now all that is left is to export it using `git format-patch -1` and overwrite patch stored in it of _build_ repository. - -Building a single package -~~~~~~~~~~~~~~~~~~~~~~~~ - -To build only one package you have to first prepare build directory. That can be -achieved by running in target directory. --- - compile_pkgs prepare_tools -t board # <1> --- - -<1> ~-t~ means `-target`, so only valid values are `turris`, `omnia`, `mox`. - -Be aware *it removes previous content of current directory*! - -Once, you have compiled required tools, you need **enter build directory** and then run `make menuconfig`, select the package you want to compile and save it. -Then you can build it using this command: + --- - make package/name/compile # <2> --- - -<2> ~name~ is package name, which you want to compile. - -You can also clean single package just by replacing `compile` with `clean`. - -The resulting package is placed in directory **bin/packages/~ARCH~/~REPO~** - -;; `ARCH` is target architecture specific string. -;; `REPO` is the name of package's source repository. - -Occasionally, you can meet cases, where you need to run `make package/name/compile` with parameters `-j1 V=s` or `-j1 V=sc` to be able to see, what went wrong. diff --git a/compile_pkgs b/compile_pkgs index 187bfd52f..babaf42ab 100755 --- a/compile_pkgs +++ b/compile_pkgs @@ -61,10 +61,19 @@ set_target() { esac } +# Get OpenWRT URL and branch from feeds.conf file +openwrt_feed() { + # OpenWRT git repository URL + OPENWRT_URL="$(sed -n 's/# openwrt \([^;^]\+\).*/\1/p' "$src_dir/feeds.conf")" + # Git reference used to checkout OpenWRT repository + OPENWRT_BRANCH="$(sed -n 's/# openwrt [^;^]\+[;^]\([^\s]\+\).*/\1/p' "$src_dir/feeds.conf")" + # Check if ^ is used to separate URL and branch and in such case it is hash not branch + grep -E '^# openwrt [^;^]+\^.+' "$src_dir/feeds.conf" && OPENWRT_BRANCH="#$OPENWRT_BRANCH" + [ -n "$OPENWRT_BRANCH" ] || OPENWRT_BRANCH="master" +} + # Configuration variables -OPENWRT_URL="https://git.openwrt.org/openwrt/openwrt.git" # OpenWRT git repository URL -OPENWRT_BRANCH="openwrt-18.06" # Git reference used to checkout OpenWRT repository -PUBLISH_BRANCH="hbs" # Target publish branch +. "$src_dir/defaults.sh" FORCE="" # Force build EVERYTHING="" # Set this variable to build all packages not only minimal set CLONE_DEEP="" # Set this variable to clone OpenWRT tree in full depth not just latest commit @@ -76,6 +85,7 @@ DL_MIRROR="" # Path to downloads mirror directory CCACHE_HOST_DIR="" # Path to ccache directory for host compilations CCACHE_TARGET_DIR="" # Path to ccache directory for target compilations OUTPUT_DIR="./pkgsrepo" # Output directory for pkgsrepo command +openwrt_feed # Load configurations [ -f "${src_dir}"/turris-build.conf ] && . "${src_dir}"/turris-build.conf diff --git a/defaults.sh b/defaults.sh new file mode 100644 index 000000000..5a7d6e9e7 --- /dev/null +++ b/defaults.sh @@ -0,0 +1,8 @@ +# This file contains project wide defaults. They are here because we have to tweak +# these defaults every time we fork new release. + +# This sets default publish branch +# Expected values are: +# "hbd" for master branch +# "hbs" for release branch +PUBLISH_BRANCH="hbs" diff --git a/feeds.conf b/feeds.conf index a2736c5ae..11049daf9 100644 --- a/feeds.conf +++ b/feeds.conf @@ -1,3 +1,7 @@ +## Following line defines used openwrt repository. +## It is commented out because it is not feed but is used by compile_pkgs script. +# openwrt https://git.openwrt.org/openwrt/openwrt.git;openwrt-18.06 + src-git turrispackages https://gitlab.labs.nic.cz/turris/turris-os-packages.git^origin/master src-git packages https://git.openwrt.org/feed/packages.git^origin/openwrt-18.06 src-git luci https://git.openwrt.org/project/luci.git^origin/openwrt-18.06 diff --git a/generate_medkit b/generate_medkit index 655554bb6..06b776f40 100755 --- a/generate_medkit +++ b/generate_medkit @@ -16,8 +16,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. set -e +. "$(readlink -f "$(dirname "$0")")/defaults.sh" export BOARD= -export BRANCH="hbs" +export BRANCH="$PUBLISH_BRANCH" export UPDATER_BRANCH= export L10N=cs,de # TODO fill in default lists when we have them selected diff --git a/helpers/new_release.sh b/helpers/new_release.sh new file mode 100755 index 000000000..228882756 --- /dev/null +++ b/helpers/new_release.sh @@ -0,0 +1,251 @@ +#!/bin/bash +# Turris OS script verifying new release +# (C) 2019 CZ.NIC, z.s.p.o. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +set -e + +# TODO: +# * Do we want to verify medkit somehow? + +# Constants +REPO="https://repo.turris.cz" +BOARDS=('mox' 'omnia' 'turris') +DEFAULT_VERIFY_BRANCH="hbk" +DEFAULT_RELEASE_BRANCH="hbs" + + +COLOR_RED="\033[0;31m" +COLOR_GREEN="\033[0;32m" +COLOR_ORANGE="\033[0;33m" +COLOR_OFF="\033[0m" +info() { + printf "%s\n" "$@" >&2 +} +warning() { + if [ -t 2 ]; then + echo -e "${COLOR_ORANGE}$*${COLOR_OFF}" >&2 + else + echo -e "WARNING: $*" >&2 + fi +} +error() { + if [ -t 2 ]; then + echo -e "${COLOR_RED}$*${COLOR_OFF}" >&2 + else + echo -e "ERROR: $*" >&2 + fi +} +fail() { + error "$@" + exit 1 +} +ask() { + echo -e "${COLOR_GREEN}$*${COLOR_OFF}" >&2 + local answer + read -r -p "Write upper case yes to continue: " answer + [ "$answer" = "YES" ] || return 1 +} + +FETCH_DIR= +cleanup() { + [ -d "$FETCH_DIR" ] && rm -rf "$FETCH_DIR" + return 0 +} +trap cleanup EXIT TERM INT QUIT ABRT + +# Fetch all files we need from repository +fetch_files() { + local branch="$1" + FETCH_DIR="$(mktemp -d)" + GIT_HASH_LISTS="$FETCH_DIR/git-hash-lists" + GIT_HASH_PACKAGES="$FETCH_DIR/git-hash-packages" + VERSION_LISTS="$FETCH_DIR/version-lists" + + curl -s "$REPO/$branch/lists/git-hash" >"$GIT_HASH_LISTS" + curl -s "$REPO/$branch/lists/turris-version" >"$VERSION_LISTS" + for board in "${BOARDS[@]}"; do + curl -s "$REPO/$branch/packages/$board/git-hash" >"$GIT_HASH_PACKAGES-$board" + done +} + +# Get git hash from git-hash file on REPO +# Expected arguments are: BOARD FEED +git_hash() { + awk -v feed="$2:" '$2 == feed { print $3; exit }' "$GIT_HASH_PACKAGES-$1" +} + +# Get turris-build hash +# (version is primarily sourced from lists so consider lists as authoritative) +tb_hash() { + local ec=0 + local l_hash b_hash + l_hash="$(cat "$GIT_HASH_LISTS")" + for board in "${BOARDS[@]}"; do + b_hash="$(git_hash "$board" "turris-build")" + [ "$b_hash" = "$l_hash" ] || { + error "Turris build used to generate lists is not same as for packages for board: $board ($l_hash / $b_hash)" + ec=1 + } + done + echo "$l_hash" + return $ec +} + +# Get hash for openwrt +owrt_hash() { + local ec=0 + local hsh="" t_hsh + # TODO this is not optimal and better would be to decide which is authoritative (newer?) + for board in "${BOARDS[@]}"; do + t_hsh="$(git_hash "$board" openwrt)" + [ -n "$hsh" ] || hsh="$t_hsh" + if [ "$t_hsh" != "$hsh" ]; then + error "Different OpenWRT commit build for board: $board ($hsh / $t_hsh)" + ec=1 + fi + done + echo "$hsh" + return $ec +} + +# This function sets dictionary FEEDS by collecting all feeds in git-hash +# Caller should define associative array FEEDS +feeds() { + local ec=0 + # TODO this is not optimal and better would be to decide which is authoritative (newer?) + for board in "${BOARDS[@]}"; do + local lines feed hsh + lines="$(sed -En 's|^ \* feeds/([^:]+): ([^\s]+)|\1 \2|p' "$GIT_HASH_PACKAGES-$board")" + while read -r feed hsh; do + if [[ -v "FEEDS[$feed]" ]]; then + if [ "$hsh" != "${FEEDS["$feed"]}" ]; then + error "Different feed ($feed) commit compiled for $board (${FEEDS["$feed"]} / $hsh)" + ec=1 + fi + else + FEEDS["$feed"]="$hsh" + fi + done <<<"$lines" + done + return $ec +} + +# Sets given hash as a feed target +# Arguments: FEED HASH +feeds_conf_set() { + awk -v feed="$1" -v hash="$2" \ + '$2 == feed { gsub("[;^].*$", "", $3); gsub("$", "^" hash) } { print $0 }' \ + ./feeds.conf > feeds.conf.new + mv ./feeds.conf.new ./feeds.conf +} + +check_for_turris_build_root() { + [ -e .git -a -f ./feeds.conf ] || \ + fail "This has to be run from turris-build root" +} + +########## +verify() { + local branch="$1" + local ec=0 + declare -A FEEDS + fetch_files "$branch" + + tb_hash >/dev/null || ec=$? + owrt_hash >/dev/null || ec=$? + feeds || ec=$? + [ "$ec" = 0 ] && info "No problems detected in branch: $branch" + return $ec +} + +########## +release() { + local branch="$1" + local tversion target_hsh owrt_hsh + declare -A FEEDS + fetch_files "$branch" + + tversion="$(cat "$VERSION_LISTS")" + target_hsh="$(tb_hash)" || ask "turris-build hashes do not match. Planning to use: $target_hsh" + owrt_hsh="$(owrt_hash)" || ask "openwrt hashes do not match. Planning to use: $owrt_hsh" + feeds || ask "feed hashes do not match. Please review difference." + + check_for_turris_build_root + local tag="v$tversion" + git rev-parse "$tag" &>/dev/null && \ + fail "Tag for version $tag exists." + + git checkout "$target_hsh" + feeds_conf_set openwrt "$owrt_hsh" + for feed in "${!FEEDS[@]}"; do + feeds_conf_set "$feed" "${FEEDS["$feed"]}" + done + git add ./feeds.conf + git ci -m "Turris OS $tversion" + git tag -s -m "Turris OS $tversion release" "v$tversion" + + info "Tag $tag was created. Review changes and push it with: git push --tags origin" +} + +################################################################################## +print_help() { + echo "Usage: $0 [OPTION].. [MODE [BRANCH]]" + echo "Turris OS new releases managing tool." + echo + echo "Options:" + echo " -v Run script with verbose output" + echo " -h Print this help text" + echo "Modes:" + echo " verify" + echo " Run script in verify mode where BRANCH (in default $DEFAULT_VERIFY_BRANCH) is checked" + echo " for possible release problems. This is default." + echo " release" + echo " Create new commit and tag for release to BRANCH (in default $DEFAULT_RELEASE_BRANCH)" + echo + echo "Example usage:" + echo " Verify branch to be released: $0 verify" + echo " Commit and tag new release: $0 release" +} + +while getopts ':hd' OPT; do + case "$OPT" in + h) + print_help + exit 0 + ;; + d) + set -x + ;; + \?) + error "Illegal option '-$OPTARG'" + exit 1 + ;; + esac +done +shift $(( OPTIND-1 )) + +[ $# -le 2 ] || fail "Provided too many arguments. See help \`-h\`" + +case "${1:-verify}" in + verify) + verify "${2:-${DEFAULT_VERIFY_BRANCH}}" + ;; + release) + release "${2:-${DEFAULT_RELEASE_BRANCH}}" + ;; + *) + fail "Invalid mode: $1" + ;; +esac diff --git a/turris-build.conf.example b/turris-build.conf.example index 53b74cba1..d5a933536 100644 --- a/turris-build.conf.example +++ b/turris-build.conf.example @@ -17,8 +17,6 @@ SIGN_KEY="mime.key" # Set target board. Allowed arguments are: turris, omnia and mox set_target mox -# Git reference used to checkout OpenWRT repository -#OPENWRT_BRANCH=master # Target publish branch #PUBLISH_BRANCH="hbs" # Force build (set to some number to try build multiple times) @@ -46,8 +44,6 @@ set_target mox #BUILD_ARGS=() ## Variables that you most probably want to let in default ####################### -# OpenWRT git repository URL -#OPENWRT_URL="https://git.openwrt.org/openwrt/openwrt.git" # Set this variable to clone OpenWRT tree in full depth not just latest commit #CLONE_DEEP="y" -- GitLab