diff --git a/.circleci/config.yml b/.circleci/config.yml index 7566ed9c78..86de651ea4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ default_docker: &default_docker defaults: &defaults parameters: base_image: - default: ghcr.io/etalab/transport-ops:elixir-1.15.5-erlang-24.3.4.13-ubuntu-focal-20230126-transport-tools-1.0.7 + default: ghcr.io/etalab/transport-ops:elixir-1.16.2-erlang-25.3.2.10-ubuntu-focal-20240216-transport-tools-1.0.7 type: string # useful to invalidate the build cache manually by bumping the version build_cache_key: diff --git a/.tool-versions b/.tool-versions index c455319d11..693ae08b43 100644 --- a/.tool-versions +++ b/.tool-versions @@ -3,16 +3,20 @@ # provides an easy way to ensure local development and test will rely on roughly # the same versions as in production, if one uses the "asdf" version manager. +# Update ASDF and plugins: asdf update && asdf plugin update --all + # See: # - https://hexdocs.pm/elixir/compatibility-and-deprecations.html # - https://github.com/elixir-lang/elixir/releases # - `asdf list all elixir` -elixir 1.15.5-otp-24 +elixir 1.16.2-otp-25 # See: # - https://github.com/erlang/otp/releases +# - Blog, e.g. https://www.erlang.org/blog/my-otp-25-highlights/ # - https://github.com/erlang/otp/blob/master/otp_versions.table # - `asdf list all erlang` -erlang 24.3.4.13 +erlang 25.3.2.10 -nodejs 18.17.1 +# Take an LTS version on https://nodejs.org/ +nodejs 20.11.1 diff --git a/Dockerfile b/Dockerfile index b4615b274a..e1ca670fdf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/etalab/transport-ops:elixir-1.15.5-erlang-24.3.4.13-ubuntu-focal-20230126-transport-tools-1.0.7 +FROM ghcr.io/etalab/transport-ops:elixir-1.16.2-erlang-25.3.2.10-ubuntu-focal-20240216-transport-tools-1.0.7 RUN mkdir phoenixapp WORKDIR /phoenixapp diff --git a/Dockerfile.dev b/Dockerfile.dev index 966d22ef7e..670d386c86 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM ghcr.io/etalab/transport-ops:elixir-1.15.5-erlang-24.3.4.13-ubuntu-focal-20230126-transport-tools-1.0.7 +FROM ghcr.io/etalab/transport-ops:elixir-1.16.2-erlang-25.3.2.10-ubuntu-focal-20240216-transport-tools-1.0.7 RUN apt-get install -y git inotify-tools postgresql-client>=11 diff --git a/apps/shared/lib/hasher.ex b/apps/shared/lib/hasher.ex index 763b7f91a1..1b326e1946 100644 --- a/apps/shared/lib/hasher.ex +++ b/apps/shared/lib/hasher.ex @@ -89,7 +89,7 @@ defmodule Hasher do def get_file_hash(file_path) do file_path - |> File.stream!([], 2048) + |> File.stream!(2048) |> compute_checksum(:sha256) end diff --git a/apps/transport/lib/db/contact.ex b/apps/transport/lib/db/contact.ex index e969053b65..c2888176ac 100644 --- a/apps/transport/lib/db/contact.ex +++ b/apps/transport/lib/db/contact.ex @@ -165,8 +165,7 @@ defmodule DB.Contact do def organization_name(orgs) do certified_orgs = - orgs - |> Enum.filter(fn %DB.Organization{badges: badges} -> Enum.any?(badges, &match?(&1, %{"kind" => "certified"})) end) + Enum.filter(orgs, fn %DB.Organization{badges: badges} -> %{"kind" => "certified"} in badges end) case certified_orgs do [] -> orgs |> List.first() |> Map.fetch!(:name) diff --git a/apps/transport/lib/transport_web/views/backoffice/page_view.ex b/apps/transport/lib/transport_web/views/backoffice/page_view.ex index 494c5a49b0..3e2e236b9b 100644 --- a/apps/transport/lib/transport_web/views/backoffice/page_view.ex +++ b/apps/transport/lib/transport_web/views/backoffice/page_view.ex @@ -77,7 +77,7 @@ defmodule TransportWeb.Backoffice.PageView do def unaccent(nil), do: "" def unaccent(value) when is_binary(value) do - ~R<\p{Mn}>u + ~r/\p{Mn}/u |> Regex.replace(value |> :unicode.characters_to_nfd_binary(), "") |> :unicode.characters_to_nfc_binary() end diff --git a/apps/transport/test/transport/jobs/dataset_quality_score_test.exs b/apps/transport/test/transport/jobs/dataset_quality_score_test.exs index 7f848ff2ce..faa2812086 100644 --- a/apps/transport/test/transport/jobs/dataset_quality_score_test.exs +++ b/apps/transport/test/transport/jobs/dataset_quality_score_test.exs @@ -58,7 +58,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do assert %{ format: "GTFS", - freshness: 0.0, + freshness: +0.0, raw_measure: %{end_date: _, start_date: _}, resource_id: _ } = resource_freshness(resource) @@ -127,7 +127,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do metadata: %{"feed_timestamp_delay" => 1000} ) - assert %{format: "gbfs", freshness: 0.0, raw_measure: 1000, resource_id: _} = resource_freshness(resource) + assert %{format: "gbfs", freshness: +0.0, raw_measure: 1000, resource_id: _} = resource_freshness(resource) end test "GBFS resource without metadata for today" do @@ -178,7 +178,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do insert(:resource_unavailability, start: hours_ago(2), resource: resource) assert %{ - availability: 0.0, + availability: +0.0, raw_measure: (22 / 24 * 100) |> Float.floor(1), resource_id: resource.id } == resource_availability(resource) @@ -240,7 +240,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do details: %{ resources: [ %{availability: 1.0, raw_measure: nil, resource_id: r1.id}, - %{availability: 0.0, raw_measure: 0, resource_id: r2.id} + %{availability: +0.0, raw_measure: 0, resource_id: r2.id} ] }, score: 0.5 @@ -269,7 +269,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do assert [] == dataset |> DB.Repo.preload(:resources) |> Map.fetch!(:resources) - assert %{score: 0.0, details: %{resources: []}} == current_dataset_availability(dataset.id) + assert %{score: +0.0, details: %{resources: []}} == current_dataset_availability(dataset.id) end end @@ -298,7 +298,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do }, %{ format: "gtfs-rt", - freshness: 0.0, + freshness: +0.0, raw_measure: 1000, resource_id: ^resource_id_2 } @@ -319,12 +319,12 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do # average freshness for only 1 resource with freshness information available assert %{ - score: 0.0, + score: +0.0, details: %{ resources: [ %{ format: "GTFS", - freshness: 0.0, + freshness: +0.0, raw_measure: %{end_date: _, start_date: _}, resource_id: ^resource_id }, @@ -369,7 +369,9 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do assert %{ score: 0, details: %{ - resources: [%{compliance: 0.0, raw_measure: %{"has_errors" => true}, resource_id: geojson_resource.id}] + resources: [ + %{compliance: +0.0, raw_measure: %{"has_errors" => true}, resource_id: geojson_resource.id} + ] } } == current_dataset_compliance(dataset.id) end @@ -395,7 +397,7 @@ defmodule Transport.Test.Transport.Jobs.DatasetQualityScoreTest do score: 0.5, details: %{ resources: [ - %{compliance: 0.0, raw_measure: %{"max_error" => "Error"}, resource_id: gtfs_1.id}, + %{compliance: +0.0, raw_measure: %{"max_error" => "Error"}, resource_id: gtfs_1.id}, %{compliance: 1.0, raw_measure: %{"max_error" => "Warning"}, resource_id: gtfs_2.id} ] } diff --git a/apps/transport/test/transport/jobs/geo_data/lez_to_geo_data_test.exs b/apps/transport/test/transport/jobs/geo_data/lez_to_geo_data_test.exs index d1fe4bda70..f62603a785 100644 --- a/apps/transport/test/transport/jobs/geo_data/lez_to_geo_data_test.exs +++ b/apps/transport/test/transport/jobs/geo_data/lez_to_geo_data_test.exs @@ -29,7 +29,7 @@ defmodule Transport.Jobs.LowEmissionZonesToGeoDataTest do coordinates: [ [[{102.0, 2.0}, {103.0, 2.0}, {103.0, 3.0}, {102.0, 3.0}, {102.0, 2.0}]], [ - [{100.0, 0.0}, {101.0, 0.0}, {101.0, 1.0}, {100.0, 1.0}, {100.0, 0.0}], + [{100.0, +0.0}, {101.0, +0.0}, {101.0, 1.0}, {100.0, 1.0}, {100.0, +0.0}], [{100.2, 0.2}, {100.2, 0.8}, {100.8, 0.8}, {100.8, 0.2}, {100.2, 0.2}] ] ], diff --git a/docs/upgrade_versions.md b/docs/upgrade_versions.md new file mode 100644 index 0000000000..91f30e9332 --- /dev/null +++ b/docs/upgrade_versions.md @@ -0,0 +1,27 @@ +## Gestion des versions et des images Docker + +Le setup standard de développement s’appuie sur ASDF pour la gestion des versions. Cependant, la CI/CD (CircleCI) et la production s’appuient sur Docker. + +Une première image Docker est mise à disposition par le dépôt tranport-ops : elle récupère une image Docker standard sur le hub Docker avec déjà la bonne version de Elixir et Erlang, rajoute Node et les outils annexes (transport-tools), et est publiée sur le dépôt d’images Docker de Github. + +L’application transport-site récupère l’image Docker de transport-ops, et y rajoute uniquement son propre code, le compile, lance le serveur, les migrations, et expose le serveur à l’extérieur. + +CircleCI pour les tests va donc faire ces étapes là de compilation du code Elixir, mais sans devoir reconstruire toute l’image (puisque s’appuyant sur l’image de transport-ops). Quand on pousse sur les serveurs de CleverCloud, un premier serveur va créer l’image Docker finale (mêmes étapes que sur CircleCI, donc un temps de compilation existe) puis déployer l’image résultante sur un autre serveur. Potentiellement, on pourrait réduire à l’avenir le temps de déploiement en fournissant directement l’image Docker avec l’application précompilée, et que la même image serve pour les tests et pour la production. + +## Processus de mise à jour + +Les versions de ASDF et de Docker doivent être mises à jour dans la même branche de transport-site (sinon des tests ratent). Il faut donc en préalable du merge de la branche qu’une image Docker avec les bonnes versions de Elixir, Erlang/OTP et Node et les outils transport existe, donc qu’une branche correspondante sur transport-ops ait été mergée et un package crée. + +Dans les grandes lignes : on teste d’abord avec ASDF que tout va bien, puis on fait le nécessaire sur le repo transport-ops pour créer un package, et on finalise la branche sur transport-site avec la référence de l’image. + +1. Créer une branche +2. Mettre à jour `.tool_versions`. Le fichier contient un peu de documentation sur les commandes ASDF, et où trouver les versions disponibles, la compatibilité Elixir/Erlang et les notes de versions. +3. Vérifier que : + 1. Ça compile + 2. Les tests passent (il y aura forcément une erreur liée à la différence de version avec Docker) + 3. Credo et Dialyxir n’aient pas de warning. +4. Noter tous les warnings, qui serviront soit dans une issue pour un traitement postérieur, soit seront mis dans la pull request. Exemple : https://github.com/etalab/transport-site/issues/3307 +5. Créer un package Docker correspondant dans le dépôt https://github.com/etalab/transport-ops On peut pousser sur une branche pour faire tourner la CI Github Workflow, pas besoin d’avoir Docker en local. Lire le README de transport-ops pour le détail. +6. Modifier transport-site avec la bonne image Docker. Il n’est pas nécessaire de tester en local transport-site avec l’image Docker : les tests sufiront + prochainement. Il n’y a pas de grosse diff entre passage asdf et docker. +7. Créer une pull request en draft pour faire tourner Circle CI. +8. Tester le plus possible : en local et sur le serveur de staging (`git push origin ma_branche:prochainement`)