Restructured .travis.yml to span more jobs

The core of littlefs's CI testing is the full test suite, `make test`, run
under a number of configurations:

- Processor architecture:
  - x86 (native)
  - Arm Thumb
  - MIPS
  - PowerPC
- Storage geometry:
  - rs=16   ps=16   cs=64   bs=512   (default)
  - rs=1    ps=1    cs=64   bs=4KiB  (NOR flash)
  - rs=512  ps=512  cs=512  bs=512   (eMMC)
  - rs=4KiB ps=4KiB cs=4KiB bs=32KiB (NAND flash)
- Other corner cases:
  - no intrinsics
  - no inline
  - byte-level read/writes
  - single block-cycles
  - odd block counts
  - odd block sizes

The number of different configurations we need to test quickly exceeds the
50 minute time limit Travis has on jobs. Fortunately, we can split these
tests out into multiple jobs. This seems to be the intended course of
action for large CI "builds" in Travis, as this gives Travis a finer
grain of control over limiting builds.

Unfortunately, this created a couple issues:

1. The Travis configuration isn't actually that flexible. It allows a
   single "matrix expansion" which can be generated from top-level lists
   of different configurations. But it doesn't let you generate a matrix
   from two seperate environment variable lists (for arch + geometry).

   Without multiple matrix expansions, we're stuck writing out each test
   permutation by hand.

   On the bright-side, this was a good chance to really learn how YAML
   anchors work. I'm torn because on one hand anchors add what feels
   like unnecessary complexity to a config language, on the other hand,
   they did help quite a bit in working around Travis's limitations.

2. Now that we have 47 jobs instead of 7, reporting a separate status
   for each job stops making sense.

   What I've opted for here is to use a special NAME variable to
   deduplicate jobs, and used a few state-less rules to hopefully have
   the reported status make sense most of the time.

   - Overwrite "pending" statuses so that the last job to start owns the
     most recent "pending" status
   - Don't overwrite "failure" statuses unless the job number matches
     our own (in the case of CI restarts)
   - Don't write "success" statuses unless the job number matches our
     own, this should delay a green check-mark until the last-to-start
     job finishes
   - Always overwrite non-failures with "failure" statuses

   This does mean a temporary "success" may appear if the last job
   terminates before earlier jobs. But this is the simpliest solution
   I can think of without storing some complex state somewhere.

   Note we can only report the size this way because it's cheap to
   calculate in every job.
This commit is contained in:
Christopher Haster
2020-02-16 15:11:20 -06:00
parent dcae185a00
commit c7987a3162

View File

