diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 45aaad75..225d7f6d 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,49 +1,7 @@ # Frequenz Repository Configuration Release Notes -## Summary - -This release improves dependabot groups, so it is less likely that breaking updates are grouped with non-breaking updates and upgrades the GitHub workflows to use more actions, run PR checks faster and use Ubuntu 24.04 instead of 20.04. - -## Upgrading - -### Cookiecutter template - -* Branch protection rule **Protect version branches** was updated, please re-import it following the [instructions](https://frequenz-floss.github.io/frequenz-repo-config-python/v0.13/user-guide/start-a-new-project/configure-github/#rulesets). - - > [!IMPORTANT] - > For **api** projects make sure to require the **Check proto files with protolint** status check too, which is not included by the provided ruleset by default. - -All other upgrading should be done via the migration script or regenerating the templates. - -```bash -curl -sSL https://raw.githubusercontent.com/frequenz-floss/frequenz-repo-config-python/v0.12/cookiecutter/migrate.py | python3 -``` - -But you might still need to adapt your code: - -* The new workflows will test using Python 3.12 too, if your code is not compatible with it, you might need to fix it, or you can just remove the Python 3.12 from the test matrix if you need a quick fix. For example, the `typing-extension` library is compatible with Python 3.12 from version 4.6.0, so you might need to upgrade it if you are using it. -* Check the new dependabot configuration file if you customized the dependabot configuration for the `pip` ecosystem. -* Add exclusions for any other dependency you have at v0.x.x or that breaks frequently, so dependabot PRs are easy to merge. - -## New Features +## Bug Fixes ### Cookiecutter template -- Dependabot config now uses a new grouping that should make upgrades more smooth. - - * We group patch updates as they should always work. - * We also group minor updates, as it works too for most libraries, typically except libraries that don't have a stable release yet (v0.x.x branch), so we make some exceptions for them. - * Major updates and dependencies excluded by the above groups are still managed, but they'll create one PR per dependency, as breakage is expected, so it might need manual intervention. - * Finally, we group some dependencies that are related to each other, and usually needs to be updated together. - -- The GitHub workflows is now split into PRs and CI workflows. - - These new workflows also start using a new reusable `gh-action-nox`, native arm runners and Ubuntu 24.04, as [Ubuntu 20.04 will be removed from GitHub runners by April's 1st][ubuntu-20.04]. Python 3.12 is also added to the test matrix. - - The PR action is more lightweight, and only tests with one matrix (the most widely used), so PRs can be tested more quickly. - - The push workflow does a more intense testing with all matrix combinations. This also runs for the merge queue, so before PRs are actually merged the tests will run for the complete matrix. - -[ubuntu-20.04]: https://github.blog/changelog/2025-01-15-github-actions-ubuntu-20-runner-image-brownout-dates-and-other-breaking-changes/ - -- The Python `Protect version branches` branch protection rule now request review to Copilot by default. +- Fix the repo-config version number that was outdated. diff --git a/cookiecutter/migrate.py b/cookiecutter/migrate.py index 801eba0c..c0e1dba0 100644 --- a/cookiecutter/migrate.py +++ b/cookiecutter/migrate.py @@ -21,10 +21,8 @@ """ # noqa: E501 import hashlib -import json import os import subprocess -import sys import tempfile from pathlib import Path from typing import SupportsIndex @@ -34,1057 +32,10 @@ def main() -> None: """Run the migration steps.""" # Add a separation line like this one after each migration step. print("=" * 72) - regroup_dependabot() - print("=" * 72) - use_new_workflows() - print("=" * 72) print("Migration script finished. Remember to follow any manual instructions.") print("=" * 72) -# pylint: disable=too-many-lines - - -def regroup_dependabot() -> None: - """Use new dependabot groups to separate dependencies that break often.""" - print("Using new dependabot groups to separate dependencies that break often...") - # Dependabot configuration file - dependabot_file = Path(".github/dependabot.yml") - - # Skip if the file doesn't exist - if not dependabot_file.exists(): - manual_step( - "Dependabot configuration file not found, not excluding " - "frequenz-repo-config from group updates. Please consider adding a " - "dependabot configuration file." - ) - return - - dependabot_content = dependabot_file.read_text(encoding="utf-8") - - new_groups = """\ - # We group patch updates as they should always work. - # We also group minor updates, as it works too for most libraries, - # typically except libraries that don't have a stable release yet (v0.x.x - # branch), so we make some exceptions for them. - # Major updates and dependencies excluded by the above groups are still - # managed, but they'll create one PR per dependency, as breakage is - # expected, so it might need manual intervention. - # Finally, we group some dependencies that are related to each other, and - # usually need to be updated together. - groups: - patch: - update-types: - - "patch" - exclude-patterns: - # pydoclint has shipped breaking changes in patch updates often - - "pydoclint" - minor: - update-types: - - "minor" - exclude-patterns: - - "async-solipsism" - - "frequenz-repo-config*" - - "markdown-callouts" - - "mkdocs-gen-files" - - "mkdocs-literate-nav" - - "mkdocstrings*" - - "pydoclint" - - "pytest-asyncio" - # We group repo-config updates as it uses optional dependencies that are - # considered different dependencies otherwise, and will create one PR for - # each if we don't group them. - repo-config: - patterns: - - "frequenz-repo-config*" - mkdocstrings: - patterns: - - "mkdocstrings*" -""" - - marker = " open-pull-requests-limit: 10" - if marker not in dependabot_content: - manual_step( - f"Could not file marker ({marker!r}) in {dependabot_file}, " - "can't update automatically. Please consider using these new groups " - "in the dependabot configuration file:" - ) - return - - text_to_replace = "" - found_marker = False - for line in dependabot_content.splitlines(): - if line == marker: - found_marker = True - continue - if not found_marker: - continue - if line == "" and found_marker: - break - text_to_replace += line + "\n" - - if not text_to_replace: - manual_step( - "Could not find the text to replace with the new depenndabot " - "groups. Please consider using these new groups in the dependabot " - "configuration file:" - ) - return - - replace_file_contents_atomically( - dependabot_file, - text_to_replace, - new_groups, - count=1, - content=dependabot_content, - ) - - manual_step( - "Please review the changes to the dependabot config if you made any " - "customizations. Also please check your dependencies and if you have other " - "dependencies at v0.x.x or that break often, add them to the exclusion list." - ) - - -def use_new_workflows() -> None: - """Use the new GitHub Actions workflows.""" - print("Splitting the old GitHub ci.yaml workflow into ci.yaml and ci-pr.yaml...") - try: - os.unlink(".github/workflows/ci.yaml") - except OSError as err: - print(f"Failed to remove old ci.yaml: {err}", file=sys.stderr) - - project_type: str | None = None - try: - with open(".cookiecutter-replay.json", "r", encoding="utf-8") as json_file: - cookiecutter_json = json.load(json_file) - project_type = cookiecutter_json["cookiecutter"]["type"] - except Exception as err: # pylint: disable=broad-except - print(f"Failed to load .cookiecutter-replay.json: {err}", file=sys.stderr) - print("The project will be considered a regular project, not a API project") - - def print_todos(file_name: str, contents: str) -> None: - for index, line in enumerate(contents.splitlines(), start=1): - if "TODO(cookiecutter):" in line: - print(f" {file_name}:{index}: {line}") - - with open(".github/workflows/ci.yaml", "w", encoding="utf-8") as new_file: - contents_ci = NEW_CI_API if project_type == "api" else NEW_CI - new_file.write(contents_ci) - - with open(".github/workflows/ci-pr.yaml", "w", encoding="utf-8") as new_file: - contents_pr = NEW_CI_PR_API if project_type == "api" else NEW_CI_PR - new_file.write(contents_pr) - - manual_step( - "The ci.yaml and ci-pr.yaml files have been created. Please review the " - "changes and make sure they work for your project and remember to add the new " - "ci-pr.yaml to git: git add .github/workflows/ci-pr.yaml. Please also check " - "the new TODOs." - ) - print_todos(".github/workflows/ci.yaml", contents_ci) - print_todos(".github/workflows/ci-pr.yaml", contents_pr) - - -NEW_CI = r"""name: CI - -on: - merge_group: - push: - # We need to explicitly include tags because otherwise when adding - # `branches-ignore` it will only trigger on branches. - tags: - - '*' - branches-ignore: - # Ignore pushes to merge queues. - # We only want to test the merge commit (`merge_group` event), the hashes - # in the push were already tested by the PR checks - - 'gh-readonly-queue/**' - - 'dependabot/**' - workflow_dispatch: - -env: - # Please make sure this version is included in the `matrix`, as the - # `matrix` section can't use `env`, so it must be entered manually - DEFAULT_PYTHON_VERSION: '3.11' - # It would be nice to be able to also define a DEFAULT_UBUNTU_VERSION - # but sadly `env` can't be used either in `runs-on`. - -jobs: - nox: - name: Test with nox - strategy: - fail-fast: false - matrix: - arch: - - amd64 - - arm - os: - - ubuntu-24.04 - python: - - "3.11" - - "3.12" - nox-session: - # To speed things up a bit we use the special ci_checks_max session - # that uses the same venv to run multiple linting sessions - - "ci_checks_max" - - "pytest_min" - runs-on: ${{ matrix.os }}${{ matrix.arch != 'amd64' && format('-{0}', matrix.arch) || '' }} - - steps: - - name: Run nox - uses: frequenz-floss/gh-action-nox@v1.0.0 - with: - python-version: ${{ matrix.python }} - nox-session: ${{ matrix.nox-session }} - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # git-username: ${{ secrets.GIT_USER }} - # git-password: ${{ secrets.GIT_PASS }} - - # This job runs if all the `nox` matrix jobs ran and succeeded. - # It is only used to have a single job that we can require in branch - # protection rules, so we don't have to update the protection rules each time - # we add or remove a job from the matrix. - nox-all: - # The job name should match the name of the `nox` job. - name: Test with nox - needs: ["nox"] - # We skip this job only if nox was also skipped - if: always() && needs.nox.result != 'skipped' - runs-on: ubuntu-24.04 - env: - DEPS_RESULT: ${{ needs.nox.result }} - steps: - - name: Check matrix job result - run: test "$DEPS_RESULT" = "success" - - build: - name: Build distribution packages - # Since this is a pure Python package, we only need to build it once. If it - # had any architecture specific code, we would need to build it for each - # architecture. - runs-on: ubuntu-24.04 - - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: build - - - name: Build the source and binary distribution - run: python -m build - - - name: Upload distribution files - uses: actions/upload-artifact@v4 - with: - name: dist-packages - path: dist/ - if-no-files-found: error - - test-installation: - name: Test package installation - needs: ["build"] - strategy: - fail-fast: false - matrix: - arch: - - amd64 - - arm - os: - - ubuntu-24.04 - python: - - "3.11" - - "3.12" - runs-on: ${{ matrix.os }}${{ matrix.arch != 'amd64' && format('-{0}', matrix.arch) || '' }} - - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Print environment (debug) - run: env - - - name: Download package - uses: actions/download-artifact@v4 - with: - name: dist-packages - path: dist - - # This is necessary for the `pip` caching in the setup-python action to work - - name: Fetch the pyproject.toml file for this action hash - env: - GH_TOKEN: ${{ github.token }} - REPO: ${{ github.repository }} - REF: ${{ github.sha }} - run: | - set -ux - gh api \ - -X GET \ - -H "Accept: application/vnd.github.raw" \ - "/repos/$REPO/contents/pyproject.toml?ref=$REF" \ - > pyproject.toml - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ matrix.python }} - dependencies: dist/*.whl - - - name: Print installed packages (debug) - run: python -m pip freeze - - # This job runs if all the `test-installation` matrix jobs ran and succeeded. - # It is only used to have a single job that we can require in branch - # protection rules, so we don't have to update the protection rules each time - # we add or remove a job from the matrix. - test-installation-all: - # The job name should match the name of the `test-installation` job. - name: Test package installation - needs: ["test-installation"] - # We skip this job only if test-installation was also skipped - if: always() && needs.test-installation.result != 'skipped' - runs-on: ubuntu-24.04 - env: - DEPS_RESULT: ${{ needs.test-installation.result }} - steps: - - name: Check matrix job result - run: test "$DEPS_RESULT" = "success" - - test-docs: - name: Test documentation website generation - if: github.event_name != 'push' - runs-on: ubuntu-24.04 - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: .[dev-mkdocs] - - - name: Generate the documentation - env: - MIKE_VERSION: gh-${{ github.job }} - run: | - mike deploy $MIKE_VERSION - mike set-default $MIKE_VERSION - - - name: Upload site - uses: actions/upload-artifact@v4 - with: - name: docs-site - path: site/ - if-no-files-found: error - - publish-docs: - name: Publish documentation website to GitHub pages - needs: ["nox-all", "test-installation-all"] - if: github.event_name == 'push' - runs-on: ubuntu-24.04 - permissions: - contents: write - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: .[dev-mkdocs] - - - name: Calculate and check version - id: mike-version - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPO: ${{ github.repository }} - GIT_REF: ${{ github.ref }} - GIT_SHA: ${{ github.sha }} - run: | - python -m frequenz.repo.config.cli.version.mike.info - - - name: Fetch the gh-pages branch - if: steps.mike-version.outputs.version - run: git fetch origin gh-pages --depth=1 - - - name: Build site - if: steps.mike-version.outputs.version - env: - VERSION: ${{ steps.mike-version.outputs.version }} - TITLE: ${{ steps.mike-version.outputs.title }} - ALIASES: ${{ steps.mike-version.outputs.aliases }} - # This is not ideal, we need to define all these variables here - # because we need to calculate all the repository version information - # to be able to show the correct versions in the documentation when - # building it. - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPO: ${{ github.repository }} - GIT_REF: ${{ github.ref }} - GIT_SHA: ${{ github.sha }} - run: | - mike deploy --update-aliases --title "$TITLE" "$VERSION" $ALIASES - - - name: Sort site versions - if: steps.mike-version.outputs.version - run: | - git checkout gh-pages - python -m frequenz.repo.config.cli.version.mike.sort versions.json - git commit -a -m "Sort versions.json" - - - name: Publish site - if: steps.mike-version.outputs.version - run: | - git push origin gh-pages - - create-github-release: - name: Create GitHub release - needs: ["publish-docs"] - # Create a release only on tags creation - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - permissions: - # We need write permissions on contents to create GitHub releases and on - # discussions to create the release announcement in the discussion forums - contents: write - discussions: write - runs-on: ubuntu-24.04 - steps: - - name: Download distribution files - uses: actions/download-artifact@v4 - with: - name: dist-packages - path: dist - - - name: Download RELEASE_NOTES.md - run: | - set -ux - gh api \ - -X GET \ - -f ref=$REF \ - -H "Accept: application/vnd.github.raw" \ - "/repos/$REPOSITORY/contents/RELEASE_NOTES.md" \ - > RELEASE_NOTES.md - env: - REF: ${{ github.ref }} - REPOSITORY: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create GitHub release - run: | - set -ux - extra_opts= - if echo "$REF_NAME" | grep -- -; then extra_opts=" --prerelease"; fi - gh release create \ - -R "$REPOSITORY" \ - --notes-file RELEASE_NOTES.md \ - --generate-notes \ - $extra_opts \ - $REF_NAME \ - dist/* - env: - REF_NAME: ${{ github.ref_name }} - REPOSITORY: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-to-pypi: - name: Publish packages to PyPI - needs: ["create-github-release"] - runs-on: ubuntu-24.04 - permissions: - # For trusted publishing. See: - # https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/ - id-token: write - steps: - - name: Download distribution files - uses: actions/download-artifact@v4 - with: - name: dist-packages - path: dist - - - name: Publish the Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 -""" - -NEW_CI_API = r"""name: CI - -on: - merge_group: - push: - # We need to explicitly include tags because otherwise when adding - # `branches-ignore` it will only trigger on branches. - tags: - - '*' - branches-ignore: - # Ignore pushes to merge queues. - # We only want to test the merge commit (`merge_group` event), the hashes - # in the push were already tested by the PR checks - - 'gh-readonly-queue/**' - - 'dependabot/**' - workflow_dispatch: - -env: - # Please make sure this version is included in the `matrix`, as the - # `matrix` section can't use `env`, so it must be entered manually - DEFAULT_PYTHON_VERSION: '3.11' - # It would be nice to be able to also define a DEFAULT_UBUNTU_VERSION - # but sadly `env` can't be used either in `runs-on`. - -jobs: - protolint: - name: Check proto files with protolint - runs-on: ubuntu-24.04 - - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v3 - with: - submodules: true - - - name: Run protolint - # Only use hashes here, as we are passing the github token, we want to - # make sure updates are done consciously to avoid security issues if the - # action repo gets hacked - uses: yoheimuta/action-protolint@e94cc01b1ad085ed9427098442f66f2519c723eb # v1.0.0 - with: - fail_on_error: true - filter_mode: nofilter - github_token: ${{ secrets.github_token }} - protolint_flags: proto/ - protolint_version: "0.53.0" - reporter: github-check - - nox: - name: Test with nox - strategy: - fail-fast: false - matrix: - arch: - - amd64 - - arm - os: - - ubuntu-24.04 - python: - - "3.11" - - "3.12" - nox-session: - # To speed things up a bit we use the special ci_checks_max session - # that uses the same venv to run multiple linting sessions - - "ci_checks_max" - - "pytest_min" - runs-on: ${{ matrix.os }}${{ matrix.arch != 'amd64' && format('-{0}', matrix.arch) || '' }} - - steps: - - name: Run nox - uses: frequenz-floss/gh-action-nox@v1.0.0 - with: - python-version: ${{ matrix.python }} - nox-session: ${{ matrix.nox-session }} - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # git-username: ${{ secrets.GIT_USER }} - # git-password: ${{ secrets.GIT_PASS }} - - # This job runs if all the `nox` matrix jobs ran and succeeded. - # It is only used to have a single job that we can require in branch - # protection rules, so we don't have to update the protection rules each time - # we add or remove a job from the matrix. - nox-all: - # The job name should match the name of the `nox` job. - name: Test with nox - needs: ["nox"] - # We skip this job only if nox was also skipped - if: always() && needs.nox.result != 'skipped' - runs-on: ubuntu-24.04 - env: - DEPS_RESULT: ${{ needs.nox.result }} - steps: - - name: Check matrix job result - run: test "$DEPS_RESULT" = "success" - - build: - name: Build distribution packages - # Since this is a pure Python package, we only need to build it once. If it - # had any architecture specific code, we would need to build it for each - # architecture. - runs-on: ubuntu-24.04 - - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: build - - - name: Build the source and binary distribution - run: python -m build - - - name: Upload distribution files - uses: actions/upload-artifact@v4 - with: - name: dist-packages - path: dist/ - if-no-files-found: error - - test-installation: - name: Test package installation - needs: ["build"] - strategy: - fail-fast: false - matrix: - arch: - - amd64 - - arm - os: - - ubuntu-24.04 - python: - - "3.11" - - "3.12" - runs-on: ${{ matrix.os }}${{ matrix.arch != 'amd64' && format('-{0}', matrix.arch) || '' }} - - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Print environment (debug) - run: env - - - name: Download package - uses: actions/download-artifact@v4 - with: - name: dist-packages - path: dist - - # This is necessary for the `pip` caching in the setup-python action to work - - name: Fetch the pyproject.toml file for this action hash - env: - GH_TOKEN: ${{ github.token }} - REPO: ${{ github.repository }} - REF: ${{ github.sha }} - run: | - set -ux - gh api \ - -X GET \ - -H "Accept: application/vnd.github.raw" \ - "/repos/$REPO/contents/pyproject.toml?ref=$REF" \ - > pyproject.toml - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ matrix.python }} - dependencies: dist/*.whl - - - name: Print installed packages (debug) - run: python -m pip freeze - - # This job runs if all the `test-installation` matrix jobs ran and succeeded. - # It is only used to have a single job that we can require in branch - # protection rules, so we don't have to update the protection rules each time - # we add or remove a job from the matrix. - test-installation-all: - # The job name should match the name of the `test-installation` job. - name: Test package installation - needs: ["test-installation"] - # We skip this job only if test-installation was also skipped - if: always() && needs.test-installation.result != 'skipped' - runs-on: ubuntu-24.04 - env: - DEPS_RESULT: ${{ needs.test-installation.result }} - steps: - - name: Check matrix job result - run: test "$DEPS_RESULT" = "success" - - test-docs: - name: Test documentation website generation - if: github.event_name != 'push' - runs-on: ubuntu-24.04 - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: .[dev-mkdocs] - - - name: Generate the documentation - env: - MIKE_VERSION: gh-${{ github.job }} - run: | - mike deploy $MIKE_VERSION - mike set-default $MIKE_VERSION - - - name: Upload site - uses: actions/upload-artifact@v4 - with: - name: docs-site - path: site/ - if-no-files-found: error - - publish-docs: - name: Publish documentation website to GitHub pages - needs: ["nox-all", "test-installation-all"] - if: github.event_name == 'push' - runs-on: ubuntu-24.04 - permissions: - contents: write - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: .[dev-mkdocs] - - - name: Calculate and check version - id: mike-version - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPO: ${{ github.repository }} - GIT_REF: ${{ github.ref }} - GIT_SHA: ${{ github.sha }} - run: | - python -m frequenz.repo.config.cli.version.mike.info - - - name: Fetch the gh-pages branch - if: steps.mike-version.outputs.version - run: git fetch origin gh-pages --depth=1 - - - name: Build site - if: steps.mike-version.outputs.version - env: - VERSION: ${{ steps.mike-version.outputs.version }} - TITLE: ${{ steps.mike-version.outputs.title }} - ALIASES: ${{ steps.mike-version.outputs.aliases }} - # This is not ideal, we need to define all these variables here - # because we need to calculate all the repository version information - # to be able to show the correct versions in the documentation when - # building it. - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_REPO: ${{ github.repository }} - GIT_REF: ${{ github.ref }} - GIT_SHA: ${{ github.sha }} - run: | - mike deploy --update-aliases --title "$TITLE" "$VERSION" $ALIASES - - - name: Sort site versions - if: steps.mike-version.outputs.version - run: | - git checkout gh-pages - python -m frequenz.repo.config.cli.version.mike.sort versions.json - git commit -a -m "Sort versions.json" - - - name: Publish site - if: steps.mike-version.outputs.version - run: | - git push origin gh-pages - - create-github-release: - name: Create GitHub release - needs: ["publish-docs"] - # Create a release only on tags creation - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - permissions: - # We need write permissions on contents to create GitHub releases and on - # discussions to create the release announcement in the discussion forums - contents: write - discussions: write - runs-on: ubuntu-24.04 - steps: - - name: Download distribution files - uses: actions/download-artifact@v4 - with: - name: dist-packages - path: dist - - - name: Download RELEASE_NOTES.md - run: | - set -ux - gh api \ - -X GET \ - -f ref=$REF \ - -H "Accept: application/vnd.github.raw" \ - "/repos/$REPOSITORY/contents/RELEASE_NOTES.md" \ - > RELEASE_NOTES.md - env: - REF: ${{ github.ref }} - REPOSITORY: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create GitHub release - run: | - set -ux - extra_opts= - if echo "$REF_NAME" | grep -- -; then extra_opts=" --prerelease"; fi - gh release create \ - -R "$REPOSITORY" \ - --notes-file RELEASE_NOTES.md \ - --generate-notes \ - $extra_opts \ - $REF_NAME \ - dist/* - env: - REF_NAME: ${{ github.ref_name }} - REPOSITORY: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - publish-to-pypi: - name: Publish packages to PyPI - needs: ["create-github-release"] - runs-on: ubuntu-24.04 - permissions: - # For trusted publishing. See: - # https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/ - id-token: write - steps: - - name: Download distribution files - uses: actions/download-artifact@v4 - with: - name: dist-packages - path: dist - - - name: Publish the Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 -""" - -NEW_CI_PR = r"""name: Test PR - -on: - pull_request: - -env: - # Please make sure this version is included in the `matrix`, as the - # `matrix` section can't use `env`, so it must be entered manually - DEFAULT_PYTHON_VERSION: '3.11' - # It would be nice to be able to also define a DEFAULT_UBUNTU_VERSION - # but sadly `env` can't be used either in `runs-on`. - -jobs: - nox: - name: Test with nox - runs-on: ubuntu-24.04 - - steps: - - name: Run nox - uses: frequenz-floss/gh-action-nox@v1.0.0 - with: - python-version: "3.11" - nox-session: ci_checks_max - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # git-username: ${{ secrets.GIT_USER }} - # git-password: ${{ secrets.GIT_PASS }} - - test-docs: - name: Test documentation website generation - runs-on: ubuntu-24.04 - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: .[dev-mkdocs] - - - name: Generate the documentation - env: - MIKE_VERSION: gh-${{ github.job }} - run: | - mike deploy $MIKE_VERSION - mike set-default $MIKE_VERSION - - - name: Upload site - uses: actions/upload-artifact@v4 - with: - name: docs-site - path: site/ - if-no-files-found: error -""" - -NEW_CI_PR_API = r"""name: Test PR - -on: - pull_request: - -env: - # Please make sure this version is included in the `matrix`, as the - # `matrix` section can't use `env`, so it must be entered manually - DEFAULT_PYTHON_VERSION: '3.11' - # It would be nice to be able to also define a DEFAULT_UBUNTU_VERSION - # but sadly `env` can't be used either in `runs-on`. - -jobs: - protolint: - name: Check proto files with protolint - runs-on: ubuntu-24.04 - - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v3 - with: - submodules: true - - - name: Run protolint - # Only use hashes here, as we are passing the github token, we want to - # make sure updates are done consciously to avoid security issues if the - # action repo gets hacked - uses: yoheimuta/action-protolint@e94cc01b1ad085ed9427098442f66f2519c723eb # v1.0.0 - with: - fail_on_error: true - filter_mode: nofilter - github_token: ${{ secrets.github_token }} - protolint_flags: proto/ - protolint_version: "0.53.0" - reporter: github-check - - nox: - name: Test with nox - runs-on: ubuntu-24.04 - - steps: - - name: Run nox - uses: frequenz-floss/gh-action-nox@v1.0.0 - with: - python-version: "3.11" - nox-session: ci_checks_max - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # git-username: ${{ secrets.GIT_USER }} - # git-password: ${{ secrets.GIT_PASS }} - - test-docs: - name: Test documentation website generation - runs-on: ubuntu-24.04 - steps: - - name: Setup Git - uses: frequenz-floss/gh-action-setup-git@v1.0.0 - # TODO(cookiecutter): Uncomment this for projects with private dependencies - # with: - # username: ${{ secrets.GIT_USER }} - # password: ${{ secrets.GIT_PASS }} - - - name: Fetch sources - uses: actions/checkout@v4 - with: - submodules: true - - - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - dependencies: .[dev-mkdocs] - - - name: Generate the documentation - env: - MIKE_VERSION: gh-${{ github.job }} - run: | - mike deploy $MIKE_VERSION - mike set-default $MIKE_VERSION - - - name: Upload site - uses: actions/upload-artifact@v4 - with: - name: docs-site - path: site/ - if-no-files-found: error -""" - - def apply_patch(patch_content: str) -> None: """Apply a patch using the patch utility.""" subprocess.run(["patch", "-p1"], input=patch_content.encode(), check=True) diff --git a/cookiecutter/{{cookiecutter.github_repo_name}}/pyproject.toml b/cookiecutter/{{cookiecutter.github_repo_name}}/pyproject.toml index deb7e33b..3ee77e64 100644 --- a/cookiecutter/{{cookiecutter.github_repo_name}}/pyproject.toml +++ b/cookiecutter/{{cookiecutter.github_repo_name}}/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 75.8.0", "setuptools_scm[toml] == 8.1.0", - "frequenz-repo-config[{{cookiecutter.type}}] == 0.12.3", + "frequenz-repo-config[{{cookiecutter.type}}] == 0.13.1", {%- if cookiecutter.type == "api" %} # We need to pin the protobuf, grpcio and grpcio-tools dependencies to make # sure the code is generated using the minimum supported versions, as older @@ -101,7 +101,7 @@ dev-mkdocs = [ "mkdocs-material == 9.6.2", "mkdocstrings[python] == 0.28.0", "mkdocstrings-python == 1.14.6", - "frequenz-repo-config[{{cookiecutter.type}}] == 0.12.3", + "frequenz-repo-config[{{cookiecutter.type}}] == 0.13.1", ] dev-mypy = [ "mypy == 1.9.0", @@ -114,7 +114,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2024.10.9", - "frequenz-repo-config[{{cookiecutter.type}}] == 0.12.3", + "frequenz-repo-config[{{cookiecutter.type}}] == 0.13.1", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -124,7 +124,7 @@ dev-pylint = [ dev-pytest = [ "pytest == 8.3.4", "pylint == 3.3.4", # We need this to check for the examples - "frequenz-repo-config[extra-lint-examples] == 0.12.3", + "frequenz-repo-config[extra-lint-examples] == 0.13.1", {%- if cookiecutter.type != "api" %} "pytest-mock == 3.14.0", "pytest-asyncio == 0.25.3", diff --git a/tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/pyproject.toml b/tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/pyproject.toml index be7b632a..4528a8af 100644 --- a/tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/pyproject.toml +++ b/tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 75.8.0", "setuptools_scm[toml] == 8.1.0", - "frequenz-repo-config[actor] == 0.12.3", + "frequenz-repo-config[actor] == 0.13.1", ] build-backend = "setuptools.build_meta" @@ -60,7 +60,7 @@ dev-mkdocs = [ "mkdocs-material == 9.6.2", "mkdocstrings[python] == 0.28.0", "mkdocstrings-python == 1.14.6", - "frequenz-repo-config[actor] == 0.12.3", + "frequenz-repo-config[actor] == 0.13.1", ] dev-mypy = [ "mypy == 1.9.0", @@ -70,7 +70,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2024.10.9", - "frequenz-repo-config[actor] == 0.12.3", + "frequenz-repo-config[actor] == 0.13.1", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -80,7 +80,7 @@ dev-pylint = [ dev-pytest = [ "pytest == 8.3.4", "pylint == 3.3.4", # We need this to check for the examples - "frequenz-repo-config[extra-lint-examples] == 0.12.3", + "frequenz-repo-config[extra-lint-examples] == 0.13.1", "pytest-mock == 3.14.0", "pytest-asyncio == 0.25.3", "async-solipsism == 0.7", diff --git a/tests_golden/integration/test_cookiecutter_generation/api/frequenz-api-test/pyproject.toml b/tests_golden/integration/test_cookiecutter_generation/api/frequenz-api-test/pyproject.toml index 6dcacc12..e063a5dc 100644 --- a/tests_golden/integration/test_cookiecutter_generation/api/frequenz-api-test/pyproject.toml +++ b/tests_golden/integration/test_cookiecutter_generation/api/frequenz-api-test/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 75.8.0", "setuptools_scm[toml] == 8.1.0", - "frequenz-repo-config[api] == 0.12.3", + "frequenz-repo-config[api] == 0.13.1", # We need to pin the protobuf, grpcio and grpcio-tools dependencies to make # sure the code is generated using the minimum supported versions, as older # versions can't work with code that was generated with newer versions. @@ -71,7 +71,7 @@ dev-mkdocs = [ "mkdocs-material == 9.6.2", "mkdocstrings[python] == 0.28.0", "mkdocstrings-python == 1.14.6", - "frequenz-repo-config[api] == 0.12.3", + "frequenz-repo-config[api] == 0.13.1", ] dev-mypy = [ "mypy == 1.9.0", @@ -82,7 +82,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2024.10.9", - "frequenz-repo-config[api] == 0.12.3", + "frequenz-repo-config[api] == 0.13.1", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -92,7 +92,7 @@ dev-pylint = [ dev-pytest = [ "pytest == 8.3.4", "pylint == 3.3.4", # We need this to check for the examples - "frequenz-repo-config[extra-lint-examples] == 0.12.3", + "frequenz-repo-config[extra-lint-examples] == 0.13.1", ] dev = [ "frequenz-api-test[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]", diff --git a/tests_golden/integration/test_cookiecutter_generation/app/frequenz-app-test/pyproject.toml b/tests_golden/integration/test_cookiecutter_generation/app/frequenz-app-test/pyproject.toml index df8fb0bb..dd744057 100644 --- a/tests_golden/integration/test_cookiecutter_generation/app/frequenz-app-test/pyproject.toml +++ b/tests_golden/integration/test_cookiecutter_generation/app/frequenz-app-test/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 75.8.0", "setuptools_scm[toml] == 8.1.0", - "frequenz-repo-config[app] == 0.12.3", + "frequenz-repo-config[app] == 0.13.1", ] build-backend = "setuptools.build_meta" @@ -59,7 +59,7 @@ dev-mkdocs = [ "mkdocs-material == 9.6.2", "mkdocstrings[python] == 0.28.0", "mkdocstrings-python == 1.14.6", - "frequenz-repo-config[app] == 0.12.3", + "frequenz-repo-config[app] == 0.13.1", ] dev-mypy = [ "mypy == 1.9.0", @@ -69,7 +69,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2024.10.9", - "frequenz-repo-config[app] == 0.12.3", + "frequenz-repo-config[app] == 0.13.1", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -79,7 +79,7 @@ dev-pylint = [ dev-pytest = [ "pytest == 8.3.4", "pylint == 3.3.4", # We need this to check for the examples - "frequenz-repo-config[extra-lint-examples] == 0.12.3", + "frequenz-repo-config[extra-lint-examples] == 0.13.1", "pytest-mock == 3.14.0", "pytest-asyncio == 0.25.3", "async-solipsism == 0.7", diff --git a/tests_golden/integration/test_cookiecutter_generation/lib/frequenz-test-python/pyproject.toml b/tests_golden/integration/test_cookiecutter_generation/lib/frequenz-test-python/pyproject.toml index 8cb3c7d4..160f5c5a 100644 --- a/tests_golden/integration/test_cookiecutter_generation/lib/frequenz-test-python/pyproject.toml +++ b/tests_golden/integration/test_cookiecutter_generation/lib/frequenz-test-python/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 75.8.0", "setuptools_scm[toml] == 8.1.0", - "frequenz-repo-config[lib] == 0.12.3", + "frequenz-repo-config[lib] == 0.13.1", ] build-backend = "setuptools.build_meta" @@ -56,7 +56,7 @@ dev-mkdocs = [ "mkdocs-material == 9.6.2", "mkdocstrings[python] == 0.28.0", "mkdocstrings-python == 1.14.6", - "frequenz-repo-config[lib] == 0.12.3", + "frequenz-repo-config[lib] == 0.13.1", ] dev-mypy = [ "mypy == 1.9.0", @@ -66,7 +66,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2024.10.9", - "frequenz-repo-config[lib] == 0.12.3", + "frequenz-repo-config[lib] == 0.13.1", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -76,7 +76,7 @@ dev-pylint = [ dev-pytest = [ "pytest == 8.3.4", "pylint == 3.3.4", # We need this to check for the examples - "frequenz-repo-config[extra-lint-examples] == 0.12.3", + "frequenz-repo-config[extra-lint-examples] == 0.13.1", "pytest-mock == 3.14.0", "pytest-asyncio == 0.25.3", "async-solipsism == 0.7", diff --git a/tests_golden/integration/test_cookiecutter_generation/model/frequenz-model-test/pyproject.toml b/tests_golden/integration/test_cookiecutter_generation/model/frequenz-model-test/pyproject.toml index d9ca29e6..f841ae70 100644 --- a/tests_golden/integration/test_cookiecutter_generation/model/frequenz-model-test/pyproject.toml +++ b/tests_golden/integration/test_cookiecutter_generation/model/frequenz-model-test/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 75.8.0", "setuptools_scm[toml] == 8.1.0", - "frequenz-repo-config[model] == 0.12.3", + "frequenz-repo-config[model] == 0.13.1", ] build-backend = "setuptools.build_meta" @@ -60,7 +60,7 @@ dev-mkdocs = [ "mkdocs-material == 9.6.2", "mkdocstrings[python] == 0.28.0", "mkdocstrings-python == 1.14.6", - "frequenz-repo-config[model] == 0.12.3", + "frequenz-repo-config[model] == 0.13.1", ] dev-mypy = [ "mypy == 1.9.0", @@ -70,7 +70,7 @@ dev-mypy = [ ] dev-noxfile = [ "nox == 2024.10.9", - "frequenz-repo-config[model] == 0.12.3", + "frequenz-repo-config[model] == 0.13.1", ] dev-pylint = [ # dev-pytest already defines a dependency to pylint because of the examples @@ -80,7 +80,7 @@ dev-pylint = [ dev-pytest = [ "pytest == 8.3.4", "pylint == 3.3.4", # We need this to check for the examples - "frequenz-repo-config[extra-lint-examples] == 0.12.3", + "frequenz-repo-config[extra-lint-examples] == 0.13.1", "pytest-mock == 3.14.0", "pytest-asyncio == 0.25.3", "async-solipsism == 0.7",