gitlabform 5.5.4__tar.gz → 5.5.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. {gitlabform-5.5.4 → gitlabform-5.5.5}/PKG-INFO +4 -4
  2. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/changelog.md +12 -0
  3. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/files.md +43 -1
  4. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/files_processor.py +145 -108
  5. {gitlabform-5.5.4 → gitlabform-5.5.5}/pyproject.toml +10 -10
  6. {gitlabform-5.5.4 → gitlabform-5.5.5}/tbump.toml +1 -1
  7. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_branches.py +52 -1
  8. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_files.py +176 -0
  9. gitlabform-5.5.5/tests/unit/processors/test_files_processor.py +312 -0
  10. {gitlabform-5.5.4 → gitlabform-5.5.5}/uv.lock +169 -169
  11. {gitlabform-5.5.4 → gitlabform-5.5.5}/.coveragerc +0 -0
  12. {gitlabform-5.5.4 → gitlabform-5.5.5}/.dockerignore +0 -0
  13. {gitlabform-5.5.4 → gitlabform-5.5.5}/.git-blame-ignore-revs +0 -0
  14. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/CODEOWNERS +0 -0
  15. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  16. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  17. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/ISSUE_TEMPLATE/question-or-other-issue.md +0 -0
  18. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/actions/setup-uv-local/README.md +0 -0
  19. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/actions/setup-uv-local/action.yml +0 -0
  20. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/dependabot.yml +0 -0
  21. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/_main.yml +0 -0
  22. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/_releases.yml +0 -0
  23. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/docs.yml +0 -0
  24. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/linters.yml +0 -0
  25. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/pr_on_fork.yml +0 -0
  26. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/pr_on_main_repo.yml +0 -0
  27. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/prs.yml +0 -0
  28. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/tests-premium.yml +0 -0
  29. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/tests-standard.yml +0 -0
  30. {gitlabform-5.5.4 → gitlabform-5.5.5}/.github/workflows/tests-ultimate.yml +0 -0
  31. {gitlabform-5.5.4 → gitlabform-5.5.5}/.gitignore +0 -0
  32. {gitlabform-5.5.4 → gitlabform-5.5.5}/.lgtm.yml +0 -0
  33. {gitlabform-5.5.4 → gitlabform-5.5.5}/.mypy.ini +0 -0
  34. {gitlabform-5.5.4 → gitlabform-5.5.5}/.overrides/gitlabform-logo-favicon.png +0 -0
  35. {gitlabform-5.5.4 → gitlabform-5.5.5}/.overrides/gitlabform-logo-favicon.svg +0 -0
  36. {gitlabform-5.5.4 → gitlabform-5.5.5}/.python-version +0 -0
  37. {gitlabform-5.5.4 → gitlabform-5.5.5}/CONTRIBUTING.md +0 -0
  38. {gitlabform-5.5.4 → gitlabform-5.5.5}/Dockerfile +0 -0
  39. {gitlabform-5.5.4 → gitlabform-5.5.5}/LICENSE +0 -0
  40. {gitlabform-5.5.4 → gitlabform-5.5.5}/README.md +0 -0
  41. {gitlabform-5.5.4 → gitlabform-5.5.5}/codecov.yml +0 -0
  42. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/__init__.py +0 -0
  43. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/common.py +0 -0
  44. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/docs.py +0 -0
  45. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/env.py +0 -0
  46. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/gitlab/await-healthy.sh +0 -0
  47. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/gitlab/gitlab.rb +0 -0
  48. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/gitlab/healthcheck-and-setup.sh +0 -0
  49. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/gitlab/run_gitlab_in_docker.sh +0 -0
  50. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/gitlab/tests.Dockerfile +0 -0
  51. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/infra.py +0 -0
  52. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/main.py +0 -0
  53. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/qa.py +0 -0
  54. {gitlabform-5.5.4 → gitlabform-5.5.5}/dev/release.py +0 -0
  55. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/automation.md +0 -0
  56. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/contrib/coding_guidelines.md +0 -0
  57. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/contrib/implementation_design.md +0 -0
  58. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/contrib/index.md +0 -0
  59. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/contrib/local_development.md +0 -0
  60. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/contrib/releases.md +0 -0
  61. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/contrib/workflows.md +0 -0
  62. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/features.md +0 -0
  63. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/egnyte-logo.svg +0 -0
  64. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/elastic-path-logo.svg +0 -0
  65. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/gitlabform-logo-square.png +0 -0
  66. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/gitlabform-logo.png +0 -0
  67. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/gitlabform-logo.svg +0 -0
  68. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/group-ldap-links-provider.png +0 -0
  69. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/liquidlight-logo.svg +0 -0
  70. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/roche-logo.png +0 -0
  71. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/images/stroeer-online-marketing-logo.svg +0 -0
  72. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/index.md +0 -0
  73. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/installation.md +0 -0
  74. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/archive_unarchive.md +0 -0
  75. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/avatar.md +0 -0
  76. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/badges.md +0 -0
  77. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/ci_cd_variables.md +0 -0
  78. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/deploy_keys.md +0 -0
  79. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/group_ldap_links.md +0 -0
  80. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/group_saml_links.md +0 -0
  81. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/index.md +0 -0
  82. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/integrations.md +0 -0
  83. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/job_token_scope.md +0 -0
  84. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/labels.md +0 -0
  85. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/members.md +0 -0
  86. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/merge_requests.md +0 -0
  87. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/pipeline_schedules.md +0 -0
  88. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/project_security_settings.md +0 -0
  89. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/project_transfer.md +0 -0
  90. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/protected_branches.md +0 -0
  91. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/protected_environments.md +0 -0
  92. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/push_mirrors.md +0 -0
  93. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/push_rules.md +0 -0
  94. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/resource_groups.md +0 -0
  95. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/settings.md +0 -0
  96. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/tags_protection.md +0 -0
  97. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/reference/webhooks.md +0 -0
  98. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/requirements.md +0 -0
  99. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/running.md +0 -0
  100. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/similar_apps.md +0 -0
  101. {gitlabform-5.5.4 → gitlabform-5.5.5}/docs/upgrade.md +0 -0
  102. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlab-config/config.yml +0 -0
  103. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlab-config/gitlab-config.md +0 -0
  104. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/__init__.py +0 -0
  105. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/configuration/__init__.py +0 -0
  106. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/configuration/common.py +0 -0
  107. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/configuration/core.py +0 -0
  108. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/configuration/groups.py +0 -0
  109. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/configuration/projects.py +0 -0
  110. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/configuration/transform.py +0 -0
  111. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/constants.py +0 -0
  112. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/__init__.py +0 -0
  113. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/commits.py +0 -0
  114. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/core.py +0 -0
  115. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/group_badges.py +0 -0
  116. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/group_ldap_links.py +0 -0
  117. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/groups.py +0 -0
  118. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/merge_requests.py +0 -0
  119. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/pipelines.py +0 -0
  120. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/project_badges.py +0 -0
  121. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/project_deploy_keys.py +0 -0
  122. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/project_merge_requests_approvals.py +0 -0
  123. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/project_protected_environments.py +0 -0
  124. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/projects.py +0 -0
  125. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/python_gitlab.py +0 -0
  126. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/gitlab/variables.py +0 -0
  127. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/lists/__init__.py +0 -0
  128. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/lists/filter.py +0 -0
  129. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/lists/groups.py +0 -0
  130. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/lists/projects.py +0 -0
  131. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/output.py +0 -0
  132. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/__init__.py +0 -0
  133. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/abstract_processor.py +0 -0
  134. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/application/__init__.py +0 -0
  135. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/application/application_settings_processor.py +0 -0
  136. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/defining_keys.py +0 -0
  137. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/__init__.py +0 -0
  138. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_badges_processor.py +0 -0
  139. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_hooks_processor.py +0 -0
  140. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_labels_processor.py +0 -0
  141. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_ldap_links_processor.py +0 -0
  142. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_members_processor.py +0 -0
  143. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_protected_branches_processor.py +0 -0
  144. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_push_rules_processor.py +0 -0
  145. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_saml_links_processor.py +0 -0
  146. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_settings_processor.py +0 -0
  147. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/group/group_variables_processor.py +0 -0
  148. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/multiple_entities_processor.py +0 -0
  149. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/__init__.py +0 -0
  150. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/badges_processor.py +0 -0
  151. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/branches_processor.py +0 -0
  152. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/deploy_keys_processor.py +0 -0
  153. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/hooks_processor.py +0 -0
  154. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/integrations_processor.py +0 -0
  155. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/job_token_scope_processor.py +0 -0
  156. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/members_processor.py +0 -0
  157. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/merge_requests_approval_rules.py +0 -0
  158. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/merge_requests_approvals.py +0 -0
  159. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/project_labels_processor.py +0 -0
  160. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/project_processor.py +0 -0
  161. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/project_push_rules_processor.py +0 -0
  162. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/project_security_settings.py +0 -0
  163. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/project_settings_processor.py +0 -0
  164. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/project_variables_processor.py +0 -0
  165. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/remote_mirrors_processor.py +0 -0
  166. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/resource_groups_processor.py +0 -0
  167. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/schedules_processor.py +0 -0
  168. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/project/tags_processor.py +0 -0
  169. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/shared/__init__.py +0 -0
  170. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/shared/protected_environments_processor.py +0 -0
  171. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/util/__init__.py +0 -0
  172. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/util/branch_protection.py +0 -0
  173. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/util/decorators.py +0 -0
  174. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/util/difference_logger.py +0 -0
  175. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/util/labels_processor.py +0 -0
  176. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/processors/util/variables_processor.py +0 -0
  177. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/run.py +0 -0
  178. {gitlabform-5.5.4 → gitlabform-5.5.5}/gitlabform/util.py +0 -0
  179. {gitlabform-5.5.4 → gitlabform-5.5.5}/mkdocs.yml +0 -0
  180. {gitlabform-5.5.4 → gitlabform-5.5.5}/prek.toml +0 -0
  181. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/__init__.py +0 -0
  182. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/__init__.py +0 -0
  183. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/conftest.py +0 -0
  184. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_branches.py +0 -0
  185. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_branches_users_case_insensitive.py +0 -0
  186. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_group_ldap_links.py +0 -0
  187. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_group_protected_branches.py +0 -0
  188. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_group_push_rules.py +0 -0
  189. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_group_saml_links.py +0 -0
  190. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_group_settings.py +0 -0
  191. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_group_variables.py +0 -0
  192. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_merge_request_approval_rules.py +0 -0
  193. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_merge_request_approvals_settings.py +0 -0
  194. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_protected_environments.py +0 -0
  195. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_push_rules.py +0 -0
  196. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/premium/test_tags.py +0 -0
  197. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/__init__.py +0 -0
  198. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_application_settings.py +0 -0
  199. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_archive_project.py +0 -0
  200. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_badges.py +0 -0
  201. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_deploy_keys.py +0 -0
  202. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_deploy_keys_all_projects.py +0 -0
  203. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_files_templates.py +0 -0
  204. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_avatar.py +0 -0
  205. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_badges.py +0 -0
  206. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_hooks.py +0 -0
  207. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_labels.py +0 -0
  208. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_members_case_insensitive.py +0 -0
  209. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_members_groups.py +0 -0
  210. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_members_users.py +0 -0
  211. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_settings.py +0 -0
  212. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_group_variables.py +0 -0
  213. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_hooks.py +0 -0
  214. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_integrations.py +0 -0
  215. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_job_token_scope.py +0 -0
  216. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_members.py +0 -0
  217. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_members_add_group.py +0 -0
  218. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_members_enforce.py +0 -0
  219. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_project_avatar.py +0 -0
  220. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_project_group_members_case_insensitive.py +0 -0
  221. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_project_labels.py +0 -0
  222. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_project_members_case_insensitve.py +0 -0
  223. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_project_settings.py +0 -0
  224. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_project_variables.py +0 -0
  225. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_remote_mirrors.py +0 -0
  226. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_resource_groups.py +0 -0
  227. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_running.py +0 -0
  228. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_scheduled_for_deletion_project.py +0 -0
  229. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_schedules.py +0 -0
  230. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_tags.py +0 -0
  231. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_token_from_config.py +0 -0
  232. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/standard/test_transfer_project.py +0 -0
  233. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/ultimate/test_group_members.py +0 -0
  234. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/ultimate/test_group_settings.py +0 -0
  235. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/ultimate/test_members.py +0 -0
  236. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/ultimate/test_project_security_settings.py +0 -0
  237. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/acceptance/ultimate/test_project_settings.py +0 -0
  238. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/__init__.py +0 -0
  239. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/__init__.py +0 -0
  240. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_case_sensitivity.py +0 -0
  241. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_inheritance_break_projects_and_groups.py +0 -0
  242. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_inheritance_break_subgroups.py +0 -0
  243. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_inheritance_break_validation.py +0 -0
  244. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_projects_and_groups.py +0 -0
  245. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_skip_groups_skip_projects.py +0 -0
  246. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_subgroups.py +0 -0
  247. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/test_yaml_version.py +0 -0
  248. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/transform/test_access_level_transformer.py +0 -0
  249. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/transform/test_group_transformer.py +0 -0
  250. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/transform/test_implicit_name_transformer.py +0 -0
  251. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/transform/test_user_and_group_transformers.py +0 -0
  252. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/configuration/transform/test_user_transformer.py +0 -0
  253. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/gitlab/test_core.py +0 -0
  254. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/gitlab/test_python_gitlab.py +0 -0
  255. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/__init__.py +0 -0
  256. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/test_abstract_processor.py +0 -0
  257. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/test_abstract_processors.py +0 -0
  258. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/test_branches_processor.py +0 -0
  259. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/test_difference_logger.py +0 -0
  260. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/test_group_protected_branches_processor.py +0 -0
  261. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/processors/test_schedules_processor_extended_cron_pattern.py +0 -0
  262. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/test_access_levels.py +0 -0
  263. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/test_non_empty_configs_provider.py +0 -0
  264. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/test_parse_args.py +0 -0
  265. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/test_projects_provider.py +0 -0
  266. {gitlabform-5.5.4 → gitlabform-5.5.5}/tests/unit/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitlabform
3
- Version: 5.5.4
3
+ Version: 5.5.5
4
4
  Summary: 🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML
5
5
  Project-URL: Homepage, https://gitlabform.github.io/gitlabform/
6
6
  Project-URL: Repository, https://github.com/gitlabform/gitlabform.git
@@ -19,7 +19,7 @@ Classifier: Operating System :: POSIX :: Linux
19
19
  Classifier: Programming Language :: Python :: 3.14
20
20
  Classifier: Topic :: Software Development :: Version Control :: Git
21
21
  Requires-Python: >=3.12.0
22
- Requires-Dist: certifi==2026.4.22
22
+ Requires-Dist: certifi==2026.5.20
23
23
  Requires-Dist: cli-ui==0.19.0
24
24
  Requires-Dist: ez-yaml==1.2.0
25
25
  Requires-Dist: jinja2==3.1.6
@@ -27,8 +27,8 @@ Requires-Dist: luddite==1.0.4
27
27
  Requires-Dist: markupsafe==3.0.3
28
28
  Requires-Dist: mergedeep==1.3.4
29
29
  Requires-Dist: packaging==26.2
30
- Requires-Dist: python-gitlab[graphql]==8.3.0
31
- Requires-Dist: requests==2.33.1
30
+ Requires-Dist: python-gitlab[graphql]==8.4.0
31
+ Requires-Dist: requests==2.34.2
32
32
  Requires-Dist: rich==15.0.0