@@ -1,51 +1,64 @@
# Environment variables # environment variables
env: env:
global: global:
- CFLAGS=-Werror - CFLAGS=-Werror
- MAKEFLAGS=-j - MAKEFLAGS=-j
# Common test script # common installation
script: _: &install-common
# need toml, also pip3 isn't installed by default?
- sudo apt-get install python3-pip
- sudo pip3 install toml
# setup a ram-backed disk to speed up reentrant tests
- mkdir disks
- sudo mount -t tmpfs -o size=100m tmpfs disks
- export TFLAGS="$TFLAGS --disk=disks/disk"
# test cases
_: &test-example
# make sure example can at least compile # make sure example can at least compile
- sed -n '/``` c/,/```/{/```/d; p;}' README.md > test.c && - sed -n '/``` c/,/```/{/```/d; p}' README.md > test.c &&
make all CFLAGS+=" make all CFLAGS+="
-Duser_provided_block_device_read=NULL -Duser_provided_block_device_read=NULL
-Duser_provided_block_device_prog=NULL -Duser_provided_block_device_prog=NULL
-Duser_provided_block_device_erase=NULL -Duser_provided_block_device_erase=NULL
-Duser_provided_block_device_sync=NULL -Duser_provided_block_device_sync=NULL
-include stdio.h" -include stdio.h"
# default tests
# setup a ram-backed disk to speed up reentrant tests _: &test-default
- | # normal+reentrant tests
mkdir disks - make test TFLAGS+="-nrk"
sudo mount -t tmpfs -o size=100m tmpfs disks # common real-life geometries
export TFLAGS="$TFLAGS --disk=disks/disk" _: &test-nor
# run tests
- make clean test TFLAGS+="-nrk"
# common real-life geometries
# NOR flash: read/prog = 1 block = 4KiB # NOR flash: read/prog = 1 block = 4KiB
- make clean test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096" - make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096"
# SD card: read/prog = 512 block = 512 _: &test-emmc
- make clean test TFLAGS+="-nrk -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512" # eMMC: read/prog = 512 block = 512
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512"
_: &test-nand
# NAND flash: read/prog = 4KiB block = 32KiB # NAND flash: read/prog = 4KiB block = 32KiB
- make clean test TFLAGS+="-nrk -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)" - make test TFLAGS+="-nrk -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)"
# other extreme geometries that are useful for testing various corner cases
# other extreme geometries for corner cases _: &test-no-intrinsics
- make clean test TFLAGS+="-nrk -DLFS_NO_INTRINSICS" - make test TFLAGS+="-nrk -DLFS_NO_INTRINSICS"
- make clean test TFLAGS+="-nrk -DLFS_INLINE_MAX=0" _: &test-no-inline
- make clean test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1" - make test TFLAGS+="-nrk -DLFS_INLINE_MAX=0"
- make clean test TFLAGS+="-nrk -DLFS_BLOCK_CYCLES=1" _: &test-byte-writes
- make clean test TFLAGS+="-nrk -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" - make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1"
- make clean test TFLAGS+="-nrk -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704" _: &test-block-cycles
- make test TFLAGS+="-nrk -DLFS_BLOCK_CYCLES=1"
_: &test-odd-block-count
- make test TFLAGS+="-nrk -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256"
_: &test-odd-block-size
- make test TFLAGS+="-nrk -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704"
# report size
_: &report-size
# compile and find the code size with the smallest configuration # compile and find the code size with the smallest configuration
- make clean size - make -j1 clean size
OBJ="$(ls lfs*.c | sed 's/\.c/\.o/' | tr '\n' ' ')" OBJ="$(ls lfs*.c | sed 's/\.c/\.o/' | tr '\n' ' ')"
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR" CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
| tee sizes | tee sizes
# update status if we succeeded, compare with master if possible # update status if we succeeded, compare with master if possible
- | - |
if [ "$TRAVIS_TEST_RESULT" -eq 0 ] if [ "$TRAVIS_TEST_RESULT" -eq 0 ]
@@ -53,7 +66,7 @@ script:
CURR=$(tail -n1 sizes | awk '{print $1}') CURR=$(tail -n1 sizes | awk '{print $1}')
PREV=$(curl -u "$GEKY_BOT_STATUSES" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \ PREV=$(curl -u "$GEKY_BOT_STATUSES" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \
| jq -re "select(.sha != \"$TRAVIS_COMMIT\") | jq -re "select(.sha != \"$TRAVIS_COMMIT\")
| .statuses[] | select(.context == \"$STAGE/$NAME\").description | .statuses[] | select(.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\").description
| capture(\"code size is (?<size>[0-9]+)\").size" \ | capture(\"code size is (?<size>[0-9]+)\").size" \
|| echo 0) || echo 0)
@@ -64,270 +77,351 @@ script:
fi fi
fi fi
# CI matrix # stage control
stages:
- name: test
- name: deploy
if: branch = master AND type = push
# job control
jobs: jobs:
include: # native testing
# native testing - &x86
- stage: test stage: test
env: env:
- STAGE=test - NAME=littlefs-x86
- NAME=littlefs-x86 install: *install-common
script: [*test-example, *report-size]
- {<<: *x86, script: [*test-default, *report-size]}
- {<<: *x86, script: [*test-nor, *report-size]}
- {<<: *x86, script: [*test-emmc, *report-size]}
- {<<: *x86, script: [*test-nand, *report-size]}
- {<<: *x86, script: [*test-no-intrinsics, *report-size]}
- {<<: *x86, script: [*test-no-inline, *report-size]}
- {<<: *x86, script: [*test-byte-writes, *report-size]}
- {<<: *x86, script: [*test-block-cycles, *report-size]}
- {<<: *x86, script: [*test-odd-block-count, *report-size]}
- {<<: *x86, script: [*test-odd-block-size, *report-size]}
# cross-compile with ARM (thumb mode) # cross-compile with ARM (thumb mode)
- stage: test - &arm
env: stage: test
- STAGE=test env:
- NAME=littlefs-arm - NAME=littlefs-arm
- CC="arm-linux-gnueabi-gcc --static -mthumb" - CC="arm-linux-gnueabi-gcc --static -mthumb"
- TFLAGS="-e qemu-arm" - TFLAGS="$TFLAGS -e qemu-arm"
install: install:
- sudo apt-get install - *install-common
gcc-arm-linux-gnueabi - sudo apt-get install
libc6-dev-armel-cross gcc-arm-linux-gnueabi
qemu-user libc6-dev-armel-cross
- arm-linux-gnueabi-gcc --version qemu-user
- qemu-arm -version - arm-linux-gnueabi-gcc --version
- qemu-arm -version
script: [*test-example, *report-size]
- {<<: *arm, script: [*test-default, *report-size]}
- {<<: *arm, script: [*test-nor, *report-size]}
- {<<: *arm, script: [*test-emmc, *report-size]}
- {<<: *arm, script: [*test-nand, *report-size]}
- {<<: *arm, script: [*test-no-intrinsics, *report-size]}
- {<<: *arm, script: [*test-no-inline, *report-size]}
- {<<: *arm, script: [*test-byte-writes, *report-size]}
- {<<: *arm, script: [*test-block-cycles, *report-size]}
- {<<: *arm, script: [*test-odd-block-count, *report-size]}
- {<<: *arm, script: [*test-odd-block-size, *report-size]}
# cross-compile with PowerPC # cross-compile with MIPS
- stage: test - &mips
env: stage: test
- STAGE=test env:
- NAME=littlefs-powerpc - NAME=littlefs-mips
- CC="powerpc-linux-gnu-gcc --static" - CC="mips-linux-gnu-gcc --static"
- TFLAGS="-e qemu-ppc" - TFLAGS="$TFLAGS -e qemu-mips"
install: install:
- sudo apt-get install - *install-common
gcc-powerpc-linux-gnu - sudo apt-get install
libc6-dev-powerpc-cross gcc-mips-linux-gnu
qemu-user libc6-dev-mips-cross
- powerpc-linux-gnu-gcc --version qemu-user
- qemu-ppc -version - mips-linux-gnu-gcc --version
- qemu-mips -version
script: [*test-example, *report-size]
- {<<: *mips, script: [*test-default, *report-size]}
- {<<: *mips, script: [*test-nor, *report-size]}
- {<<: *mips, script: [*test-emmc, *report-size]}
- {<<: *mips, script: [*test-nand, *report-size]}
- {<<: *mips, script: [*test-no-intrinsics, *report-size]}
- {<<: *mips, script: [*test-no-inline, *report-size]}
- {<<: *mips, script: [*test-byte-writes, *report-size]}
- {<<: *mips, script: [*test-block-cycles, *report-size]}
- {<<: *mips, script: [*test-odd-block-count, *report-size]}
- {<<: *mips, script: [*test-odd-block-size, *report-size]}
# cross-compile with MIPS # cross-compile with PowerPC
- stage: test - &powerpc
env: stage: test
- STAGE=test env:
- NAME=littlefs-mips - NAME=littlefs-powerpc
- CC="mips-linux-gnu-gcc --static" - CC="powerpc-linux-gnu-gcc --static"
- TFLAGS="-e qemu-mips" - TFLAGS="$TFLAGS -e qemu-ppc"
install: install:
- sudo apt-get install - *install-common
gcc-mips-linux-gnu - sudo apt-get install
libc6-dev-mips-cross gcc-powerpc-linux-gnu
qemu-user libc6-dev-powerpc-cross
- mips-linux-gnu-gcc --version qemu-user
- qemu-mips -version - powerpc-linux-gnu-gcc --version
- qemu-ppc -version
script: [*test-example, *report-size]
- {<<: *powerpc, script: [*test-default, *report-size]}
- {<<: *powerpc, script: [*test-nor, *report-size]}
- {<<: *powerpc, script: [*test-emmc, *report-size]}
- {<<: *powerpc, script: [*test-nand, *report-size]}
- {<<: *powerpc, script: [*test-no-intrinsics, *report-size]}
- {<<: *powerpc, script: [*test-no-inline, *report-size]}
- {<<: *powerpc, script: [*test-byte-writes, *report-size]}
- {<<: *powerpc, script: [*test-block-cycles, *report-size]}
- {<<: *powerpc, script: [*test-odd-block-count, *report-size]}
- {<<: *powerpc, script: [*test-odd-block-size, *report-size]}
# test under valgrind, checking for memory errors # test under valgrind, checking for memory errors
- stage: test - &valgrind
env: stage: test
- STAGE=test env:
- NAME=littlefs-valgrind - NAME=littlefs-valgrind
- TFLAGS="--valgrind" - TFLAGS="$TFLAGS --valgrind"
install: install:
- sudo apt-get install valgrind - *install-common
- valgrind --version - sudo apt-get install valgrind
- valgrind --version
script: *test-example
- {<<: *valgrind, script: *test-default}
- {<<: *valgrind, script: *test-nor}
- {<<: *valgrind, script: *test-emmc}
- {<<: *valgrind, script: *test-nand}
- {<<: *valgrind, script: *test-no-intrinsics}
- {<<: *valgrind, script: *test-no-inline}
- {<<: *valgrind, script: *test-byte-writes}
- {<<: *valgrind, script: *test-block-cycles}
- {<<: *valgrind, script: *test-odd-block-count}
- {<<: *valgrind, script: *test-odd-block-size}
# self-host with littlefs-fuse for fuzz test # self-host with littlefs-fuse for fuzz test
- stage: test - stage: test
env: env:
- STAGE=test - NAME=littlefs-fuse
- NAME=littlefs-fuse if: branch !~ -prefix$
if: branch !~ -prefix$ install:
install: - *install-common
- sudo apt-get install libfuse-dev - sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2
- fusermount -V - fusermount -V
- gcc --version - gcc --version
before_script:
# setup disk for littlefs-fuse
- rm -rf littlefs-fuse/littlefs/*
- cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
- mkdir mount # setup disk for littlefs-fuse
- sudo chmod a+rw /dev/loop0 - rm -rf littlefs-fuse/littlefs/*
- dd if=/dev/zero bs=512 count=4096 of=disk - cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
- losetup /dev/loop0 disk
script:
# self-host test
- make -C littlefs-fuse
- littlefs-fuse/lfs --format /dev/loop0 - mkdir mount
- littlefs-fuse/lfs /dev/loop0 mount - sudo chmod a+rw /dev/loop0
- dd if=/dev/zero bs=512 count=4096 of=disk
- losetup /dev/loop0 disk
script:
# self-host test
- make -C littlefs-fuse
- ls mount - littlefs-fuse/lfs --format /dev/loop0
- mkdir mount/littlefs - littlefs-fuse/lfs /dev/loop0 mount
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs
- stat .
- ls -flh
- make -B test_dirs test_files QUIET=1
# self-host with littlefs-fuse for fuzz test - ls mount
- stage: test - mkdir mount/littlefs
env: - cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- STAGE=test - cd mount/littlefs
- NAME=littlefs-migration - stat .
if: branch !~ -prefix$ - ls -flh
install: - make -B test_dirs test_files QUIET=1
- sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1
- fusermount -V
- gcc --version
before_script:
# setup disk for littlefs-fuse
- rm -rf v2/littlefs/*
- cp -r $(git ls-tree --name-only HEAD) v2/littlefs
- mkdir mount # test migration using littlefs-fuse
- sudo chmod a+rw /dev/loop0 - stage: test
- dd if=/dev/zero bs=512 count=4096 of=disk env:
- losetup /dev/loop0 disk - NAME=littlefs-migration
script: if: branch !~ -prefix$
# compile v1 and v2 install:
- make -C v1 - *install-common
- make -C v2 - sudo apt-get install libfuse-dev
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2
- git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1
- fusermount -V
- gcc --version
# run self-host test with v1 # setup disk for littlefs-fuse
- v1/lfs --format /dev/loop0 - rm -rf v2/littlefs/*
- v1/lfs /dev/loop0 mount - cp -r $(git ls-tree --name-only HEAD) v2/littlefs
- ls mount - mkdir mount
- mkdir mount/littlefs - sudo chmod a+rw /dev/loop0
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs - dd if=/dev/zero bs=512 count=4096 of=disk
- cd mount/littlefs - losetup /dev/loop0 disk
- stat . script:
- ls -flh # compile v1 and v2
- make -B test_dirs test_files QUIET=1 - make -C v1
- make -C v2
# attempt to migrate # run self-host test with v1
- cd ../.. - v1/lfs --format /dev/loop0
- fusermount -u mount - v1/lfs /dev/loop0 mount
- v2/lfs --migrate /dev/loop0 - ls mount
- v2/lfs /dev/loop0 mount - mkdir mount/littlefs
- cp -r $(git ls-tree --name-only HEAD) mount/littlefs
- cd mount/littlefs
- stat .
- ls -flh
- make -B test_dirs test_files QUIET=1
# run self-host test with v2 right where we left off # attempt to migrate
- ls mount - cd ../..
- cd mount/littlefs - fusermount -u mount
- stat .
- ls -flh
- make -B test_dirs test_files QUIET=1
# Automatically create releases - v2/lfs --migrate /dev/loop0
- stage: deploy - v2/lfs /dev/loop0 mount
env:
- STAGE=deploy
- NAME=deploy
script:
- |
bash << 'SCRIPT'
set -ev
# Find version defined in lfs.h
LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
# Grab latests patch from repo tags, default to 0, needs finagling
# to get past github's pagination api
PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.
PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I \
| sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' \
|| echo $PREV_URL)
LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \
| jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g")
.captures[].string | tonumber) | max + 1' \
|| echo 0)
# We have our new version
LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
echo "VERSION $LFS_VERSION"
# Check that we're the most recent commit
CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \
| jq -re '.sha')
[ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0
# Create major branch
git branch v$LFS_VERSION_MAJOR HEAD
# Create major prefix branch
git config user.name "geky bot"
git config user.email "bot@geky.net"
git fetch https://github.com/$TRAVIS_REPO_SLUG.git \
--depth=50 v$LFS_VERSION_MAJOR-prefix || true
./scripts/prefix.py lfs$LFS_VERSION_MAJOR
git branch v$LFS_VERSION_MAJOR-prefix $( \
git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \
-m "Generated v$LFS_VERSION_MAJOR prefixes")
git reset --hard
# Update major version branches (vN and vN-prefix)
git push --atomic https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \
v$LFS_VERSION_MAJOR \
v$LFS_VERSION_MAJOR-prefix
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
if [ ! -z "$PREV" ]
then
echo "PREV $PREV"
CHANGES=$(git log --oneline $PREV.. --grep='^Merge' --invert-grep)
printf "CHANGES\n%s\n\n" "$CHANGES"
fi
case ${GEKY_BOT_DRAFT:-minor} in
true) DRAFT=true ;;
minor) DRAFT=$(jq -R 'endswith(".0")' <<< "$LFS_VERSION") ;;
false) DRAFT=false ;;
esac
# Create the release and patch version tag (vN.N.N)
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
-d "{
\"tag_name\": \"$LFS_VERSION\",
\"name\": \"${LFS_VERSION%.0}\",
\"target_commitish\": \"$TRAVIS_COMMIT\",
\"draft\": $DRAFT,
\"body\": $(jq -sR '.' <<< "$CHANGES")
}" #"
SCRIPT
# Manage statuses # run self-host test with v2 right where we left off
- ls mount
- cd mount/littlefs
- stat .
- ls -flh
- make -B test_dirs test_files QUIET=1
# automatically create releases
- stage: deploy
env:
- NAME=deploy
script:
- |
bash << 'SCRIPT'
set -ev
# Find version defined in lfs.h
LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3)
LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16)))
LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0)))
# Grab latests patch from repo tags, default to 0, needs finagling
# to get past github's pagination api
PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.
PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I \
| sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' \
|| echo $PREV_URL)
LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \
| jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g")
.captures[].string | tonumber) | max + 1' \
|| echo 0)
# We have our new version
LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH"
echo "VERSION $LFS_VERSION"
# Check that we're the most recent commit
CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \
| jq -re '.sha')
[ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0
# Create major branch
git branch v$LFS_VERSION_MAJOR HEAD
# Create major prefix branch
git config user.name "geky bot"
git config user.email "bot@geky.net"
git fetch https://github.com/$TRAVIS_REPO_SLUG.git \
--depth=50 v$LFS_VERSION_MAJOR-prefix || true
./scripts/prefix.py lfs$LFS_VERSION_MAJOR
git branch v$LFS_VERSION_MAJOR-prefix $( \
git commit-tree $(git write-tree) \
$(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \
-p HEAD \
-m "Generated v$LFS_VERSION_MAJOR prefixes")
git reset --hard
# Update major version branches (vN and vN-prefix)
git push --atomic https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \
v$LFS_VERSION_MAJOR \
v$LFS_VERSION_MAJOR-prefix
# Build release notes
PREV=$(git tag --sort=-v:refname -l "v*" | head -1)
if [ ! -z "$PREV" ]
then
echo "PREV $PREV"
CHANGES=$(git log --oneline $PREV.. --grep='^Merge' --invert-grep)
printf "CHANGES\n%s\n\n" "$CHANGES"
fi
case ${GEKY_BOT_DRAFT:-minor} in
true) DRAFT=true ;;
minor) DRAFT=$(jq -R 'endswith(".0")' <<< "$LFS_VERSION") ;;
false) DRAFT=false ;;
esac
# Create the release and patch version tag (vN.N.N)
curl -f -u "$GEKY_BOT_RELEASES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \
-d "{
\"tag_name\": \"$LFS_VERSION\",
\"name\": \"${LFS_VERSION%.0}\",
\"target_commitish\": \"$TRAVIS_COMMIT\",
\"draft\": $DRAFT,
\"body\": $(jq -sR '.' <<< "$CHANGES")
}" #"
SCRIPT
# manage statuses
before_install: before_install:
- | - |
curl -u "$GEKY_BOT_STATUSES" -X POST \ # don't clobber other (not us) failures
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{ | jq -e ".statuses[] | select(
\"context\": \"$STAGE/$NAME\", .context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
\"state\": \"pending\", .state == \"failure\" and
\"description\": \"${STATUS:-In progress}\", (.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
\"target_url\": \"https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$TRAVIS_JOB_ID\" then
}" curl -u "$GEKY_BOT_STATUSES" -X POST \
- sudo apt-get install python3-pip https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
- sudo pip3 install toml -d "{
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
\"state\": \"pending\",
\"description\": \"${STATUS:-In progress}\",
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
}"
fi
after_failure: after_failure:
- | - |
curl -u "$GEKY_BOT_STATUSES" -X POST \ # don't clobber other (not us) failures
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{ | jq -e ".statuses[] | select(
\"context\": \"$STAGE/$NAME\", .context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
\"state\": \"failure\", .state == \"failure\" and
\"description\": \"${STATUS:-Failed}\", (.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
\"target_url\": \"https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$TRAVIS_JOB_ID\" then
}" curl -u "$GEKY_BOT_STATUSES" -X POST \
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
-d "{
\"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
\"state\": \"failure\",
\"description\": \"${STATUS:-Failed}\",
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
}"
fi
after_success: after_success:
- | - |
curl -u "$GEKY_BOT_STATUSES" -X POST \ # don't clobber other (not us) failures
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ # only update if we were last job to mark in progress,
-d "{ # this isn't perfect but is probably good enough
\"context\": \"$STAGE/$NAME\", if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
\"state\": \"success\", | jq -e ".statuses[] | select(
\"description\": \"${STATUS:-Passed}\", .context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and
\"target_url\": \"https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$TRAVIS_JOB_ID\" (.state == \"failure\" or .state == \"pending\") and
}" (.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))"
then
# Job control curl -u "$GEKY_BOT_STATUSES" -X POST \
stages: https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \
- name: test -d "{
- name: deploy \"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\",
if: branch = master AND type = push \"state\": \"success\",
\"description\": \"${STATUS:-Passed}\",
\"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\"
}"
fi