Page MenuHomeSoftware Heritage

D8831.id31835.diff
No OneTemporary

D8831.id31835.diff

diff --git a/gitlab/cli.py b/gitlab/cli.py
new file mode 100755
--- /dev/null
+++ b/gitlab/cli.py
@@ -0,0 +1,326 @@
+#!/usr/bin/env python3
+
+import json
+import logging
+from pathlib import Path
+from typing import Any, Dict, Iterable, Tuple
+
+import click
+import yaml
+
+import gitlab
+
+logger = logging.getLogger(__name__)
+
+
+def get_gitlab(gitlab_instance):
+ """Instantiate a gitlab instance.
+
+ This uses the python-gitlab configuration parsing.
+ """
+ gl = gitlab.Gitlab.from_config(gitlab_instance)
+ gl.auth()
+
+ return gl
+
+
+def load_config_file(config_file: str) -> Dict[str, Any]:
+ """Load the configuration yaml file as Dict."""
+ with open(config_file, "r") as f:
+ return yaml.safe_load(f)
+
+
+@click.group()
+@click.option(
+ "--gitlab",
+ "-g",
+ "gitlab_instance",
+ help="Which GitLab instance to use, as configured in the python-gitlab config",
+)
+@click.option(
+ "--do-it", "do_it", is_flag=True, help="Actually perform the operations",
+)
+@click.pass_context
+def manage(ctx, gitlab_instance, do_it):
+ if not do_it:
+ logger.info(
+ "Will not perform any actions, please use --do-it once you're satisfied"
+ " with the expected actions."
+ )
+
+ ctx.ensure_object(dict)
+ ctx.obj["gitlab"] = get_gitlab(gitlab_instance)
+ ctx.obj["do_it"] = do_it
+
+
+@manage.command("groups")
+@click.argument("config_file")
+@click.pass_context
+def groups(ctx, config_file):
+ """Ensure that GitLab users and group memberships match the structure defined in the
+ configuration file."""
+
+ gl = ctx.obj["gitlab"]
+ do_it = ctx.obj["do_it"]
+
+ config = load_config_file(config_file)
+
+ config_groups = config.get("groups")
+ if not config_groups:
+ raise ValueError(
+ "Missing config key <groups>, please fill in the configuration file"
+ )
+
+ for group_path, group_conf in config_groups.items():
+ group = gl.groups.get(group_path, with_projects=False)
+ expected_members = {
+ username: gitlab.const.AccessLevel[access_level.upper()]
+ for username, access_level in group_conf["users"].items()
+ }
+ recorded_members = set()
+
+ expected_group_shares = {
+ other_path: gitlab.const.AccessLevel[access_level.upper()]
+ for other_path, access_level in group_conf.get(
+ "share_with_groups", {}
+ ).items()
+ }
+ recorded_members = set()
+
+ remove_extra_memberships = group_conf.get("remove_extra_memberships", False)
+ for member in group.members.list():
+ username = member.username
+ expected_access_level = expected_members.get(member.username)
+ if expected_access_level and member.access_level != expected_access_level:
+ logger.info(
+ "Adjusting membership for %s in %s to %s (was %s)",
+ username,
+ group_path,
+ expected_access_level.name,
+ member.access_level,
+ )
+ if do_it:
+ member.access_level = expected_access_level
+ member.save()
+
+ if remove_extra_memberships and not expected_access_level:
+ logger.info("Removing member %s from %s", username, group_path)
+ if do_it:
+ member.delete()
+
+ recorded_members.add(username)
+
+ for username, access_level in expected_members.items():
+ if username in recorded_members:
+ continue
+
+ users = gl.users.list(username=username)
+ if not users:
+ logger.warning(
+ "User %s not found, cannot add them to %s!", username, group_path
+ )
+ continue
+
+ user_id = users[0].id
+
+ logger.info(
+ "Adding member %s in %s at level %s", username, group_path, access_level
+ )
+ if do_it:
+ group.members.create({"user_id": user_id, "access_level": access_level})
+
+ recorded_group_shares = set()
+
+ for group_share in group.shared_with_groups:
+ other_path = group_share["group_full_path"]
+ other_id = group_share["group_id"]
+ other_access_level = group_share["group_access_level"]
+ expected_access_level = expected_group_shares.get(other_path)
+ if expected_access_level and other_access_level != expected_access_level:
+ logger.info(
+ "Adjusting group_share for %s in %s to %s (was %s)",
+ other_path,
+ group_path,
+ expected_access_level,
+ other_access_level,
+ )
+ if do_it:
+ group.share(other_id, expected_access_level)
+
+ if remove_extra_memberships and not expected_access_level:
+ logger.info("Removing group %s from %s", other_path, group_path)
+ if do_it:
+ group.unshare(other_id)
+
+ recorded_group_shares.add(other_path)
+
+ for other_path, access_level in expected_group_shares.items():
+ if other_path in recorded_group_shares:
+ continue
+
+ other_group = gl.groups.get(other_path)
+ if not other_group:
+ logger.warning(
+ "Group %s not found, cannot add them to %s!", other_path, group_path
+ )
+ continue
+
+ logger.info(
+ "Adding group %s in %s at level %s",
+ other_path,
+ group_path,
+ access_level,
+ )
+ if do_it:
+ group.share(other_group.id, access_level)
+
+
+def update_project(
+ project,
+ global_settings: Dict[str, Any],
+ namespace_settings: Dict[str, Any],
+ project_settings: Dict[str, Any],
+) -> Tuple:
+ """Given a project and settings configuration dicts, update the project.
+
+ Returns:
+ Tuple (updated, updated_project). If updated is a dict, then updated_project is
+ the project with its attributes updated according to the configuration dicts.
+ Otherwise, updated_project is the same instance as 'project' input parameter.
+
+ """
+ # override from generic to specific in that order: global -> namespace -> project
+ config: Dict[str, Any] = {
+ **global_settings,
+ **namespace_settings,
+ **project_settings,
+ }
+ logger.debug(
+ "Project <%s>: merged configuration: %s", project.path_with_namespace, config
+ )
+
+ updated = {}
+ # Iterate over the new settings to apply
+ for attribute, value in config.items():
+ existing_value = getattr(project, attribute)
+ # If any changes is detected
+ if existing_value != value:
+ # New settings is applied
+ setattr(project, attribute, value)
+ new_value = getattr(project, attribute)
+ logger.debug(
+ "Update attribute <%s> with value '%s' to value '%s'",
+ attribute,
+ existing_value,
+ new_value,
+ )
+ updated[attribute] = dict(old=existing_value, new=new_value)
+
+ return updated, project
+
+
+def namespaces_from_path(path_with_namespace: str) -> Iterable[str]:
+ """Given a path, computes the hierarchic namespaces from generic to specific."""
+ namespaces = []
+ # FIXME: make that a reduce call!?
+ for part in Path(path_with_namespace).parts[:-1]:
+ if namespaces:
+ last_part = namespaces[-1]
+ ns = f"{last_part}/{part}"
+ else:
+ ns = part
+ namespaces.append(ns)
+
+ return namespaces
+
+
+@manage.command("projects")
+@click.argument("config_file")
+@click.pass_context
+def projects(ctx, config_file: str,) -> None:
+ gl = ctx.obj["gitlab"]
+ do_it = ctx.obj["do_it"]
+
+ config = load_config_file(config_file)
+
+ config_projects = config.get("projects")
+ if not config_projects:
+ raise ValueError(
+ "Missing config key <projects>, please fill in the configuration file"
+ )
+
+ # Global configuration for all projects
+ global_settings: Dict[str, Any] = config_projects["global_settings"]
+
+ # Namespace project configuration (with possible override on the global config)
+ namespace_settings: Dict[str, Any] = config_projects["namespace_settings"]
+
+ # List of projects that the script should act upon (other projects are skipped)
+ managed_project_namespaces = config_projects["managed_namespaces"]
+
+ # Local specific project configuration (with possible override on the global config)
+ project_settings: Dict[str, Any] = config_projects["project_settings"]
+
+ # TODO: Determine whether we want to iterate over all gitlab projects or over the
+ # configured projects in the configuration files. For now, this iterates over the
+ # gitlab projects and skips non-configured ones. That way, we could discover
+ # projects we forgot to configure (by processing the logs afterwards).
+
+ projects: Dict = {}
+ project_updated_count = 0
+
+ # Configure the project according to global settings (with potential specific
+ # project override)
+ for project in gl.projects.list(iterator=True):
+ path_with_namespace = project.path_with_namespace
+ # For the last print statement to explain how many got updated
+ projects[path_with_namespace] = project
+
+ project_namespaces = namespaces_from_path(path_with_namespace)
+ if project_namespaces[0] not in managed_project_namespaces:
+ logger.debug("Skipped non-managed project <%s>", path_with_namespace)
+ continue
+
+ namespace_config = {}
+ # Merge configuration from generic namespace to specific
+ for ns in project_namespaces:
+ namespace_config.update(namespace_settings.get(ns, {}))
+
+ project_config = project_settings.get(path_with_namespace, {})
+
+ logger.debug("Project <%s> %s", path_with_namespace, project.id)
+ updates, project = update_project(
+ project, global_settings, namespace_config, project_config
+ )
+
+ if updates and do_it:
+ project.save()
+ project_updated_count += 1
+
+ if updates:
+ print(json.dumps({path_with_namespace: updates}))
+
+ dry_run = not do_it
+ prefix_msg = "(**DRY RUN**) " if dry_run else ""
+ summary = {
+ "nb_projects": len(projects),
+ "nb_updated_projects": project_updated_count,
+ }
+ if dry_run:
+ summary["dry_run"] = dry_run
+
+ logger.debug(
+ "%sNumber of projects updated: %s / %s",
+ prefix_msg,
+ project_updated_count,
+ len(projects),
+ )
+
+ print(json.dumps(summary))
+
+
+if __name__ == "__main__":
+ logging.basicConfig(
+ level=logging.INFO, format="%(asctime)s %(name)s:%(levelname)s %(message)s"
+ )
+ manage(auto_envvar_prefix="SWH")
diff --git a/gitlab/configuration.yml b/gitlab/configuration.yml
new file mode 100644
--- /dev/null
+++ b/gitlab/configuration.yml
@@ -0,0 +1,283 @@
+# Owner
+# Maintainer
+# Developer
+# Reporter
+# Guest
+
+groups:
+ teams/staff:
+ users:
+ phabricator-migration: Owner
+ anlambert: Maintainer
+ ardumont: Maintainer
+ bchauvet: Owner
+ douardda: Maintainer
+ jayeshv: Maintainer
+ lunar: Maintainer
+ marla.dasilva: Maintainer
+ moranegg: Maintainer
+ olasd: Maintainer
+ rdicosmo: Owner
+ sgranger: Maintainer
+ vlorentz: Maintainer
+ vsellier: Maintainer
+ zack: Owner
+ remove_extra_memberships: true
+ teams/developers:
+ users:
+ phabricator-migration: Owner
+ anlambert: Maintainer
+ ardumont: Maintainer
+ bchauvet: Maintainer
+ douardda: Maintainer
+ jayeshv: Maintainer
+ lunar: Maintainer
+ moranegg: Maintainer
+ olasd: Maintainer
+ rdicosmo: Maintainer
+ vlorentz: Maintainer
+ vsellier: Maintainer
+ zack: Maintainer
+ remove_extra_memberships: true
+ teams/sysadmin:
+ users:
+ phabricator-migration: Owner
+ ardumont: Owner
+ olasd: Owner
+ vsellier: Owner
+ remove_extra_memberships: true
+ teams/interns:
+ users:
+ phabricator-migration: Owner
+ remove_extra_memberships: true
+ teams/management:
+ users:
+ phabricator-migration: Owner
+ bchauvet: Owner
+ douardda: Maintainer
+ rdicosmo: Owner
+ vsellier: Maintainer
+ zack: Owner
+ remove_extra_memberships: true
+ infra:
+ users:
+ phabricator-migration: Owner
+ remove_extra_memberships: true
+ share_with_groups:
+ teams/sysadmin: Owner
+ modules:
+ users:
+ phabricator-migration: Owner
+ share_with_groups:
+ teams/developers: Maintainer
+ remove_extra_memberships: true
+ migrated:
+ users:
+ phabricator-migration: Owner
+ share_with_groups:
+ teams/sysadmin: Owner
+ teams/developers: Maintainer
+ remove_extra_memberships: true
+
+projects:
+ # [1] https://docs.gitlab.com/ee/api/projects.html#edit-project
+
+ # List of namespaces managed by the script (It should be the first level of the
+ # project namespace). Other unmanaged projects will be skipped during the script
+ # execution.
+ managed_namespaces:
+ - infra
+
+ namespace_settings:
+ # Dict[str, Any] of key the project namespace, and value a dict of any of the global
+ # settings keys above and value, whatever we want to set.
+ infra/puppet/3rdparty:
+ issues_access_level: disabled
+ infra/ci-cd/debs:
+ issues_access_level: disabled
+
+ # Dict[str, Any] of key the project with its path namespace, and value a dict of any of
+ # the global settings keys above (e.g. visibility) and value, whatever we want to set
+ # (e.g. assuming the key 'visibility', some credentials repositories, we want to set it
+ # 'private').
+ project_settings:
+ infra/ci-cd/k8s-swh-private-data:
+ visibility: private
+ infra/puppet/puppet-swh-private-data:
+ visibility: private
+ # staging extra repositories
+ infra/websites/www.softwareheritage.org-gandi:
+ visibility: private
+ infra/credentials:
+ visibility: private
+ infra/k8s-swh-private-data:
+ visibility: private
+ infra/annex/annex-private:
+ visibility: private
+ infra/iFWCFG:
+ visibility: private
+
+ # Dict[str, Any] of key the setting to change (e.g. 'merge_method') and as value
+ # whatever we want to set (e.g. assuming the 'merge_method', 'ff' as in fast-forward).
+ # The keys were determined out of the gitlab api documentation [1]. Some were not
+ # supported. Those are located after the 'unsupported' comment.
+ global_settings:
+ # string (optional): See project visibility level.
+ visibility: public
+ # string (optional): Set the merge method used.
+ merge_method: ff
+ # boolean (optional): Enable Delete source branch option by default for all new merge
+ # requests.
+ remove_source_branch_after_merge: true
+ # string (optional): One of disabled, private, or enabled.
+ # releases_access_level: enabled
+ # boolean: Set whether or not merge requests can be merged with skipped jobs.
+ # allow_merge_on_skipped_pipeline: false
+ # string: One of disabled, private or enabled
+ # analytics_access_level: enabled
+ # boolean: Enable Auto DevOps for this project.
+ # auto_devops_enabled: false
+ # boolean: Set whether auto-closing referenced issues on default branch.
+ # autoclose_referenced_issues: true
+ # string (optional): The Git strategy. Defaults to fetch.
+ # build_git_strategy: fetch
+ # integer (optional): The maximum amount of time, in seconds, that a job can run.
+ # build_timeout: 3600
+ # string (optional): One of disabled, private, or enabled.
+ # builds_access_level: enabled
+ # string (optional): The path to CI configuration file.
+ # ci_config_path: ""
+ # integer (optional): Default number of revisions for shallow cloning.
+ # ci_default_git_depth: 20
+ # boolean (optional): Enable or disable prevent outdated deployment jobs.
+ # ci_forward_deployment_enabled: true
+ # boolean (optional): Enable or disable running pipelines in the parent project for
+ # merge requests from forks. (Introduced in GitLab 15.3.)
+ # ci_allow_fork_pipelines_to_run_in_parent_project: true
+ # boolean (optional): Set whether or not caches should be separated by branch
+ # protection status.
+ # ci_separated_caches: true
+ # string (optional): Set visibility of container registry, for this project, to one of
+ # disabled, private or enabled.
+ # container_registry_access_level: disabled
+ # string (optional): The default branch name.
+ # default_branch: master
+ # string (optional): Short project description.
+ # description: ""
+ # boolean (optional): Disable email notifications.
+ # emails_disabled: true
+ # boolean (optional): Enforce auth checks on uploads.
+ # enforce_auth_checks_on_uploads: true
+ # string (optional): One of disabled, private, or enabled.
+ # forking_access_level: enabled
+ # string (optional): One of disabled, private, or enabled.
+ # issues_access_level: enabled
+ # boolean (optional): Disable or enable the ability to keep the latest artifact for
+ # this project.
+ # keep_latest_artifact: True
+ # boolean (optional): Enable LFS.
+ # lfs_enabled: True
+ # string (optional): Template used to create merge commit message in merge requests.
+ # (Introduced in GitLab 14.5.)
+ # merge_commit_template: ""
+ # string (optional): One of disabled, private, or enabled.
+ # merge_requests_access_level: enabled
+ # boolean (optional): Set whether merge requests can only be merged when all the
+ # discussions are resolved.
+ # only_allow_merge_if_all_discussions_are_resolved: False
+ # boolean (optional): Set whether merge requests can only be merged with successful
+ # jobs.
+ # only_allow_merge_if_pipeline_succeeds: False
+ # string (optional): One of disabled, private, or enabled.
+ # operations_access_level: disabled
+ # boolean (optional): Enable or disable packages repository feature.
+ # packages_enabled: False
+ # string (optional): One of disabled, private, enabled, or public.
+ # pages_access_level: disabled
+ # boolean (optional): Show link to create/view merge request when pushing from the
+ # command line.
+ # printing_merge_request_link_enabled: true
+ # string (optional): One of disabled, private, or enabled.
+ # repository_access_level: enabled
+ # string (optional): Which storage shard the repository is on. (administrators only)
+ # repository_storage: default
+ # boolean (optional): Allow users to request member access.
+ # request_access_enabled: true
+ # boolean (optional): Automatically resolve merge request diffs discussions on lines
+ # changed with a push.
+ # resolve_outdated_diff_discussions: false
+ # boolean (optional): Allow only users with the Maintainer role to pass user-defined
+ # variables when triggering a pipeline. For example when the pipeline is triggered in
+ # the UI, with the API, or by a trigger token.
+ # restrict_user_defined_variables: false
+ # string (optional): (GitLab 14.9 and later) Security and compliance access level. One
+ # of disabled, private, or enabled.
+ # security_and_compliance_access_level: private
+ # boolean (optional): Enable or disable Service Desk feature.
+ # service_desk_enabled: false
+ # boolean (optional): Enable shared runners for this project.
+ # shared_runners_enabled: true
+ # string (optional): One of disabled, private, or enabled.
+ # snippets_access_level: enabled
+ # string (optional): Template used to create squash commit message in merge requests.
+ # (Introduced in GitLab 14.6.)
+ # squash_commit_template: ""
+ # string (optional): One of never, always, default_on, or default_off.
+ # squash_option: default_on
+ # string (optional): The commit message used to apply merge request suggestions.
+ # suggestion_commit_message: ""
+ # string (optional): One of disabled, private, or enabled.
+ # wiki_access_level: enabled
+ # -------------------------------------------------------
+ # Following keys are documented but somehow not supported
+ # -------------------------------------------------------
+ # boolean: Indicates that merges of merge requests should be blocked unless all status
+ # checks have passed. Defaults to false. Introduced in GitLab 15.5 with feature flag
+ # only_allow_merge_if_all_status_checks_passed disabled by default.
+ # only_allow_merge_if_all_status_checks_passed: ?
+ # integer: How many approvers should approve merge request by default. To configure
+ # approval rules, see Merge request approvals API.
+ # approvals_before_merge: ?
+ # string: Auto-cancel pending pipelines. This isn’t a boolean, but enabled/disabled.
+ # auto_cancel_pending_auto: ?
+ # string: Auto Deploy strategy (continuous, manual, or timed_incremental).
+ # pipelines_devops_deploy_strategy: ?
+ # mixed (optional): Image file for avatar of the project.
+ # avatar: ?
+ # hash (optional): Update the image cleanup policy for this project. Accepts: cadence
+ # (string), keep_n (integer), older_than (string), name_regex (string),
+ # name_regex_delete (string), name_regex_keep (string), enabled (boolean).
+ # container_expiration_policy_attributes: ?
+ # string (optional): The classification label for the project.
+ # external_authorization_classification_label: ?
+ # string (optional): Default description for Issues. Description is parsed with GitLab
+ # Flavored Markdown. See Templates for issues and merge requests.
+ # issues_template: ?
+ # boolean (optional): Enable or disable merge pipelines.
+ # merge_pipelines_enabled: ?
+ # string (optional): Default description for merge requests. Description is parsed
+ # with GitLab Flavored Markdown. See Templates for issues and merge requests.
+ # merge_requests_template: ?
+ # boolean (optional): Enable or disable merge trains.
+ # merge_trains_enabled: ?
+ # boolean (optional): Pull mirror overwrites diverged branches.
+ # mirror_overwrites_diverged_branches: ?
+ # boolean (optional): Pull mirroring triggers builds.
+ # mirror_trigger_builds: ?
+ # integer (optional): User responsible for all the activity surrounding a pull mirror
+ # event. (administrators only)
+ # mirror_user_id: ?
+ # boolean (optional): Enables pull mirroring in a project.
+ # mirror: ?
+ # boolean (optional): For forked projects, target merge requests to this project. If
+ # false, the target will be the upstream project.
+ # mr_default_target_self: ?
+ # boolean (optional): Only mirror protected branches.
+ # only_mirror_protected_branches: ?
+ # boolean (optional): If true, jobs can be viewed by non-project members.
+ # public_builds: ?
+ # string (optional): One of disabled, private, enabled or public
+ # requirements_access_level: ?
+ # string (optional): Template used to suggest names for branches created from issues.
+ # (Introduced in GitLab 15.6.)
+ # issue_branch_template: ?
diff --git a/gitlab/manage_users_groups.py b/gitlab/manage_users_groups.py
deleted file mode 100755
--- a/gitlab/manage_users_groups.py
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env python3
-
-import logging
-
-import click
-import yaml
-
-import gitlab
-
-logger = logging.getLogger(__name__)
-
-
-@click.command()
-@click.option(
- "--gitlab",
- "-g",
- "gitlab_instance",
- help="Which GitLab instance to use, as configured in the python-gitlab config",
-)
-@click.option(
- "--do-it",
- "do_it",
- is_flag=True,
- help="Actually perform the operations",
-)
-@click.argument("config_file")
-def cli(gitlab_instance, do_it, config_file):
- """Ensure that GitLab users and group memberships match the structure defined in the
- configuration file. This uses the python-gitlab configuration parsing."""
- gl = gitlab.Gitlab.from_config(gitlab_instance)
- gl.auth()
-
- with open(config_file, "r") as f:
- config = yaml.safe_load(f)
-
- if not do_it:
- logger.info(
- "Will not perform any actions, please use --do-it once you're satisfied"
- " with the expected actions."
- )
-
- for group_path, group_conf in config["groups"].items():
- group = gl.groups.get(group_path, with_projects=False)
- expected_members = {
- username: gitlab.const.AccessLevel[access_level.upper()]
- for username, access_level in group_conf["users"].items()
- }
- recorded_members = set()
-
- expected_group_shares = {
- other_path: gitlab.const.AccessLevel[access_level.upper()]
- for other_path, access_level in group_conf.get(
- "share_with_groups", {}
- ).items()
- }
- recorded_members = set()
-
- remove_extra_memberships = group_conf.get("remove_extra_memberships", False)
- for member in group.members.list():
- username = member.username
- expected_access_level = expected_members.get(member.username)
- if expected_access_level and member.access_level != expected_access_level:
- logger.info(
- "Adjusting membership for %s in %s to %s (was %s)",
- username,
- group_path,
- expected_access_level.name,
- member.access_level,
- )
- if do_it:
- member.access_level = expected_access_level
- member.save()
-
- if remove_extra_memberships and not expected_access_level:
- logger.info("Removing member %s from %s", username, group_path)
- if do_it:
- member.delete()
-
- recorded_members.add(username)
-
- for username, access_level in expected_members.items():
- if username in recorded_members:
- continue
-
- users = gl.users.list(username=username)
- if not users:
- logger.warning(
- "User %s not found, cannot add them to %s!", username, group_path
- )
- continue
-
- user_id = users[0].id
-
- logger.info(
- "Adding member %s in %s at level %s", username, group_path, access_level
- )
- if do_it:
- group.members.create({"user_id": user_id, "access_level": access_level})
-
- recorded_group_shares = set()
-
- for group_share in group.shared_with_groups:
- other_path = group_share["group_full_path"]
- other_id = group_share["group_id"]
- other_access_level = group_share["group_access_level"]
- expected_access_level = expected_group_shares.get(other_path)
- if expected_access_level and other_access_level != expected_access_level:
- logger.info(
- "Adjusting group_share for %s in %s to %s (was %s)",
- other_path,
- group_path,
- expected_access_level,
- other_access_level,
- )
- if do_it:
- group.share(other_id, expected_access_level)
-
- if remove_extra_memberships and not expected_access_level:
- logger.info("Removing group %s from %s", other_path, group_path)
- if do_it:
- group.unshare(other_id)
-
- recorded_group_shares.add(other_path)
-
- for other_path, access_level in expected_group_shares.items():
- if other_path in recorded_group_shares:
- continue
-
- other_group = gl.groups.get(other_path)
- if not other_group:
- logger.warning(
- "Group %s not found, cannot add them to %s!", other_path, group_path
- )
- continue
-
- logger.info(
- "Adding group %s in %s at level %s",
- other_path,
- group_path,
- access_level,
- )
- if do_it:
- group.share(other_group.id, access_level)
-
-
-if __name__ == "__main__":
- logging.basicConfig(
- level=logging.INFO, format="%(asctime)s %(name)s:%(levelname)s %(message)s"
- )
- cli()
diff --git a/gitlab/projects.yml b/gitlab/projects.yml
deleted file mode 100644
--- a/gitlab/projects.yml
+++ /dev/null
@@ -1,201 +0,0 @@
-# [1] https://docs.gitlab.com/ee/api/projects.html#edit-project
-
-# List of namespaces managed by the script (It should be the first level of the
-# project namespace). Other unmanaged projects will be skipped during the script
-# execution.
-managed_project_namespaces:
- - infra
-
-namespace_settings:
- # Dict[str, Any] of key the project namespace, and value a dict of any of the global
- # settings keys above and value, whatever we want to set.
- infra/puppet/3rdparty:
- issues_access_level: disabled
- infra/ci-cd/debs:
- issues_access_level: disabled
-
-# Dict[str, Any] of key the project with its path namespace, and value a dict of any of
-# the global settings keys above (e.g. visibility) and value, whatever we want to set
-# (e.g. assuming the key 'visibility', some credentials repositories, we want to set it
-# 'private').
-project_settings:
- infra/ci-cd/k8s-swh-private-data:
- visibility: private
- infra/puppet/puppet-swh-private-data:
- visibility: private
- # staging extra repositories
- infra/websites/www.softwareheritage.org-gandi:
- visibility: private
- infra/credentials:
- visibility: private
- infra/k8s-swh-private-data:
- visibility: private
- infra/annex/annex-private:
- visibility: private
- infra/iFWCFG:
- visibility: private
-
-# Dict[str, Any] of key the setting to change (e.g. 'merge_method') and as value
-# whatever we want to set (e.g. assuming the 'merge_method', 'ff' as in fast-forward).
-# The keys were determined out of the gitlab api documentation [1]. Some were not
-# supported. Those are located after the 'unsupported' comment.
-global_settings:
- # string (optional): See project visibility level.
- visibility: public
- # string (optional): Set the merge method used.
- merge_method: ff
- # boolean (optional): Enable Delete source branch option by default for all new merge
- # requests.
- remove_source_branch_after_merge: true
- # string (optional): One of disabled, private, or enabled.
- # releases_access_level: enabled
- # boolean: Set whether or not merge requests can be merged with skipped jobs.
- # allow_merge_on_skipped_pipeline: false
- # string: One of disabled, private or enabled
- # analytics_access_level: enabled
- # boolean: Enable Auto DevOps for this project.
- # auto_devops_enabled: false
- # boolean: Set whether auto-closing referenced issues on default branch.
- # autoclose_referenced_issues: true
- # string (optional): The Git strategy. Defaults to fetch.
- # build_git_strategy: fetch
- # integer (optional): The maximum amount of time, in seconds, that a job can run.
- # build_timeout: 3600
- # string (optional): One of disabled, private, or enabled.
- # builds_access_level: enabled
- # string (optional): The path to CI configuration file.
- # ci_config_path: ""
- # integer (optional): Default number of revisions for shallow cloning.
- # ci_default_git_depth: 20
- # boolean (optional): Enable or disable prevent outdated deployment jobs.
- # ci_forward_deployment_enabled: true
- # boolean (optional): Enable or disable running pipelines in the parent project for
- # merge requests from forks. (Introduced in GitLab 15.3.)
- # ci_allow_fork_pipelines_to_run_in_parent_project: true
- # boolean (optional): Set whether or not caches should be separated by branch
- # protection status.
- # ci_separated_caches: true
- # string (optional): Set visibility of container registry, for this project, to one of
- # disabled, private or enabled.
- # container_registry_access_level: disabled
- # string (optional): The default branch name.
- # default_branch: master
- # string (optional): Short project description.
- # description: ""
- # boolean (optional): Disable email notifications.
- # emails_disabled: true
- # boolean (optional): Enforce auth checks on uploads.
- # enforce_auth_checks_on_uploads: true
- # string (optional): One of disabled, private, or enabled.
- # forking_access_level: enabled
- # string (optional): One of disabled, private, or enabled.
- # issues_access_level: enabled
- # boolean (optional): Disable or enable the ability to keep the latest artifact for
- # this project.
- # keep_latest_artifact: True
- # boolean (optional): Enable LFS.
- # lfs_enabled: True
- # string (optional): Template used to create merge commit message in merge requests.
- # (Introduced in GitLab 14.5.)
- # merge_commit_template: ""
- # string (optional): One of disabled, private, or enabled.
- # merge_requests_access_level: enabled
- # boolean (optional): Set whether merge requests can only be merged when all the
- # discussions are resolved.
- # only_allow_merge_if_all_discussions_are_resolved: False
- # boolean (optional): Set whether merge requests can only be merged with successful
- # jobs.
- # only_allow_merge_if_pipeline_succeeds: False
- # string (optional): One of disabled, private, or enabled.
- # operations_access_level: disabled
- # boolean (optional): Enable or disable packages repository feature.
- # packages_enabled: False
- # string (optional): One of disabled, private, enabled, or public.
- # pages_access_level: disabled
- # boolean (optional): Show link to create/view merge request when pushing from the
- # command line.
- # printing_merge_request_link_enabled: true
- # string (optional): One of disabled, private, or enabled.
- # repository_access_level: enabled
- # string (optional): Which storage shard the repository is on. (administrators only)
- # repository_storage: default
- # boolean (optional): Allow users to request member access.
- # request_access_enabled: true
- # boolean (optional): Automatically resolve merge request diffs discussions on lines
- # changed with a push.
- # resolve_outdated_diff_discussions: false
- # boolean (optional): Allow only users with the Maintainer role to pass user-defined
- # variables when triggering a pipeline. For example when the pipeline is triggered in
- # the UI, with the API, or by a trigger token.
- # restrict_user_defined_variables: false
- # string (optional): (GitLab 14.9 and later) Security and compliance access level. One
- # of disabled, private, or enabled.
- # security_and_compliance_access_level: private
- # boolean (optional): Enable or disable Service Desk feature.
- # service_desk_enabled: false
- # boolean (optional): Enable shared runners for this project.
- # shared_runners_enabled: true
- # string (optional): One of disabled, private, or enabled.
- # snippets_access_level: enabled
- # string (optional): Template used to create squash commit message in merge requests.
- # (Introduced in GitLab 14.6.)
- # squash_commit_template: ""
- # string (optional): One of never, always, default_on, or default_off.
- # squash_option: default_on
- # string (optional): The commit message used to apply merge request suggestions.
- # suggestion_commit_message: ""
- # string (optional): One of disabled, private, or enabled.
- # wiki_access_level: enabled
- # -------------------------------------------------------
- # Following keys are documented but somehow not supported
- # -------------------------------------------------------
- # boolean: Indicates that merges of merge requests should be blocked unless all status
- # checks have passed. Defaults to false. Introduced in GitLab 15.5 with feature flag
- # only_allow_merge_if_all_status_checks_passed disabled by default.
- # only_allow_merge_if_all_status_checks_passed: ?
- # integer: How many approvers should approve merge request by default. To configure
- # approval rules, see Merge request approvals API.
- # approvals_before_merge: ?
- # string: Auto-cancel pending pipelines. This isn’t a boolean, but enabled/disabled.
- # auto_cancel_pending_auto: ?
- # string: Auto Deploy strategy (continuous, manual, or timed_incremental).
- # pipelines_devops_deploy_strategy: ?
- # mixed (optional): Image file for avatar of the project.
- # avatar: ?
- # hash (optional): Update the image cleanup policy for this project. Accepts: cadence
- # (string), keep_n (integer), older_than (string), name_regex (string),
- # name_regex_delete (string), name_regex_keep (string), enabled (boolean).
- # container_expiration_policy_attributes: ?
- # string (optional): The classification label for the project.
- # external_authorization_classification_label: ?
- # string (optional): Default description for Issues. Description is parsed with GitLab
- # Flavored Markdown. See Templates for issues and merge requests.
- # issues_template: ?
- # boolean (optional): Enable or disable merge pipelines.
- # merge_pipelines_enabled: ?
- # string (optional): Default description for merge requests. Description is parsed
- # with GitLab Flavored Markdown. See Templates for issues and merge requests.
- # merge_requests_template: ?
- # boolean (optional): Enable or disable merge trains.
- # merge_trains_enabled: ?
- # boolean (optional): Pull mirror overwrites diverged branches.
- # mirror_overwrites_diverged_branches: ?
- # boolean (optional): Pull mirroring triggers builds.
- # mirror_trigger_builds: ?
- # integer (optional): User responsible for all the activity surrounding a pull mirror
- # event. (administrators only)
- # mirror_user_id: ?
- # boolean (optional): Enables pull mirroring in a project.
- # mirror: ?
- # boolean (optional): For forked projects, target merge requests to this project. If
- # false, the target will be the upstream project.
- # mr_default_target_self: ?
- # boolean (optional): Only mirror protected branches.
- # only_mirror_protected_branches: ?
- # boolean (optional): If true, jobs can be viewed by non-project members.
- # public_builds: ?
- # string (optional): One of disabled, private, enabled or public
- # requirements_access_level: ?
- # string (optional): Template used to suggest names for branches created from issues.
- # (Introduced in GitLab 15.6.)
- # issue_branch_template: ?
diff --git a/gitlab/users_groups.yml b/gitlab/users_groups.yml
--- a/gitlab/users_groups.yml
+++ b/gitlab/users_groups.yml
@@ -1,80 +0,0 @@
-# Owner
-# Maintainer
-# Developer
-# Reporter
-# Guest
-
-groups:
- teams/staff:
- users:
- phabricator-migration: Owner
- anlambert: Maintainer
- ardumont: Maintainer
- bchauvet: Owner
- douardda: Maintainer
- jayeshv: Maintainer
- lunar: Maintainer
- marla.dasilva: Maintainer
- moranegg: Maintainer
- olasd: Maintainer
- rdicosmo: Owner
- sgranger: Maintainer
- vlorentz: Maintainer
- vsellier: Maintainer
- zack: Owner
- remove_extra_memberships: true
- teams/developers:
- users:
- phabricator-migration: Owner
- anlambert: Maintainer
- ardumont: Maintainer
- bchauvet: Maintainer
- douardda: Maintainer
- jayeshv: Maintainer
- lunar: Maintainer
- moranegg: Maintainer
- olasd: Maintainer
- rdicosmo: Maintainer
- vlorentz: Maintainer
- vsellier: Maintainer
- zack: Maintainer
- remove_extra_memberships: true
- teams/sysadmin:
- users:
- phabricator-migration: Owner
- ardumont: Owner
- olasd: Owner
- vsellier: Owner
- remove_extra_memberships: true
- teams/interns:
- users:
- phabricator-migration: Owner
- remove_extra_memberships: true
- teams/management:
- users:
- phabricator-migration: Owner
- bchauvet: Owner
- douardda: Maintainer
- rdicosmo: Owner
- vsellier: Maintainer
- zack: Owner
- remove_extra_memberships: true
- infra:
- users:
- phabricator-migration: Owner
- remove_extra_memberships: true
- share_with_groups:
- teams/sysadmin: Owner
- modules:
- users:
- phabricator-migration: Owner
- share_with_groups:
- teams/developers: Maintainer
- remove_extra_memberships: true
- migrated:
- users:
- phabricator-migration: Owner
- share_with_groups:
- teams/sysadmin: Owner
- teams/developers: Maintainer
- remove_extra_memberships: true

File Metadata

Mime Type
text/plain
Expires
Thu, Jul 3, 12:27 PM (2 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3216950

Event Timeline