diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c854ff98b..c3275899a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,30 +4,122 @@ stages: - test - build-release - release - - docs + - release-docs image: docker:23.0.1 variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" CI_REGISTRY_IMAGE: registry.internal.syslifters.com/reportcreator/reportcreator + DOCKER_HUB_IMAGE: syslifters/sysreptor services: - - docker:23.0.1-dind + - docker:27.1.2-dind .depends_docker: before_script: - i=0; while [ "$i" -lt 12 ]; do docker info && break; sleep 5; i=$(( i + 1 )) ; done - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD registry.internal.syslifters.com - export DOCKER_BUILDKIT=1 + - docker buildx create --use + +.deploy_docs: + image: python:latest + script: + - cd docs + - git clone https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/Syslifters/sysreptor-docs.git ghpages + - cd ghpages + - git config --global user.email $GITHUB_USER_MAIL + - git config --global user.name $GITHUB_USERNAME + - shopt -u dotglob + - rm -rf * + - cp -r ../site/* . + - git add . + - git commit -m "INIT" + - git reset $(git commit-tree HEAD^{tree} -m "INIT") + - git push --force + allow_failure: + exit_codes: 127 + +sync: + stage: sync + rules: + - if: $CI_COMMIT_BRANCH == "main" + variables: + GIT_STRATEGY: clone + script: + - apk add git + - git checkout -b $CI_COMMIT_BRANCH + - git remote add public https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/Syslifters/sysreptor.git + - git status + - git config --global user.email $GITHUB_USER_MAIL + - git config --global user.name $GITHUB_USERNAME + - git push public main + +build-docs: + image: python:latest + stage: build-release + needs: [] + artifacts: + when: always + paths: + - docs/site/ + expire_in: 2 days + allow_failure: + exit_codes: 127 + script: + - cd docs + - pip3 install -r requirements.txt + - set +e + - python3 -c 'from hooks import *; generate_software_lists()' || EXIT_CODE=$? + - set -e + # Publish latest version number + - VERSION_NUMBER_LEADING_ZEROS=`git tag | grep ^prod- | sort -r | head -n 1 | sed -nr 's/^(prod|test|ltest)-([0-9]+\.[0-9]+([\.ab][0-9]+)?)$/\2/p'` + - VERSION_NUMBER=$(python3 -c "from packaging.version import Version;print(Version('${VERSION_NUMBER_LEADING_ZEROS}'))") + - echo "$VERSION_NUMBER" > docs/latest.version + # Pack demo data archives + - for archive_dir in ../demo_data/*; do reptor packarchive "$archive_dir" -o "docs/assets/${archive_dir##*/}.tar.gz"; done + # Fetch remote docs from reptor CLI + - mkdir -p docs/cli && cd docs/cli + - git init && git remote add -f origin https://github.com/Syslifters/reptor.git + - git config core.sparseCheckout true + - echo "docs" >> .git/info/sparse-checkout + - git pull origin main + - mv docs/* . + - rm -rf docs .git + - cd ../.. + # Build docs + - mkdocs build build-test-api: stage: build-test extends: .depends_docker script: - # Build container - - docker build --build-arg BUILDKIT_INLINE_CACHE=1 --target=api-test -t $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA . - - docker push $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA + - ISO_WEEK=$(date +%V) + - | + for img in rendering api-dev; do + if docker manifest inspect $CI_REGISTRY_IMAGE/$img:$ISO_WEEK > /dev/null; then + docker pull $CI_REGISTRY_IMAGE/$img:$ISO_WEEK + else + docker buildx build --provenance false --build-arg BUILDKIT_INLINE_CACHE=1 --no-cache --pull --target=$img --platform linux/amd64,linux/arm64 --push -t $CI_REGISTRY_IMAGE/$img:$ISO_WEEK . + fi + done + - docker buildx build --provenance false --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $CI_REGISTRY_IMAGE/rendering:$ISO_WEEK --cache-from $CI_REGISTRY_IMAGE/api-dev:$ISO_WEEK --target=api-test --platform linux/amd64,linux/arm64 --push -t $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA . + +build-test-frontend: + stage: build-test + extends: .depends_docker + script: + - ISO_WEEK=$(date +%V) + - | + for img in pdfviewer-dev frontend-dev; do + if docker manifest inspect $CI_REGISTRY_IMAGE/$img:$ISO_WEEK > /dev/null; then + docker pull $CI_REGISTRY_IMAGE/$img:$ISO_WEEK + else + docker buildx build --provenance false --build-arg BUILDKIT_INLINE_CACHE=1 --no-cache --pull --target=$img --platform linux/amd64,linux/arm64 --push -t $CI_REGISTRY_IMAGE/$img:$ISO_WEEK . + fi + done + - docker buildx build --provenance false --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $CI_REGISTRY_IMAGE/pdfviewer-dev:$ISO_WEEK --cache-from $CI_REGISTRY_IMAGE/frontend-dev:$ISO_WEEK --target=frontend-test --platform linux/amd64,linux/arm64 --push -t $CI_REGISTRY_IMAGE/frontend-test:$CI_COMMIT_SHORT_SHA . test-api: stage: test @@ -55,14 +147,8 @@ test-api: script: - mkdir api/test-reports - chmod 777 api/test-reports - - docker run -e DATABASE_HOST=${POSTGRES_PORT_5432_TCP_ADDR} -e DATABASE_NAME=${POSTGRES_DB} -e DATABASE_USER=${POSTGRES_USER} -e DATABASE_PASSWORD=${POSTGRES_PASSWORD} --mount=type=bind,source=$PWD/api/test-reports,target=/app/api/test-reports $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA pytest -n auto --junitxml=test-reports/junit.xml --cov=reportcreator_api --cov-report=term --cov-report=xml:test-reports/coverage.xml + - docker run -e DATABASE_HOST=${POSTGRES_PORT_5432_TCP_ADDR} -e DATABASE_NAME=${POSTGRES_DB} -e DATABASE_USER=${POSTGRES_USER} -e DATABASE_PASSWORD=${POSTGRES_PASSWORD} --mount=type=bind,source=$PWD/api/test-reports,target=/app/api/test-reports $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA pytest -n auto --junitxml=test-reports/junit.xml --cov=reportcreator_api --cov-report=term --cov-report=xml:test-reports/coverage.xml -build-test-frontend: - stage: build-test - extends: .depends_docker - script: - - docker build --build-arg BUILDKIT_INLINE_CACHE=1 --target=frontend-test -t $CI_REGISTRY_IMAGE/frontend-test:$CI_COMMIT_SHORT_SHA . - - docker push $CI_REGISTRY_IMAGE/frontend-test:$CI_COMMIT_SHORT_SHA test-frontend: stage: test @@ -78,21 +164,6 @@ test-frontend: - mkdir frontend/test-reports - docker run --mount=type=bind,source=$PWD/frontend/test-reports,target=/app/frontend/test-reports $CI_REGISTRY_IMAGE/frontend-test:$CI_COMMIT_SHORT_SHA npm run test -sync: - stage: sync - rules: - - if: $CI_COMMIT_BRANCH == "main" - variables: - GIT_STRATEGY: clone - script: - - apk add git - - git checkout -b $CI_COMMIT_BRANCH - - git remote add public https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/Syslifters/sysreptor.git - - git status - - git config --global user.email $GITHUB_USER_MAIL - - git config --global user.name $GITHUB_USERNAME - - git push public main - build-release: stage: build-release extends: .depends_docker @@ -104,19 +175,27 @@ build-release: - VERSION_NUMBER_LEADING_ZEROS=$(echo "$CI_COMMIT_TAG" | sed -nr 's/^(prod|test|ltest)-([0-9]+\.[0-9]+([\.ab][0-9]+)?)$/\2/p') - VERSION_NUMBER=$(python3 -c "from packaging.version import Version;print(Version('${VERSION_NUMBER_LEADING_ZEROS}'))") # Ensure the version number is in the changelog for prod deployments - - if [[ $CI_COMMIT_TAG =~ '^prod-.*' ]]; then grep -qE "^## (v${VERSION_NUMBER})" CHANGELOG.md || exit 1; fi + - | + if [[ $CI_COMMIT_TAG =~ '^prod-.*' ]]; then + grep -qE "^## (v${VERSION_NUMBER})" CHANGELOG.md || exit 1 + CACHE_RELEASE_TAG=$(test-$VERSION_NUMBER_LEADING_ZEROS) + else: + CACHE_RELEASE_TAG=$CI_COMMIT_SHORT_SHA + fi # Build containers - - docker pull $CI_REGISTRY_IMAGE/frontend-test:$CI_COMMIT_SHORT_SHA - - docker pull $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA - - docker build --cache-from $CI_REGISTRY_IMAGE/frontend-test:$CI_COMMIT_SHORT_SHA --cache-from $CI_REGISTRY_IMAGE/api-test:$CI_COMMIT_SHORT_SHA --build-arg VERSION=$VERSION_NUMBER --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - - cd languagetool && docker build -t $CI_REGISTRY_IMAGE/languagetool:$CI_COMMIT_SHORT_SHA . && cd .. - - docker push $CI_REGISTRY_IMAGE/languagetool:$CI_COMMIT_SHORT_SHA + - docker pull $CI_REGISTRY_IMAGE/frontend-test:$CACHE_RELEASE_TAG + - docker pull $CI_REGISTRY_IMAGE/api-test:$CACHE_RELEASE_TAG + - docker pull $CI_REGISTRY_IMAGE/languagetool:$CACHE_RELEASE_TAG + - export VERSION_NUMBER + - docker buildx build --provenance false --build-arg VERSION="$VERSION_NUMBER" --cache-from $CI_REGISTRY_IMAGE/frontend-test:$CACHE_RELEASE_TAG --cache-from $CI_REGISTRY_IMAGE/api-test:$CACHE_RELEASE_TAG --target=api --platform linux/amd64,linux/arm64 --push --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . + - cd languagetool + - docker buildx build --provenance false --cache-from $CI_REGISTRY_IMAGE/languagetool:$CACHE_RELEASE_TAG --target=api --platform linux/amd64,linux/arm64 --push -t $CI_REGISTRY_IMAGE/languagetool:$CI_COMMIT_SHORT_SHA . + - cd .. -release_job_docker: +release-docker-internal: stage: release - needs: [build-release] extends: .depends_docker + needs: [build-release] rules: - if: $CI_COMMIT_TAG # Run this job when a tag is created script: @@ -127,9 +206,9 @@ release_job_docker: - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG - docker push $CI_REGISTRY_IMAGE/languagetool:$CI_COMMIT_TAG -release_job_release: +release-gitlab-release: stage: release - needs: [release_job_docker] + needs: [release-docker-internal] image: registry.gitlab.com/gitlab-org/release-cli:latest script: - echo "works" @@ -139,9 +218,9 @@ release_job_release: tag_name: "$CI_COMMIT_TAG" description: "$CI_COMMIT_TAG" -release_job_github: +release-prod: stage: release - needs: [build-release] + needs: [build-release, build-docs] extends: - .depends_docker variables: @@ -154,17 +233,27 @@ release_job_github: - VERSION_NUMBER_LEADING_ZEROS=$(echo "$CI_COMMIT_TAG" | sed -nr 's/^(prod|test|ltest)-([0-9]+\.[0-9]+([\.ab][0-9]+)?)$/\2/p') - VERSION_NUMBER=$(python3 -c "from packaging.version import Version;print(Version('${VERSION_NUMBER_LEADING_ZEROS}'))") - RELEASE_NOTES=$(awk "/## v${VERSION_NUMBER}.*/{include=1; next} /## v.*/{include=0} include && NF" CHANGELOG.md) - - echo "# Do not modify. This file is automatically generated." > deploy/.env - - echo "# Make changes to host.env instead." >> deploy/.env - - echo "SYSREPTOR_VERSION=${VERSION_NUMBER}" >> deploy/.env + - sed -i '1s/^/SYSREPTOR_VERSION=${VERSION_NUMBER}\n/' deploy/.env # Generate api notice file - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - - docker run -u0 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA /app/api/generate_notice.sh - - CONTAINER_ID=$(docker ps -qa --filter "ancestor=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA") + - CONTAINER_ID=$(docker create $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA) - docker cp $CONTAINER_ID:/app/api/NOTICE api/NOTICE + - docker rm -v $CONTAINER_ID # Delete unnecessary files - rm -rf docs/docs/s docs/README.md docs/reporting_software.yml docs/wip docs/hooks.py dev .vscode api/.vscode + # Build container with copyleft source code + - docker buildx build --provenance false --cache-from $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA --target api-src --build-arg VERSION=$VERSION_NUMBER --target=api --platform linux/amd64,linux/arm64 --load --tag $DOCKER_HUB_IMAGE:$VERSION_NUMBER-src . + # Push containers to Docker Hub + - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $DOCKER_HUB_IMAGE:$VERSION_NUMBER + - docker tag $DOCKER_HUB_IMAGE:$VERSION_NUMBER $DOCKER_HUB_IMAGE:latest + - docker push $DOCKER_HUB_IMAGE:$VERSION_NUMBER-src + - docker push $DOCKER_HUB_IMAGE:$VERSION_NUMBER + - docker push $DOCKER_HUB_IMAGE:latest + - docker tag $CI_REGISTRY_IMAGE/languagetool:$CI_COMMIT_SHORT_SHA $DOCKER_HUB_IMAGE-languagetool:$VERSION_NUMBER + - docker push $DOCKER_HUB_IMAGE-languagetool:$VERSION_NUMBER + - docker push $DOCKER_HUB_IMAGE-languagetool:latest + # Publish to github - apk add git github-cli @@ -173,22 +262,25 @@ release_job_github: - docker cp $CONTAINER_ID:/app/api/static api/src/ - docker cp $CONTAINER_ID:/app/api/frontend/index.html api/src/frontend/index.html - sed -i "/^src\/static$/d" api/.gitignore - - sed -i "s/target:\ api/target:\ api-prebuilt/g" deploy/sysreptor/docker-compose.yml # Copy pre-built rendering files - docker cp $CONTAINER_ID:/app/rendering/dist rendering/dist - sed -i "/^dist$/d" rendering/.gitignore - rm -rf api/.vscode - # Create archive + # Create archive with prebuilt sources - mkdir -p /tmp/sysreptor - cp -r * .gitignore .dockerignore /tmp/sysreptor - - tar -czf /tmp/source-prebuilt.tar.gz -C /tmp sysreptor --exclude=sysreptor/.git + # Prebuilt sources are deprecated, required for legacy update scripts. Delete in 08/2025. + - tar -czf /tmp/source-prebuilt-deprecated.tar.gz -C /tmp --exclude=sysreptor/.git --exclude=sysreptor/demo_data --exclude=sysreptor/docs sysreptor + + # Create archive with setup files + - tar -czf /tmp/setup.tar.gz -C /tmp --exclude=sysreptor/.git --exclude=sysreptor/deploy/.gitignore sysreptor/deploy sysreptor/update.sh sysreptor/LICENSE sysreptor/INSTALL.md - git remote add public https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/Syslifters/sysreptor.git - git config --global user.email $GITHUB_USER_MAIL - git config --global user.name $GITHUB_USERNAME # Upload to GitHub - "RELEASE_NOTES=$RELEASE_NOTES$(echo -n '\n\nClick here to go to the update instructions: https://docs.sysreptor.com/setup/updates/')" - - gh release create "${VERSION_NUMBER}" /tmp/source-prebuilt.tar.gz --title="${VERSION_NUMBER}" --target="${CI_COMMIT_SHA}" --notes="$RELEASE_NOTES" + - gh release create "${VERSION_NUMBER}" /tmp/source-prebuilt.tar.gz /tmp/setup.tar.gz --title="${VERSION_NUMBER}" --target="${CI_COMMIT_SHA}" --notes="$RELEASE_NOTES" # Send notification for new release - > @@ -198,60 +290,18 @@ release_job_github: -H "Content-Type: application/json" \ -d "{\"title\": \"🎊 Update available\", \"text\": \"There's a new SysReptor version (v${VERSION_NUMBER}) waiting for you.\", \"link_url\": \"https://github.com/Syslifters/sysreptor/releases/tag/${VERSION_NUMBER}\", \"instance_conditions\": {\"version\": \"<${VERSION_NUMBER}\"} }" -build-docs: - image: python:latest - stage: docs - needs: [] - artifacts: - when: always - paths: - - docs/site/ - expire_in: 2 days - allow_failure: - exit_codes: 127 - script: - - cd docs - - pip3 install -r requirements.txt - - set +e - - python3 -c 'from hooks import *; generate_software_lists()' || EXIT_CODE=$? - - set -e - # Pack demo data archives - - for archive_dir in ../demo_data/*; do reptor packarchive "$archive_dir" -o "docs/assets/${archive_dir##*/}.tar.gz"; done - # Fetch remote docs from reptor CLI - - mkdir -p docs/cli && cd docs/cli - - git init && git remote add -f origin https://github.com/Syslifters/reptor.git - - git config core.sparseCheckout true - - echo "docs" >> .git/info/sparse-checkout - - git pull origin main - - mv docs/* . - - rm -rf docs .git - - cd ../.. - # Build docs - - mkdocs build - -deploy-docs: - image: python:latest - stage: docs +release-docs: + stage: release + extends: .deploy_docs needs: [build-docs] rules: - - if: $CI_COMMIT_TAG =~ /^prod-.*/ # Run this job on prod deployments - when: always - if: $CI_COMMIT_TAG || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manual - allow_failure: - exit_codes: 127 - script: - - cd docs - - git clone https://${GITHUB_USERNAME}:${GITHUB_TOKEN}@github.com/Syslifters/sysreptor-docs.git ghpages - - ls -lA - - cd ghpages - - ls -lA - - git config --global user.email $GITHUB_USER_MAIL - - git config --global user.name $GITHUB_USERNAME - - shopt -u dotglob - - rm -rf * - - cp -r ../site/* . - - git add . - - git commit -m "INIT" - - git reset $(git commit-tree HEAD^{tree} -m "INIT") - - git push --force + +release-docs-on-prod-release: + stage: release + extends: .deploy_docs + rules: + - if: $CI_COMMIT_TAG # Run this job when a tag is created + needs: [release-prod] + diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ec75440a..e66daba7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * Improve error messages for decryption errors * Fix user.is_active checkbox not reactive in edit user page * Fix checkboxes not rendered as checked in PDF +* Provide prebuilt Docker images * Fix chromium error while rendering PDFs diff --git a/Dockerfile b/Dockerfile index a324488b9..479a3e537 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,11 @@ -FROM node:20-alpine3.19 AS pdfviewer-dev - -# Add custom CA certificates -ARG CA_CERTIFICATES="" -RUN mkdir -p /usr/local/share/ca-certificates/ && \ - echo "${CA_CERTIFICATES}" | tee -a /usr/local/share/ca-certificates/custom-user-cert.crt /etc/ssl/certs/ca-certificates.crt && \ - apk add --no-cache ca-certificates && \ - update-ca-certificates +FROM --platform=$BUILDPLATFORM node:20-alpine3.19 AS pdfviewer-dev # Install dependencies WORKDIR /app/packages/pdfviewer/ COPY packages/pdfviewer/package.json packages/pdfviewer/package-lock.json /app/packages/pdfviewer// RUN npm install -FROM pdfviewer-dev AS pdfviewer +FROM --platform=$BUILDPLATFORM pdfviewer-dev AS pdfviewer # Build JS bundle COPY packages/pdfviewer /app/packages/pdfviewer// RUN npm run build @@ -20,20 +13,10 @@ RUN npm run build - - - -FROM node:20-alpine3.19 AS frontend-dev +FROM --platform=$BUILDPLATFORM node:20-alpine3.19 AS frontend-dev ENV NODE_OPTIONS="--max-old-space-size=4096" -# Add custom CA certificates -ARG CA_CERTIFICATES="" -RUN mkdir -p /usr/local/share/ca-certificates/ && \ - echo "${CA_CERTIFICATES}" | tee -a /usr/local/share/ca-certificates/custom-user-cert.crt /etc/ssl/certs/ca-certificates.crt && \ - apk add --no-cache ca-certificates && \ - update-ca-certificates - # Install dependencies WORKDIR /app/packages/markdown/ COPY packages/markdown/package.json packages/markdown/package-lock.json /app/packages/markdown/ @@ -44,7 +27,7 @@ COPY frontend/package.json frontend/package-lock.json /app/frontend/ RUN npm install -FROM frontend-dev AS frontend-test +FROM --platform=$BUILDPLATFORM frontend-dev AS frontend-test # Include source code COPY packages/markdown/ /app/packages/markdown/ COPY frontend /app/frontend/ @@ -52,10 +35,10 @@ COPY api/src/reportcreator_api/tasks/rendering/global_assets /app/frontend/src/a COPY --from=pdfviewer /app/packages/pdfviewer/dist/ /app/frontend/src/public/static/pdfviewer/ # Test command -CMD npm run test +CMD ["npm", "run", "test"] -FROM frontend-test AS frontend +FROM --platform=$BUILDPLATFORM frontend-test AS frontend # Build JS bundle RUN npm run generate @@ -65,14 +48,7 @@ RUN npm run generate -FROM node:20-alpine3.19 AS rendering-dev - -# Add custom CA certificates -ARG CA_CERTIFICATES="" -RUN mkdir -p /usr/local/share/ca-certificates/ && \ - echo "${CA_CERTIFICATES}" | tee -a /usr/local/share/ca-certificates/custom-user-cert.crt /etc/ssl/certs/ca-certificates.crt && \ - apk add --no-cache ca-certificates && \ - update-ca-certificates +FROM --platform=$BUILDPLATFORM node:20-alpine3.19 AS rendering-dev # Install dependencies WORKDIR /app/packages/markdown/ @@ -84,7 +60,7 @@ COPY rendering/package.json rendering/package-lock.json /app/rendering/ RUN npm install -FROM rendering-dev AS rendering +FROM --platform=$BUILDPLATFORM rendering-dev AS rendering # Include source code COPY rendering /app/rendering/ COPY packages/markdown/ /app/packages/markdown/ @@ -96,14 +72,11 @@ RUN npm run build FROM python:3.12-slim-bookworm AS api-dev -# Add custom CA certificates -ARG CA_CERTIFICATES="" -RUN echo "${CA_CERTIFICATES}" | tee -a /usr/local/share/ca-certificates/custom-user-cert.crt && \ - update-ca-certificates && \ - cat /etc/ssl/certs/* > /etc/ssl/certs/bundle.pem && \ - pip config set global.cert /etc/ssl/certs/bundle.pem -ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt -ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt +# Get a list a preinstalled apt packages +RUN mkdir /src && \ + chown 1000:1000 /src && \ + dpkg-query -W -f='${binary:Package}=${Version}\n' > /src/pre_installed.txt && \ + echo "This image distributes binaries of copyleft licensed software. Please find the corresponding source code in our source-code distributing images (append `-src` to the image tags; e.g. syslifters/sysreptor:2024.58-src)." > /src/SOURCES.txt # Install system dependencies required by weasyprint and chromium RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -140,10 +113,15 @@ ENV PYTHONUNBUFFERED=on \ PYTHONDONTWRITEBYTECODE=on \ CHROMIUM_EXECUTABLE=/usr/lib/chromium/chromium \ GHOSTSCRIPT_EXECUTABLE=/usr/bin/gs \ - PATH=$PATH:/root/.local/bin + PATH=$PATH:/root/.local/bin \ + REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \ + SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + + WORKDIR /app/api/ COPY api/pyproject.toml api/poetry.lock /app/api/ -RUN pip install --no-cache poetry==1.8.3 && \ +RUN --mount=type=cache,target=/root/.cache/ \ + pip install --no-cache poetry==1.8.3 && \ poetry config virtualenvs.create false && \ poetry install --no-cache --no-interaction --no-root @@ -161,21 +139,13 @@ ENV VERSION=${VERSION} \ SERVER_WORKERS=4 \ PDF_RENDER_SCRIPT_PATH=/app/rendering/dist/bundle.js -# Copy license and changelog -COPY LICENSE CHANGELOG.md /app/ -COPY api/generate_notice.sh api/NOTICE /app/api/ - # Start server EXPOSE 8000 -CMD python3 manage.py migrate && \ - gunicorn \ - --bind=:8000 --worker-class=uvicorn.workers.UvicornWorker --workers=${SERVER_WORKERS} \ - --max-requests=500 --max-requests-jitter=100 --graceful-timeout=300 \ - reportcreator_api.conf.asgi:application +CMD ["/bin/bash", "/app/api/start.sh"] -FROM api-dev AS api-prebuilt +FROM --platform=$BUILDPLATFORM api-dev AS api-prebuilt # Copy source code (including pre-build static files) COPY --chown=user:user api/src /app/api/ @@ -183,7 +153,7 @@ COPY --chown=user:user rendering/dist /app/rendering/dist/ -FROM api-dev AS api-test +FROM --platform=$BUILDPLATFORM api-dev AS api-test # Copy source code COPY --chown=user:user api/src /app/api/ @@ -191,7 +161,7 @@ COPY --chown=user:user api/src /app/api/ COPY --from=rendering --chown=user:user /app/rendering/dist /app/rendering/dist/ -FROM api-test AS api +FROM --platform=$BUILDPLATFORM api-test AS api-statics # Generate static frontend files # Post-process django files (for admin, API browser) and post-process them (e.g. add unique file hash) # Do not post-process nuxt files, because they already have hash names (and django failes to post-process them) @@ -200,3 +170,24 @@ COPY --from=frontend /app/frontend/dist/index.html /app/frontend/dist/static/ /a RUN mv /app/api/frontend/static/index.html /app/api/frontend/index.html \ && python3 manage.py collectstatic --no-input --no-post-process \ && python3 -m whitenoise.compress /app/api/static/ map + + + +FROM api-test AS api +COPY --from=api-statics /app/api/frontend/index.html /app/api/frontend/index.html +COPY --from=api-statics /app/api/static/ /app/api/static/ +USER 0 +COPY --chown=1000:1000 api/generate_notice.sh api/download_sources.sh api/start.sh api/NOTICE /app/api/ +RUN /bin/bash /app/api/generate_notice.sh +# Copy of changelog should be one of the last things to use cache for prod releases +COPY LICENSE CHANGELOG.md /app/ +USER 1000 + + + + +FROM api AS api-src +USER 0 +RUN dpkg-query -W -f='${binary:Package}=${Version}\n' > /src/post_installed.txt \ + && bash /app/api/download_sources.sh +USER 1000 \ No newline at end of file diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000..f06a5481f --- /dev/null +++ b/INSTALL.md @@ -0,0 +1 @@ +Find installation instructions at https://docs.sysreptor.com/setup/installation/ \ No newline at end of file diff --git a/api/download_sources.sh b/api/download_sources.sh new file mode 100644 index 000000000..d32ad296b --- /dev/null +++ b/api/download_sources.sh @@ -0,0 +1,141 @@ +#!/bin/bash +set -e + +skip_license () { + copyright_file="$1" + if test -f "$copyright_file"; then + license=`cat "$copyright_file" | grep -m 1 "^License:" | cut -d" " -f 2` + if test -n "$license" && echo "$skip_licenses" | grep -wq "$license"; then + return 0 + fi + fi + return 1 +} + +fetch_source() { + package="$1" + package_name=`echo $package | cut -d= -f1 | cut -d: -f1` + if echo "$skip_packages" | grep -wq "$package_name"; then + echo "Skipping $package" + return + fi + if skip_license "/usr/share/doc/$package_name/copyright"; then + echo "$package_name (installed) $license license doesn't require source code distribution" + return + fi + echo "Fetching $package" + mkdir "$package" + cd "$package" + apt-get source "$package" --download-only > /dev/null 2>&1 + cd .. + echo "Done $package" +} + +skip_packages="fonts-dejavu-core +libgl1 +libglvnd0 +libglx0 +libtiff6 +fontconfig +fontconfig-config +fonts-noto-color-emoji +libavahi-client3 +libavahi-common-data +libavahi-common3 +libcairo-gobject2 +libcairo2 +libdrm-amdgpu1 +libdrm-common +libdrm-intel1 +libdrm-nouveau2 +libdrm-radeon1 +libdrm2 +libfontconfig1 +libfontenc1 +libice6 +libpciaccess0 +libpixman-1-0 +libsensors-config +libsensors5 +libsm6 +libwebp7 +libx11-6 +libx11-data +libx11-xcb1 +libxau6 +libxaw7 +libxcb-dri2-0 +libxcb-dri3-0 +libxcb-glx0 +libxcb-present0 +libxcb-randr0 +libxcb-render0 +libxcb-shape0 +libxcb-shm0 +libxcb-sync1 +libxcb-xfixes0 +libxcb1 +libxcomposite1 +libxcursor1 +libxdamage1 +libxdmcp6 +libxext6 +libxfixes3 +libxft2 +libxi6 +libxinerama1 +libxkbcommon0 +libxkbfile1 +libxmu6 +libxmuu1 +libxpm4 +libxrandr2 +libxrender1 +libxshmfence1 +libxslt1.1 +libxt6 +libxtst6 +libxv1 +libxxf86dga1 +libxxf86vm1 +unzip +x11-common +x11-utils +xfonts-encodings +xfonts-utils +xkb-data" + +skip_licenses="MIT +curl +CC-BY-SA-3.0 +LGPL-2+ +BSD-3-clause +OFL-1.1 +SIL-1.1 +CC0 +LPGL-2.1+ +APACHE-2-LLVM-EXCEPTIONS +Apache-2.0-with-GPL2-LGPL2-Exception +BSD-2-clause +Expat +FTL +BSD-BY-LC-NE +Apache-2.0 +zlib +BSD-2 +libpng +PostgreSQL +X11 +MIT-1" + +cd /src +sed -i "s/^Types: deb$/Types: deb deb-src/" /etc/apt/sources.list.d/debian.sources +apt-get update > /dev/null 2>&1 + +# Diff with previously installed packages +for package in `grep -Fxv -f pre_installed.txt post_installed.txt`; do + fetch_source "$package" +done + +apt-get clean > /dev/null 2>&1 +rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/api/generate_notice.sh b/api/generate_notice.sh index a4b81e274..3804f1b1c 100755 --- a/api/generate_notice.sh +++ b/api/generate_notice.sh @@ -25,11 +25,11 @@ ignore="$ignore freetype2" ignore="$ignore cwe" ignore="$ignore randomcolor" +export PATH="/home/user/.local/bin:$PATH" pip3 install pip-licenses pip-licenses --allow-only "$allow_only" --ignore-packages $ignore >/dev/null pip-licenses -l --no-license-path -f plain-vertical --no-version --ignore-packages $ignore > NOTICE - # Those packages do not include valid license files webencodings=$(cat << EOF BSD License diff --git a/api/start.sh b/api/start.sh new file mode 100644 index 000000000..2065da996 --- /dev/null +++ b/api/start.sh @@ -0,0 +1,14 @@ +#!/bin/bash +if [[ -n "$CA_CERTIFICATES" ]]; then + echo "${CA_CERTIFICATES}" >> /usr/local/share/ca-certificates/custom-user-cert.crt + update-ca-certificates +fi + +python3 manage.py migrate +gunicorn --bind=:8000 \ + --worker-class=uvicorn.workers.UvicornWorker \ + --workers=${SERVER_WORKERS} \ + --max-requests=500 \ + --max-requests-jitter=100 \ + --graceful-timeout=300 \ + reportcreator_api.conf.asgi:application diff --git a/deploy/.env b/deploy/.env index d10ed2559..f76cdbb9e 100644 --- a/deploy/.env +++ b/deploy/.env @@ -1,3 +1 @@ -# Do not modify. This file is automatically generated. -# Make changes to host.env instead. -SYSREPTOR_VERSION=dev +# BIND_PORT="127.0.0.1:8000:8000" \ No newline at end of file diff --git a/deploy/languagetool/docker-compose.yml b/deploy/languagetool/docker-compose.yml index b91c5606d..26a57903e 100644 --- a/deploy/languagetool/docker-compose.yml +++ b/deploy/languagetool/docker-compose.yml @@ -2,10 +2,7 @@ # Changes will be overwritten. services: languagetool: - build: - context: ../../languagetool - args: - CA_CERTIFICATES: ${SYSREPTOR_CA_CERTIFICATES-} + image: syslifters/sysreptor-languagetool:${SYSREPTOR_VERSION:-latest} container_name: 'sysreptor-languagetool' init: true environment: diff --git a/deploy/sysreptor/docker-compose.yml b/deploy/sysreptor/docker-compose.yml index a873ccdcd..b27c27344 100644 --- a/deploy/sysreptor/docker-compose.yml +++ b/deploy/sysreptor/docker-compose.yml @@ -33,12 +33,7 @@ services: - 6379 restart: unless-stopped app: - build: - context: ../.. - target: api - args: - VERSION: ${SYSREPTOR_VERSION} - CA_CERTIFICATES: ${SYSREPTOR_CA_CERTIFICATES-} + image: 'syslifters/sysreptor:${SYSREPTOR_VERSION:-latest}' container_name: 'sysreptor-app' init: true volumes: diff --git a/docs/docs/install.sh b/docs/docs/install.sh index ad001559f..a5d6f756a 100644 --- a/docs/docs/install.sh +++ b/docs/docs/install.sh @@ -57,8 +57,8 @@ then exit -4 fi -download_url=https://github.com/syslifters/sysreptor/releases/latest/download/source-prebuilt.tar.gz -echo "Downloading SysReptor from $download_url ..." +download_url=https://github.com/syslifters/sysreptor/releases/latest/download/setup.tar.gz +echo "Downloading Docker Compose files from $download_url ..." curl -s -L --output sysreptor.tar.gz "$download_url" echo "Checking download..." if @@ -100,10 +100,6 @@ else fi done - # Delete docker-compose.override.yml because that's needed for existing PRO installations only due to legacy reasons - # ...not for new installations - rm docker-compose.override.yml 2>/dev/null || true - echo "Creating app.env..." cp app.env.example app.env @@ -143,24 +139,30 @@ then source caddy/setup.sh || true # do not exit on error fi +# Delete docker-compose.override.yml because that's needed for existing PRO installations only due to legacy reasons +# ...not for new installations +rm docker-compose.override.yml 2>/dev/null || true + echo "Creating docker volumes..." echo -n "Volume: " docker volume create sysreptor-db-data echo -n "Volume: " docker volume create sysreptor-app-data -echo "Build and launch SysReptor via docker compose..." -echo "We are downloading and installing all dependencies." -echo "This may take a few minutes." +echo "Launching SysReptor via docker compose..." +echo "Downloading the Docker images may take a few minutes." if + source .env + export SYSREPTOR_VERSION ! docker compose up -d then echo "Ups. Something did not work while bringing up your containers." exit -2 fi -echo "Running migrations..." +echo "" +echo "Waiting for database setup..." while sleep 1 ! echo '' | docker compose exec --no-TTY app python3 manage.py migrate --check 1>/dev/null 2>&1 @@ -206,7 +208,7 @@ do read -p "Copy your password now. Copied? [y/n]: " CONFIRM if [[ $CONFIRM == [nN] ]] then - echo "C'mon. Copy it. It's a good password." + echo "It's a good password. You will like it." fi done diff --git a/docs/docs/setup/configuration.md b/docs/docs/setup/configuration.md index f87bebe3f..88361b1e8 100644 --- a/docs/docs/setup/configuration.md +++ b/docs/docs/setup/configuration.md @@ -241,9 +241,8 @@ Uploaded images are compressed to reduce file size, but to retain quality suitab COMPRESS_IMAGES=false ``` - ### Reverse Proxy -Interpret `X-Forwared-*` headers when SysReptor is behind a reverse proxy. +Interpret `X-Forwarded-*` headers when SysReptor is behind a reverse proxy. See also https://docs.djangoproject.com/en/stable/ref/settings/#use-x-forwarded-host ``` @@ -257,6 +256,26 @@ This flag also enables setting the `Secure` flag for cookies. SECURE_SSL_REDIRECT=on ``` +### Proxy Server +Set the proxy variables `HTTP_PROXY` and `HTTPS_PROXY` to allow outbound connections using a proxy server. + +```bash title="Example:" +HTTP_PROXY="http://192.168.0.111:8080" +HTTPS_PROXY="http://192.168.0.111:8080" +``` + +!!! info "The proxy server must be reachable from container" + + Make sure that the proxy server is reachable from inside your docker container. + Loopback addresses (e. g. `127.0.0.1`) or `localhost` will not work. + + +### Custom CA Certificates +If your SysReptor is behind a proxy with a custom certificate, you can use this setting to specify your custom CA certificates. + +``` +CA_CERTIFICATES="-----BEGIN CERTIFICATE-----\nMIIDqDCCApCgAwIBAgIFAMjv7sswDQYJKoZIhv..." +``` ### WebSockets Disable WebSockets and always use HTTP fallback for collaborative editing. diff --git a/docs/docs/setup/installation.md b/docs/docs/setup/installation.md index 4d88c265c..1053387ef 100755 --- a/docs/docs/setup/installation.md +++ b/docs/docs/setup/installation.md @@ -38,15 +38,15 @@ ``` The installation script creates a new `sysreptor` directory holding the source code and everything you need. - It will build a docker image, create volumes and secrets and bring up your containers. + It will set up all configurations, create volumes and secrets, download images from Docker hub and bring up your containers. === "Manual Installation" You need (official) [Docker](https://docs.docker.com/engine/install/ubuntu/){ target=_blank } installed. - Download and extract the latest SysReptor release: + Download and extract the latest SysReptor setup files: ```shell - curl -s -L --output sysreptor.tar.gz https://github.com/syslifters/sysreptor/releases/latest/download/source-prebuilt.tar.gz + curl -s -L --output sysreptor.tar.gz https://github.com/syslifters/sysreptor/releases/latest/download/setup.tar.gz tar xzf sysreptor.tar.gz ``` @@ -86,7 +86,7 @@ docker volume create sysreptor-app-data ``` - Build Docker image and run container from the `deploy` directory: + Launch containers (from the `deploy` directory): ```shell docker compose up -d diff --git a/docs/docs/setup/network.md b/docs/docs/setup/network.md deleted file mode 100644 index 63580f7cc..000000000 --- a/docs/docs/setup/network.md +++ /dev/null @@ -1,54 +0,0 @@ -# Network Settings -:octicons-server-24: Self-Hosted - -## Bind to different port or interface -SysReptor is bound to port 8000 on localhost by default. If you want to bind it to a different port, use the `BIND_PORT` environment variable and restart your containers from the `deploy` directory. - -The format is `IP:HOST_PORT:CONTAINER_PORT`(note that `CONTAINER_PORT` should always be 8000). - -``` title="Examples:" -export BIND_PORT="127.0.0.1:8000:8000" -export BIND_PORT="127.0.0.1:80:8000" # Bind to localhost port 80 -export BIND_PORT="8000:8000" # Bind to all interfaces -export BIND_PORT="1.1.1.1:8000:8000" # Bind to dedicated interface -``` - -```bash linenums="1" title="Export port variable and run container" -export BIND_PORT="127.0.0.1:8000:8000" -cd deploy -docker compose up -d -``` - -Binding SysReptor to a publicly reachable network port exposes the application to untrusted networks without encryption. We recommend setting up a [web server](webserver.md). - -Make sure that environment variables are set persistently, e.g. by adding the `export` command to your `~/.profile`. - -## Proxy Configuration - -We pass the proxy environment variables (`HTTP_PROXY` and `HTTPS_PROXY`) from your host system into the Docker containers. To use a proxy, set those variables on your host system and start your containers from the `deploy` directory. - -```bash title="Export proxy variables and run container" -export HTTP_PROXY="http://192.168.0.111:8080" -export HTTPS_PROXY="http://192.168.0.111:8080" -cd deploy -docker compose up -d -``` - -!!! info "The proxy server must be reachable from container" - - Make sure that the proxy server is reachable from inside your docker container. - Loopback addresses (e. g. `127.0.0.1`) or `localhost` will not work. - -Make sure that environment variables are set persistently, e.g. by adding the `export` command to your `~/.profile`. - -### CA Certificates - -Your proxy server will probably not have a publicly trusted CA certificate. Build your Docker image with custom CA certificates: - -```bash title="Set CA certificate, build and run" -cd deploy -export SYSREPTOR_CA_CERTIFICATES="-----BEGIN CERTIFICATE-----\nMIIDqDCCApCgAwIBAgIFAMjv7sswDQYJKoZIhv..." -docker compose up -d --build -``` - -Make sure that environment variables are set persistently, e.g. by adding the `export` command to your `~/.profile`. \ No newline at end of file diff --git a/docs/docs/setup/updates.md b/docs/docs/setup/updates.md index d8fda976a..ed5df3bdb 100644 --- a/docs/docs/setup/updates.md +++ b/docs/docs/setup/updates.md @@ -7,14 +7,11 @@ We recommend to create a [backup](backups.md) of your installation before updati === "Update via Script (recommended)" We deliver the shell script `update.sh` in the `sysreptor` directory. - If updates are available, the script downloads the release from GitHub. It rebuilds your Docker images and restarts all containers. - If no updates are available, the script checks when the Docker images were last built. If the last build date was more then seven days ago, the Docker images are rebuilt to ensure that all base images and dependencies are up to date. - - Use the `--force` option to force rebuilding the Docker images. + If updates are available, the script downloads the release from GitHub. It replaces your Docker images by the newest release and restarts all containers. Your current SysReptor directory will be renamed for backup purposes. The script will download the newer version and place it into the directory where the old version was. - It will then copy your `app.env` and the `docker-compose.yml` to the `deploy` directory of your newer version. The new docker images are build and launched. + It will then copy your `app.env`, `.env`, `docker-compose.yml` and if present the `Caddyfile` to the correct locations of your newer version. The new SysReptor version launched and the docker images of your old verions are cleaned up. ```shell title="Run update script:" bash sysreptor/update.sh @@ -23,21 +20,26 @@ We recommend to create a [backup](backups.md) of your installation before updati === "Manual update" Download and extract the latest SysReptor release: ```shell - curl -s -L --output sysreptor.tar.gz https://github.com/syslifters/sysreptor/releases/latest/download/source-prebuilt.tar.gz + curl -s -L --output sysreptor.tar.gz https://github.com/syslifters/sysreptor/releases/latest/download/setup.tar.gz tar xzf sysreptor.tar.gz ``` - Copy `deploy/app.env` and `deploy/docker-compose.yml` from your old installation to the new installation. + Copy the following files from your old installation to the new installation. + * `deploy/app.env` + * `deploy/docker-compose.yml` + * `deploy/caddy/Caddyfile` (optional, if present) + + Copy the contents of your `deploy/.env` file to the new installation. Make sure to keep the new version number intact and don't replace it by the old version number. - `cd` to `sysreptor/deploy`. Then, build Docker images and launch containers: + `cd` to `sysreptor/deploy` and launch the containers: ```shell - docker compose up -d --build + docker compose up -d ``` ## Recommended: Automatic updates -We recommend to deploy automatic updates and run the script once per day. This ensures you receive updates early and you regularly update all dependencies and base images. +We recommend to deploy automatic updates and run the script once per day. This ensures you receive updates early. If `cron` is not installed, install and start: ```shell @@ -57,10 +59,4 @@ Schedule your update, e.g. every day at midnight: 0 0 * * * /bin/bash /home/yourpath/sysreptor/update.sh ``` -If you bound SysReptor to a different port, make sure to include the `BIND_PORT` variable: - -```shell -0 0 * * * BIND_PORT=443 /bin/bash /home/yourpath/sysreptor/update.sh -``` - Make sure your user has write permissions to the parent directory of your SysReptor directory. In this example, you need write permissions to `/home/yourpath/`. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 979e8c8c2..b64fa3aa2 100755 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -8,7 +8,6 @@ nav: - Installation: setup/installation.md - Configuration: setup/configuration.md - Setup Webserver: setup/webserver.md - - Network Settings: setup/network.md - Updates: setup/updates.md - Backups: setup/backups.md - Upgrade to PRO: setup/upgrade-to-professional.md @@ -144,6 +143,7 @@ plugins: "setup/oidc-google.md": "users/oidc-google.md" "setup/oidc-generic.md": "users/oidc-generic.md" "setup/proxy.md": "setup/network.md" + "setup/network.md": "setup/configuration.md" markdown_extensions: - attr_list diff --git a/languagetool/Dockerfile b/languagetool/Dockerfile index 454b07aa3..78d2214f9 100644 --- a/languagetool/Dockerfile +++ b/languagetool/Dockerfile @@ -1,16 +1,9 @@ FROM erikvl87/languagetool:6.4 -# Add custom CA certificates -ARG CA_CERTIFICATES="" USER root -RUN mkdir -p /usr/local/share/ca-certificates/ && \ - echo "${CA_CERTIFICATES}" | tee -a /usr/local/share/ca-certificates/custom-user-cert.crt /etc/ssl/certs/ca-certificates.crt && \ - apk add --no-cache ca-certificates && \ - update-ca-certificates - # PostgreSQL support -RUN apk add postgresql-client zip unzip wget \ - && wget https://jdbc.postgresql.org/download/postgresql-42.7.3.jar -P libs --quiet \ +RUN wget https://github.com/pgjdbc/pgjdbc/releases/download/REL42.7.3/postgresql-42.7.3.jar -P libs --quiet \ + && wget https://github.com/pgjdbc/pgjdbc/archive/refs/tags/REL42.7.3.tar.gz -P /src --quiet \ && mkdir -p org/languagetool/server \ && unzip -p languagetool-server.jar org/languagetool/server/mybatis-config.xml | \ sed '/^\s*<\/dataSource>/i<property name="driver.prepareThreshold" value="0"\/>' \ @@ -20,6 +13,6 @@ RUN apk add postgresql-client zip unzip wget \ # Add custom wordlists COPY scripts/* ./ COPY wordlists /custom-wordlists/ -RUN bash add_wordlists.sh +RUN /bin/bash add_wordlists.sh USER 100 diff --git a/update.sh b/update.sh index 5863c1ad0..31dc1e7c9 100755 --- a/update.sh +++ b/update.sh @@ -11,8 +11,10 @@ error_cleanup() { mv "$sysreptor_directory" "$sysreptor_directory"-failed-update-$(date -Iseconds) mv "$backup_copy" "$sysreptor_directory" cd "$sysreptor_directory"/deploy + source .env + export SYSREPTOR_VERSION=$OLD_SYSREPTOR_VERSION docker compose up -d - echo "Error failed during installation." + echo "An error happened during installation." exit -3 fi exit -4 @@ -21,7 +23,7 @@ trap 'error_cleanup' ERR INT echo "Easy update of SysReptor" echo "" error=1 -for cmd in curl tar docker date +for cmd in curl tar docker date grep do if ! command -v "$cmd" >/dev/null @@ -51,46 +53,39 @@ then echo "\"`readlink -e ..`\" not writeable. Exiting..." exit -2 fi -download_url=https://github.com/syslifters/sysreptor/releases/latest/download/source-prebuilt.tar.gz +DOWNLOAD_URL=https://github.com/syslifters/sysreptor/releases/latest/download/setup.tar.gz +DOCKER_HUB_IMAGE=syslifters/sysreptor +DOCKER_HUB_LANGUAGETOOL_IMAGE=syslifters/sysreptor-languagetool + source deploy/.env -echo "Your current version is $SYSREPTOR_VERSION" -if [ "$1" != "--force" ] +OLD_SYSREPTOR_VERSION=$SYSREPTOR_VERSION +echo "Your current version is $OLD_SYSREPTOR_VERSION" + +echo "Checking if update is available..." +version=`curl -s https://docs.sysreptor.org/latest.version` +if ! [[ $version =~ ^[0-9]{4}\.[0-9]+$ ]] then - echo "Checking if update is available..." - redirect_location=`curl -I -s "$download_url" | grep -i ^location | tr -d '\n\r'` - download=`echo "$redirect_location" | rev | cut -d/ -f 3 | rev` - version=`echo "$redirect_location" | rev | cut -d/ -f 2 | rev` - filename=`echo "$redirect_location" | rev | cut -d/ -f 1 | rev` - if [ "$download" != "download" ] || [ "$filename" != "source-prebuilt.tar.gz" ] - then - echo "Checking for new version failed." - exit -6 - fi - if [ "$version" != "$SYSREPTOR_VERSION" ] - then - echo "Found newer version $version" - else - echo "The latest SysReptor version is already installed." - echo "" - echo "Checking when last docker image build was..." - if [[ `docker inspect -f '{{ .Created }}' sysreptor-app` > `date +%F -d '7 days ago'` ]] - then - echo "Last build was less then seven days ago. Use '--force' to force update." - exit 0 - else - echo "Last build was more then seven days ago. Updating to get the latest dependencies installed..." - fi - fi + echo "Checking for new version failed." + exit -6 fi +if [ "$version" != "$OLD_SYSREPTOR_VERSION" ] +then + echo "Found newer version $version" +else + echo "The latest SysReptor version is already installed." + exit 0 +fi +NEW_SYSREPTOR_VERSION=$version -echo "Downloading SysReptor from $download_url ..." -curl -s -L --output ../sysreptor.tar.gz "$download_url" +echo "Downloading SysReptor from $DOWNLOAD_URL ..." +curl -s -L --output ../sysreptor.tar.gz "$DOWNLOAD_URL" echo "Checking download..." if ! tar -tzf ../sysreptor.tar.gz >/dev/null 2>&1 then echo "Download did not succeed..." exit -5 fi + echo "Creating backup copy of your current installation..." sysreptor_directory=${PWD##*/} backup_copy="$sysreptor_directory"-backup-$(date -Iseconds) @@ -101,21 +96,25 @@ echo "Backup copy located at $backup_copy" echo "Unpacking sysreptor.tar.gz..." mkdir "$sysreptor_directory" tar xzf sysreptor.tar.gz -C "$sysreptor_directory" --strip-components=1 -echo "Copy your app.env..." +echo "Copying your config files app.env and .env..." +source "${sysreptor_directory}/deploy/.env" # get new SYSREPTOR_VERSION +NEW_SYSREPTOR_VERSION=$SYSREPTOR_VERSION cp "${backup_copy}/deploy/app.env" "${sysreptor_directory}/deploy/app.env" +grep -v "^NEW_SYSREPTOR_VERSION=" "${backup_copy}/deploy/.env" > "${sysreptor_directory}/deploy/.env" +sed -i '1s/^/NEW_SYSREPTOR_VERSION=${NEW_SYSREPTOR_VERSION}\n/' "${sysreptor_directory}/deploy/app.env" + if grep "sysreptor/docker-compose.yml" "${backup_copy}/deploy/docker-compose.yml" >/dev/null 2>&1 then # Copy docker-compose.yml if it is not the old version (2024.58 and earlier) - echo "Copy your docker-compose.yml..." + echo "Copying your docker-compose.yml..." cp "${backup_copy}/deploy/docker-compose.yml" "${sysreptor_directory}/deploy/docker-compose.yml" fi if [ -f "${backup_copy}/deploy/caddy/Caddyfile" ]; then echo "Copying Caddyfile..." cp "${backup_copy}/deploy/caddy/Caddyfile" "${sysreptor_directory}/deploy/caddy/Caddyfile" fi -echo "Build and launch SysReptor via docker compose..." -echo "We are downloading and installing all dependencies." -echo "This may take a few minutes." +echo "Launching SysReptor via docker compose..." +echo "Downloading the Docker images may take a few minutes." # Remove deprecated docker-compose.override.yml which is there for legacy reasons rm "${sysreptor_directory}/deploy/docker-compose.override.yml" 2>/dev/null || true @@ -131,10 +130,18 @@ then fi if cd "$sysreptor_directory"/deploy - ! docker compose build --no-cache --pull || ! docker compose up -d + source .env + export SYSREPTOR_VERSION=$NEW_SYSREPTOR_VERSION + ! docker compose up -d then echo "Ups. Something did not work while building and launching your containers." error_cleanup fi + +echo "Cleaning up your old docker images..." +for image in $DOCKER_HUB_IMAGE $DOCKER_HUB_LANGUAGETOOL_IMAGE; do + docker rmi "$image:$OLD_SYSREPTOR_VERSION" 2>/dev/null || true +done + echo "Nice. Successfully updated." echo "Easy peasy lemon squeezy."