diff --git a/.UPGRADE_INSTRUCTIONS b/.UPGRADE_INSTRUCTIONS new file mode 100644 index 000000000..9d03b90f4 --- /dev/null +++ b/.UPGRADE_INSTRUCTIONS @@ -0,0 +1,6 @@ +Manually apply the ngeo application changes as shown in the `ngeo.diff` file. +You should apply the changes shown in the diff file on `CONST_create_template/` on your project's ``. +Some advice to be more efficient: if the changes on a file concern a file that you never customize, you can simply copy the new file from `CONST_create_template` (`cp CONST_create_template/ `).You can furthermore add this file to the `unmanaged_files` section of the `project.yaml` file, to avoid its contents appearing in the diff file for the next upgrade. +Note that you can also apply them using: git apply --3way ngeo.diff +To continue, type: +./upgrade 2.9 10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd59b8f55..2518e8f65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,15 +1,35 @@ +# https://pre-commit.com/hooks.html + +ci: + autoupdate_schedule: quarterly + skip: + - ripsecrets + repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: detect-private-key + - id: end-of-file-fixer + - id: trailing-whitespace + args: + - --markdown-linebreak-ext=.md + - id: mixed-line-ending + args: + - --fix=lf - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.7.1 + rev: v3.1.0 hooks: - id: prettier - additional_dependencies: - - prettier@2.8.4 - - repo: https://github.com/sbrunner/jsonschema-validator - rev: 0.1.0 + - repo: https://github.com/PyCQA/autoflake + rev: v2.3.1 hooks: - - id: jsonschema-validator - files: ^ci/config\.yaml$ -ci: - skip: - - jsonschema-validator + - id: autoflake + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black diff --git a/.upgrade.yaml b/.upgrade.yaml new file mode 100644 index 000000000..88feb5601 --- /dev/null +++ b/.upgrade.yaml @@ -0,0 +1,61 @@ +--- +# The list (by include, exclude) of default files that will not be overwritten by the upgrade. +# That that can be extended with managed_files or reduced with unmanaged_files from the +# project.yaml file in the project root directory. +default_project_file: + include: + - geoportal/setup\.py + - geoportal/vars\.yaml + - geoportal/Makefile + - geoportal/geomapfish_geoportal/__init__\.py + - geoportal/geomapfish_geoportal/templates/.* + - geoportal/geomapfish_geoportal/locale/.* + - geoportal/geomapfish_geoportal/static/.* + - geoportal/geomapfish_geoportal/static-ngeo/.* + - print/print-apps/.* + - mapserver/.* + - tilegeneration/config\.yaml\.tmpl + - project\.yaml + - docker-compose\.yaml + - env\.project + - README\.rst + - \.github/workflows/main\.yaml + - \.github/workflows/rebuild\.yaml + exclude: + - mapserver/demo\.map\.tmpl + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/image/favicon\.ico + +# Files ignored when creating the diff files => will just be left untouched. +no_diff: + - .*\.po + - CONST_.+ + - .*/CONST_.+ + +# Files that will be present in the CONST_create_template but will not be considered in the upgrade. +# Used to provide the alt applications => does not disturb the user during upgrade. +extra: + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/mobile_alt\.html\.ejs + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/oeedit\.html\.ejs + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/Controllermobile_alt\.js + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/Controlleroeedit\.js + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/sass/mobile_alt\.scss + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/sass/vars_mobile_alt\.scss + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/sass/oeedit\.scss + - geoportal/geomapfish_geoportal/static-ngeo/js/apps/sass/vars_oeedit\.scss + - geoportal/interfaces/desktop_alt\.html\.mako + - geoportal/geomapfish_geoportal/static/images/background-layer-button\.png + - tests/test_testapp.py + +# Automated file system operations: +# Remove some files or directories: +# - action: remove +# paths: +# - +# Move a file: +# - action: move +# from: +# to: +upgrade_files: + - action: remove + paths: + - geoportal/tools/extract-messages.js diff --git a/CONST_CHANGELOG.txt b/CONST_CHANGELOG.txt index f5d7b6257..f58031fff 100644 --- a/CONST_CHANGELOG.txt +++ b/CONST_CHANGELOG.txt @@ -1,14 +1,28 @@ This file includes migration steps for each release of c2cgeoportal. ============= -Version 2.8.1 +Version 2.9.0 ============= -1. Update dependencies to use GDAL 3.7 +Information to know before starting the upgrade +=============================================== + +1. The build command will use Docker Compose version 2 (with the `docker compose` command). + +Information +=========== + +1. Hostname check: + We add a hostname check on the `came_from` parameter, in the oauth2 login, allowed by + `vars.authentication.allowed_hosts` and in the OGC server clear cache, allowed by `vars.allowed_hosts`. + The behavior change a little bit in the `shortener.allowed_hosts` and in the `authorized_referers`. + Now everywhere: + - If the hostname (with port) of the candidate URL equals to the request's header "Host", then it's OK. + - If the hostname (with port) of the candidate URL is in the allowed list, then it's OK. + And they should be netloc (hostname with port) without schema or path. - Use MapServer 8.0 with GDAL 3.7 (instead of 3.6) - Use QGIS server 3.28 with GDAL 3.7 (instead of 3.6) - Use GDAL 3.7 as based image (instead of 3.6) +2. We replace checks (formatting) done by `c2cciutils` by `pre-commit` hooks. + This will me more standard and transparent for the project. ============= Version 2.8.0 diff --git a/CONST_create_template/.github/workflows/main.yaml b/CONST_create_template/.github/workflows/main.yaml index 2c12c26e5..a8bde0e0a 100644 --- a/CONST_create_template/.github/workflows/main.yaml +++ b/CONST_create_template/.github/workflows/main.yaml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # To publish the images to be used on Kubernetes # - uses: camptocamp/initialise-gopass-summon-action@v2 @@ -33,8 +33,8 @@ jobs: # - run: make secrets # - run: cat env.secrets |grep '^[# A-Z0-9_]\+='|sed -e 's/^[# A-Z0-9_]\+=\(.*\)/::add-mask::\1/g' - - name: Checks - run: c2cciutils-checks + - name: Environment information + run: c2cciutils-env # - name: Initialize the acceptance tests # run: make acceptance-init diff --git a/CONST_create_template/.github/workflows/rebuild.yaml b/CONST_create_template/.github/workflows/rebuild.yaml index 3358348af..cd71fd158 100644 --- a/CONST_create_template/.github/workflows/rebuild.yaml +++ b/CONST_create_template/.github/workflows/rebuild.yaml @@ -10,7 +10,7 @@ env: # Requires CI_GPG_PRIVATE_KEY and GOPASS_CI_GITHUB_TOKEN secrets. # OPENSHIFT_PROJECT: gs-gmf-geomapfish # The release branches - HELM_RELEASE_NAMES: int-2-8,prod-2-8 + HELM_RELEASE_NAMES: int-2-9,prod-2-9 jobs: rebuild: @@ -22,11 +22,11 @@ jobs: fail-fast: false matrix: branch: - - int-2-8 - - prod-2-8 + - int-2-9 + - prod-2-9 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: ref: ${{ matrix.branch }} diff --git a/CONST_create_template/.github/workflows/update_l10n.yaml b/CONST_create_template/.github/workflows/update_l10n.yaml index a9bf46842..966a3e022 100644 --- a/CONST_create_template/.github/workflows/update_l10n.yaml +++ b/CONST_create_template/.github/workflows/update_l10n.yaml @@ -15,13 +15,13 @@ jobs: fail-fast: false matrix: include: - - branch: int-2-8 + - branch: int-2-9 base_url: int.customer.ch - - branch: prod-2-8 + - branch: prod-2-9 base_url: prod.customer.ch steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: ref: ${{ matrix.branch }} token: ${{ secrets.GOPASS_CI_GITHUB_TOKEN }} diff --git a/CONST_create_template/.pre-commit-config.yaml b/CONST_create_template/.pre-commit-config.yaml new file mode 100644 index 000000000..2518e8f65 --- /dev/null +++ b/CONST_create_template/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +# https://pre-commit.com/hooks.html + +ci: + autoupdate_schedule: quarterly + skip: + - ripsecrets + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: detect-private-key + - id: end-of-file-fixer + - id: trailing-whitespace + args: + - --markdown-linebreak-ext=.md + - id: mixed-line-ending + args: + - --fix=lf + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.1.0 + hooks: + - id: prettier + - repo: https://github.com/PyCQA/autoflake + rev: v2.3.1 + hooks: + - id: autoflake + - repo: https://github.com/PyCQA/isort + rev: 5.13.2 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black diff --git a/CONST_create_template/Dockerfile b/CONST_create_template/Dockerfile index a16720ee0..aa2c3eddb 100644 --- a/CONST_create_template/Dockerfile +++ b/CONST_create_template/Dockerfile @@ -62,7 +62,6 @@ RUN \ /usr/local/tomcat/webapps/ROOT/print-apps \ /etc/haproxy_dev \ /etc/haproxy \ - && adduser www-data root \ && sed 's#bind :80#bind *:443 ssl crt /etc/haproxy_dev/localhost.pem#g' /etc/haproxy/haproxy.cfg.tmpl \ > /etc/haproxy_dev/haproxy.cfg.tmpl \ && echo ' http-request set-header X-Forwarded-Proto https' >> /etc/haproxy_dev/haproxy.cfg.tmpl diff --git a/CONST_create_template/Makefile b/CONST_create_template/Makefile index ae6d8ca4a..38318f18f 100644 --- a/CONST_create_template/Makefile +++ b/CONST_create_template/Makefile @@ -16,30 +16,30 @@ update-po-from-url: ## Update the po files from the URL provide by PROJECT_PUBLI curl --fail --retry 5 --retry-delay 1 \ $(PROJECT_PUBLIC_URL)locale.pot > geoportal/${PACKAGE}_geoportal/locale/${PACKAGE}_geoportal-client${SUFFIX}.pot sed -i '/^"POT-Creation-Date: /d' geoportal/${PACKAGE}_geoportal/locale/${PACKAGE}_geoportal-client${SUFFIX}.pot - docker-compose run --rm -T tools update-po-only `id --user` `id --group` $(LANGUAGES) + docker compose run --rm -T tools update-po-only `id --user` `id --group` $(LANGUAGES) .PHONY: update-po update-po: ## Update the po files from the running composition - docker-compose exec -T tools sh -c "USER_ID=`id --user` GROUP_ID=`id --group` make --directory=geoportal update-po" + docker compose exec -T tools sh -c "USER_ID=`id --user` GROUP_ID=`id --group` make --directory=geoportal update-po" .PHONY: checks checks: prospector eslint ## Runs the checks .PHONY: prospector prospector: ## Runs the Prospector checks - docker-compose run --entrypoint= --no-deps --rm --volume=$(CURDIR)/geoportal:/app geoportal \ + docker compose run --entrypoint= --no-deps --rm --volume=$(CURDIR)/geoportal:/app geoportal \ prospector --output-format=pylint --die-on-tool-error .PHONY: eslint eslint: ## Runs the eslint checks - docker-compose run --entrypoint= --no-deps --rm --volume=$(CURDIR)/geoportal:/app geoportal \ + docker compose run --entrypoint= --no-deps --rm --volume=$(CURDIR)/geoportal:/app geoportal \ eslint $(find geomapfish -type f -name '*.js' -print 2> /dev/null) - docker-compose run --entrypoint= --no-deps --rm --volume=$(CURDIR)/geoportal:/app geoportal \ + docker compose run --entrypoint= --no-deps --rm --volume=$(CURDIR)/geoportal:/app geoportal \ eslint $(find geomapfish -type f -name '*.ts' -print 2> /dev/null) .PHONY: qgis qgis: ## Run QGIS desktop - docker-compose -f docker-compose.yaml -f docker-compose-qgis.yaml run --rm qgis + docker compose -f docker-compose.yaml -f docker-compose-qgis.yaml run --rm qgis secrets.tar.bz2.gpg: env.secrets ## Encrypt the secrets for committing changes tar -jcf secrets.tar.bz2 $^ @@ -57,14 +57,14 @@ secrets: ## Decrypt the secrets.tar.bz2.gpg file .PHONY: acceptance-init acceptance-init: ## Initialize the acceptance tests - docker-compose --file=docker-compose.yaml --file=docker-compose-db.yaml up -d db tools - docker-compose exec -T tools wait-db - docker-compose exec -T tools psql --command="DROP EXTENSION IF EXISTS postgis CASCADE" + docker compose --file=docker-compose.yaml --file=docker-compose-db.yaml up -d db tools + docker compose exec -T tools wait-db + docker compose exec -T tools psql --command="DROP EXTENSION IF EXISTS postgis CASCADE" scripts/db-restore --docker-compose-file=docker-compose.yaml --docker-compose-file=docker-compose-db.yaml \ --arg=--clean --arg=--if-exists --arg=--verbose $(DUMP_FILE) - docker-compose --file=docker-compose.yaml --file=docker-compose-db.yaml up -d + docker compose --file=docker-compose.yaml --file=docker-compose-db.yaml up -d .PHONY: acceptance acceptance: ## Run the acceptance tests - docker-compose exec -T tools pytest -vv tests/ + docker compose exec -T tools pytest -vv tests/ ci/docker-compose-check diff --git a/CONST_create_template/README.rst b/CONST_create_template/README.rst index daaf08928..5062c105d 100644 --- a/CONST_create_template/README.rst +++ b/CONST_create_template/README.rst @@ -1,7 +1,7 @@ demo_geomapfish project =================== -Read the `Documentation `_ +Read the `Documentation `_ Checkout -------- @@ -24,6 +24,6 @@ Run .. code:: - docker-compose up -d + docker compose up -d .. Feel free to add project-specific things. diff --git a/CONST_create_template/build b/CONST_create_template/build index 2a3a67f2b..8acca59a6 100755 --- a/CONST_create_template/build +++ b/CONST_create_template/build @@ -22,17 +22,13 @@ def run( args: argparse.Namespace, command: List[str], exit_on_error: bool = True, **kwargs: Any ) -> Optional[CompletedProcess]: if args.verbose or args.dry_run: - print(" ".join([shlex.quote(c) for c in command])) + print(shlex.join(command)) if not args.dry_run or "stdout" in kwargs: if args.stack_trace and exit_on_error and not "checks" in kwargs: kwargs["check"] = True process = subprocess.run(command, **kwargs) # nosec if exit_on_error and process.returncode != 0: - print( - "An error occurred during execution of `{}`".format( - " ".join([shlex.quote(c) for c in command]) - ) - ) + print(f"An error occurred during execution of `{shlex.join(command)}`") sys.exit(process.returncode) return process return None @@ -103,6 +99,7 @@ def main() -> None: sys.exit(1) sys.exit(0) + docker_compose_command = ["docker", "compose"] with open("project.yaml", encoding="utf-8") as project_file: project_env = yaml.load(project_file, Loader=yaml.SafeLoader)["env"] if len(args.env_files) != project_env["required_args"]: @@ -112,7 +109,7 @@ def main() -> None: print("Use env files: {}".format(", ".join(env_files))) for env_file in env_files: if not os.path.exists(env_file): - print("Error: the env file '{env_file}' does not exist.".format(env_file=env_file)) + print(f"Error: the env file '{env_file}' does not exist.") sys.exit(1) with open(".env", "w", encoding="utf-8") as dest: @@ -128,18 +125,18 @@ def main() -> None: git_hash = run(args, ["git", "rev-parse", "HEAD"], stdout=subprocess.PIPE).stdout.decode().strip() - dest.write("SIMPLE={}\n".format(str(simple).upper())) - dest.write("GIT_HASH={git_hash}\n".format(git_hash=git_hash)) + dest.write(f"SIMPLE={str(simple).upper()}\n") + dest.write(f"GIT_HASH={git_hash}\n") dest.write("# Used env files: {}\n".format(", ".join(env_files))) if not args.env: - docker_compose_build_cmd = ["docker-compose", "build"] + docker_compose_build_cmd = [*docker_compose_command, "build"] if not args.no_pull: # Pull all the images if not args.service: - run(args, ["docker-compose", "pull", "--ignore-pull-failures"]) # nosec + run(args, [*docker_compose_command, "pull", "--ignore-buildable"]) # nosec docker_compose_build_cmd.append("--pull") if args.service: @@ -163,7 +160,7 @@ def main() -> None: service for service in run( args, - ["docker-compose", "ps", "--services", "--all"], + [*docker_compose_command, "ps", "--services", "--all"], stdout=subprocess.PIPE, exit_on_error=True, ) @@ -173,9 +170,9 @@ def main() -> None: ] if args.reload is not None: - run(args, ["docker-compose", "rm", "--force", "-v", "config"]) + run(args, [*docker_compose_command, "rm", "--force", "-v", "config"]) for service in services: - run(args, ["docker-compose", "up", "--detach", "--force-recreate", service]) + run(args, [*docker_compose_command, "up", "--detach", "--force-recreate", service]) if __name__ == "__main__": diff --git a/CONST_create_template/ci/config.yaml b/CONST_create_template/ci/config.yaml index 69d38da9f..8b738862e 100644 --- a/CONST_create_template/ci/config.yaml +++ b/CONST_create_template/ci/config.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/camptocamp/c2cciutils/1.4/c2cciutils/schema.json +# yaml-language-server: $schema=https://raw.githubusercontent.com/camptocamp/c2cciutils/master/c2cciutils/schema.json checks: codespell: False diff --git a/CONST_create_template/ci/docker-compose-check b/CONST_create_template/ci/docker-compose-check index 5feb9c31b..ed31693b9 100755 --- a/CONST_create_template/ci/docker-compose-check +++ b/CONST_create_template/ci/docker-compose-check @@ -11,7 +11,7 @@ def _main() -> None: services = [ s.strip() - for s in subprocess.run(["docker-compose", "ps"], check=True, stdout=subprocess.PIPE) + for s in subprocess.run(["docker", "compose", "ps"], check=True, stdout=subprocess.PIPE) .stdout.decode("utf-8") .splitlines() ] diff --git a/CONST_create_template/ci/requirements.txt b/CONST_create_template/ci/requirements.txt index 993e22779..140d774a5 100644 --- a/CONST_create_template/ci/requirements.txt +++ b/CONST_create_template/ci/requirements.txt @@ -1 +1 @@ -c2cciutils[checks,publish]==1.4.16 +c2cciutils[checks,publish]==1.6.21 diff --git a/CONST_create_template/docker-compose-db.yaml b/CONST_create_template/docker-compose-db.yaml index 6e5e99221..800dc8727 100644 --- a/CONST_create_template/docker-compose-db.yaml +++ b/CONST_create_template/docker-compose-db.yaml @@ -1,7 +1,5 @@ # This file is used by the acceptance tests to have a local database. -version: '2.3' - volumes: postgresql_data: diff --git a/CONST_create_template/docker-compose-lib.yaml b/CONST_create_template/docker-compose-lib.yaml index ef39976cb..8af69fa0f 100644 --- a/CONST_create_template/docker-compose-lib.yaml +++ b/CONST_create_template/docker-compose-lib.yaml @@ -1,7 +1,5 @@ # This file is managed by c2cgeoportal, it contains the default services configuration -version: '2.3' - services: config: image: ${DOCKER_BASE}-config:${DOCKER_TAG} @@ -77,7 +75,7 @@ services: - PGOPTIONS mapserver: - image: camptocamp/mapserver:8.0-gdal3.7 + image: camptocamp/mapserver:8.0-gdal3.6 user: www-data restart: unless-stopped entrypoint: [] @@ -137,7 +135,7 @@ services: restart: unless-stopped redis: - image: &redis-image redis:7.0 + image: redis:7.2 user: www-data restart: unless-stopped command: @@ -154,21 +152,32 @@ services: - '30' redis_master: - image: *redis-image + image: bitnami/redis:7.2.5 + environment: + - REDIS_REPLICATION_MODE=master + - ALLOW_EMPTY_PASSWORD=yes redis_slave: - image: *redis-image - command: redis-server --slaveof redis_master 6379 + image: bitnami/redis:7.2.5 + environment: + - REDIS_REPLICATION_MODE=slave + - REDIS_MASTER_HOST=redis_master + - ALLOW_EMPTY_PASSWORD=yes + depends_on: + - redis_master redis_sentinel: - image: camptocamp/c2cwsgiutils-redis-sentinel:6 + image: bitnami/redis-sentinel:7.2.5 environment: - - MASTER_NAME=mymaster - - QUORUM=1 - - MASTER=redis_master + - REDIS_MASTER_HOST=redis_master + - REDIS_MASTER_SET=mymaster + - ALLOW_EMPTY_PASSWORD=yes + depends_on: + - redis_master + - redis_slave tilecloudchain: - image: &tilecloudchain-image camptocamp/tilecloud-chain:1.17 + image: &tilecloudchain-image camptocamp/tilecloud-chain:1.20 user: www-data restart: unless-stopped environment: @@ -217,7 +226,7 @@ services: user: www-data restart: unless-stopped entrypoint: - - generate_tiles + - generate-tiles - --role=slave - --daemon environment: diff --git a/CONST_create_template/docker-compose-qgis.yaml b/CONST_create_template/docker-compose-qgis.yaml index af3860dd7..3a2bd3506 100644 --- a/CONST_create_template/docker-compose-qgis.yaml +++ b/CONST_create_template/docker-compose-qgis.yaml @@ -1,7 +1,5 @@ # This file is used to run QGIS client from the Docker image -version: '2' - services: qgis: extends: diff --git a/CONST_create_template/docker-compose.override.sample.yaml b/CONST_create_template/docker-compose.override.sample.yaml index 7c460042b..2d2359f70 100644 --- a/CONST_create_template/docker-compose.override.sample.yaml +++ b/CONST_create_template/docker-compose.override.sample.yaml @@ -1,8 +1,6 @@ # This file can be renamed as `docker-compose.override.yaml` and uncomment the desired lines for # development. The file `docker-compose.override.yaml` is ignored by Git by default. -version: '2.3' - services: geoportal: user: root @@ -27,6 +25,7 @@ services: ports: - 5678:5678 # For remote debugging using Visual Studio Code + # Also uncomment the PRINT_URL in geoportal # print: # extends: @@ -45,10 +44,6 @@ services: # - QGIS_SERVER_LOG_LEVEL=0 # - QGIS_CATCH_SEGV=1 # The result stack traces will be available in /var/log/qgis.log - tools: - volumes_from: - - config:rw - # # For Javascript project development. # The debug application will be available at ``https:////dev/.html``. # webpack_dev_server: diff --git a/CONST_create_template/docker-compose.yaml b/CONST_create_template/docker-compose.yaml index 2b70200bc..748dd4073 100644 --- a/CONST_create_template/docker-compose.yaml +++ b/CONST_create_template/docker-compose.yaml @@ -1,7 +1,5 @@ # The project Docker compose file. -version: '2.3' - volumes: postgresql_data: diff --git a/CONST_create_template/env.default b/CONST_create_template/env.default index 72f4a308e..725092046 100644 --- a/CONST_create_template/env.default +++ b/CONST_create_template/env.default @@ -1,7 +1,7 @@ # Default values for c2cgeoportal -GEOMAPFISH_VERSION=2.8.1.110 -GEOMAPFISH_MAIN_VERSION=2.8 -GEOMAPFISH_MAIN_MINOR_VERSION=2.8.1 +GEOMAPFISH_VERSION=2.9 +GEOMAPFISH_MAIN_VERSION=2.9 +GEOMAPFISH_MAIN_MINOR_VERSION=2.9.0 COMPOSE_PROJECT_NAME=geomapfish PACKAGE=geomapfish SRID=2056 diff --git a/CONST_create_template/env.project b/CONST_create_template/env.project index d3ef88947..5f55fe3c6 100644 --- a/CONST_create_template/env.project +++ b/CONST_create_template/env.project @@ -58,7 +58,7 @@ C2C_REDIS_URL=redis://redis:6379/0 # Set a strong password here for authentication on technical interfaces behind path /c2c C2C_SECRET= -# Or use connection via GitHub, see: https://camptocamp.github.io/c2cgeoportal/2.8/integrator/c2cwsgiutils.html#authentication +# Or use connection via GitHub, see: https://camptocamp.github.io/c2cgeoportal/2.9/integrator/c2cwsgiutils.html#authentication C2C_AUTH_GITHUB_REPOSITORY=camptocamp/geomapfish C2C_AUTH_GITHUB_ACCESS_TYPE=admin C2C_AUTH_GITHUB_CLIENT_ID=210aefe26259de1e9532 diff --git a/CONST_create_template/geoportal/geomapfish_geoportal/locale/de/LC_MESSAGES/geomapfish_geoportal-client.po b/CONST_create_template/geoportal/geomapfish_geoportal/locale/de/LC_MESSAGES/geomapfish_geoportal-client.po index 880b07871..fd1e53a94 100644 --- a/CONST_create_template/geoportal/geomapfish_geoportal/locale/de/LC_MESSAGES/geomapfish_geoportal-client.po +++ b/CONST_create_template/geoportal/geomapfish_geoportal/locale/de/LC_MESSAGES/geomapfish_geoportal-client.po @@ -1,11 +1,12 @@ # # Translators: -# Stéphane Brunner , 2022 +# Stéphane Brunner , 2023 +# Wolfgang Kaltz , 2023 # msgid "" msgstr "" "Project-Id-Version: \n" -"Last-Translator: Stéphane Brunner , 2022\n" +"Last-Translator: Wolfgang Kaltz , 2023\n" "Language-Team: German (https://app.transifex.com/camptocamp/teams/36764/de/)\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -75,8 +76,8 @@ msgid "" "Draw a line on the map to display the corresponding elevation profile.\n" " Use double-click to finish the drawing." msgstr "" -"Zeichnen Sie eine Linie auf die Karte, um das entsprechende Höhenprofil " -"anzuzeigen. Schliessen Sie mit einem Doppelklick ab." +"Zeichnen Sie eine Linie auf die Karte, um das entsprechende Höhenprofil anzuzeigen.\n" +" Schliessen Sie mit einem Doppelklick ab." #: contribs/gmf/apps/desktop_alt.html:179 #: contribs/gmf/apps/desktop_alt/index.html.ejs:179 @@ -84,8 +85,8 @@ msgid "" "Draw a line on the map to display the corresponding elevation profile.\n" " Use double-click to finish the drawing." msgstr "" -"Zeichnen Sie eine Linie auf die Karte, um das entsprechende Höhenprofil " -"anzuzeigen. Schliessen Sie mit einem Doppelklick ab." +"Zeichnen Sie eine Linie auf die Karte, um das entsprechende Höhenprofil anzuzeigen.\n" +" Schliessen Sie mit einem Doppelklick ab." #: contribs/gmf/apps/desktop.html:149 contribs/gmf/apps/desktop.html:66 #: contribs/gmf/apps/desktop/index.html.ejs:149 @@ -135,7 +136,7 @@ msgstr "Höhenprofil" #: contribs/gmf/apps/desktop_alt/index.html.ejs:118 #: contribs/gmf/apps/desktop_alt/index.html.ejs:128 msgid "Filter" -msgstr "Filter" +msgstr "Filtrieren" #: contribs/gmf/apps/desktop_alt.html:207 #: contribs/gmf/apps/desktop_alt/index.html.ejs:207 @@ -250,7 +251,7 @@ msgstr "Abfrage" #: contribs/gmf/apps/desktop_alt.html:264 #: contribs/gmf/apps/desktop_alt/index.html.ejs:264 msgid "Routing" -msgstr "Routing" +msgstr "Routenplanung" #: contribs/gmf/apps/desktop.html:221 contribs/gmf/apps/desktop.html:85 #: contribs/gmf/apps/desktop/index.html.ejs:221 @@ -338,10 +339,10 @@ msgid "" "You're using the mobile application. Check out the standard application." msgstr "" -"Sie verwenden die mobile Anwendung. Wechsel zur Standard-Anwendung." #: contribs/gmf/apps/desktop_alt.html:92 #: contribs/gmf/apps/desktop_alt/index.html.ejs:92 msgid "debug" -msgstr "debug" +msgstr "Debug" diff --git a/CONST_create_template/geoportal/geomapfish_geoportal/locale/fr/LC_MESSAGES/geomapfish_geoportal-client.po b/CONST_create_template/geoportal/geomapfish_geoportal/locale/fr/LC_MESSAGES/geomapfish_geoportal-client.po index ebd199827..0b894bd03 100644 --- a/CONST_create_template/geoportal/geomapfish_geoportal/locale/fr/LC_MESSAGES/geomapfish_geoportal-client.po +++ b/CONST_create_template/geoportal/geomapfish_geoportal/locale/fr/LC_MESSAGES/geomapfish_geoportal-client.po @@ -1,11 +1,11 @@ # # Translators: -# Stéphane Brunner , 2022 +# Stéphane Brunner , 2023 # msgid "" msgstr "" "Project-Id-Version: \n" -"Last-Translator: Stéphane Brunner , 2022\n" +"Last-Translator: Stéphane Brunner , 2023\n" "Language-Team: French (https://app.transifex.com/camptocamp/teams/36764/fr/)\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" diff --git a/CONST_create_template/geoportal/geomapfish_geoportal/static/apihelp/index.html.tmpl b/CONST_create_template/geoportal/geomapfish_geoportal/static/apihelp/index.html.tmpl index 2e49d9b56..557da88d0 100644 --- a/CONST_create_template/geoportal/geomapfish_geoportal/static/apihelp/index.html.tmpl +++ b/CONST_create_template/geoportal/geomapfish_geoportal/static/apihelp/index.html.tmpl @@ -1,4 +1,4 @@ - + diff --git a/CONST_create_template/geoportal/vars.yaml b/CONST_create_template/geoportal/vars.yaml index 78ad75a8f..ac36a0005 100644 --- a/CONST_create_template/geoportal/vars.yaml +++ b/CONST_create_template/geoportal/vars.yaml @@ -303,6 +303,9 @@ vars: host: '{REDIS_HOST}' port: '{REDIS_PORT}' db: '{REDIS_DB}' + password: '{REDIS_PASSWORD}' + connection_kwargs: + ssl: '{REDIS_SSL}' # Kubernetes version # arguments: &redis-cache-arguments # sentinels: @@ -347,7 +350,6 @@ update_paths: - admin_interface.functionalities - admin_interface.available_in_templates - api - - authorized_referers - cache.std.arguments - cache.ogc-server.arguments - cache.obj @@ -418,3 +420,7 @@ runtime_postprocess: - expression: int({}) vars: - cache.std.arguments.port + - expression: str({}).lower() in ("true", "yes", "1") + vars: + - cache.std.arguments.connection_kwargs.ssl + - cache.ogc-server.arguments.connection_kwargs.ssl diff --git a/CONST_create_template/scripts/db-backup b/CONST_create_template/scripts/db-backup index faedb3ce8..f2b133b3d 100755 --- a/CONST_create_template/scripts/db-backup +++ b/CONST_create_template/scripts/db-backup @@ -89,7 +89,8 @@ def main() -> None: else: subprocess.run( [ - "docker-compose", + "docker", + "compose", "exec", "-T", "tools", diff --git a/CONST_create_template/scripts/db-restore b/CONST_create_template/scripts/db-restore index 7412cd801..5da9984ba 100755 --- a/CONST_create_template/scripts/db-restore +++ b/CONST_create_template/scripts/db-restore @@ -43,7 +43,7 @@ def main() -> None: "--docker-compose-file", action="append", default=[], - help="The docker-compose file to used.", + help="The docker compose file to used.", ) parser.add_argument( "--arg", @@ -92,8 +92,8 @@ def main() -> None: ) else: subprocess.run( - ["docker-compose"] - + ["--file={}".format(f) for f in args.docker_compose_file] + ["docker", "compose"] + + [f"--file={f}" for f in args.docker_compose_file] + [ "exec", "-T", diff --git a/CONST_create_template/tests/test_app.py b/CONST_create_template/tests/test_app.py index a1f91b5eb..f4f246ba6 100644 --- a/CONST_create_template/tests/test_app.py +++ b/CONST_create_template/tests/test_app.py @@ -1,5 +1,3 @@ -from typing import Dict - import pytest import requests @@ -7,7 +5,7 @@ @pytest.mark.parametrize( "url,params,timeout", [ - ("https://front", {}, 10), + ("https://front/", {}, 10), ("https://front/themes", {}, 120), ("https://front/static-geomapfish/0/locales/fr.json", {}, 2), ("https://front/dynamic.json", {"interface": "desktop"}, 10), @@ -25,7 +23,7 @@ ), ], ) -def test_url(url: str, params: Dict[str, str], timeout: int) -> None: +def test_url(url: str, params: dict[str, str], timeout: int) -> None: """Tests that some URL didn't return an error.""" response = requests.get(url, params=params, verify=False, timeout=timeout) # nosec assert response.status_code == 200, response.text diff --git a/CONST_create_template/tests/test_testapp.py b/CONST_create_template/tests/test_testapp.py index 3288581d0..aad6500ef 100644 --- a/CONST_create_template/tests/test_testapp.py +++ b/CONST_create_template/tests/test_testapp.py @@ -34,7 +34,7 @@ def test_desktop_alt(url: str) -> None: assert response.status_code == 200, response.text assert re.search( - r'', + r'', response.text, ), response.text assert re.search(r' Optional[CompletedProcess]: if args.verbose or args.dry_run: - print(" ".join([shlex.quote(c) for c in command])) + print(shlex.join(command)) if not args.dry_run or "stdout" in kwargs: if args.stack_trace and exit_on_error and not "checks" in kwargs: kwargs["check"] = True process = subprocess.run(command, **kwargs) # nosec if exit_on_error and process.returncode != 0: - print( - "An error occurred during execution of `{}`".format( - " ".join([shlex.quote(c) for c in command]) - ) - ) + print(f"An error occurred during execution of `{shlex.join(command)}`") sys.exit(process.returncode) return process return None @@ -103,6 +99,7 @@ def main() -> None: sys.exit(1) sys.exit(0) + docker_compose_command = ["docker", "compose"] with open("project.yaml", encoding="utf-8") as project_file: project_env = yaml.load(project_file, Loader=yaml.SafeLoader)["env"] if len(args.env_files) != project_env["required_args"]: @@ -112,7 +109,7 @@ def main() -> None: print("Use env files: {}".format(", ".join(env_files))) for env_file in env_files: if not os.path.exists(env_file): - print("Error: the env file '{env_file}' does not exist.".format(env_file=env_file)) + print(f"Error: the env file '{env_file}' does not exist.") sys.exit(1) with open(".env", "w", encoding="utf-8") as dest: @@ -128,18 +125,18 @@ def main() -> None: git_hash = run(args, ["git", "rev-parse", "HEAD"], stdout=subprocess.PIPE).stdout.decode().strip() - dest.write("SIMPLE={}\n".format(str(simple).upper())) - dest.write("GIT_HASH={git_hash}\n".format(git_hash=git_hash)) + dest.write(f"SIMPLE={str(simple).upper()}\n") + dest.write(f"GIT_HASH={git_hash}\n") dest.write("# Used env files: {}\n".format(", ".join(env_files))) if not args.env: - docker_compose_build_cmd = ["docker-compose", "build"] + docker_compose_build_cmd = [*docker_compose_command, "build"] if not args.no_pull: # Pull all the images if not args.service: - run(args, ["docker-compose", "pull", "--ignore-pull-failures"]) # nosec + run(args, [*docker_compose_command, "pull", "--ignore-buildable"]) # nosec docker_compose_build_cmd.append("--pull") if args.service: @@ -163,7 +160,7 @@ def main() -> None: service for service in run( args, - ["docker-compose", "ps", "--services", "--all"], + [*docker_compose_command, "ps", "--services", "--all"], stdout=subprocess.PIPE, exit_on_error=True, ) @@ -173,9 +170,9 @@ def main() -> None: ] if args.reload is not None: - run(args, ["docker-compose", "rm", "--force", "-v", "config"]) + run(args, [*docker_compose_command, "rm", "--force", "-v", "config"]) for service in services: - run(args, ["docker-compose", "up", "--detach", "--force-recreate", service]) + run(args, [*docker_compose_command, "up", "--detach", "--force-recreate", service]) if __name__ == "__main__": diff --git a/ci/docker-compose-check b/ci/docker-compose-check index 5feb9c31b..ed31693b9 100755 --- a/ci/docker-compose-check +++ b/ci/docker-compose-check @@ -11,7 +11,7 @@ def _main() -> None: services = [ s.strip() - for s in subprocess.run(["docker-compose", "ps"], check=True, stdout=subprocess.PIPE) + for s in subprocess.run(["docker", "compose", "ps"], check=True, stdout=subprocess.PIPE) .stdout.decode("utf-8") .splitlines() ] diff --git a/ci/requirements.txt b/ci/requirements.txt index 993e22779..140d774a5 100644 --- a/ci/requirements.txt +++ b/ci/requirements.txt @@ -1 +1 @@ -c2cciutils[checks,publish]==1.4.16 +c2cciutils[checks,publish]==1.6.21 diff --git a/docker-compose-lib.yaml b/docker-compose-lib.yaml index ef39976cb..8af69fa0f 100644 --- a/docker-compose-lib.yaml +++ b/docker-compose-lib.yaml @@ -1,7 +1,5 @@ # This file is managed by c2cgeoportal, it contains the default services configuration -version: '2.3' - services: config: image: ${DOCKER_BASE}-config:${DOCKER_TAG} @@ -77,7 +75,7 @@ services: - PGOPTIONS mapserver: - image: camptocamp/mapserver:8.0-gdal3.7 + image: camptocamp/mapserver:8.0-gdal3.6 user: www-data restart: unless-stopped entrypoint: [] @@ -137,7 +135,7 @@ services: restart: unless-stopped redis: - image: &redis-image redis:7.0 + image: redis:7.2 user: www-data restart: unless-stopped command: @@ -154,21 +152,32 @@ services: - '30' redis_master: - image: *redis-image + image: bitnami/redis:7.2.5 + environment: + - REDIS_REPLICATION_MODE=master + - ALLOW_EMPTY_PASSWORD=yes redis_slave: - image: *redis-image - command: redis-server --slaveof redis_master 6379 + image: bitnami/redis:7.2.5 + environment: + - REDIS_REPLICATION_MODE=slave + - REDIS_MASTER_HOST=redis_master + - ALLOW_EMPTY_PASSWORD=yes + depends_on: + - redis_master redis_sentinel: - image: camptocamp/c2cwsgiutils-redis-sentinel:6 + image: bitnami/redis-sentinel:7.2.5 environment: - - MASTER_NAME=mymaster - - QUORUM=1 - - MASTER=redis_master + - REDIS_MASTER_HOST=redis_master + - REDIS_MASTER_SET=mymaster + - ALLOW_EMPTY_PASSWORD=yes + depends_on: + - redis_master + - redis_slave tilecloudchain: - image: &tilecloudchain-image camptocamp/tilecloud-chain:1.17 + image: &tilecloudchain-image camptocamp/tilecloud-chain:1.20 user: www-data restart: unless-stopped environment: @@ -217,7 +226,7 @@ services: user: www-data restart: unless-stopped entrypoint: - - generate_tiles + - generate-tiles - --role=slave - --daemon environment: diff --git a/docker-compose-qgis.yaml b/docker-compose-qgis.yaml index af3860dd7..3a2bd3506 100644 --- a/docker-compose-qgis.yaml +++ b/docker-compose-qgis.yaml @@ -1,7 +1,5 @@ # This file is used to run QGIS client from the Docker image -version: '2' - services: qgis: extends: diff --git a/env.default b/env.default index 9c824bd9a..725092046 100644 --- a/env.default +++ b/env.default @@ -1,6 +1,7 @@ # Default values for c2cgeoportal GEOMAPFISH_VERSION=2.9 GEOMAPFISH_MAIN_VERSION=2.9 +GEOMAPFISH_MAIN_MINOR_VERSION=2.9.0 COMPOSE_PROJECT_NAME=geomapfish PACKAGE=geomapfish SRID=2056 diff --git a/geoportal/CONST_config-schema.yaml b/geoportal/CONST_config-schema.yaml index 4424e910e..3c3167bfd 100644 --- a/geoportal/CONST_config-schema.yaml +++ b/geoportal/CONST_config-schema.yaml @@ -409,6 +409,11 @@ mapping: model: type: str required: True + # Host allowed in the OGC server clear cache + allowed_hosts: + type: seq + sequence: + - type: str getitfixed: type: map diff --git a/geoportal/CONST_vars.yaml b/geoportal/CONST_vars.yaml index a417d7ab6..17ef37b04 100644 --- a/geoportal/CONST_vars.yaml +++ b/geoportal/CONST_vars.yaml @@ -21,13 +21,13 @@ vars: pool_recycle: '{SQLALCHEMY_POOL_RECYCLE}' pool_size: '{SQLALCHEMY_POOL_SIZE}' max_overflow: '{SQLALCHEMY_MAX_OVERFLOW}' - executemany_mode: batch + executemany_mode: values_plus_batch sqlalchemy_slave: url: postgresql://{PGUSER}:{PGPASSWORD}@{PGHOST_SLAVE}:{PGPORT_SLAVE}/{PGDATABASE}?sslmode={PGSSLMODE} pool_recycle: '{SQLALCHEMY_SLAVE_POOL_RECYCLE}' pool_size: '{SQLALCHEMY_SLAVE_POOL_SIZE}' max_overflow: '{SQLALCHEMY_SLAVE_MAX_OVERFLOW}' - executemany_mode: batch + executemany_mode: values_plus_batch # Session backend session: @@ -51,7 +51,6 @@ vars: ns: - geomapfish defaultNS: geomapfish - keySeparator: false debug: false detection: order: @@ -822,7 +821,7 @@ vars: description: > MapServer substitution of a variable in the mapfile. See the documentation here: - https://camptocamp.github.io/c2cgeoportal/2.8/administrator/mapfile.html?highlight=mapserver_substitution#variable-substitution + https://camptocamp.github.io/c2cgeoportal/2.9/administrator/mapfile.html?highlight=mapserver_substitution#variable-substitution - name: filterable_layers description: > Grant access for filtering considered layer. @@ -935,8 +934,6 @@ vars: shortener: # The base of created URL base_url: '{VISIBLE_WEB_PROTOCOL}://{VISIBLE_WEB_HOST}{VISIBLE_ENTRY_POINT}s/' - allowed_hosts: - - '{VISIBLE_WEB_HOST}' length: 4 # Define whether the MapServer proxy should hide the OGC capabilities. @@ -954,10 +951,13 @@ vars: lingua_extractor: {} content_security_policy_main_default_src_extra: '' + # Google Maps uses map.google.com and map.googleapis.com + # More info: https://developers.google.com/maps/documentation/javascript/content-security-policy?hl=fr#allowlist_csp + # Google Analytics 4 uses googletagmanager.com + # More info: https://developers.google.com/tag-platform/tag-manager/csp?hl=fr#google_analytics_4_google_analytics content_security_policy_main_script_src_extra: ' - https://maps.google.com/ - https://maps.googleapis.com/ - https://www.google-analytics.com/ + https://*.google.com/ + https://*.googleapis.com/ https://*.googletagmanager.com/' content_security_policy_main_style_src_extra: ' https://fonts.googleapis.com/' @@ -1241,8 +1241,7 @@ vars: level: 10 # What web page is authorized to use the API - authorized_referers: - - '{VISIBLE_WEB_PROTOCOL}://{VISIBLE_WEB_HOST}/' + authorized_referers: [] metrics: memory_maps_rss: False @@ -1335,6 +1334,10 @@ runtime_environment: default: '30' - name: REDIS_LOCK_TIMEOUT default: '120' # Two minutes + - name: REDIS_PASSWORD + default: '' + - name: REDIS_SSL + default: 'false' - name: REDIS_EXPIRATION_TIME default: '86400' # One day - name: TILEGENERATION_SQS_QUEUE diff --git a/geoportal/vars.yaml b/geoportal/vars.yaml index 28cd47336..ff719f2b9 100644 --- a/geoportal/vars.yaml +++ b/geoportal/vars.yaml @@ -891,7 +891,6 @@ update_paths: - admin_interface.functionalities - admin_interface.available_in_templates - api - - authorized_referers - cache.std.arguments - cache.ogc-server.arguments - cache.obj @@ -1003,5 +1002,11 @@ environment: runtime_postprocess: - expression: str({}).lower() in ("true", "yes", "1") vars: +<<<<<<< ours +======= + - cache.std.arguments.port + - expression: str({}).lower() in ("true", "yes", "1") + vars: +>>>>>>> theirs - cache.std.arguments.connection_kwargs.ssl - cache.ogc-server.arguments.connection_kwargs.ssl diff --git a/ngeo.diff b/ngeo.diff new file mode 100644 index 000000000..f65c21b95 --- /dev/null +++ b/ngeo.diff @@ -0,0 +1,30 @@ +diff --git a/geoportal/vars.yaml b/geoportal/vars.yaml +index 78ad75a..ac36a00 100644 +--- a/geoportal/vars.yaml ++++ b/geoportal/vars.yaml +@@ -303,6 +303,9 @@ vars: + host: '{REDIS_HOST}' + port: '{REDIS_PORT}' + db: '{REDIS_DB}' ++ password: '{REDIS_PASSWORD}' ++ connection_kwargs: ++ ssl: '{REDIS_SSL}' + # Kubernetes version + # arguments: &redis-cache-arguments + # sentinels: +@@ -347,7 +350,6 @@ update_paths: + - admin_interface.functionalities + - admin_interface.available_in_templates + - api +- - authorized_referers + - cache.std.arguments + - cache.ogc-server.arguments + - cache.obj +@@ -418,3 +420,7 @@ runtime_postprocess: + - expression: int({}) + vars: + - cache.std.arguments.port ++ - expression: str({}).lower() in ("true", "yes", "1") ++ vars: ++ - cache.std.arguments.connection_kwargs.ssl ++ - cache.ogc-server.arguments.connection_kwargs.ssl diff --git a/pyproject.toml b/pyproject.toml index 4dc4297ea..f1c321984 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,9 +5,3 @@ target-version = ['py39'] [tool.isort] profile = "black" line_length = 110 - -[tool.poetry] -name = "GeoMapFish demo" -version = "0.0.0" -description = "GeoMapFish demo" -authors = ["Camptocamp"] diff --git a/scripts/db-backup b/scripts/db-backup index faedb3ce8..f2b133b3d 100755 --- a/scripts/db-backup +++ b/scripts/db-backup @@ -89,7 +89,8 @@ def main() -> None: else: subprocess.run( [ - "docker-compose", + "docker", + "compose", "exec", "-T", "tools", diff --git a/scripts/db-restore b/scripts/db-restore index 7412cd801..5da9984ba 100755 --- a/scripts/db-restore +++ b/scripts/db-restore @@ -43,7 +43,7 @@ def main() -> None: "--docker-compose-file", action="append", default=[], - help="The docker-compose file to used.", + help="The docker compose file to used.", ) parser.add_argument( "--arg", @@ -92,8 +92,8 @@ def main() -> None: ) else: subprocess.run( - ["docker-compose"] - + ["--file={}".format(f) for f in args.docker_compose_file] + ["docker", "compose"] + + [f"--file={f}" for f in args.docker_compose_file] + [ "exec", "-T", diff --git a/upgrade b/upgrade new file mode 100755 index 000000000..c52341095 --- /dev/null +++ b/upgrade @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2019-2023, Camptocamp SA +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: + +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# The views and conclusions contained in the software and documentation are those +# of the authors and should not be interpreted as representing official policies, +# either expressed or implied, of the FreeBSD Project. + + +import argparse +import os +import platform +import re +import subprocess +import sys + +parser = argparse.ArgumentParser(description="Upgrade the project") +parser.add_argument( + "--debug", help="Path to c2cgeoportal source folder to be able to debug the upgrade procedure" +) +parser.add_argument("version", help="the version to upgrade to (master or x.y.z)") +parser.add_argument("step", nargs="?", help="the step to run") +parser_finalize = argparse.ArgumentParser(description="Upgrade the project", add_help=False) +parser_finalize.add_argument("--finalize", action="store_true", help="finalize the upgrade") +parser_finalize.add_argument("--help", action="help", help="show this help message and exit") +parser_finalize.add_argument("build_arg", nargs="*", help="build arguments") + +if len(sys.argv) >= 2 and sys.argv[1] == "--finalize": + args = parser_finalize.parse_args() + + if platform.system() == "Windows": + code = subprocess.call(["python", "build"] + args.build_arg) + else: + code = subprocess.call(["./build"] + args.build_arg) + if code != 0: + sys.exit(code) + + subprocess.call(["docker", "compose", "down", "--remove-orphans"]) + subprocess.call( + ["docker", "compose", "pull", "--ignore-pull-failures"], + env={**os.environ, "DOCKER_TAG": "unexisting"}, + ) + subprocess.check_call(["docker", "compose", "up", "-d"]) + subprocess.check_call( + [ + "docker", + "compose", + "exec", + "geoportal", + "alembic", + "--name=main", + "--config=alembic.ini", + "upgrade", + "head", + ] + ) + +else: + args = parser.parse_args() + + c2cupgrade_args = ["--step", args.step] if args.step is not None else [] + + if os.environ.get("CI") != "true" and args.step is None: + major_version = args.version + match = re.match(r"^([0-9]+\.[0-9]+)\.[0-9]+$", args.version) + if match is not None: + major_version = match.group(1) + match = re.match(r"^([0-9]+\.[0-9]+)\.[0-9a-z]+\.[0-9]+$", args.version) + if match is not None: + major_version = match.group(1) + if not args.debug: + subprocess.check_call( + [ + "docker", + "pull", + f"camptocamp/geomapfish:{major_version}", + ] + ) + subprocess.check_call(["docker", "pull", f"camptocamp/geomapfish-tools:{args.version}"]) + subprocess.check_call( + [ + "docker", + "pull", + f"camptocamp/geomapfish-config:{major_version}", + ] + ) + + debug_volumes = ( + [ + "--volume={debug}/geoportal/c2cgeoportal_geoportal/scripts/c2cupgrade.py:".format( + debug=args.debug + ), + "/opt/c2cgeoportal/geoportal/c2cgeoportal_geoportal/scripts/c2cupgrade.py", + ] + if args.debug + else [] + ) + + win = platform.system() == "Windows" + sys.exit( + subprocess.call( + [ + "docker", + "run", + "--rm", + "--env=CI", + f"--volume={os.getcwd()}:/src", + ] + + debug_volumes + + [ + f"camptocamp/geomapfish-tools:{args.version}", + "run-git", + subprocess.check_output(["git", "config", "--get", "user.name"]).decode().strip(), + subprocess.check_output(["git", "config", "--get", "user.email"]).decode().strip(), + "" if win else subprocess.check_output(["id", "-u"]).decode().strip(), + "" if win else subprocess.check_output(["id", "-g"]).decode().strip(), + "/src", + "c2cupgrade", + ] + + c2cupgrade_args + ) + )