From a6e06f59f0a2cae0f4ddc631caad3c5685a59439 Mon Sep 17 00:00:00 2001 From: Filippo Cremonese <filippocremonese@rev.ng> Date: Fri, 26 Feb 2021 16:46:51 +0100 Subject: [PATCH] Checkout and promote orchestra next-* branches Checkout the appropriate orchestra configuration branch before invoking the CI script. If the build succeeds and the branch was named next-*, it gets promoted as *. --- .orchestra/ci/ci-run.sh | 265 ++++++++++++++++++++++++++++++++++++++++ .orchestra/ci/ci.sh | 253 +++++++------------------------------- 2 files changed, 306 insertions(+), 212 deletions(-) create mode 100755 .orchestra/ci/ci-run.sh diff --git a/.orchestra/ci/ci-run.sh b/.orchestra/ci/ci-run.sh new file mode 100755 index 00000000..619001d3 --- /dev/null +++ b/.orchestra/ci/ci-run.sh @@ -0,0 +1,265 @@ +#!/bin/bash + +# rev.ng CI script +# This script runs orchestra to build the required components. +# If the build is successful the script can push the newly produced binary +# archives and promote next-<name> branches to <name>. +# +# Parameters are supplied as environment variables. +# +# Target component is mandatory and done with these parameters: +# +# TARGET_COMPONENTS: list of components to build +# TARGET_COMPONENTS_URL: +# list of glob patterns used to select additional target components +# by matching their remote URL +# +# Optional parameters: +# +# BASE_USER_OPTIONS_YML: +# user_options.yml is initialized to this value. +# %GITLAB_ROOT% is replaced with the base URL of the Gitlab instance. +# COMPONENT_TARGET_BRANCH: +# branch name to try first when checking out component sources +# PUSH_CHANGES: +# if != 1 do not push binary archives and do not promote next-* branches +# PUSH_BINARY_ARCHIVE_EMAIL: used as author's email in binary archive commit +# PUSH_BINARY_ARCHIVE_NAME: used as author's name in binary archive commit +# SSH_PRIVATE_KEY: private key used to push binary archives +# REVNG_ORCHESTRA_URL: +# alternative URL from where orchestra is installed (passed to pip install) + +set -e +set -x + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +ORCHESTRA_ROOT="$(realpath "$DIR/../..")" +ORCHESTRA_DOTDIR="$ORCHESTRA_ROOT/.orchestra" +USER_OPTIONS="$ORCHESTRA_DOTDIR/config/user_options.yml" + +function log() { + echo "$1" > /dev/stderr +} + +PUSH_BINARY_ARCHIVE_EMAIL="${PUSH_BINARY_ARCHIVE_EMAIL:-sysadmin@rev.ng}" +PUSH_BINARY_ARCHIVE_NAME="${PUSH_BINARY_ARCHIVE_NAME:-rev.ng CI}" + +cd "$DIR" + +# Install dependencies +"$DIR/install-dependencies.sh" + +# +# Register deploy key, if any +# +set +x +if test -n "$SSH_PRIVATE_KEY"; then + eval "$(ssh-agent -s)" + echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - + unset SSH_PRIVATE_KEY + mkdir -p ~/.ssh + chmod 700 ~/.ssh + + # Disable checking the host key + if ! test -e ~/.ssh/config; then + cat > ~/.ssh/config <<EOF +Host * + StrictHostKeyChecking no + UserKnownHostsFile=/dev/null +EOF + fi +fi +set -x + +# +# Install orchestra +# +if test -n "$REVNG_ORCHESTRA_URL"; then + pip3 install --user "$REVNG_ORCHESTRA_URL" +else + pip3 install --user revng-orchestra +fi + +# Make sure we can run orchestra +export PATH="$HOME/.local/bin:$PATH" +which orc + +# +# Prepare the user_options.yml file +# +if test -e "$USER_OPTIONS"; then + log "$USER_OPTIONS already exists!" + exit 1 +fi + +REMOTE="$(git remote get-url origin | sed 's|^\([^:]*:\)\([^/]\)|\1/\2|')" +GITLAB_ROOT="$(dirname "$(dirname "$REMOTE")")" +echo "${BASE_USER_OPTIONS_YML//\%GITLAB_ROOT\%/$GITLAB_ROOT}" > "$USER_OPTIONS" + +# Register target components +if test -n "$TARGET_COMPONENTS_URL"; then + # Add components by repository URL + for TARGET_COMPONENT_URL in $TARGET_COMPONENTS_URL; do + NEW_COMPONENT="$(orc components --repository-url "$TARGET_COMPONENT_URL" \ + | grep '^Component' \ + | cut -d' ' -f2)" + if test -z "$NEW_COMPONENT"; then + log "Warning: ignoring URL $TARGET_COMPONENT_URL since it doesn't "\ + "match any component" + else + TARGET_COMPONENTS="$NEW_COMPONENT $TARGET_COMPONENTS" + fi + done +fi + +if test -z "$TARGET_COMPONENTS"; then + log "Nothing to do!" + exit 1 +fi + +# Register components to build from source +cat >> "$USER_OPTIONS" <<EOF +#@overlay/replace +build_from_source: +EOF +for TARGET_COMPONENT in $TARGET_COMPONENTS; do + echo " - $TARGET_COMPONENT" >> "$USER_OPTIONS" +done + +# Build branches list +cat >> "$USER_OPTIONS" <<EOF +#@overlay/replace +branches: +EOF + +if [[ -n "$COMPONENT_TARGET_BRANCH" ]] \ + && ! [[ "$COMPONENT_TARGET_BRANCH" =~ ^(next-develop|develop|next-master|master)$ ]]; then + + echo " - $COMPONENT_TARGET_BRANCH" >> "$USER_OPTIONS" + if test "${COMPONENT_TARGET_BRANCH:0:5}" == "next-"; then + echo " - ${COMPONENT_TARGET_BRANCH:5}" >> "$USER_OPTIONS" + fi +fi + +cat >> "$USER_OPTIONS" <<EOF + - next-develop + - develop + - next-master + - master +EOF + +# Print debug information +cat "$USER_OPTIONS" +find .. + +orc update --no-config + +# Print debugging information +# Full dependency graph +orc graph -b +# Solved dependency graph for the target component +orc graph --solved -b "$TARGET_COMPONENT" +# Information about the components +orc components --hashes --deps +# Binary archives commit +for BINARY_ARCHIVE_PATH in $(orc ls --binary-archives); do + echo "Commit for $BINARY_ARCHIVE_PATH: "\ + "$(git -C "$BINARY_ARCHIVE_PATH" rev-parse HEAD)" +done + +# +# Actually run the build +# +RESULT=0 +for TARGET_COMPONENT in $TARGET_COMPONENTS; do + if ! orc install -b --test --create-binary-archives "$TARGET_COMPONENT"; then + RESULT=1 + break + fi +done + +if test "$PUSH_CHANGES" = 1; then + # + # Promote `next-*` branches to `*` + # + if test "$RESULT" -eq 0; then + + # Clone all the components having branch next-* + for COMPONENT in $(orc components --branch 'next-*' \ + | grep '^Component' \ + | awk '{ print $2 }'); do + # TODO: find a more robust way to clone if not already cloned + if ! test -d "$ORCHESTRA_ROOT/sources/$COMPONENT"; then + orc clone "$COMPONENT" + fi + done + + # Promote next-* to *. + # We also promote orchestra config because fix-binary-archive-symlinks + # uses the current branch name + for SOURCE_PATH in $(orc ls --git-sources) "$ORCHESTRA_ROOT"; do + if test -e "$SOURCE_PATH/.git"; then + cd "$SOURCE_PATH" + BRANCH="$(git rev-parse --abbrev-ref HEAD)" + if test "${BRANCH:0:5}" == "next-"; then + PUSH_TO="${BRANCH:5}" + git branch -d "$PUSH_TO" || true + git checkout -b "$PUSH_TO" "$BRANCH" + git push origin "$PUSH_TO" + fi + cd - + fi + done + + orc fix-binary-archives-symlinks + fi + + # + # Push to binary archives + # + for BINARY_ARCHIVE_PATH in $(orc ls --binary-archives); do + + cd "$BINARY_ARCHIVE_PATH" + + # Ensure we have git lfs + git lfs >& /dev/null + + git config user.email "$PUSH_BINARY_ARCHIVE_EMAIL" + git config user.name "$PUSH_BINARY_ARCHIVE_NAME" + + if ! test -e .gitattributes; then + git lfs track "*.tar.gz" + git add .gitattributes + git commit -m'Initialize .gitattributes' + fi + + ls -lh + git add . + + # TODO: cleanup-binary-archives.sh + + if ! git diff --cached --quiet; then + git commit -m'Automatic binary archives' + git status + git stash + GIT_LFS_SKIP_SMUDGE=1 git fetch + GIT_LFS_SKIP_SMUDGE=1 git rebase -Xtheirs origin/master + + git config --add lfs.dialtimeout 300 + git config --add lfs.tlstimeout 300 + git config --add lfs.activitytimeout 300 + git config --add lfs.keepalive 300 + git push + git lfs push origin master + else + log "Nothing new to push" + fi + + done + + exit "$RESULT" + +else + echo "PUSH_CHANGES != 1, exiting without pushing changes" + exit $RESULT +fi diff --git a/.orchestra/ci/ci.sh b/.orchestra/ci/ci.sh index 66a2c9df..3d604cae 100755 --- a/.orchestra/ci/ci.sh +++ b/.orchestra/ci/ci.sh @@ -1,240 +1,69 @@ #!/bin/bash -set -e -set -x +# rev.ng CI entrypoint script +# This script checks out the correct configuration branch and initializes +# variables for the actual CI script (ci-run.sh) +# +# Parameters are supplied as environment variables. +# +# Optional parameters: +# +# PUSHED_REF: +# orchestra config commit/branch to use. +# Normally set by Gitlab or whoever triggers the CI. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -ORCHESTRA_ROOT="$DIR/../.." +ORCHESTRA_DIR="$DIR/../.." + +# Runs git in the orchestra directory +function ogit () { + git -C "$ORCHESTRA_DIR" "$@" +} function log() { echo "$1" > /dev/stderr } -PUSH_BINARY_ARCHIVE_EMAIL="${PUSH_BINARY_ARCHIVE_EMAIL:-sysadmin@rev.ng}" -PUSH_BINARY_ARCHIVE_NAME="${PUSH_BINARY_ARCHIVE_NAME:-rev.ng CI}" - -cd "$DIR" +set -e +set -x +# Determine target branch # -# Register deploy key, if any +# PUSHED_REF contains the git ref that was pushed and triggered the CI. # -set +x -if test -n "$SSH_PRIVATE_KEY"; then - eval "$(ssh-agent -s)" - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - - unset SSH_PRIVATE_KEY - mkdir -p ~/.ssh - chmod 700 ~/.ssh +# If this ref is a branch, it will be used as the first default branch to try +# for all components and for orchestra configuration - # Disable checking the host key - if ! test -e ~/.ssh/config; then - cat > ~/.ssh/config <<EOF -Host * - StrictHostKeyChecking no - UserKnownHostsFile=/dev/null -EOF - fi -fi -set -x +COMPONENT_TARGET_BRANCH="" -# -# Detect target branch -# -BRANCH="" -if test -n "$PUSHED_REF"; then +if [[ -n "$PUSHED_REF" ]]; then if [[ "$PUSHED_REF" = refs/heads/* ]]; then - BRANCH="${PUSHED_REF#refs/heads/}" - - # Switch orchestra to that branch too, if it exists - git fetch - git checkout "$BRANCH" || true + COMPONENT_TARGET_BRANCH="${PUSHED_REF#refs/heads/}" else log "PUSHED_REF ($PUSHED_REF) is not a branch, bailing out" exit 0 fi fi -# -# Install orchestra -# -if test -n "$REVNG_ORCHESTRA_URL"; then - pip3 install --user "$REVNG_ORCHESTRA_URL" -else - pip3 install --user revng-orchestra -fi - -# Make sure we can run orchestra -export PATH="$HOME/.local/bin:$PATH" -which orc - -# -# Prepare the user_options.yml file -# -if test -e ../config/user_options.yml; then - log "user_options.yml already exists!" - exit 1 -fi - -REMOTE="$(git remote get-url origin | sed 's|^\([^:]*:\)\([^/]\)|\1/\2|')" -GITLAB_ROOT="$(dirname "$(dirname "$REMOTE")")" -echo "$BASE_USER_OPTIONS_YML" | sed "s|%GITLAB_ROOT%|$GITLAB_ROOT|g" > ../config/user_options.yml - -# Register target components -if test -n "$TARGET_COMPONENTS_URL"; then - # Add components by repository URL - for TARGET_COMPONENT_URL in $TARGET_COMPONENTS_URL; do - NEW_COMPONENT="$(orc components --repository-url "$TARGET_COMPONENT_URL" \ - | grep '^Component' \ - | cut -d' ' -f2)" - if test -z "$NEW_COMPONENT"; then - log "Warning: ignoring URL $TARGET_COMPONENT_URL since it doesn't match any component" - else - TARGET_COMPONENTS="$NEW_COMPONENT $TARGET_COMPONENTS" - fi - done -fi - -if test -z "$TARGET_COMPONENTS"; then - log "Nothing to do!" - exit 1 -fi - -# Register components to build from source -cat >> ../config/user_options.yml <<EOF -#@overlay/replace -build_from_source: -EOF -for TARGET_COMPONENT in $TARGET_COMPONENTS; do - echo " - $TARGET_COMPONENT" >> ../config/user_options.yml -done - -# Build branches list -cat >> ../config/user_options.yml <<EOF -#@overlay/replace -branches: -EOF - -if test -n "$BRANCH" && ! [[ "$BRANCH" =~ ^(next-develop|develop|next-master|master)$ ]]; then - echo " - $BRANCH" >> ../config/user_options.yml - if test "${BRANCH:0:5}" == "next-"; then - echo " - ${BRANCH:5}" >> ../config/user_options.yml - fi -fi - -cat >> ../config/user_options.yml <<EOF - - next-develop - - develop - - next-master - - master -EOF - -# Print debug information -cat ../config/user_options.yml -find .. - -orc update --no-config - -# Print debugging information -# Full dependency graph -orc graph -b -# Solved dependency graph for the target component -orc graph --solved -b "$TARGET_COMPONENT" -# Information about the components -orc components --hashes --deps -# Binary archives commit -for BINARY_ARCHIVE_PATH in $(orc ls --binary-archives); do - echo "Commit for $BINARY_ARCHIVE_PATH:" "$(git -C "$BINARY_ARCHIVE_PATH" rev-parse HEAD)" -done - -# -# Actually run the build -# -RESULT=0 -for TARGET_COMPONENT in $TARGET_COMPONENTS; do - if ! orc install -b --test --create-binary-archives "$TARGET_COMPONENT"; then - RESULT=1 +# Switch orchestra to the target branch or try the default list +ogit fetch +for B in "$COMPONENT_TARGET_BRANCH" next-develop develop next-master master; do + if ogit checkout "$B"; then + ORCHESTRA_TARGET_BRANCH="$B" break fi done -if test "$PUSH_CHANGES" = 1; then - # - # Promote `next-*` branches to `*` - # - if test "$RESULT" -eq 0; then - - # Clone all the components having branch next-* - for COMPONENT in $(orc components --branch 'next-*' | grep '^Component' | awk '{ print $2 }'); do - # TODO: find a more robust way to clone if not already cloned - if ! test -d "$ORCHESTRA_ROOT/sources/$COMPONENT"; then - orc clone "$COMPONENT" - fi - done - - # Promote next-* to * - for SOURCE_PATH in $(orc ls --git-sources); do - if test -e "$SOURCE_PATH/.git"; then - cd "$SOURCE_PATH" - BRANCH="$(git rev-parse --abbrev-ref HEAD)" - if test "${BRANCH:0:5}" == "next-"; then - PUSH_TO="${BRANCH:5}" - git branch -d "$PUSH_TO" || true - git checkout -b "$PUSH_TO" "$BRANCH" - git push origin "$PUSH_TO" - fi - cd - - fi - done - - orc fix-binary-archives-symlinks - fi - - # - # Push to binary archives - # - for BINARY_ARCHIVE_PATH in $(orc ls --binary-archives); do - - cd "$BINARY_ARCHIVE_PATH" - - # Ensure we have git lfs - git lfs >& /dev/null - - git config user.email "$PUSH_BINARY_ARCHIVE_EMAIL" - git config user.name "$PUSH_BINARY_ARCHIVE_NAME" - - if ! test -e .gitattributes; then - git lfs track "*.tar.gz" - git add .gitattributes - git commit -m'Initialize .gitattributes' - fi - - ls -lh - git add . - - # TODO: cleanup-binary-archives.sh - - if ! git diff --cached --quiet; then - git commit -m'Automatic binary archives' - git status - git stash - GIT_LFS_SKIP_SMUDGE=1 git fetch - GIT_LFS_SKIP_SMUDGE=1 git rebase -Xtheirs origin/master - - git config --add lfs.dialtimeout 300 - git config --add lfs.tlstimeout 300 - git config --add lfs.activitytimeout 300 - git config --add lfs.keepalive 300 - git push - git lfs push origin master - else - log "Nothing new to push" - fi +if [[ -z "$ORCHESTRA_TARGET_BRANCH" ]]; then + echo "[!] All checkout attempts failed, aborting" + exit 1 +fi - done +ORCHESTRA_CONFIG_COMMIT="$(ogit rev-parse --short "$ORCHESTRA_TARGET_BRANCH")" +echo "[+] Using configuration branch $ORCHESTRA_TARGET_BRANCH "\ + "(commit $ORCHESTRA_CONFIG_COMMIT)" - exit "$RESULT" +export COMPONENT_TARGET_BRANCH -else - echo "PUSH_CHANGES != 1, exiting without pushing changes" - exit $RESULT -fi +# Run "true" CI script +"$DIR/ci-run.sh"