diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..53980e454 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" + cooldown: + default-days: 7 + # Dependabot never writes news fragments, so exempt its pull requests from + # the changelog check. Both labels must exist in the repository, otherwise + # they are silently ignored. + labels: + - "dependencies" + - "skip changelog" diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 17f9b613b..50f1ffab8 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -1,4 +1,4 @@ -name: Changelog check +name: "Changelog" on: pull_request: types: [assigned, opened, synchronize, reopened, labeled, unlabeled] @@ -6,40 +6,17 @@ on: - main env: - NODE_VERSION: 24.x - ADDON_NAME: kitconcept-intranet - BASE_BRANCH: main + python-version: 3.14 + base-branch: main jobs: config: - runs-on: ubuntu-latest - outputs: - backend: ${{ steps.filter.outputs.backend }} - frontend: ${{ steps.filter.outputs.frontend }} - repository: ${{ steps.filter.outputs.repository }} - steps: - - name: Checkout - uses: actions/checkout@v7 - - - uses: dorny/paths-filter@v4 - id: filter - with: - filters: | - backend: - - 'backend/**' - repository: - - '.github/**' - - '.vscode/**' - - 'devops/**' - - 'docs/**' - - 'docker-compose.yml' - - 'README.md' - frontend: - - 'frontend/**' + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip changelog') }} + uses: ./.github/workflows/config.yml - backend: - if: ${{ needs.config.outputs.backend == 'true' }} + checks: runs-on: ubuntu-latest + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip changelog') }} needs: - config steps: @@ -48,88 +25,42 @@ jobs: # Fetch all history fetch-depth: '0' - - name: Install pipx - run: pip install towncrier - - - name: Check for presence of a Change Log fragment (only pull requests) - if: github.event_name == 'pull_request' - run: | - # Fetch the pull request' base branch so towncrier will be able to - # compare the current branch with the base branch. - # Source: https://github.com/actions/checkout/#fetch-all-branches. - git fetch --no-tags origin ${BASE_BRANCH} - towncrier check --compare-with origin/${{ env.BASE_BRANCH }} --config backend/pyproject.toml --dir backend/ - - frontend: - if: ${{ needs.config.outputs.frontend == 'true' }} - runs-on: ubuntu-latest - needs: - - config - defaults: - run: - working-directory: ./frontend - steps: - - uses: actions/checkout@v7 + - name: Setup uv + uses: plone/meta/.github/actions/setup_uv@2.x with: - # Fetch all history - fetch-depth: '0' + python-version: ${{ env.python-version }} + working-directory: '.' - - name: Install pipx - run: pip install towncrier - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v6 - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Enable corepack - run: npm i -g corepack@latest && corepack enable - - - name: Get pnpm store directory - shell: bash + - name: "Fetch base branch" run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - - uses: actions/cache@v6 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- + git fetch --no-tags origin ${{ env.base-branch }} - - name: Install dependencies - run: make install - - - name: Check for presence of a Change Log fragment (only pull requests) - if: github.event_name == 'pull_request' + - name: "Backend: Check" + id: backend-changelog + if: ${{ always() && needs.config.outputs.changelog-backend == 'true' }} run: | - # Fetch the pull request' base branch so towncrier will be able to - # compare the current branch with the base branch. - # Source: https://github.com/actions/checkout/#fetch-all-branches. - git fetch --no-tags origin ${BASE_BRANCH} - cd .. - towncrier check --compare-with origin/${{ env.BASE_BRANCH }} --config frontend/packages/${{ env.ADDON_NAME }}/towncrier.toml --dir frontend/packages/${{ env.ADDON_NAME }} + git fetch --no-tags origin ${{ env.base-branch }} + uvx towncrier check --compare-with origin/${{ env.base-branch }} --config backend/pyproject.toml --dir backend/ - repository: - if: ${{ needs.config.outputs.repository == 'true' }} - runs-on: ubuntu-latest - needs: - - config - steps: - - uses: actions/checkout@v7 - with: - # Fetch all history - fetch-depth: '0' + - name: "Frontend: Check" + id: frontend-changelog + if: ${{ always() && needs.config.outputs.changelog-frontend == 'true' }} + run: | + git fetch --no-tags origin ${{ env.base-branch }} + uvx towncrier check --compare-with origin/${{ env.base-branch }} --config ${{ needs.config.outputs.path-frontend }}/towncrier.toml --dir ${{ needs.config.outputs.path-frontend }} - - name: Install pipx - run: pip install towncrier + - name: "Repository: Check" + id: repository-changelog + if: ${{ always() && needs.config.outputs.changelog-repository == 'true' }} + run: | + git fetch --no-tags origin ${{ env.base-branch }} + uvx towncrier check --compare-with origin/${{ env.base-branch }} --config ${{ needs.config.outputs.path-root }}/towncrier.toml --dir ${{ needs.config.outputs.path-root }} - - name: Check for presence of a Change Log fragment (only pull requests) - if: github.event_name == 'pull_request' + - name: "Report check" run: | - # Fetch the pull request' base branch so towncrier will be able to - # compare the current branch with the base branch. - # Source: https://github.com/actions/checkout/#fetch-all-branches. - git fetch --no-tags origin ${BASE_BRANCH} - towncrier check --compare-with origin/${{ env.BASE_BRANCH }} --config towncrier.toml --dir . + echo '# Workflow Report' >> $GITHUB_STEP_SUMMARY + echo '| Job ID | Conclusion |' >> $GITHUB_STEP_SUMMARY + echo '| --- | --- |' >> $GITHUB_STEP_SUMMARY + echo '| backend | ${{ steps.backend-changelog.conclusion }} |' >> $GITHUB_STEP_SUMMARY + echo '| frontend | ${{ steps.frontend-changelog.conclusion }} |' >> $GITHUB_STEP_SUMMARY + echo '| repository | ${{ steps.repository-changelog.conclusion }} |' >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index b4fa1ea8b..f2a0f0631 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -51,7 +51,7 @@ on: value: ${{ jobs.config.outputs.base-tag }} image-name-prefix: description: "Image name prefix for container images" - value: ${{ inputs.image-name-prefix }} + value: ${{ jobs.config.outputs.image-name-prefix }} node-version: description: "Node version to be used" value: ${{ inputs.node-version }} @@ -79,6 +79,24 @@ on: stack-prefix: description: "Deploy: Short name to be used to create Traefik labels" value: ${{ inputs.stack-prefix }} + changelog-backend: + description: "Flag reporting if we should run changelog jobs for the backend" + value: ${{ jobs.config.outputs.changelog-backend }} + changelog-frontend: + description: "Flag reporting if we should run changelog jobs for the frontend" + value: ${{ jobs.config.outputs.changelog-frontend }} + changelog-repository: + description: "Flag reporting if we should run changelog jobs for the repository" + value: ${{ jobs.config.outputs.changelog-repository }} + path-backend: + description: "Path to the backend package, relative to the repository root" + value: ${{ jobs.config.outputs.path-backend }} + path-frontend: + description: "Path to the frontend package, relative to the repository root" + value: ${{ jobs.config.outputs.path-frontend }} + path-root: + description: "Path to the repository root" + value: ${{ jobs.config.outputs.path-root }} jobs: config: @@ -90,27 +108,48 @@ jobs: docs: ${{ steps.filter.outputs.docs }} frontend: ${{ steps.filter.outputs.frontend }} deploy: ${{ steps.filter.outputs.deploy }} - base-tag: ${{ steps.vars.outputs.BASE_TAG }} + base-tag: ${{ steps.vars.outputs.base-tag }} kc-version: ${{ steps.vars.outputs.kc-version }} volto-version: ${{ steps.vars.outputs.volto-version }} environment: ${{ steps.vars.outputs.environment }} stack-name: ${{ steps.vars.outputs.stack-name }} + image-name-prefix: ${{ steps.vars.outputs.image-name-prefix }} + changelog-backend: ${{ steps.filter.outputs.changelog-backend }} + changelog-frontend: ${{ steps.filter.outputs.changelog-frontend }} + changelog-repository: ${{ steps.filter.outputs.changelog-repository }} + path-backend: ${{ steps.vars.outputs.path-backend }} + path-frontend: ${{ steps.vars.outputs.path-frontend }} + path-root: ${{ steps.vars.outputs.path-root }} steps: - name: Checkout uses: actions/checkout@v7 + - name: Setup uv + uses: plone/meta/.github/actions/setup_uv@2.x + with: + python-version: ${{ inputs.python-version }} + working-directory: '.' + - name: Compute several vars needed for the CI id: vars run: | - echo "BASE_TAG=sha-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - echo "kc-version=$(cat backend/version.txt)" >> $GITHUB_OUTPUT - python3 -c 'import json; data = json.load(open("./frontend/mrs.developer.json")); print("volto-version=" + (data["core"].get("tag") or "latest"))' >> $GITHUB_OUTPUT + REPOSITORY_SETTINGS="$(uvx repoplone settings dump)" + # `repoplone` reports absolute paths, but the checks need them + # relative to the repository root. + ROOT="$(jq -r '.root_path' <<< "$REPOSITORY_SETTINGS")" + echo "base-tag=sha-$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + echo "image-name-prefix=$(jq -r '.container_images_prefix' <<< "$REPOSITORY_SETTINGS")" >> "$GITHUB_OUTPUT" + echo "kc-version=$(jq -r '.backend.base_package_version' <<< "$REPOSITORY_SETTINGS")" >> "$GITHUB_OUTPUT" + echo "volto-version=$(jq -r '.frontend.volto_version' <<< "$REPOSITORY_SETTINGS")" >> "$GITHUB_OUTPUT" + echo "path-backend=$(jq -r '.backend.path' <<< "$REPOSITORY_SETTINGS" | sed "s|^${ROOT}/||")" >> "$GITHUB_OUTPUT" + echo "path-frontend=$(jq -r '.frontend.path' <<< "$REPOSITORY_SETTINGS" | sed "s|^${ROOT}/||")" >> "$GITHUB_OUTPUT" + echo "path-root=." >> "$GITHUB_OUTPUT" environment=${{ inputs.hostname }} echo "environment=${environment}" >> $GITHUB_OUTPUT echo "stack-name=${environment//./-}" >> $GITHUB_OUTPUT - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@v4.0.3 id: filter with: filters: | @@ -141,12 +180,26 @@ jobs: - '.github/workflows/frontend*' - '.github/workflows/main*' - 'devops/**' + changelog-backend: + - 'backend/**' + changelog-frontend: + - 'frontend/**' + changelog-repository: + - '.github/**' + - '.vscode/**' + - 'devops/**' + - 'docs/**' + - 'docker-compose.yml' + - 'README.md' - name: Test vars run: | - echo "BASE_TAG: ${{ steps.vars.outputs.BASE_TAG }}" + echo "BASE_TAG: ${{ steps.vars.outputs.base-tag }}" echo 'kc-version: ${{ steps.vars.outputs.kc-version }}' echo 'volto-version: ${{ steps.vars.outputs.volto-version }}' + echo 'path-backend: ${{ steps.vars.outputs.path-backend }}' + echo 'path-frontend: ${{ steps.vars.outputs.path-frontend }}' + echo 'path-root: ${{ steps.vars.outputs.path-root }}' echo 'environment: ${{ steps.vars.outputs.environment }}' echo 'stack-name: ${{ steps.vars.outputs.stack-name }}' echo 'event-name: ${{ github.event_name }}' @@ -156,3 +209,6 @@ jobs: echo 'Paths - devops: ${{ steps.filter.outputs.devops }}' echo 'Paths - docs: ${{ steps.filter.outputs.docs }}' echo 'Paths - frontend: ${{ steps.filter.outputs.frontend }}' + echo 'Paths - changelog-backend: ${{ steps.filter.outputs.changelog-backend }}' + echo 'Paths - changelog-frontend: ${{ steps.filter.outputs.changelog-frontend }}' + echo 'Paths - changelog-repository: ${{ steps.filter.outputs.changelog-repository }}' diff --git a/.vscode/settings.json b/.vscode/settings.json index 8d1b22298..132a62af3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,8 +2,6 @@ "eslint.workingDirectories": ["./frontend"], "python.defaultInterpreterPath": "${workspaceFolder}/backend/.venv/bin/python", "python-envs.workspaceSearchPaths": [ - ".venv", - "*/.venv", "backend/.venv" ], "ruff.organizeImports": true, diff --git a/Makefile b/Makefile index 9acb7eaa5..7502f5f6b 100644 --- a/Makefile +++ b/Makefile @@ -63,14 +63,6 @@ all: install help: ## This help message @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -########################################### -# Volto Plate -########################################### -.PHONY: update-volto-plate -update-volto-plate: ## Update Volto Plate - @echo "Update Volto Plate" - @uv run scripts/update-volto-plate.py - ########################################### # Frontend ########################################### diff --git a/backend/Dockerfile b/backend/Dockerfile index df30129bd..b1e49c3ac 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,10 +2,6 @@ ARG KC_VERSION FROM ghcr.io/kitconcept/core-builder:${KC_VERSION:-latest} AS builder -# Copy only the files needed for installing dependencies first to leverage Docker cache -# In this case, kitconcept-plate -COPY ./container /container - # Install dependencies RUN --mount=type=cache,target=/root/.cache \ --mount=type=bind,source=uv.lock,target=uv.lock \ diff --git a/backend/Dockerfile.acceptance b/backend/Dockerfile.acceptance index 1cdf14b52..84a645679 100644 --- a/backend/Dockerfile.acceptance +++ b/backend/Dockerfile.acceptance @@ -2,10 +2,6 @@ ARG KC_VERSION=latest FROM ghcr.io/kitconcept/core-builder:${KC_VERSION} AS builder -# Copy only the files needed for installing dependencies first to leverage Docker cache -# In this case, kitconcept-plate -COPY ./container /container - # Install dependencies RUN --mount=type=cache,target=/root/.cache \ --mount=type=bind,source=uv.lock,target=uv.lock \ diff --git a/backend/container/kitconcept-plate.tar.gz b/backend/container/kitconcept-plate.tar.gz deleted file mode 100644 index 14da07937..000000000 Binary files a/backend/container/kitconcept-plate.tar.gz and /dev/null differ diff --git a/backend/news/463.test b/backend/news/463.tests similarity index 100% rename from backend/news/463.test rename to backend/news/463.tests diff --git a/backend/news/593.internal b/backend/news/593.internal new file mode 100644 index 000000000..33a5046d6 --- /dev/null +++ b/backend/news/593.internal @@ -0,0 +1 @@ +Depend on the released `kitconcept.plate` 1.0.0a23 from PyPI instead of the source distribution vendored in `container/`. @ericof diff --git a/backend/pyproject.toml b/backend/pyproject.toml index b137332c5..9006fabf9 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ "collective-solr==10.1.1", "kitconcept.solr", "kitconcept.contactblock==1.0.0a6", - "kitconcept-plate", + "kitconcept.plate==1.0.0a23", ] [dependency-groups] @@ -66,7 +66,6 @@ container = [ ] [tool.uv.sources] -kitconcept-plate = { path = "container/kitconcept-plate.tar.gz" } kitconcept-solr = { git = "https://github.com/kitconcept/kitconcept.solr.git", subdirectory = "backend", rev = "a8953cefb2d250bb83213bef0099ffceda87dc78" } [tool.hatch.metadata] @@ -157,8 +156,8 @@ name = "Documentation" showcontent = true [[tool.towncrier.type]] -directory = "test" -name = "Test" +directory = "tests" +name = "Tests" showcontent = true [tool.ruff] diff --git a/backend/uv.lock b/backend/uv.lock index 497016b4a..bcbfbc83f 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = "==3.14.*" [options] @@ -1519,7 +1519,7 @@ requires-dist = [ { name = "collective-solr", specifier = "==10.1.1" }, { name = "kitconcept-contactblock", specifier = "==1.0.0a6" }, { name = "kitconcept-core", specifier = "==2.0.0b4" }, - { name = "kitconcept-plate", path = "container/kitconcept-plate.tar.gz" }, + { name = "kitconcept-plate", specifier = "==1.0.0a23" }, { name = "kitconcept-solr", git = "https://github.com/kitconcept/kitconcept.solr.git?subdirectory=backend&rev=a8953cefb2d250bb83213bef0099ffceda87dc78" }, { name = "pas-plugins-authomatic", specifier = "==2.0.0" }, { name = "pas-plugins-keycloakgroups", specifier = "==1.0.0b1" }, @@ -1559,32 +1559,18 @@ test = [ [[package]] name = "kitconcept-plate" -version = "1.0.0a22" -source = { path = "container/kitconcept-plate.tar.gz" } +version = "1.0.0a23" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "plone-api" }, { name = "plone-restapi" }, { name = "plone-volto" }, { name = "products-cmfplone" }, ] -sdist = { hash = "sha256:91dcee93361c85aae4ab7ae841df0a2aabe5bfa648bb184da8944738854b3b49" } - -[package.metadata] -requires-dist = [ - { name = "collective-mockmailhost", marker = "extra == 'test'" }, - { name = "horse-with-no-namespace", marker = "extra == 'test'", specifier = ">=20250408.0" }, - { name = "plone-api" }, - { name = "plone-app-testing", marker = "extra == 'test'" }, - { name = "plone-restapi" }, - { name = "plone-restapi", extras = ["test"], marker = "extra == 'test'" }, - { name = "plone-volto" }, - { name = "products-cmfplone" }, - { name = "products-printingmailhost", marker = "extra == 'test'" }, - { name = "pytest", marker = "extra == 'test'" }, - { name = "pytest-cov", marker = "extra == 'test'" }, - { name = "pytest-plone", marker = "extra == 'test'", specifier = ">=1.0.0" }, +sdist = { url = "https://files.pythonhosted.org/packages/95/cb/a7c09221a0a4b6811b08ad25b0f55d1020872ca4dea8fbaa8208c59ac775/kitconcept_plate-1.0.0a23.tar.gz", hash = "sha256:977021867d23a6e3f497d74f3bfd3ed5b605161b4614e1b23b8f88dfe3fe1b2b", size = 4550216, upload-time = "2026-08-18T18:02:51.029Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/bd/58e9825575cfa61042cb47a569910adbb7d9a409fc7b48af3bc9242297e9/kitconcept_plate-1.0.0a23-py3-none-any.whl", hash = "sha256:c3bb1c74647977ff9d2b6968f84ad83851107497e963c6b3ce8e8f1144769ef0", size = 4583368, upload-time = "2026-08-18T18:02:48.592Z" }, ] -provides-extras = ["test"] [[package]] name = "kitconcept-solr" diff --git a/dependabot.yml b/dependabot.yml deleted file mode 100644 index df4d15b35..000000000 --- a/dependabot.yml +++ /dev/null @@ -1,8 +0,0 @@ -version: 2 -updates: - - - package-ecosystem: "github-actions" - directory: "/" - schedule: - # Check for updates to GitHub Actions every week - interval: "weekly" diff --git a/frontend/Dockerfile b/frontend/Dockerfile index d5f70b4c1..668e53c56 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -8,7 +8,6 @@ COPY --chown=node pnpm-workspace.yaml /app/ COPY --chown=node package.json /app/package.json COPY --chown=node mrs.developer.json /app/mrs.developer.json COPY --chown=node pnpm-lock.yaml /app/pnpm-lock.yaml -COPY --chown=node artifacts /app/artifacts RUN --mount=type=cache,id=pnpm,target=/app/.pnpm-store,uid=1000 < .changelog.draft", - "pipx run towncrier build --yes --version ${version}", + "uvx towncrier build --draft --yes --version ${version} > .changelog.draft", + "uvx towncrier build --yes --version ${version}", "cp ../../README.md ./ && cp CHANGELOG.md ../../CHANGELOG.md", "python3 -c 'import json; data = json.load(open(\"../../package.json\")); data[\"version\"] = \"${version}\"; json.dump(data, open(\"../../package.json\", \"w\"), indent=2)'", "git add ../../CHANGELOG.md ../../package.json" ], "after:release": "rm .changelog.draft README.md" }, + "npm": { + "publish": false + }, + "plonePrePublish": { + "publish": false + }, "git": { - "changelog": "pipx run towncrier build --draft --yes --version 0.0.0", + "changelog": "uvx towncrier build --draft --yes --version 0.0.0", "commit": false, "tag": false }, - "npm": { - "publish": false - }, "github": { "release": false, "releaseName": "${version}", diff --git a/frontend/packages/kitconcept-intranet/+core-a6.bugfix b/frontend/packages/kitconcept-intranet/news/+core-a6.bugfix similarity index 100% rename from frontend/packages/kitconcept-intranet/+core-a6.bugfix rename to frontend/packages/kitconcept-intranet/news/+core-a6.bugfix diff --git a/frontend/packages/kitconcept-intranet/news/.changelog_template.jinja b/frontend/packages/kitconcept-intranet/news/.changelog_template.jinja new file mode 100644 index 000000000..b35bff39d --- /dev/null +++ b/frontend/packages/kitconcept-intranet/news/.changelog_template.jinja @@ -0,0 +1,15 @@ +{% if sections[""] %} +{% for category, val in definitions.items() if category in sections[""] %} + +### {{ definitions[category]['name'] }} + +{% for text, values in sections[""][category].items() %} +- {{ text }} {{ values|join(', ') }} +{% endfor %} + +{% endfor %} +{% else %} +No significant changes. + + +{% endif %} \ No newline at end of file diff --git a/frontend/packages/kitconcept-intranet/news/593.internal b/frontend/packages/kitconcept-intranet/news/593.internal new file mode 100644 index 000000000..a41bd7d25 --- /dev/null +++ b/frontend/packages/kitconcept-intranet/news/593.internal @@ -0,0 +1 @@ +Depend on the released `@kitconcept/volto-plate` 1.0.0-alpha.23 from npm instead of the tarball vendored in `frontend/artifacts/`. @ericof diff --git a/frontend/packages/kitconcept-intranet/package.json b/frontend/packages/kitconcept-intranet/package.json index b18d05dc4..5b0d78666 100644 --- a/frontend/packages/kitconcept-intranet/package.json +++ b/frontend/packages/kitconcept-intranet/package.json @@ -100,7 +100,7 @@ "lodash": "4.17.21", "react-aria-components": "catalog:", "volto-rss-block": "^3.0.1", - "@kitconcept/volto-plate": "file:../../artifacts/kitconcept-volto-plate.tgz" + "@kitconcept/volto-plate": "^1.0.0-alpha.23" }, "volto_version": "19.1.4" } diff --git a/frontend/packages/kitconcept-intranet/towncrier.toml b/frontend/packages/kitconcept-intranet/towncrier.toml index e1b86b5ef..5071ea54c 100644 --- a/frontend/packages/kitconcept-intranet/towncrier.toml +++ b/frontend/packages/kitconcept-intranet/towncrier.toml @@ -3,7 +3,7 @@ filename = "CHANGELOG.md" directory = "news/" title_format = "## {version} ({project_date})" underlines = ["", "", ""] -template = "./node_modules/@plone/scripts/templates/towncrier_template.jinja" +template = "./news/.changelog_template.jinja" start_string = "\n" issue_format = "[#{issue}](https://github.com/kitconcept/kitconcept.intranet/issue/{issue})" @@ -33,6 +33,6 @@ name = "Documentation" showcontent = true [[tool.towncrier.type]] -directory = "test" -name = "Test" +directory = "tests" +name = "Tests" showcontent = true diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 3b03c5dc3..b2862b764 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -1445,8 +1445,8 @@ importers: specifier: workspace:* version: link:../volto-logos-block/packages/volto-logos-block '@kitconcept/volto-plate': - specifier: file:../../artifacts/kitconcept-volto-plate.tgz - version: file:artifacts/kitconcept-volto-plate.tgz(668a5b4091d1647ee08dbb34248f717f) + specifier: ^1.0.0-alpha.23 + version: 1.0.0-alpha.23(668a5b4091d1647ee08dbb34248f717f) '@kitconcept/volto-separator-block': specifier: workspace:* version: link:../volto-separator-block/packages/volto-separator-block @@ -1917,43 +1917,6 @@ importers: specifier: ^3.2.4 version: 3.2.6(@types/debug@4.1.13)(@types/node@24.13.1)(@vitest/ui@3.2.6)(jiti@2.7.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@3.13.1)(lightningcss@1.32.0)(sass@1.58.0)(terser@5.48.0)(yaml@2.9.0) - packages/volto-kitconcept-deepl/frontend/packages/volto-kitconcept-deepl: - dependencies: - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - devDependencies: - '@plone/registry': - specifier: workspace:* - version: link:../../../../../core/packages/registry - '@plone/scripts': - specifier: workspace:* - version: link:../../../../../core/packages/scripts - '@plone/types': - specifier: workspace:* - version: link:../../../../../core/packages/types - '@testing-library/react': - specifier: ^16.2.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.31))(@types/react@18.3.31)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@types/react': - specifier: ^18.3.1 - version: 18.3.31 - '@types/react-dom': - specifier: ^18.3.1 - version: 18.3.7(@types/react@18.3.31) - release-it: - specifier: ^19.0.5 - version: 19.2.4(@types/node@24.13.1)(magicast@0.3.5) - typescript: - specifier: ^5.7.3 - version: 5.9.3 - vitest: - specifier: ^3.1.2 - version: 3.2.6(@types/debug@4.1.13)(@types/node@24.13.1)(@vitest/ui@3.2.6)(jiti@2.7.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@3.13.1)(lightningcss@1.32.0)(sass@1.58.0)(terser@5.48.0)(yaml@2.9.0) - packages/volto-light-theme/frontend/packages/volto-light-theme: dependencies: '@dnd-kit/core': @@ -2246,6 +2209,43 @@ importers: specifier: ^3.2.4 version: 3.2.6(@types/debug@4.1.13)(@types/node@24.13.1)(@vitest/ui@3.2.6)(jiti@2.7.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@3.13.1)(lightningcss@1.32.0)(sass@1.58.0)(terser@5.48.0)(yaml@2.9.0) + packages/volto-social-media/frontend/packages/volto-social-media: + dependencies: + '@plone/components': + specifier: workspace:* + version: link:../../../../../core/packages/components + react: + specifier: 18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + devDependencies: + '@plone/scripts': + specifier: ^3.6.2 + version: 3.10.6 + '@plone/types': + specifier: workspace:* + version: link:../../../../../core/packages/types + '@types/jest': + specifier: ^29.5.8 + version: 29.5.14 + '@types/lodash': + specifier: ^4.14.201 + version: 4.17.24 + '@types/react': + specifier: ^18.3.12 + version: 18.3.31 + '@types/react-dom': + specifier: ^18.3.1 + version: 18.3.7(@types/react@18.3.31) + react-intl: + specifier: ^3.12.1 + version: 3.12.1(@types/react@18.3.31)(react@18.2.0) + release-it: + specifier: ^17.7.0 + version: 17.11.0(typescript@5.9.3) + packages/volto-solr/frontend/packages/volto-solr: dependencies: buffer: @@ -4208,9 +4208,8 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} - '@kitconcept/volto-plate@file:artifacts/kitconcept-volto-plate.tgz': - resolution: {integrity: sha512-znG++JldVTAIbqmL1tw9S7QLeZE8AwydRl4MLDJ+SfUfZ/km8yNS3MBcrXY8YuTK+94CKO4MQmcyizPPrRrD0A==, tarball: file:artifacts/kitconcept-volto-plate.tgz} - version: 1.0.0-alpha.22 + '@kitconcept/volto-plate@1.0.0-alpha.23': + resolution: {integrity: sha512-OH5ac9Qc+gr3U4r5VqQiQPcAeHSrNk5umiF5EscBR+sOyA/NgIsXKcUOUXfIWv1Fsb56a5CU/wZrJ3UyE2dEOg==} peerDependencies: '@platejs/ai': ^50.3.7 '@plone/registry': workspace:* @@ -16396,7 +16395,7 @@ snapshots: '@keyv/serialize@1.1.1': {} - '@kitconcept/volto-plate@file:artifacts/kitconcept-volto-plate.tgz(668a5b4091d1647ee08dbb34248f717f)': + '@kitconcept/volto-plate@1.0.0-alpha.23(668a5b4091d1647ee08dbb34248f717f)': dependencies: '@internationalized/date': 3.12.2 '@platejs/ai': 50.3.7(platejs@49.2.21(@types/react@18.3.31)(immer@10.2.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(scheduler@0.23.2)(use-sync-external-store@1.6.0(react@18.2.0)))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.9.3) diff --git a/news/+changelog-workflow.internal b/news/+changelog-workflow.internal new file mode 100644 index 000000000..d6346f9f7 --- /dev/null +++ b/news/+changelog-workflow.internal @@ -0,0 +1 @@ +Reworked the changelog CI workflow: the backend, frontend and repository checks now run as steps of a single job, derive their paths from `uvx repoplone settings dump`, and report their outcome in the workflow summary. @ericof diff --git a/news/+dependabot-config.internal b/news/+dependabot-config.internal new file mode 100644 index 000000000..43a8d9aff --- /dev/null +++ b/news/+dependabot-config.internal @@ -0,0 +1 @@ +Moved `dependabot.yml` to `.github/`, where GitHub actually reads it, and labelled its pull requests with `skip changelog` so they are exempt from the changelog check. @ericof diff --git a/news/+drop-update-volto-plate.internal b/news/+drop-update-volto-plate.internal new file mode 100644 index 000000000..eb6d41666 --- /dev/null +++ b/news/+drop-update-volto-plate.internal @@ -0,0 +1 @@ +Dropped the `update-volto-plate` script and its `Makefile` target, no longer needed now that `volto-plate` is consumed from its public releases. @ericof diff --git a/news/+towncrier-tests-type.internal b/news/+towncrier-tests-type.internal new file mode 100644 index 000000000..9042a7bba --- /dev/null +++ b/news/+towncrier-tests-type.internal @@ -0,0 +1 @@ +Renamed the towncrier `test` fragment type to `tests`, and added it to the repository-level configuration. @ericof diff --git a/scripts/update-volto-plate.py b/scripts/update-volto-plate.py deleted file mode 100644 index 2fd588c24..000000000 --- a/scripts/update-volto-plate.py +++ /dev/null @@ -1,458 +0,0 @@ -#!/usr/bin/env python3 -"""Sync ``kitconcept/volto-plate`` artifacts into the intranet repo. - -Downloads the upstream source archive **once** from -``https://github.com///archive/refs/tags/.tar.gz`` and -serves both tracks from those bytes: - -* **Frontend** — extracts ``/frontend/artifacts/kitconcept-volto-plate.tgz`` - (looked up by exact filename) and writes it to - ``frontend/artifacts/kitconcept-volto-plate.tgz``. Then rewrites the - matching dependency entry in ``frontend/packages/gmbh-intranet/package.json``. -* **Backend** — keeps only the ``backend/`` subtree, repacks it as - ``kitconcept-plate.tar.gz`` (top-level directory renamed to - ``kitconcept-plate``), drops it into ``backend/container/``, and rewrites - (or inserts) the ``kitconcept-plate`` source entry under - ``[tool.uv.sources]`` in ``backend/pyproject.toml`` to point at it. Then - refreshes ``backend/uv.lock`` so the locked ``kitconcept-plate`` version - matches the freshly pulled backend artifact. - -Both local artifact filenames are unversioned so consumer manifests -(``package.json`` and ``pyproject.toml``) hold stable file references across -syncs — the only thing that changes between syncs is the file contents. - -After both tracks are updated, the script runs ``make install`` in the repo -root so the working tree is reinstalled against the synced artifacts. - -Usage:: - - uv run update-volto-plate.py [--tag ] - -If ``--tag`` is omitted, the most recent tag from the upstream repository is -used. ``kitconcept/volto-plate`` is a private repository, so a -``GITHUB_TOKEN`` (or ``GH_TOKEN``) environment variable is required. -""" - -import argparse -import io -import json -import os -import re -import subprocess -import sys -import tarfile -import urllib.error -import urllib.request -from pathlib import Path - -OWNER = "kitconcept" -REPO = "volto-plate" -PACKAGE_NAME = "@kitconcept/volto-plate" -ASSET_STEM = "kitconcept-volto-plate" -ASSET_SUFFIX = ".tgz" -FRONTEND_ARTIFACT_NAME = f"{ASSET_STEM}{ASSET_SUFFIX}" - -BACKEND_PACKAGE_NAME = "kitconcept-plate" -BACKEND_ASSET_STEM = "kitconcept-plate" -BACKEND_ASSET_SUFFIX = ".tar.gz" -BACKEND_ARTIFACT_NAME = f"{BACKEND_ASSET_STEM}{BACKEND_ASSET_SUFFIX}" - -GITHUB_API = "https://api.github.com" - -SCRIPT_DIR = Path(__file__).resolve().parent -ROOT_DIR = SCRIPT_DIR.parent -BACKEND_DIR = ROOT_DIR / "backend" -BACKEND_ARTIFACTS_DIR = BACKEND_DIR / "container" -BACKEND_PYPROJECT_PATH = BACKEND_DIR / "pyproject.toml" -FRONTEND_DIR = ROOT_DIR / "frontend" -FRONTEND_ARTIFACTS_DIR = FRONTEND_DIR / "artifacts" -ADDON_PACKAGE_JSON_PATH = ( - FRONTEND_DIR / "packages" / "kitconcept-intranet" / "package.json" -) - - -def github_token() -> str | None: - """Return the GitHub token from the environment, if one is configured.""" - return os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") - - -def github_headers(extra: dict[str, str] | None = None) -> dict[str, str]: - """Build the standard headers used for every GitHub API request. - - :param extra: Additional headers merged on top of the defaults. - :returns: Header mapping suitable for :class:`urllib.request.Request`. - """ - headers: dict[str, str] = { - "Accept": "application/vnd.github+json", - "User-Agent": "kitconcept-intranet-artifact-sync", - } - token = github_token() - if token: - headers["Authorization"] = f"Bearer {token}" - if extra: - headers.update(extra) - return headers - - -def github_request(url: str, *, headers: dict[str, str] | None = None) -> bytes: - """Perform an authenticated GitHub request and return the response body. - - :param url: Absolute URL to request. - :param headers: Optional extra headers merged with the defaults. - :returns: Raw response bytes. - :raises RuntimeError: If the response status is not in the 2xx range. - """ - request = urllib.request.Request(url, headers=github_headers(headers)) - try: - with urllib.request.urlopen(request) as response: - return response.read() - except urllib.error.HTTPError as exc: - body = exc.read().decode("utf-8", errors="replace") - raise RuntimeError( - f"GitHub request failed ({exc.code} {exc.reason}) for {url}\n{body}" - ) from exc - - -def get_tag(requested_tag: str | None) -> str: - """Resolve the tag to sync, falling back to the latest GitHub tag. - - :param requested_tag: Explicit tag override, or ``None`` to use latest. - :returns: The resolved tag name. - :raises RuntimeError: If no tags are available upstream. - """ - if requested_tag: - return requested_tag - - body = github_request(f"{GITHUB_API}/repos/{OWNER}/{REPO}/tags?per_page=20") - tags = json.loads(body) - if not isinstance(tags, list) or not tags: - raise RuntimeError(f"No tags found for {OWNER}/{REPO}.") - return tags[0]["name"] - - -def remove_existing_artifacts() -> None: - """Delete previously synced frontend tarballs from ``FRONTEND_ARTIFACTS_DIR``. - - Matches both the unversioned ``kitconcept-volto-plate.tgz`` (current - naming) and any legacy ``kitconcept-volto-plate-.tgz`` files - that may still be around. - """ - FRONTEND_ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True) - for entry in FRONTEND_ARTIFACTS_DIR.iterdir(): - if entry.name.startswith(ASSET_STEM) and entry.name.endswith(ASSET_SUFFIX): - entry.unlink() - - -def extract_frontend_artifact(source_bytes: bytes) -> Path: - """Extract the frontend ``.tgz`` artifact from the source tarball. - - Looks for ``/frontend/artifacts/kitconcept-volto-plate.tgz`` - (exact filename) inside the source archive and writes its bytes to - ``FRONTEND_ARTIFACTS_DIR/kitconcept-volto-plate.tgz``. Any prior - ``kitconcept-volto-plate*.tgz`` in that directory is removed first - (covers both the unversioned name and any legacy versioned files). - - :param source_bytes: Raw bytes of the GitHub source archive. - :returns: Path to the extracted ``.tgz`` file. - :raises RuntimeError: If the expected artifact is missing. - """ - with tarfile.open(fileobj=io.BytesIO(source_bytes), mode="r:gz") as src: - members = src.getmembers() - - top_levels = {m.name.split("/", 1)[0] for m in members if m.name} - if len(top_levels) != 1: - raise RuntimeError( - "Source tarball does not have a single top-level directory; " - f"found: {sorted(top_levels)}" - ) - repo_prefix = next(iter(top_levels)) - artifacts_prefix = f"{repo_prefix}/frontend/artifacts/" - member_name = f"{artifacts_prefix}{FRONTEND_ARTIFACT_NAME}" - - member = next((m for m in members if m.name == member_name), None) - if member is None or not member.isfile(): - available = sorted( - m.name[len(artifacts_prefix) :] - for m in members - if m.name.startswith(artifacts_prefix) - and m.isfile() - and m.name.endswith(ASSET_SUFFIX) - ) - detail = ( - f"Other .tgz files there: {', '.join(available)}" - if available - else "No .tgz files were found under that directory." - ) - raise RuntimeError( - f"Expected {member_name} inside the source archive, " - f"but it was not found.\n{detail}" - ) - - extracted = src.extractfile(member) - if extracted is None: - raise RuntimeError(f"Could not read {member.name} from the source archive.") - data = extracted.read() - - remove_existing_artifacts() - artifact_path = FRONTEND_ARTIFACTS_DIR / FRONTEND_ARTIFACT_NAME - artifact_path.write_bytes(data) - return artifact_path - - -def update_dependency(artifact_path: Path) -> str: - """Rewrite the gmbh-intranet ``package.json`` to point at ``artifact_path``. - - :param artifact_path: Path to the freshly downloaded artifact. - :returns: The new dependency value (``file:``). - """ - package_json = json.loads(ADDON_PACKAGE_JSON_PATH.read_text(encoding="utf-8")) - relative_artifact_path = os.path.relpath( - artifact_path, ADDON_PACKAGE_JSON_PATH.parent - ).replace(os.sep, "/") - dependency_value = f"file:{relative_artifact_path}" - package_json["dependencies"][PACKAGE_NAME] = dependency_value - ADDON_PACKAGE_JSON_PATH.write_text( - json.dumps(package_json, indent=2) + "\n", encoding="utf-8" - ) - return dependency_value - - -def download_source_tarball(tag: str) -> bytes: - """Download the ``kitconcept/volto-plate`` source archive for ``tag``. - - Hits ``https://github.com///archive/refs/tags/.tar.gz``, - which returns a 302 to a short-lived ``codeload.github.com`` URL. - ``urllib`` follows the redirect transparently; the auth header is - harmless on the signed redirect target and required on the initial GET - for private repositories. - - :param tag: Tag name to fetch. - :returns: Raw ``.tar.gz`` bytes. - :raises RuntimeError: If the download fails. - """ - url = f"https://github.com/{OWNER}/{REPO}/archive/refs/tags/{tag}.tar.gz" - request = urllib.request.Request(url, headers=github_headers()) - try: - with urllib.request.urlopen(request) as response: - return response.read() - except urllib.error.HTTPError as exc: - body = exc.read().decode("utf-8", errors="replace") - raise RuntimeError( - f"Source archive download failed ({exc.code} {exc.reason}) " - f"for {url}\n{body}" - ) from exc - - -def remove_existing_backend_artifacts() -> None: - """Delete previously synced backend tarballs from ``BACKEND_ARTIFACTS_DIR``. - - Matches both the unversioned ``kitconcept-plate.tar.gz`` (current naming) - and any legacy ``kitconcept-plate-.tar.gz`` files that may still - be around. - """ - BACKEND_ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True) - for entry in BACKEND_ARTIFACTS_DIR.iterdir(): - if entry.name.startswith(BACKEND_ASSET_STEM) and entry.name.endswith( - BACKEND_ASSET_SUFFIX - ): - entry.unlink() - - -def repack_backend(source_bytes: bytes) -> Path: - """Repack the ``backend/`` subtree as a ``kitconcept-plate`` sdist. - - Reads the source archive in-memory, keeps only members whose path is - under ``/backend/``, rewrites that prefix to - ``kitconcept-plate/``, and writes a fresh ``.tar.gz`` to - ``BACKEND_ARTIFACTS_DIR/kitconcept-plate.tar.gz``. Any existing - ``kitconcept-plate*.tar.gz`` in that directory is removed first. - - :param source_bytes: Raw bytes of the GitHub source archive. - :returns: Path to the freshly written backend tarball. - :raises RuntimeError: If the archive does not contain a ``backend/`` - subtree under a single top-level directory. - """ - output_path = BACKEND_ARTIFACTS_DIR / BACKEND_ARTIFACT_NAME - - with tarfile.open(fileobj=io.BytesIO(source_bytes), mode="r:gz") as src: - members = src.getmembers() - - top_levels = {m.name.split("/", 1)[0] for m in members if m.name} - if len(top_levels) != 1: - raise RuntimeError( - "Source tarball does not have a single top-level directory; " - f"found: {sorted(top_levels)}" - ) - repo_prefix = next(iter(top_levels)) - backend_prefix = f"{repo_prefix}/backend/" - - backend_members = [m for m in members if m.name.startswith(backend_prefix)] - if not backend_members: - raise RuntimeError(f"No 'backend/' subtree found inside {repo_prefix}/.") - - remove_existing_backend_artifacts() - - with tarfile.open(output_path, mode="w:gz") as dst: - for member in backend_members: - new_name = ( - f"{BACKEND_PACKAGE_NAME}/" + member.name[len(backend_prefix) :] - ) - if not new_name.rstrip("/"): - continue - rewritten = tarfile.TarInfo(name=new_name) - rewritten.size = member.size - rewritten.mtime = member.mtime - rewritten.mode = member.mode - rewritten.type = member.type - rewritten.linkname = member.linkname - rewritten.uid = 0 - rewritten.gid = 0 - rewritten.uname = "" - rewritten.gname = "" - if member.isfile(): - extracted = src.extractfile(member) - dst.addfile(rewritten, extracted) - else: - dst.addfile(rewritten) - - return output_path - - -def update_backend_dependency(artifact_path: Path) -> str: - """Rewrite (or insert) the ``kitconcept-plate`` line in backend ``pyproject.toml``. - - Within ``[tool.uv.sources]``, replaces an existing - ``kitconcept-plate = { ... }`` line with a local - ``path = "container/"`` form, or appends a fresh one at the end of - the section's content when no such line exists. ``[project].dependencies`` - is intentionally left alone — that declaration must already be in place - for ``uv`` to pick up this source. - - :param artifact_path: Path to the freshly built backend tarball. - :returns: The new dependency value (the right-hand side of the assignment). - :raises RuntimeError: If the ``[tool.uv.sources]`` section is missing. - """ - relative_artifact_path = os.path.relpath( - artifact_path, BACKEND_PYPROJECT_PATH.parent - ).replace(os.sep, "/") - new_line = f'{BACKEND_PACKAGE_NAME} = {{ path = "{relative_artifact_path}" }}' - new_value = new_line.split("=", 1)[1].strip() - - text = BACKEND_PYPROJECT_PATH.read_text(encoding="utf-8") - lines = text.splitlines(keepends=True) - - section_header_re = re.compile(r"^\[tool\.uv\.sources\]\s*$") - next_section_re = re.compile(r"^\[") - package_line_re = re.compile(rf"^{re.escape(BACKEND_PACKAGE_NAME)}\s*=") - - section_idx = next( - (i for i, line in enumerate(lines) if section_header_re.match(line)), - None, - ) - if section_idx is None: - raise RuntimeError( - f"Could not find a '[tool.uv.sources]' section in {BACKEND_PYPROJECT_PATH}." - ) - - end_idx = next( - ( - i - for i in range(section_idx + 1, len(lines)) - if next_section_re.match(lines[i]) - ), - len(lines), - ) - - for i in range(section_idx + 1, end_idx): - if package_line_re.match(lines[i]): - lines[i] = new_line + "\n" - BACKEND_PYPROJECT_PATH.write_text("".join(lines), encoding="utf-8") - return new_value - - insert_at = end_idx - while insert_at > section_idx + 1 and lines[insert_at - 1].strip() == "": - insert_at -= 1 - lines.insert(insert_at, new_line + "\n") - BACKEND_PYPROJECT_PATH.write_text("".join(lines), encoding="utf-8") - return new_value - - -def run_command(args: list[str], *, cwd: Path) -> None: - """Run a command in ``cwd`` and raise ``RuntimeError`` on failure. - - :param args: Command and arguments to execute. - :param cwd: Working directory for the subprocess. - :raises RuntimeError: If the command exits with a non-zero status. - """ - try: - subprocess.run(args, cwd=cwd, check=True) - except subprocess.CalledProcessError as exc: - command = " ".join(args) - raise RuntimeError(f"Command failed ({exc.returncode}): {command}") from exc - - -def refresh_backend_lock() -> None: - """Refresh ``backend/uv.lock`` for the synced backend artifact.""" - run_command( - ["uv", "lock", "--upgrade-package", BACKEND_PACKAGE_NAME], - cwd=BACKEND_DIR, - ) - - -def install_repo() -> None: - """Run ``make install`` in the repo root.""" - run_command(["make", "install"], cwd=ROOT_DIR) - - -def parse_args(argv: list[str] | None = None) -> argparse.Namespace: - """Parse command-line arguments. - - :param argv: Argument list (``sys.argv[1:]`` when ``None``). - :returns: Namespace with a ``tag`` attribute (``str | None``). - """ - parser = argparse.ArgumentParser( - description="Sync the latest @kitconcept/volto-plate artifact." - ) - parser.add_argument( - "--tag", - default=None, - help="Specific tag to sync. Defaults to the most recent tag.", - ) - return parser.parse_args(argv) - - -def main(argv: list[str] | None = None) -> int: - """Run the artifact sync and reinstall workflow. - - :param argv: Optional argument override (useful for tests). - :returns: Process exit code. - """ - args = parse_args(argv) - try: - tag = get_tag(args.tag) - source_bytes = download_source_tarball(tag) - - artifact_path = extract_frontend_artifact(source_bytes) - dependency_value = update_dependency(artifact_path) - - backend_artifact_path = repack_backend(source_bytes) - backend_dependency_value = update_backend_dependency(backend_artifact_path) - refresh_backend_lock() - install_repo() - except (RuntimeError, urllib.error.URLError, OSError, tarfile.TarError) as exc: - print(str(exc), file=sys.stderr) - return 1 - - print(f"Synced {PACKAGE_NAME}") - print(f"Tag: {tag}") - print(f"Frontend artifact: {artifact_path.relative_to(FRONTEND_DIR)}") - print(f"Frontend dependency: {dependency_value}") - print(f"Backend artifact: {backend_artifact_path.relative_to(BACKEND_DIR)}") - print(f"Backend dependency: {BACKEND_PACKAGE_NAME} = {backend_dependency_value}") - print("Backend lock: uv.lock refreshed") - print("Install: make install") - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/towncrier.toml b/towncrier.toml index c09e1ac02..2ff20d5f0 100644 --- a/towncrier.toml +++ b/towncrier.toml @@ -31,3 +31,8 @@ showcontent = true directory = "documentation" name = "Documentation" showcontent = true + +[[tool.towncrier.type]] +directory = "tests" +name = "Tests" +showcontent = true