33
33
  Requires-Dist: ruamel-yaml==0.17.21
34
34
  Requires-Dist: yamlpath==3.8.2
@@ -5,6 +5,18 @@ This changelog follows industry-standard best practices. Each release includes t
5
5
  For details on how to migrate between major versions, please refer to the [upgrade guide](upgrade.md), which contains important instructions for breaking changes.
6
6
 
7
7
  ---
8
+ ## 5.5.5
9
+
10
+ ### Bug Fixes
11
+
12
+ * allow editing and creation of files on wildcard protected branches [#1282](https://github.com/gitlabform/gitlabform/pull/1282). ([timknight01](https://github.com/TimKnight01) & [rickbrouwer](https://github.com/rickbrouwer))
13
+
14
+ ### Dependencies
15
+
16
+ * Update various dependencies to newer versions.
17
+
18
+ Thanks to all the contributors of this release!
19
+
8
20
  ## 5.5.4
9
21
 
10
22
  ### Build
@@ -8,7 +8,7 @@ Each key in this section is a path to a file in the repo and the values are dict
8
8
 
9
9
  * `overwrite` - if set to `false` and the file already exists, but has a different content, then it is not changed; default is `true`,
10
10
  * `skip_ci` - if set to `true` then the changes to a given file will be done with commits that will not trigger the CI pipeline; default is `false`,
11
- * `branches` - can be a single string `all`, string `protected` or an array of branch names,
11
+ * `branches` - can be a single string `all`, string `protected` (all protected branches, with wildcard-protected rules expanded to matching branches), or an array of branch names where `*` can be used to match any sequence of characters (e.g. `bugfix/*`, `*release*`),
12
12
  * `only_first_branch` - if set to `true` then only the first branch from the list above that exists will be processed (unless you pass `--strict` as cli parameter to the app - then it will fail when trying to process a non-existent branch),
13
13
  * `commit_message` - set this to a custom commit message that will be used by the app; optional,
14
14
  * `content` - the literal contents that should be put into the target file; use this or `file`,
@@ -94,3 +94,45 @@ projects_and_groups:
94
94
  only_first_branch: true
95
95
  skip_ci: true
96
96
  ```
97
+
98
+ Example 5 - adding a README to all branches with "gitlab" in their name:
99
+
100
+ ```yaml
101
+ projects_and_groups:
102
+ group_1/project_1:
103
+ files:
104
+ "README.md":
105
+ overwrite: false
106
+ branches:
107
+ - "*gitlab*"
108
+ skip_ci: true
109
+ content: |
110
+ This is a default README. Please replace it with a proper one!
111
+ commit_message: Set default README
112
+ ```
113
+
114
+ Example 6 - adding a README to protected branches, including protected branches defined with wildcards (e.g. all branches with "bugfix/" in their name are protected and will have the file added):
115
+
116
+ ```yaml
117
+ projects_and_groups:
118
+ group_1/project_1:
119
+ branches:
120
+ main:
121
+ allow_force_push: false
122
+ code_owner_approval_required: true
123
+ merge_access_level: developer
124
+ protected: true
125
+ bugfix/*:
126
+ allow_force_push: true
127
+ code_owner_approval_required: false
128
+ merge_access_level: developer
129
+ protected: true
130
+ files:
131
+ "README.md":
132
+ overwrite: false
133
+ branches: protected
134
+ skip_ci: true
135
+ content: |
136
+ This is a protected branch README!
137
+ commit_message: Set protected branch README
138
+ ```
@@ -4,10 +4,9 @@ import sys
4
4
  from pathlib import Path
5
5
 
6
6
  from logging import debug, info, warning, critical
7
- from typing import List
8
7
 
9
8
  from jinja2 import Environment, FileSystemLoader
10
- from gitlab import GitlabGetError, GitlabUpdateError
9
+ from gitlab import GitlabGetError, GitlabUpdateError, GitlabListError
11
10
  from gitlab.v4.objects import Project, ProjectFile, ProjectBranch
12
11
  from gitlab.base import RESTObject
13
12
 
@@ -35,27 +34,20 @@ class FilesProcessor(AbstractProcessor):
35
34
  continue
36
35
 
37
36
  config_target_ref = configuration["files"][file]["branches"]
38
- branches_to_update: List[RESTObject] = []
39
-
40
- if isinstance(config_target_ref, str):
41
- # Target ref could be either 'all' or 'protected'.
42
- # Get a list of branches that should be updated.
43
- if config_target_ref == "all":
44
- branches_to_update.extend(project.branches.list(get_all=True, lazy=True))
45
- elif config_target_ref == "protected":
46
- branches_to_update.extend(project.protectedbranches.list(get_all=True, lazy=True))
37
+ branches_to_update: list[ProjectBranch] = []
38
+
39
+ if config_target_ref == "all":
40
+ # Get all Branches in the Project
41
+ branches_to_update.extend(project.branches.list(get_all=True, lazy=True))
42
+ elif config_target_ref == "protected":
43
+ # Get all Protected Branch definitions -> this could return wildcard branch names
44
+ protected_branches = project.protectedbranches.list(get_all=True, lazy=True)
45
+ for protected_branch in protected_branches:
46
+ self.append_branches_matching_ref(branches_to_update, file, project, protected_branch.name)
47
47
  elif isinstance(config_target_ref, list):
48
- # Get a list of branches from the config that should be updated.
49
- for branch_name in config_target_ref:
50
- try:
51
- branches_to_update.append(project.branches.get(branch_name))
52
- except GitlabGetError:
53
- message = f"! Branch '{branch_name}' not found, not processing file '{file}' in it"
54
- if self.strict:
55
- critical(message)
56
- sys.exit(EXIT_INVALID_INPUT)
57
- else:
58
- warning(message)
48
+ # List of specific branch refs to update -> this could contain wildcard branch names
49
+ for ref in config_target_ref:
50
+ self.append_branches_matching_ref(branches_to_update, file, project, ref)
59
51
 
60
52
  debug(
61
53
  "File '%s' to be updated in '%s' branche(s)",
@@ -63,105 +55,150 @@ class FilesProcessor(AbstractProcessor):
63
55
  len(branches_to_update),
64
56
  )
65
57
 
66
- for branch in branches_to_update:
67
- info(f"Processing file '{file}' in branch '{branch.name}'")
58
+ for branch_to_update in branches_to_update:
59
+ process_only_first: bool = configuration.get("files|" + file + "|only_first_branch", False)
68
60
 
69
- if configuration.get("files|" + file + "|content") and configuration.get("files|" + file + "|file"):
70
- critical(
71
- f"File '{file}' in '{project_and_group}' has both `content` and `file` set - "
72
- "use only one of these keys."
73
- )
61
+ self.process_branch(branch_to_update, configuration, file, project, project_and_group)
62
+
63
+ if process_only_first:
64
+ info("Skipping other branches for this file, as configured by only_first_branch.")
65
+ break
66
+
67
+ def append_branches_matching_ref(self, branches_to_update: list[ProjectBranch], file, project: Project, ref: str):
68
+
69
+ if self.branch_processor.branch_name_contains_supported_wildcard(ref):
70
+ try:
71
+ # GitLab's branches API expects an RE2 regex
72
+ regex_ref = "^" + re.escape(ref).replace(r"\*", ".*") + "$"
73
+ # sorted for deterministic only_first_branch
74
+ wildcard_branches = sorted(
75
+ project.branches.list(get_all=True, regex=regex_ref),
76
+ key=lambda b: b.name,
77
+ )
78
+ for wildcard_branch in wildcard_branches:
79
+ branch_id = wildcard_branch.get_id()
80
+ if branch_id:
81
+ branches_to_update.append(wildcard_branch)
82
+ except GitlabListError:
83
+ message = f"! Could not list branches using {ref}, not processing file '{file}' on them"
84
+ if self.strict:
85
+ critical(message)
74
86
  sys.exit(EXIT_INVALID_INPUT)
87
+ else:
88
+ warning(message)
89
+ else:
90
+ try:
91
+ branches_to_update.append(project.branches.get(ref))
92
+ except GitlabGetError:
93
+ message = f"! Branch '{ref}' not found, not processing file '{file}' in it"
94
+ if self.strict:
95
+ critical(message)
96
+ sys.exit(EXIT_INVALID_INPUT)
97
+ else:
98
+ warning(message)
75
99
 
76
- if configuration.get("files|" + file + "|delete"):
77
- try:
78
- file_to_delete: ProjectFile = project.files.get(file_path=file, ref=branch.name)
79
- debug("Deleting file '%s' in branch '%s'", file, branch.name)
80
- self.modify_file_dealing_with_branch_protection(
81
- project,
82
- branch,
83
- file_to_delete,
84
- "delete",
85
- configuration,
86
- )
87
- except GitlabGetError:
100
+ def process_branch(
101
+ self,
102
+ branch: ProjectBranch,
103
+ configuration: dict,
104
+ file: str,
105
+ project: Project,
106
+ project_and_group: str,
107
+ ):
108
+ info(f"Processing file '{file}' in branch '{branch.name}'")
109
+
110
+ if configuration.get("files|" + file + "|content") and configuration.get("files|" + file + "|file"):
111
+ critical(
112
+ f"File '{file}' in '{project_and_group}' has both `content` and `file` set - "
113
+ "use only one of these keys."
114
+ )
115
+ sys.exit(EXIT_INVALID_INPUT)
116
+
117
+ if configuration.get("files|" + file + "|delete"):
118
+ try:
119
+ file_to_delete: ProjectFile = project.files.get(file_path=file, ref=branch.name)
120
+ debug("Deleting file '%s' in branch '%s'", file, branch.name)
121
+ self.modify_file_dealing_with_branch_protection(
122
+ project,
123
+ branch,
124
+ file_to_delete,
125
+ "delete",
126
+ configuration,
127
+ )
128
+ except GitlabGetError:
129
+ debug(
130
+ "Not deleting file '%s' in branch '%s' (already doesn't exist)",
131
+ file,
132
+ branch.name,
133
+ )
134
+ else:
135
+ # change or create file
136
+
137
+ if configuration.get("files|" + file + "|content"):
138
+ new_content = configuration.get("files|" + file + "|content")
139
+ else:
140
+ path_in_config = Path(str(configuration.get("files|" + file + "|file")))
141
+ if path_in_config.is_absolute():
142
+ effective_path = path_in_config
143
+ else:
144
+ # relative paths are relative to config file location
145
+ effective_path = Path(os.path.join(self.config.config_dir, str(path_in_config)))
146
+ new_content = effective_path.read_text()
147
+
148
+ # templating is documented to be enabled by default,
149
+ # see https://gitlabform.github.io/gitlabform/reference/files/#files
150
+ templating_enabled = True
151
+
152
+ if configuration.get("files|" + file + "|template", templating_enabled):
153
+ new_content = self.get_file_content_as_template(
154
+ new_content,
155
+ project_and_group,
156
+ **configuration.get("files|" + file + "|jinja_env", dict()),
157
+ )
158
+
159
+ try:
160
+ # Returns base64 encoded content: https://python-gitlab.readthedocs.io/en/stable/gl_objects/projects.html#project-files
161
+ repo_file: ProjectFile = project.files.get(file_path=file, ref=branch.name)
162
+ decoded_file: bytes = repo_file.decode()
163
+ current_content: str = decoded_file.decode("utf-8")
164
+
165
+ if current_content != new_content:
166
+ if configuration.get("files|" + file + "|overwrite"):
88
167
  debug(
89
- "Not deleting file '%s' in branch '%s' (already doesn't exist)",
168
+ "Changing file '%s' in branch '%s'",
90
169
  file,
91
170
  branch.name,
92
171
  )
93
- else:
94
- # change or create file
95
-
96
- if configuration.get("files|" + file + "|content"):
97
- new_content = configuration.get("files|" + file + "|content")
98
- else:
99
- path_in_config = Path(str(configuration.get("files|" + file + "|file")))
100
- if path_in_config.is_absolute():
101
- effective_path = path_in_config
102
- else:
103
- # relative paths are relative to config file location
104
- effective_path = Path(os.path.join(self.config.config_dir, str(path_in_config)))
105
- new_content = effective_path.read_text()
106
-
107
- # templating is documented to be enabled by default,
108
- # see https://gitlabform.github.io/gitlabform/reference/files/#files
109
- templating_enabled = True
110
-
111
- if configuration.get("files|" + file + "|template", templating_enabled):
112
- new_content = self.get_file_content_as_template(
113
- new_content,
114
- project_and_group,
115
- **configuration.get("files|" + file + "|jinja_env", dict()),
116
- )
117
-
118
- try:
119
- # Returns base64 encoded content: https://python-gitlab.readthedocs.io/en/stable/gl_objects/projects.html#project-files
120
- repo_file: ProjectFile = project.files.get(file_path=file, ref=branch.name)
121
- decoded_file: bytes = repo_file.decode()
122
- current_content: str = decoded_file.decode("utf-8")
123
-
124
- if current_content != new_content:
125
- if configuration.get("files|" + file + "|overwrite"):
126
- debug(
127
- "Changing file '%s' in branch '%s'",
128
- file,
129
- branch.name,
130
- )
131
- self.modify_file_dealing_with_branch_protection(
132
- project,
133
- branch,
134
- repo_file,
135
- "modify",
136
- configuration,
137
- new_content,
138
- )
139
- else:
140
- debug(
141
- "Not changing file '%s' in branch '%s' - overwrite flag not set.",
142
- file,
143
- branch.name,
144
- )
145
- else:
146
- debug(
147
- "Not changing file '%s' in branch '%s' - it's content is already" " as provided)",
148
- file,
149
- branch.name,
150
- )
151
- except GitlabGetError:
152
- debug("Creating file '%s' in branch '%s'", file, branch.name)
153
172
  self.modify_file_dealing_with_branch_protection(
154
173
  project,
155
174
  branch,
156
- file,
157
- "add",
175
+ repo_file,
176
+ "modify",
158
177
  configuration,
159
178
  new_content,
160
179
  )
161
-
162
- if configuration.get("files|" + file + "|only_first_branch"):
163
- info("Skipping other branches for this file, as configured.")
164
- break
180
+ else:
181
+ debug(
182
+ "Not changing file '%s' in branch '%s' - overwrite flag not set.",
183
+ file,
184
+ branch.name,
185
+ )
186
+ else:
187
+ debug(
188
+ "Not changing file '%s' in branch '%s' - it's content is already" " as provided)",
189
+ file,
190
+ branch.name,
191
+ )
192
+ except GitlabGetError:
193
+ debug("Creating file '%s' in branch '%s'", file, branch.name)
194
+ self.modify_file_dealing_with_branch_protection(
195
+ project,
196
+ branch,
197
+ file,
198
+ "add",
199
+ configuration,
200
+ new_content,
201
+ )
165
202
 
166
203
  def modify_file_dealing_with_branch_protection(
167
204
  self,
@@ -10,7 +10,7 @@ packages = ["gitlabform"]
10
10
 
11
11
  [project]
12
12
  name = "gitlabform"
13
- version = "5.5.4"
13
+ version = "5.5.5"
14
14
  requires-python = ">=3.12.0"
15
15
  authors = [{ name = "Greg Dubicki and Contributors" }]
16
16
  description = "🏗 Specialized configuration as a code tool for GitLab projects, groups and more using hierarchical configuration written in YAML"
@@ -31,7 +31,7 @@ classifiers = [
31
31
 
32
32
  # Main runtime dependencies. Pinned strictly to ensure production stability.
33
33
  dependencies = [
34
- "certifi==2026.4.22",
34
+ "certifi==2026.5.20",
35
35
  "cli-ui==0.19.0",
36
36
  # ez_yaml >1.2.0 changes imports and also uses ruamel.yaml tied to 1.2 so wouldn't support "yes" as True
37
37
  "ez-yaml==1.2.0",
@@ -40,8 +40,8 @@ dependencies = [
40
40
  "markupsafe==3.0.3",
41
41
  "mergedeep==1.3.4",
42
42
  "packaging==26.2",
43
- "python-gitlab[graphql]==8.3.0",
44
- "requests==2.33.1",
43
+ "python-gitlab[graphql]==8.4.0",
44
+ "requests==2.34.2",
45
45
  "rich==15.0.0",
46
46
  # yamlpath and ruamel and tightly coupled, currently 0.19.1 of ruamel and 3.9.0 of yamlpath break support for
47
47
  # yaml 1.1 "yes" -> True conversion. If we want to upgrade we'd need to make a breaking-change and drop support for
@@ -58,27 +58,27 @@ dev = [
58
58
  { include-group = "lint" },
59
59
  { include-group = "docs" },
60
60
  { include-group = "release" },
61
- "commitizen==4.16.2",
62
- "prek==0.4.0",
61
+ "commitizen==4.16.3",
62
+ "prek==0.4.3",
63
63
  ]
64
64
  # Minimum set of dependencies required to execute the test suite.
65
65
  test = [
66
- "coverage==7.14.0",
66
+ "coverage==7.14.1",
67
67
  "cryptography==48.0.0",
68
68
  "deepdiff==9.1.0",
69
69
  "pytest==9.0.3",
70
70
  "pytest-cov==7.1.0",
71
- "pytest-rerunfailures==16.2",
71
+ "pytest-rerunfailures==16.3",
72
72
  "xkcdpass==1.30.0",
73
73
  ]
74
74
  # Static analysis and formatting tools.
75
75
  lint = [
76
76
  "bandit==1.9.4",
77
- "black==26.5.0",
77
+ "black==26.5.1",
78
78
  "codespell==2.4.2",
79
79
  "mypy==2.1.0",
80
80
  "mypy-extensions==1.1.0",
81
- "ruff==0.15.13",
81
+ "ruff==0.15.15",
82
82
  "types-requests==2.33.0.20260518",
83
83
  ]
84
84
  # Documentation generation stack.
@@ -2,7 +2,7 @@
2
2
  github_url = "https://github.com/gitlabform/gitlabform/"
3
3
 
4
4
  [version]
5
- current = "5.5.4"
5
+ current = "5.5.5"
6
6
 
7
7
  # Example of a semver regexp.
8
8
  # Make sure this matches current_version before
@@ -4,7 +4,7 @@ import time
4
4
  from gitlab import GitlabGetError
5
5
 
6
6
  from gitlabform.gitlab import AccessLevel
7
- from tests.acceptance import get_only_branch_access_levels, run_gitlabform
7
+ from tests.acceptance import get_only_branch_access_levels, run_gitlabform, get_random_name
8
8
 
9
9
 
10
10
  @pytest.mark.ce
@@ -401,3 +401,54 @@ class TestBranches:
401
401
  assert other_branch_unprotect_access_level is AccessLevel.MAINTAINER.value
402
402
  else:
403
403
  assert other_branch_unprotect_access_level is None
404
+
405
+ def test__can_protect_branches_with_wildcard(self, project_for_function, branch_for_function):
406
+ # Setup Test
407
+
408
+ ### Test-config:
409
+ set_file_protected_branches = f"""
410
+ protected branch: &protected_branch
411
+ allow_force_push: false
412
+ code_owner_approval_required: true
413
+ merge_access_level: developer
414
+ protected: true
415
+ push_access_level: maintainer
416
+ unprotect_access_level: maintainer
417
+
418
+ projects_and_groups:
419
+ {project_for_function.path_with_namespace}:
420
+ branches:
421
+ main: *protected_branch
422
+ bugfix/*: *protected_branch
423
+ """
424
+
425
+ ### Make sure "main" exists on project
426
+ main_branch_name: str = "main"
427
+ assert project_for_function.branches.get(main_branch_name) is not None
428
+
429
+ ### Make sure "branch_for_function" exists on project
430
+ assert project_for_function.branches.get(branch_for_function) is not None
431
+
432
+ ### Add a "bugfix/some-branch" and a "bugfix/other-fix" to project
433
+ bug_fix_branch_name_1 = f"bugfix/{get_random_name("branch")}"
434
+ bug_fix_branch_name_2 = f"bugfix/{get_random_name("branch")}"
435
+
436
+ project_for_function.branches.create({"branch": bug_fix_branch_name_1, "ref": "main"})
437
+ project_for_function.branches.create({"branch": bug_fix_branch_name_2, "ref": "main"})
438
+
439
+ time.sleep(5)
440
+ # Wait a bit to make sure GitLab has asynchronously created the branches before we run GitLabForm
441
+
442
+ # Run Test
443
+ run_gitlabform(set_file_protected_branches, project_for_function.path_with_namespace)
444
+
445
+ # Assert correct changes are applied
446
+ ### Check Main branch is protected
447
+ assert project_for_function.branches.get(main_branch_name).protected is True
448
+
449
+ ### Check both Bugfix branches are protected
450
+ assert project_for_function.branches.get(bug_fix_branch_name_1).protected is True
451
+ assert project_for_function.branches.get(bug_fix_branch_name_2).protected is True
452
+
453
+ ### Check branch_for_function is not protected
454
+ assert project_for_function.branches.get(branch_for_function).protected is False