diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1ee938339b3..18910ca50a6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -248,9 +248,8 @@ jobs: - name: Copy logs from the Docker image or build container run: | mkdir -p "artifacts/$LOGS_ARTIFACT_NAME" - cp -r .tox/$TOX_ENV/Dockerfile .tox/$TOX_ENV/log "artifacts/$LOGS_ARTIFACT_NAME" - if [ -f .tox/$TOX_ENV/Dockertags ]; then CONTAINERS=$(docker create $(tail -1 .tox/$TOX_ENV/Dockertags) /bin/bash || true); fi - if [ -n "$CONTAINERS" ]; then for CONTAINER in $CONTAINERS; do for ARTIFACT in /sage/logs; do docker cp $CONTAINER:$ARTIFACT artifacts/$LOGS_ARTIFACT_NAME && HAVE_LOG=1; done; if [ -n "$HAVE_LOG" ]; then break; fi; done; fi + cp -r .tox/$TOX_ENV/* "artifacts/$LOGS_ARTIFACT_NAME" + rm -rf "artifacts/$LOGS_ARTIFACT_NAME"/{bin,lib,pyvenv.cfg} if: always() - uses: actions/upload-artifact@v3 with: @@ -262,9 +261,46 @@ jobs: run: | .github/workflows/scan-logs.sh "artifacts/$LOGS_ARTIFACT_NAME" if: always() - - name: List docker images + - name: List Docker images run: | - if [ -f .tox/$TOX_ENV/Dockertags ]; then - cat .tox/$TOX_ENV/Dockertags + if [ -n "$DOCKER_PUSH_REPOSITORY" -a -f .tox/$TOX_ENV/Dockertags.pushed ]; then + set -- $(cat .tox/$TOX_ENV/Dockertags.pushed) + case $# in + 1) images="image"; one_image="the image";; + *) images="images"; one_image="one of the images";; + esac + echo "::notice title=Docker $images pushed::Pushed $images $*)" + echo + echo "To pull $one_image and enter the container, type:" + echo + for TAG in $*; do + echo " \$ docker run -it $TAG bash" + done + echo + echo "To use $one_image as the base for an incremental build, type:" + echo + TOX_ENV_SANS_INCREMENTAL=${TOX_ENV/-incremental/} + DOCKER_IMAGE=${TOX_ENV_SANS_INCREMENTAL#docker-} + for TAG in $*; do + echo -n " \$" + if [ "$DOCKER_PUSH_REPOSITORY" != "ghcr.io/sagemath/sage/" ]; then + echo -n " FROM_DOCKER_REPOSITORY=$DOCKER_PUSH_REPOSITORY" + fi + eval DOCKER_TARGET=\${TAG#*$DOCKER_IMAGE-} + DOCKER_TARGET=${DOCKER_TARGET%:*} + if [ "$DOCKER_TARGET" != "with-targets" ]; then + echo -n " FROM_DOCKER_TARGET=$DOCKER_TARGET" + fi + echo " FROM_DOCKER_TAG=${TAG#*:} tox -e $TOX_ENV_SANS_INCREMENTAL-incremental" + done + elif [ -n "$DOCKER_PUSH_REPOSITORY" -a -f .tox/$TOX_ENV/Dockertags ]; then + echo "Unable to push Docker images to $DOCKER_PUSH_REPOSITORY." + echo "This is normal in a pull request to sagemath/sage or to another user's repository." + echo + echo "If you need Docker images, " + echo " - either run this GitHub Actions workflow in your repository fork" + echo " - or use the method described in https://doc.sagemath.org/html/en/developer/portability_testing.html#automatic-docker-based-build-testing-using-tox" + else + echo "No Docker images created." fi - if: always() + if: always() && ${{ inputs.docker_push_repository }} diff --git a/build/bin/write-dockerfile.sh b/build/bin/write-dockerfile.sh index 2d0de123665..3c62d6082e4 100755 --- a/build/bin/write-dockerfile.sh +++ b/build/bin/write-dockerfile.sh @@ -214,6 +214,18 @@ EOF ;; esac esac + +case ${DOCKER_BUILDKIT-0} in + 1) + # With buildkit we cannot retrieve failed builds. + # So we do not allow the main step of a build stage to fail. + # Instead we record the exit code in the file STATUS. + THEN_SAVE_STATUS='; echo $? > STATUS' + # ... and at the beginning of the next build stage, + # we check the status and exit with an error status. + CHECK_STATUS_THEN='STATUS=$(cat STATUS 2>/dev/null); case "$STATUS" in ""|0) ;; *) exit $STATUS;; esac; ' +esac + cat <> {envdir}/Dockertags; \ - docker: if [ x"{env:DOCKER_PUSH_REPOSITORY:}" != x ]; then \ + docker: if [ -n "$BUILD_TAG" ]; then \ + docker: echo "Copying logs from the container to {envdir}/sage/"; \ + docker: rm -f {envdir}/sage/STATUS; \ + docker: docker run $BUILD_IMAGE:$BUILD_TAG bash -c " \ + docker: tar -c --ignore-failed-read -f - \ + docker: /sage/STATUS /sage/logs /sage/{prefix,venv}/var/lib/sage/installed \ + docker: ~/.sage/timings2.json /sage/pkgs/*/.tox/*/.sage/timings2.json \ + docker: /sage/pkgs/*/.tox/*/logs 2> /dev/null" \ + docker: | (cd {envdir} && tar xf -); \ + docker: if [ -f {envdir}/sage/STATUS ]; then status=$(cat {envdir}/sage/STATUS); fi; \ + docker: fi; \ + docker: unset PUSH_TAGS; \ + docker: if [ -n "$BUILD_TAG" ]; then \ + docker: if [ $status != 0 ]; then \ + docker: BUILD_TAG="${BUILD_TAG%-failed}-failed"; PUSH_TAGS=$BUILD_IMAGE:$BUILD_TAG; \ + docker: else \ + docker: PUSH_TAGS=$(echo $BUILD_IMAGE:$BUILD_TAG; for tag in {env:EXTRA_DOCKER_TAGS:}; do echo "$BUILD_IMAGE:$tag"; done); \ + docker: fi; \ + docker: echo $BUILD_IMAGE:$BUILD_TAG >> {envdir}/Dockertags; \ + docker: fi; \ + docker: if [ x"{env:DOCKER_PUSH_REPOSITORY:}" != x -a x"$PUSH_TAGS" != x ]; then \ docker: echo Pushing $PUSH_TAGS; \ docker: for tag in $PUSH_TAGS; do \ - docker: docker push $tag || echo "(ignoring errors)"; \ + docker: if docker push $tag; then echo $tag >> {envdir}/Dockertags.pushed; else echo "(ignoring errors)"; fi; \ docker: done; \ docker: fi; \ docker: if [ $status != 0 ]; then exit $status; fi; \