1# environment variables 2env: 3 global: 4 - CFLAGS=-Werror 5 - MAKEFLAGS=-j 6 7# cache installation dirs 8cache: 9 pip: true 10 directories: 11 - $HOME/.cache/apt 12 13# common installation 14_: &install-common 15 # need toml, also pip3 isn't installed by default? 16 - sudo apt-get install python3 python3-pip 17 - sudo pip3 install toml 18 # setup a ram-backed disk to speed up reentrant tests 19 - mkdir disks 20 - sudo mount -t tmpfs -o size=100m tmpfs disks 21 - export TFLAGS="$TFLAGS --disk=disks/disk" 22 23# test cases 24_: &test-example 25 # make sure example can at least compile 26 - sed -n '/``` c/,/```/{/```/d; p}' README.md > test.c && 27 make all CFLAGS+=" 28 -Duser_provided_block_device_read=NULL 29 -Duser_provided_block_device_prog=NULL 30 -Duser_provided_block_device_erase=NULL 31 -Duser_provided_block_device_sync=NULL 32 -include stdio.h" 33# default tests 34_: &test-default 35 # normal+reentrant tests 36 - make test TFLAGS+="-nrk" 37# common real-life geometries 38_: &test-nor 39 # NOR flash: read/prog = 1 block = 4KiB 40 - make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096" 41_: &test-emmc 42 # eMMC: read/prog = 512 block = 512 43 - make test TFLAGS+="-nrk -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512" 44_: &test-nand 45 # NAND flash: read/prog = 4KiB block = 32KiB 46 - make test TFLAGS+="-nrk -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)" 47# other extreme geometries that are useful for testing various corner cases 48_: &test-no-intrinsics 49 - make test TFLAGS+="-nrk -DLFS_NO_INTRINSICS" 50_: &test-no-inline 51 - make test TFLAGS+="-nrk -DLFS_INLINE_MAX=0" 52_: &test-byte-writes 53 - make test TFLAGS+="-nrk -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1" 54_: &test-block-cycles 55 - make test TFLAGS+="-nrk -DLFS_BLOCK_CYCLES=1" 56_: &test-odd-block-count 57 - make test TFLAGS+="-nrk -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256" 58_: &test-odd-block-size 59 - make test TFLAGS+="-nrk -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704" 60 61# report size 62_: &report-size 63 # compile and find the code size with the smallest configuration 64 - make -j1 clean size 65 OBJ="$(ls lfs*.c | sed 's/\.c/\.o/' | tr '\n' ' ')" 66 CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR" 67 | tee sizes 68 # update status if we succeeded, compare with master if possible 69 - | 70 if [ "$TRAVIS_TEST_RESULT" -eq 0 ] 71 then 72 CURR=$(tail -n1 sizes | awk '{print $1}') 73 PREV=$(curl -u "$GEKY_BOT_STATUSES" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \ 74 | jq -re "select(.sha != \"$TRAVIS_COMMIT\") 75 | .statuses[] | select(.context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\").description 76 | capture(\"code size is (?<size>[0-9]+)\").size" \ 77 || echo 0) 78 79 STATUS="Passed, code size is ${CURR}B" 80 if [ "$PREV" -ne 0 ] 81 then 82 STATUS="$STATUS ($(python -c "print '%+.2f' % (100*($CURR-$PREV)/$PREV.0)")%)" 83 fi 84 fi 85 86# stage control 87stages: 88 - name: test 89 - name: deploy 90 if: branch = master AND type = push 91 92# job control 93jobs: 94 # native testing 95 - &x86 96 stage: test 97 env: 98 - NAME=littlefs-x86 99 install: *install-common 100 script: [*test-example, *report-size] 101 - {<<: *x86, script: [*test-default, *report-size]} 102 - {<<: *x86, script: [*test-nor, *report-size]} 103 - {<<: *x86, script: [*test-emmc, *report-size]} 104 - {<<: *x86, script: [*test-nand, *report-size]} 105 - {<<: *x86, script: [*test-no-intrinsics, *report-size]} 106 - {<<: *x86, script: [*test-no-inline, *report-size]} 107 - {<<: *x86, script: [*test-byte-writes, *report-size]} 108 - {<<: *x86, script: [*test-block-cycles, *report-size]} 109 - {<<: *x86, script: [*test-odd-block-count, *report-size]} 110 - {<<: *x86, script: [*test-odd-block-size, *report-size]} 111 112 # cross-compile with ARM (thumb mode) 113 - &arm 114 stage: test 115 env: 116 - NAME=littlefs-arm 117 - CC="arm-linux-gnueabi-gcc --static -mthumb" 118 - TFLAGS="$TFLAGS --exec=qemu-arm" 119 install: 120 - *install-common 121 - sudo apt-get install 122 gcc-arm-linux-gnueabi 123 libc6-dev-armel-cross 124 qemu-user 125 - arm-linux-gnueabi-gcc --version 126 - qemu-arm -version 127 script: [*test-example, *report-size] 128 - {<<: *arm, script: [*test-default, *report-size]} 129 - {<<: *arm, script: [*test-nor, *report-size]} 130 - {<<: *arm, script: [*test-emmc, *report-size]} 131 - {<<: *arm, script: [*test-nand, *report-size]} 132 - {<<: *arm, script: [*test-no-intrinsics, *report-size]} 133 - {<<: *arm, script: [*test-no-inline, *report-size]} 134 # it just takes way to long to run byte-level writes in qemu, 135 # note this is still tested in the native tests 136 #- {<<: *arm, script: [*test-byte-writes, *report-size]} 137 - {<<: *arm, script: [*test-block-cycles, *report-size]} 138 - {<<: *arm, script: [*test-odd-block-count, *report-size]} 139 - {<<: *arm, script: [*test-odd-block-size, *report-size]} 140 141 # cross-compile with MIPS 142 - &mips 143 stage: test 144 env: 145 - NAME=littlefs-mips 146 - CC="mips-linux-gnu-gcc --static" 147 - TFLAGS="$TFLAGS --exec=qemu-mips" 148 install: 149 - *install-common 150 - sudo apt-get install 151 gcc-mips-linux-gnu 152 libc6-dev-mips-cross 153 qemu-user 154 - mips-linux-gnu-gcc --version 155 - qemu-mips -version 156 script: [*test-example, *report-size] 157 - {<<: *mips, script: [*test-default, *report-size]} 158 - {<<: *mips, script: [*test-nor, *report-size]} 159 - {<<: *mips, script: [*test-emmc, *report-size]} 160 - {<<: *mips, script: [*test-nand, *report-size]} 161 - {<<: *mips, script: [*test-no-intrinsics, *report-size]} 162 - {<<: *mips, script: [*test-no-inline, *report-size]} 163 # it just takes way to long to run byte-level writes in qemu, 164 # note this is still tested in the native tests 165 #- {<<: *mips, script: [*test-byte-writes, *report-size]} 166 - {<<: *mips, script: [*test-block-cycles, *report-size]} 167 - {<<: *mips, script: [*test-odd-block-count, *report-size]} 168 - {<<: *mips, script: [*test-odd-block-size, *report-size]} 169 170 # cross-compile with PowerPC 171 - &powerpc 172 stage: test 173 env: 174 - NAME=littlefs-powerpc 175 - CC="powerpc-linux-gnu-gcc --static" 176 - TFLAGS="$TFLAGS --exec=qemu-ppc" 177 install: 178 - *install-common 179 - sudo apt-get install 180 gcc-powerpc-linux-gnu 181 libc6-dev-powerpc-cross 182 qemu-user 183 - powerpc-linux-gnu-gcc --version 184 - qemu-ppc -version 185 script: [*test-example, *report-size] 186 - {<<: *powerpc, script: [*test-default, *report-size]} 187 - {<<: *powerpc, script: [*test-nor, *report-size]} 188 - {<<: *powerpc, script: [*test-emmc, *report-size]} 189 - {<<: *powerpc, script: [*test-nand, *report-size]} 190 - {<<: *powerpc, script: [*test-no-intrinsics, *report-size]} 191 - {<<: *powerpc, script: [*test-no-inline, *report-size]} 192 # it just takes way to long to run byte-level writes in qemu, 193 # note this is still tested in the native tests 194 #- {<<: *powerpc, script: [*test-byte-writes, *report-size]} 195 - {<<: *powerpc, script: [*test-block-cycles, *report-size]} 196 - {<<: *powerpc, script: [*test-odd-block-count, *report-size]} 197 - {<<: *powerpc, script: [*test-odd-block-size, *report-size]} 198 199 # test under valgrind, checking for memory errors 200 - &valgrind 201 stage: test 202 env: 203 - NAME=littlefs-valgrind 204 install: 205 - *install-common 206 - sudo apt-get install valgrind 207 - valgrind --version 208 script: 209 - make test TFLAGS+="-k --valgrind" 210 211 # self-host with littlefs-fuse for fuzz test 212 - stage: test 213 env: 214 - NAME=littlefs-fuse 215 if: branch !~ -prefix$ 216 install: 217 - *install-common 218 - sudo apt-get install libfuse-dev 219 - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 220 - fusermount -V 221 - gcc --version 222 223 # setup disk for littlefs-fuse 224 - rm -rf littlefs-fuse/littlefs/* 225 - cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs 226 227 - mkdir mount 228 - sudo chmod a+rw /dev/loop0 229 - dd if=/dev/zero bs=512 count=128K of=disk 230 - losetup /dev/loop0 disk 231 script: 232 # self-host test 233 - make -C littlefs-fuse 234 235 - littlefs-fuse/lfs --format /dev/loop0 236 - littlefs-fuse/lfs /dev/loop0 mount 237 238 - ls mount 239 - mkdir mount/littlefs 240 - cp -r $(git ls-tree --name-only HEAD) mount/littlefs 241 - cd mount/littlefs 242 - stat . 243 - ls -flh 244 - make -B test 245 246 # test migration using littlefs-fuse 247 - stage: test 248 env: 249 - NAME=littlefs-migration 250 if: branch !~ -prefix$ 251 install: 252 - *install-common 253 - sudo apt-get install libfuse-dev 254 - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v2 v2 255 - git clone --depth 1 https://github.com/geky/littlefs-fuse -b v1 v1 256 - fusermount -V 257 - gcc --version 258 259 # setup disk for littlefs-fuse 260 - rm -rf v2/littlefs/* 261 - cp -r $(git ls-tree --name-only HEAD) v2/littlefs 262 263 - mkdir mount 264 - sudo chmod a+rw /dev/loop0 265 - dd if=/dev/zero bs=512 count=128K of=disk 266 - losetup /dev/loop0 disk 267 script: 268 # compile v1 and v2 269 - make -C v1 270 - make -C v2 271 272 # run self-host test with v1 273 - v1/lfs --format /dev/loop0 274 - v1/lfs /dev/loop0 mount 275 276 - ls mount 277 - mkdir mount/littlefs 278 - cp -r $(git ls-tree --name-only HEAD) mount/littlefs 279 - cd mount/littlefs 280 - stat . 281 - ls -flh 282 - make -B test 283 284 # attempt to migrate 285 - cd ../.. 286 - fusermount -u mount 287 288 - v2/lfs --migrate /dev/loop0 289 - v2/lfs /dev/loop0 mount 290 291 # run self-host test with v2 right where we left off 292 - ls mount 293 - cd mount/littlefs 294 - stat . 295 - ls -flh 296 - make -B test 297 298 # automatically create releases 299 - stage: deploy 300 env: 301 - NAME=deploy 302 script: 303 - | 304 bash << 'SCRIPT' 305 set -ev 306 # Find version defined in lfs.h 307 LFS_VERSION=$(grep -ox '#define LFS_VERSION .*' lfs.h | cut -d ' ' -f3) 308 LFS_VERSION_MAJOR=$((0xffff & ($LFS_VERSION >> 16))) 309 LFS_VERSION_MINOR=$((0xffff & ($LFS_VERSION >> 0))) 310 # Grab latests patch from repo tags, default to 0, needs finagling 311 # to get past github's pagination api 312 PREV_URL=https://api.github.com/repos/$TRAVIS_REPO_SLUG/git/refs/tags/v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR. 313 PREV_URL=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" -I \ 314 | sed -n '/^Link/{s/.*<\(.*\)>; rel="last"/\1/;p;q0};$q1' \ 315 || echo $PREV_URL) 316 LFS_VERSION_PATCH=$(curl -u "$GEKY_BOT_RELEASES" "$PREV_URL" \ 317 | jq 'map(.ref | match("\\bv.*\\..*\\.(.*)$";"g") 318 .captures[].string | tonumber) | max + 1' \ 319 || echo 0) 320 # We have our new version 321 LFS_VERSION="v$LFS_VERSION_MAJOR.$LFS_VERSION_MINOR.$LFS_VERSION_PATCH" 322 echo "VERSION $LFS_VERSION" 323 # Check that we're the most recent commit 324 CURRENT_COMMIT=$(curl -f -u "$GEKY_BOT_RELEASES" \ 325 https://api.github.com/repos/$TRAVIS_REPO_SLUG/commits/master \ 326 | jq -re '.sha') 327 [ "$TRAVIS_COMMIT" == "$CURRENT_COMMIT" ] || exit 0 328 # Create major branch 329 git branch v$LFS_VERSION_MAJOR HEAD 330 # Create major prefix branch 331 git config user.name "geky bot" 332 git config user.email "bot@geky.net" 333 git fetch https://github.com/$TRAVIS_REPO_SLUG.git \ 334 --depth=50 v$LFS_VERSION_MAJOR-prefix || true 335 ./scripts/prefix.py lfs$LFS_VERSION_MAJOR 336 git branch v$LFS_VERSION_MAJOR-prefix $( \ 337 git commit-tree $(git write-tree) \ 338 $(git rev-parse --verify -q FETCH_HEAD | sed -e 's/^/-p /') \ 339 -p HEAD \ 340 -m "Generated v$LFS_VERSION_MAJOR prefixes") 341 git reset --hard 342 # Update major version branches (vN and vN-prefix) 343 git push --atomic https://$GEKY_BOT_RELEASES@github.com/$TRAVIS_REPO_SLUG.git \ 344 v$LFS_VERSION_MAJOR \ 345 v$LFS_VERSION_MAJOR-prefix 346 # Build release notes 347 PREV=$(git tag --sort=-v:refname -l "v*" | head -1) 348 if [ ! -z "$PREV" ] 349 then 350 echo "PREV $PREV" 351 CHANGES=$(git log --oneline $PREV.. --grep='^Merge' --invert-grep) 352 printf "CHANGES\n%s\n\n" "$CHANGES" 353 fi 354 case ${GEKY_BOT_DRAFT:-minor} in 355 true) DRAFT=true ;; 356 minor) DRAFT=$(jq -R 'endswith(".0")' <<< "$LFS_VERSION") ;; 357 false) DRAFT=false ;; 358 esac 359 # Create the release and patch version tag (vN.N.N) 360 curl -f -u "$GEKY_BOT_RELEASES" -X POST \ 361 https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases \ 362 -d "{ 363 \"tag_name\": \"$LFS_VERSION\", 364 \"name\": \"${LFS_VERSION%.0}\", 365 \"target_commitish\": \"$TRAVIS_COMMIT\", 366 \"draft\": $DRAFT, 367 \"body\": $(jq -sR '.' <<< "$CHANGES") 368 }" #" 369 SCRIPT 370 371# manage statuses 372before_install: 373 - | 374 # don't clobber other (not us) failures 375 if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ 376 | jq -e ".statuses[] | select( 377 .context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and 378 .state == \"failure\" and 379 (.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))" 380 then 381 curl -u "$GEKY_BOT_STATUSES" -X POST \ 382 https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ 383 -d "{ 384 \"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\", 385 \"state\": \"pending\", 386 \"description\": \"${STATUS:-In progress}\", 387 \"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\" 388 }" 389 fi 390 391after_failure: 392 - | 393 # don't clobber other (not us) failures 394 if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ 395 | jq -e ".statuses[] | select( 396 .context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and 397 .state == \"failure\" and 398 (.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))" 399 then 400 curl -u "$GEKY_BOT_STATUSES" -X POST \ 401 https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ 402 -d "{ 403 \"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\", 404 \"state\": \"failure\", 405 \"description\": \"${STATUS:-Failed}\", 406 \"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\" 407 }" 408 fi 409 410after_success: 411 - | 412 # don't clobber other (not us) failures 413 # only update if we were last job to mark in progress, 414 # this isn't perfect but is probably good enough 415 if ! curl https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ 416 | jq -e ".statuses[] | select( 417 .context == \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\" and 418 (.state == \"failure\" or .state == \"pending\") and 419 (.target_url | endswith(\"$TRAVIS_JOB_NUMBER\") | not))" 420 then 421 curl -u "$GEKY_BOT_STATUSES" -X POST \ 422 https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT} \ 423 -d "{ 424 \"context\": \"${TRAVIS_BUILD_STAGE_NAME,,}/$NAME\", 425 \"state\": \"success\", 426 \"description\": \"${STATUS:-Passed}\", 427 \"target_url\": \"$TRAVIS_JOB_WEB_URL#$TRAVIS_JOB_NUMBER\" 428 }" 429 fi 430