.circleci/config.yml
version: 2.1
orbs:
shellcheck: circleci/shellcheck@3.2.0
jobs:
pip-install:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- restore_cache:
key: pip-{{ checksum "pyproject.toml" }}-v1
- run:
name: Install pip dependencies
command: |
if [[ -d ".venv" ]]; then
echo "Virtual environment restored from cache, skipping pip install"
else
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev-pinned,pinned]
fi
- save_cache:
key: pip-{{ checksum "pyproject.toml" }}-v1
paths:
- .venv
- integreat_cms.egg-info
- /home/circleci/.cache/pip
- persist_to_workspace:
root: .
paths:
- .venv
- integreat_cms.egg-info
black:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Check black code style
command: black --check .
djlint:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Check formatting of Django templates
command: djlint --check --lint integreat_cms
pylint:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Run pylint
command: ./tools/pylint.sh
ruff:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Run ruff
command: |
ruff check
# ruff format
mypy:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Run my[py]
command: ./tools/mypy.sh
check-release-notes:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Install requirements
command: sudo apt-get update && sudo apt-get install pcregrep
- run:
name: Check release notes in Markdown
command: ./tools/make_release_notes.sh --format=md --all
- run:
name: Check release notes in reStructuredText
command: ./tools/make_release_notes.sh --format=rst --all
- run:
name: Check release notes in raw format
command: ./tools/make_release_notes.sh --format=raw --all
check-translations:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Install translation requirements
command: sudo apt-get update && sudo apt-get install gettext pcregrep
- run:
name: Check translation file for missing or empty entries
command: ./tools/check_translations.sh
compile-translations:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Install gettext
command: sudo apt-get update && sudo apt-get install gettext
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Compile translation file
command: |
cd integreat_cms
integreat-cms-cli compilemessages --settings=integreat_cms.core.circleci_settings
- persist_to_workspace:
root: .
paths:
- integreat_cms/locale/*/LC_MESSAGES/django.mo
npm-install:
docker:
- image: "cimg/node:lts"
resource_class: small
steps:
- checkout
- restore_cache:
keys:
- npm-{{ checksum "package-lock.json" }}-v2
- run:
name: Install npm dependencies
command: |
if [[ -d "node_modules" ]]; then
echo "Node modules restored from cache, skipping npm install"
else
npm ci
if [[ -n $(git diff --shortstat package-lock.json) ]]; then
echo "package-lock.json is out of date:"
git --no-pager diff package-lock.json
exit 1
fi
fi
- save_cache:
key: npm-{{ checksum "package-lock.json" }}-v2
paths:
- node_modules
- persist_to_workspace:
root: .
paths:
- node_modules
prettier:
docker:
- image: "cimg/node:lts"
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Check formatting of CSS & JS files
command: npx prettier --check .
vitest:
docker:
- image: "cimg/node:lts"
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Run frontend tests
command: npm run test
eslint:
docker:
- image: "cimg/node:lts"
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Lint static CSS, JS & YAML files
command: npx eslint .
shellcheck:
docker:
- image: cimg/base:stable
steps:
- checkout
- shellcheck/install:
version: 0.9.0
- shellcheck/check:
dir: ./tools
external_sources: true
webpack:
docker:
- image: "cimg/node:lts"
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Compile and bundle CSS and JS
command: npm run prod
- persist_to_workspace:
root: .
paths:
- integreat_cms/static/dist
- integreat_cms/webpack-stats.json
check-migrations:
docker:
- image: cimg/python:3.11.7
- image: cimg/postgres:14.1
environment:
POSTGRES_USER: integreat
POSTGRES_DB: integreat
POSTGRES_PASSWORD: password
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Check for missing migrations
command: integreat-cms-cli makemigrations cms --check --settings=integreat_cms.core.circleci_settings
setup-test-reporter:
docker:
- image: cimg/base:stable
resource_class: small
steps:
- attach_workspace:
at: .
- run:
name: Install CodeClimate Test Reporter
command: |
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
chmod +x ./cc-test-reporter
- run:
name: Notify CodeClimate of a pending report
command: ./cc-test-reporter before-build
- persist_to_workspace:
root: .
paths:
- cc-test-reporter
test:
docker:
- image: cimg/python:3.11.7
- image: cimg/postgres:14.1
environment:
POSTGRES_USER: integreat
POSTGRES_DB: integreat
POSTGRES_PASSWORD: password
resource_class: large
parallelism: 16
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Migrate database
command: integreat-cms-cli migrate --settings=integreat_cms.core.circleci_settings
- run:
name: Run tests
command: pytest --circleci-parallelize --disable-warnings --cov=integreat_cms --cov-report xml --junitxml=test-results/junit.xml --ds=integreat_cms.core.circleci_settings
- run:
name: Format test coverage
command: ./cc-test-reporter format-coverage -t coverage.py -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json"
- store_test_results:
path: test-results
- store_artifacts:
path: test-results
- persist_to_workspace:
root: .
paths:
- cc-test-reporter
- coverage
- run:
name: Copy CMS log
command: cp integreat_cms/integreat-cms.log integreat-cms.log
when: on_fail
- store_artifacts:
path: integreat-cms.log
upload-test-coverage:
docker:
- image: cimg/base:stable
resource_class: small
steps:
- attach_workspace:
at: .
- run:
name: Install CodeClimate Test Reporter
command: |
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
chmod +x ./cc-test-reporter
- run:
name: Sum coverage data and upload to CodeClimate
command: |
./cc-test-reporter sum-coverage -o - coverage/codeclimate.*.json | ./cc-test-reporter upload-coverage --debug --input -
build-package:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Use alternative README.md file
command: mv integreat_cms/README.md .
- run:
name: Build integreat-cms package
command: python3 -m build
- persist_to_workspace:
root: .
paths:
- dist
publish-package:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Publish integreat-cms package to (Test-)PyPI
command: twine upload --non-interactive ./dist/integreat_cms-*.tar.gz
build-documentation:
docker:
- image: cimg/python:3.11.7
resource_class: large
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Install requirements
command: sudo apt-get update && sudo apt-get install pcregrep
- run:
name: Generate documentation
command: ./tools/make_docs.sh
- persist_to_workspace:
root: .
paths:
- docs/dist
deploy-documentation:
docker:
- image: cimg/python:3.11.7
resource_class: small
environment:
BRANCH: gh-pages
DOC_DIR: docs/dist
TMP_DIR: .gh-pages
steps:
- attach_workspace:
at: .
- add_ssh_keys:
fingerprints: aa:6c:35:24:8a:80:d8:6a:f3:d7:b1:b3:49:42:a2:b3
- run:
name: Add GitHub's Public SSH Key to known hosts
command: echo 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=' >> ~/.ssh/known_hosts
- run:
name: Prepare git config
command: |
git config --global user.name DigitalfabrikMember
git config --global user.email 41921676+DigitalfabrikMember@users.noreply.github.com
- run:
name: Clone existing gh-pages branch into temporary directory
command: git clone --depth=1 $CIRCLE_REPOSITORY_URL -b $BRANCH $TMP_DIR
- run:
when: on_fail
name: Initialize gh-pages branch in new temporary git directory
command: |
git init $TMP_DIR
cd $TMP_DIR
git remote add origin $CIRCLE_REPOSITORY_URL
git checkout -b $BRANCH
- run:
name: Copy documentation into temporary directory
command: |
rm -rfv ${TMP_DIR}/*
cp -Rv ${TMP_DIR}/../${DOC_DIR}/. $TMP_DIR
- run:
name: Push documentation to GitHub Pages
command: |
cd $TMP_DIR
git add --all
git commit -m "Update documentation of commit ${CIRCLE_SHA1} [skip ci]" || true
git push origin $BRANCH
bump-dev-version:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Bump version
command: |
# Install recent version of pip
echo "Upgrade pip to make sure 'pip index' is available"
pip install --upgrade pip
# Check which versions of integreat-cms are available on the TestPyPI repository
AVAILABLE_VERSIONS=$(pip index versions integreat-cms --pre -i https://test.pypi.org/simple/)
echo "Current available versions on TestPyPI: ${AVAILABLE_VERSIONS}"
CURRENT_ALPHA_VERSION=$(echo "${AVAILABLE_VERSIONS}" | head -n 1)
echo "Most recent version on TestPyPI: ${CURRENT_ALPHA_VERSION}"
CURRENT_ALPHA_VERSION=$(echo "${CURRENT_ALPHA_VERSION}" | sed "s/integreat-cms (\([^()]*\)a0)/\1-alpha/")
echo "Version converted to alternative format: ${CURRENT_ALPHA_VERSION}"
# Get current prod version
CURRENT_VERSION=$(python -c "import integreat_cms; print(integreat_cms.__version__)")
echo "Current production version: ${CURRENT_VERSION}"
# Bump version to current alpha version if it is newer
# Attention: exit(True) in Python means exit(1) which is False in Bash :)
if python -c "from bumpver.version import parse_version; exit(parse_version('${CURRENT_VERSION}') > parse_version('${CURRENT_ALPHA_VERSION}'))"; then
echo "Bump to the currently existing version"
bumpver update -n --set-version="${CURRENT_ALPHA_VERSION}" --no-commit
fi
# Bump version to next alpha version
echo "Bump to the next version"
bumpver update -n -t alpha --no-commit
- persist_to_workspace:
root: .
paths:
- pyproject.toml
- integreat_cms/__init__.py
bump-version:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Install requirements
command: sudo apt-get update && sudo apt-get install pcregrep
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Request installation access token to authorize as Deliverino app
command: echo "export DELIVERINO_ACCESS_TOKEN=$(./.circleci/scripts/get_access_token.py)" >> $BASH_ENV
- run:
name: Config git repository to commit & push as Deliverino app
command: |
git config user.name "deliverino[bot]"
git config user.email "62934656+deliverino[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:$DELIVERINO_ACCESS_TOKEN@github.com/digitalfabrik/integreat-cms.git"
- run:
name: Bump version
command: bumpver update --tag=final
- run:
name: Get tag of newly created version
command: |
eval $(bumpver show --env -n)
echo "export CURRENT_VERSION=$CURRENT_VERSION" >> $BASH_ENV
- run:
name: Update release notes
command: |
# Move "unreleased" entries to new version directory
OLD_DIR="integreat_cms/release_notes/current/unreleased"
NEW_DIR="integreat_cms/release_notes/$(echo "${CURRENT_VERSION}" | cut -c1-4)"
mkdir -p "${NEW_DIR}"
git mv "${OLD_DIR}" "${NEW_DIR}/${CURRENT_VERSION}"
git commit --amend --no-edit
- run:
name: Tag and push commit
command: |
# Get most recent release notes
RELEASE_NOTES=$(./tools/make_release_notes.sh --format=raw --no-subheading)
git tag --annotate "${CURRENT_VERSION}" --message "${RELEASE_NOTES}"
git push origin --follow-tags "${CURRENT_VERSION}" HEAD
- run:
name: Merge version bump into develop
command: git checkout develop && git merge main --commit --no-edit && git push
create-release:
docker:
- image: cimg/python:3.11.7
resource_class: small
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Install requirements
command: sudo apt-get update && sudo apt-get install pcregrep
- run:
name: Enable virtual environment
command: echo "source .venv/bin/activate" >> $BASH_ENV
- run:
name: Request installation access token to authorize as Deliverino app
command: echo "export DELIVERINO_ACCESS_TOKEN=$(./.circleci/scripts/get_access_token.py)" >> $BASH_ENV
- run:
name: Get previous version tag
command: |
PREV_TAG=$(git describe --abbrev=0 --tags "${CIRCLE_TAG}^") || true
echo "export PREV_TAG=\"${PREV_TAG}\"" >> $BASH_ENV
- run:
name: Get release notes
command: |
RELEASE_NOTES=$(./tools/make_release_notes.sh --format=raw --no-heading --no-subheading | sed "s/\"/'/g")
echo "export RELEASE_NOTES=\"${RELEASE_NOTES}\"" >> $BASH_ENV
- run:
name: Get contributors
command: |
CONTRIBUTORS=$(./.circleci/scripts/get_contributors.py "${DELIVERINO_ACCESS_TOKEN}" "${PREV_TAG}" "${CIRCLE_TAG}" -v)
echo "export CONTRIBUTORS=\"${CONTRIBUTORS}\"" >> $BASH_ENV
- run:
name: Create release as Deliverino app
command: ./.circleci/scripts/create_release.py "${DELIVERINO_ACCESS_TOKEN}" "${CIRCLE_TAG}" "${PREV_TAG}" "${RELEASE_NOTES}" "${CONTRIBUTORS}" ./dist/integreat_cms-*.tar.gz
notify-mattermost:
docker:
- image: cimg/base:stable
resource_class: small
steps:
- checkout
- run:
name: Install requirements
command: sudo apt-get update && sudo apt-get install pcregrep
- run:
name: Notify mattermost about release
command: |
# Get most recent release notes
RELEASE_NOTES=$(./tools/make_release_notes.sh --format=md --no-heading --no-subheading | sed "s/\"/'/g")
# Build notification message
MM_MESSAGE="##### Integreat CMS version [${CIRCLE_TAG}](https://github.com/digitalfabrik/integreat-cms/releases/tag/${CIRCLE_TAG}) has been released successfully :tada:\n\n###### **Release Notes:**\n\n${RELEASE_NOTES}"
# Send message to mattermost
STATUS=$(curl -o /dev/null -s -w "%{http_code}\n" -X POST -H 'Content-type: application/json' \
--data \
"{
\"channel\": \"releases\",
\"username\": \"circleci\",
\"icon_emoji\": \":integreat:\",
\"text\": \"${MM_MESSAGE}\"
}" "${MM_WEBHOOK}")
if [ "$STATUS" -ne "200" ]; then
echo "Notification not sent due to an error (HTTP status: ${STATUS})."
exit 1
fi
echo "Notification sent!"
workflows:
develop:
jobs:
- pip-install:
filters:
branches:
ignore: main
- npm-install:
filters:
branches:
ignore: main
- prettier:
requires:
- npm-install
- vitest:
requires:
- npm-install
- webpack:
requires:
- npm-install
- check-migrations:
requires:
- pip-install
- setup-test-reporter:
context: codeclimate
filters:
branches:
ignore: main
- test:
requires:
- pip-install
- webpack
- compile-translations
- setup-test-reporter
- upload-test-coverage:
context: codeclimate
requires:
- test
filters:
branches:
only: /^(?!pull\/).*$/
- check-release-notes:
filters:
branches:
ignore: main
- check-translations:
requires:
- pip-install
- compile-translations:
requires:
- pip-install
- bump-dev-version:
filters:
branches:
only:
- develop
- /.*-publish-dev-package/
requires:
- pip-install
- build-package:
name: build-dev-package
requires:
- webpack
- compile-translations
- bump-dev-version
- publish-package:
name: publish-dev-package
context: pypi-test
filters:
branches:
only:
- develop
- /.*-publish-dev-package/
requires:
- build-dev-package
- black:
requires:
- pip-install
- djlint:
requires:
- pip-install
- pylint:
requires:
- pip-install
- ruff:
requires:
- pip-install
- mypy:
requires:
- pip-install
- eslint:
requires:
- npm-install
- shellcheck:
filters:
branches:
ignore: main
- build-documentation:
requires:
- pip-install
- deploy-documentation:
requires:
- build-documentation
filters:
branches:
only: develop
main:
jobs:
- pip-install:
name: pip-install-main
filters:
branches:
only: main
- bump-version:
context: deliverino
requires:
- pip-install-main
deploy:
jobs:
- pip-install:
name: pip-install-deploy
filters:
tags:
only: /.*/
branches:
ignore: /.*/
- npm-install:
name: npm-install-deploy
filters:
tags:
only: /.*/
branches:
ignore: /.*/
- webpack:
name: webpack-deploy
requires:
- npm-install-deploy
filters:
tags:
only: /.*/
- compile-translations:
name: compile-translations-deploy
requires:
- pip-install-deploy
filters:
tags:
only: /.*/
- build-package:
requires:
- webpack-deploy
- compile-translations-deploy
filters:
tags:
only: /.*/
- publish-package:
context: pypi
requires:
- build-package
filters:
tags:
only: /.*/
- create-release:
context: deliverino
requires:
- publish-package
filters:
tags:
only: /.*/
- notify-mattermost:
context: mattermost
requires:
- create-release
filters:
tags:
only: /.*/