def update_repository(repository_id, # pylint: disable=too-many-arguments repository_project_id=None, repository_type=None, repository_name=None, repository_url=None, repository_external_id=None): """ Updates a repository and returns the newly updated repository in dict format. Values of None means the field will not be updated. :param repository_id: ID of the repository to update. :type repository_id: ID :param repository_project_id: ID of the repository project. :type repository_project_id: string :param repository_name: New name for the repository. :type repository_name: string | None :param repository_type: New type for repository ('github', 'gerrit', etc). :type repository_type: string | None :param repository_url: New URL for the repository. :type repository_url: string | None :param repository_external_id: ID of the repository from the service provider. :type repository_external_id: string :return: dict representation of the repository object. :rtype: dict """ repository = Repository() try: repository.load(str(repository_id)) except DoesNotExist as err: return {'errors': {'repository_id': str(err)}} # TODO: Ensure project_id exists. if repository_project_id is not None: repository.set_repository_project_id(str(repository_project_id)) if repository_type is not None: supported_repo_types = get_supported_repository_providers().keys() if repository_type in supported_repo_types: repository.set_repository_type(repository_type) else: return {'errors': {'repository_type': 'Invalid value passed. The accepted values are: (%s)' \ %'|'.join(supported_repo_types)}} if repository_external_id is not None: # Find a repository is already linked with this external_id linked_repository = Repository().get_repository_by_external_id(repository_external_id, repository.get_repository_type()) # If found return an error if linked_repository is not None: return {'errors': {'repository_external_id': 'This repository is alredy configured for a contract group.'}} repository.set_repository_external_id(repository_external_id) if repository_name is not None: repository.set_repository_name(repository_name) if repository_url is not None: try: val = cla.hug_types.url(repository_url) repository.set_repository_url(val) except ValueError as err: return {'errors': {'repository_url': 'Invalid URL specified'}} repository.save() return repository.to_dict()
def handle_installation_repositories_added_event(action: str, body: dict): func_name = 'github.activity.handle_installation_repositories_added_event' # Who triggered the event user_login = body['sender']['login'] cla.log.debug(f'{func_name} - processing github [installation_repositories] ' f'activity {action} callback created by GitHub user {user_login}.') # Grab the list of repositories added from the event model repository_added = body.get('repositories_added', []) # Create a unique list of repositories for the email that we need to send out repository_list = set([repo.get('full_name', None) for repo in repository_added]) # All the repos in the message should be under the same GitHub Organization organization_name = '' for repo in repository_added: # Grab the information repository_external_id = repo['id'] # example: 271841254 repository_name = repo['name'] # example: PyImath repository_full_name = repo['full_name'] # example: AcademySoftwareFoundation/PyImath organization_name = repository_full_name.split('/')[0] # example: AcademySoftwareFoundation # repository_private = repo['private'] # example: False # Lookup the GitHub Organization in our table - should be there already cla.log.debug(f'{func_name} - Locating organization using name: {organization_name}') org_model = get_organization_model(organization_name) if org_model is None: # Should we create since it's missing? cla.log.warning(f'Unable to locate GitHub Organization {organization_name} in our database') continue # Should we update to ensure the installation_id is set? if org_model.get_organization_installation_id() is None: # Update the installation ID org_model.set_organization_installation_id(body.get('installation', {}).get('id', None)) org_model.save() # Check to see if the auto enabled flag is set if org_model.get_auto_enabled(): # We need to check that we only have 1 CLA Group - auto-enable only works when the entire # Organization falls under a single CLA Group - otherwise, how would we know which CLA Group # to add them to? First we query all the existing repositories associated with this Github Org - # they should all point the the single CLA Group - let's verify this... existing_github_repositories = Repository().get_repositories_by_organization(organization_name) cla_group_ids = set(()) # hoping for only 1 unique value - set collection discards duplicates cla_group_repo_sfids = set(()) # keep track of the existing SFDC IDs from existing repos for existing_repo in existing_github_repositories: cla_group_ids.add(existing_repo.get_repository_project_id()) cla_group_repo_sfids.add(existing_repo.get_repository_sfdc_id()) # We should only have one... if len(cla_group_ids) != 1 or len(cla_group_repo_sfids) != 1: cla.log.warning(f'{func_name} - Auto Enabled set for Organization {organization_name}, ' f'but we found repositories or SFIDs that belong to multiple CLA Groups. ' 'Auto Enable only works when all repositories under a given ' 'GitHub Organization are associated with a single CLA Group. This ' f'organization is associated with {len(cla_group_ids)} CLA Groups and ' f'{len(cla_group_repo_sfids)} SFIDs.') return cla_group_id = cla_group_ids.pop() project_model = get_project_instance() try: project_model.load(project_id=cla_group_id) except DoesNotExist as err: cla.log.warning(f'{func_name} - unable to load project (cla_group) by ' f'project_id: {cla_group_id}, error: {err}') cla.log.debug(f'{func_name} - Organization {organization_name} has auto_enabled set - ' f'adding repository: {repository_name} to ' f'CLA Group: {project_model.get_project_name()}') try: # Create the new repository entry and associate it with the CLA Group new_repository = Repository( repository_id=str(uuid.uuid4()), repository_project_id=cla_group_id, repository_name=repository_full_name, repository_type='github', repository_url='https://github.com/' + repository_full_name, repository_organization_name=organization_name, repository_external_id=repository_external_id, repository_sfdc_id=cla_group_repo_sfids.pop(), ) new_repository.set_enabled(True) new_repository.save() # Log the event msg = (f'Adding repository {repository_full_name} ' f'from GitHub organization : {organization_name} ' f'with URL: https://github.com/{repository_full_name} ' 'to the CLA configuration. GitHub organization was set to auto-enable.') Event.create_event( event_type=EventType.RepositoryAdded, event_project_id=cla_group_id, event_project_name=project_model.get_project_name(), event_company_id=None, event_data=msg, event_summary=msg, event_user_id=user_login, contains_pii=False, ) except Exception as err: cla.log.warning(f'{func_name} - Could not create GitHub repository: {err}') return else: cla.log.debug(f'{func_name} - Auto enabled NOT set for GitHub Organization {organization_name} - ' f'not auto-adding repository: {repository_full_name}') return # Notify the Project Managers notify_project_managers_auto_enabled(organization_name, repository_list)
def create_repository(auth_user: AuthUser, # pylint: disable=too-many-arguments repository_project_id, repository_name, repository_organization_name, repository_type, repository_url, repository_external_id=None): """ Creates a repository and returns the newly created repository in dict format. :param repository_project_id: The ID of the repository project. :type repository_project_id: string :param repository_name: The new repository name. :type repository_name: string :param repository_type: The new repository type ('github', 'gerrit', etc). :type repository_organization_name: string :param repository_organization_name: The repository organization name :type repository_type: string :param repository_url: The new repository URL. :type repository_url: string :param repository_external_id: The ID of the repository from the repository provider. :type repository_external_id: string :return: dict representation of the new repository object. :rtype: dict """ # Check that organization exists github_organization = GitHubOrg() try: github_organization.load(str(repository_organization_name)) except DoesNotExist as err: return {'errors': {'organization_name': str(err)}} # Check that project is valid. project = Project() try: project.load(str(repository_project_id)) except DoesNotExist as err: return {'errors': {'repository_project_id': str(err)}} # Get SFDC project identifier sfdc_id = project.get_project_external_id() # Validate user is authorized for this project can_access = cla.controllers.project.check_user_authorization(auth_user, sfdc_id) if not can_access['valid']: return can_access['errors'] # Validate if exist already repository linked to a contract group if repository_external_id is not None: # Seach for the repository linked_repository = Repository().get_repository_by_external_id(repository_external_id, repository_type) # If found return an error if linked_repository is not None: return {'errors': {'repository_external_id': 'This repository is alredy configured for a contract group.'}} repository = Repository() repository.set_repository_id(str(uuid.uuid4())) repository.set_repository_project_id(str(repository_project_id)) repository.set_repository_sfdc_id(str(sfdc_id)) repository.set_repository_name(repository_name) repository.set_repository_organization_name(repository_organization_name) repository.set_repository_type(repository_type) repository.set_repository_url(repository_url) if repository_external_id is not None: repository.set_repository_external_id(repository_external_id) repository.save() return repository.to_dict()