def _commit(self): """ Checkout the defined branch and create a commit from changes in given config path. The flag `self.changes` is switched to True if there were changes to commit. :rtype: None :raises ManagerError: when checkout/add/commit fails """ commit_msg = '%s at %s' % ( self.msg, time.strftime('%d %h %Y %H:%M:%S')) self.lg.debug('Using commit message: %s', commit_msg) try: self.git.checkout(['-B', self.args.branch]) self.git.add(['-A', '.']) self.git.commit(['-m', commit_msg]) except sh.ErrorReturnCode_1 as e: if re.search('nothing to commit', e.stdout): self.lg.info('No changes, nothing to commit') return else: err = '; '.join(i for i in [e.stdout, e.stderr] if i) raise ManagerError('Committing failed: %s' % err) except Exception as e: raise ManagerError('Committing failed: %s' % e) self.changes = True self.lg.info('Committed successfully')
def check_user_necessary_labels(self, user, group): """ Check if `user` has all the necessary labels for membership in `group`. :param str name: name of the user to check :param str group: name of the group to check :returns: True if `user ` has all required labels, False otherwise :rtype: bool :raises ManagerError: if `user` or `group` is not defined in config """ user_entity = find_entity(self.entities, 'user', user) if not user_entity: raise ManagerError('User %s does not exist in config' % user) group_entity = find_entity(self.entities, 'group', group) if not group_entity: raise ManagerError('Group %s does not exist in config' % group) user_labels = self._get_labels(user_entity) required = self._list_necessary_labels(group_entity, include_self=True) result = all(label in user_labels for label in required) if result: self.lg.info('User %s DOES have all required labels for group %s', user, group) else: self.lg.info('User %s DOES NOT have required labels for group %s', user, group) return result
def check_user_membership(self, user, group): """ Check if `user` is a member of a `group`. This function serves as a wrapper for easy usage from other scripts. :param str user: name of the user to check :param str group: name of the group to check :returns: True if `user` is a member of `group`, False otherwise :rtype: bool """ user_entity = find_entity(self.entities, 'user', user) if not user_entity: raise ManagerError('User %s does not exist in config' % user) group_entity = find_entity(self.entities, 'group', group) if not group_entity: raise ManagerError('Group %s does not exist in config' % group) return bool(self.check_membership(user_entity, group_entity))
def list_groups(self, user): """ Find all groups that `user` is a member of. This function serves as a wrapper for easy import into other scripts. :param str user: name of the user to check :returns: generator of group names that `user` is a member of :rtype: generator """ user_entity = find_entity(self.entities, 'user', user) if not user_entity: raise ManagerError('User %s does not exist in config' % user) groups = self.build_graph(user_entity) return (i.name for i in groups)
def _push(self): """ Push the commited change to given remote branch. NOTE: The remote name used is identical to GitHub user name supplied. The remote has to be pre-configured in the repo (e.g. by Puppet). :rtype: NoneType :raises ManagerError: when pushing fails (bad credentials etc.) """ try: self.git.push([self.args.user, self.args.branch, '-f']) except sh.ErrorReturnCode as e: raise ManagerError('Pushing failed: %s' % e.stderr) self.lg.debug('Pushed to %s/%s successfully', self.args.user, self.args.branch)
def _resolve_entities(self, entity_list): """ Find entities from config based on their types and names. :param [str] entity_list: entities in type:name format :returns: list of resolved entities :rtype: [FreeIPAEntity] :raises ManagerError: if an entity is not defined in config """ result = [] for entity_type, entity_name in entity_list: resolved = find_entity(self.entities, entity_type, entity_name) if not resolved: raise ManagerError('%s %s not found in config' % (entity_type, entity_name)) result.append(resolved) return result
def check_label_necessary(self, label, group): """ Check if `label` is necessary for membership in `group`. :param str label: label value :param str group: name of the group to start the check from :returns: True if `label` is needed, False otherwise :rtype: bool :raises ManagerError: if `group` is not defined in config """ group_entity = find_entity(self.entities, 'group', group) if not group_entity: raise ManagerError('Group %s does not exist in config' % group) labels = self._list_necessary_labels(group_entity, include_self=True) result = label in labels if result: self.lg.info('Label %s IS necessary for group %s', label, group) else: self.lg.info("Label %s ISN'T necessary for group %s", label, group) return result
def list_necessary_labels(self, group): """ Find labels that an entity needs to have based on its membership. Serves as wrapper around the related private method (plus entity resolution based on group name). :param str group: name of group whose labels to list :returns: list of labels defined for nested groups (and entity itself) :rtype: [str] :raises ManagerError: if `group` is not defined in config """ group_entity = find_entity(self.entities, 'group', group) if not group_entity: raise ManagerError('Group %s does not exist in config' % group) labels = self._list_necessary_labels(group_entity, include_self=True) if labels: self.lg.info('Group %s requires labels: [%s]', group, ', '.join(labels)) else: self.lg.info('Group %s requires NO labels', group) return labels
def list_user_missing_labels(self, user): """ List labels that a user is missing and is expected to have based on their group membership. :param str user: name of user whose labels to check :returns: set of labels that `user` is missing :rtype: {str} :raises ManagerError: if `user` is not defined in config """ user_entity = find_entity(self.entities, 'user', user) if not user_entity: raise ManagerError('User %s does not exist in config' % user) necessary = set(self.list_necessary_labels(user_entity)) current = set(self._get_labels(user_entity)) missing = necessary.difference(current) if missing: self.lg.info('User %s misses labels: {%s}', user, ', '.join(missing)) else: self.lg.info('User %s misses NO labels', user) return missing
def _create_pull_request(self): """ Create a GitHub pull request with pulled changes. As pull request head, the branch supplied/generated during forwarder initialization is used. Pushing & PR creation is executed only if `self.changes` flag was set to True by the `_commit` method (i.e. there is a new commit). :rtype: None :raises ManagerError: if PR creation fails """ if not self.changes: self.lg.info('Not creating PR because there were no changes') return self._push() response = self._make_request() parsed = response.json() if response.ok: url = parsed['html_url'] self.lg.info('Pull request %s created successfully' % url) else: err = self._parse_github_error(parsed) if 'A pull request already exists' in err: self.lg.info('PR already exists, not creating another one.') else: raise ManagerError('Creating PR failed: %s' % err)