def multiple(parameters): """Retrieve a single commit identified by its SHA-1 sum. sha1 : COMMIT_SHA1 : string Retrieve a commit identified by its SHA-1 sum. The SHA-1 sum can be abbreviated, but must be at least 4 characters long, and must be unambigious in the repository. repository : REPOSITORY : - Specify repository to access, identified by its unique numeric id or short-name. Required unless a repository is specified in the resource path.""" sha1_parameter = parameters.getQueryParameter("sha1") if sha1_parameter is None: raise jsonapi.UsageError("Missing required SHA-1 parameter.") if not re.match("[0-9A-Fa-f]{4,40}$", sha1_parameter): raise jsonapi.UsageError("Invalid SHA-1 parameter: %r" % sha1_parameter) repository = jsonapi.deduce("v1/repositories", parameters) if repository is None: raise jsonapi.UsageError( "Commit reference must have repository specified.") return api.commit.fetch(repository, sha1=sha1_parameter)
def create(parameters, value, values, data): critic = parameters.critic user = parameters.context.get("users", critic.actual_user) if value or values: raise jsonapi.UsageError("Invalid POST request") converted = jsonapi.convert( parameters, { "review?": api.review.Review, "comment?": str, }, data) review = jsonapi.deduce("v1/reviews", parameters) if not review: if "review" not in converted: raise jsonapi.UsageError("No review specified") review = converted["review"] elif "review" in converted and review != converted["review"]: raise jsonapi.UsageError("Conflicting reviews specified") if "comment" in converted: comment_text = converted["comment"].strip() if not comment_text: raise jsonapi.UsageError("Empty comment specified") else: comment_text = None result = [] def collectBatch(batch): assert isinstance(batch, api.batch.Batch) result.append(batch) with api.transaction.Transaction(critic) as transaction: modifier = transaction.modifyReview(review) if comment_text: note = modifier.createComment(comment_type="note", author=critic.actual_user, text=comment_text) else: note = None modifier.submitChanges(note, callback=collectBatch) assert len(result) == 1 return result[0], None
def multiple(parameters): """TODO: add documentation""" changeset = jsonapi.deduce("v1/changesets", parameters) if changeset is None: raise jsonapi.UsageError( "changeset needs to be specified, ex. &changeset=<id>") repository = jsonapi.deduce("v1/repositories", parameters) if repository is None: raise jsonapi.UsageError( "repository needs to be specified, " "ex. &repository=<id or name>") return api.filediff.fetchAll(parameters.critic, changeset)
def update(parameters, value, values, data): critic = parameters.critic if parameters.subresource_path: assert parameters.subresource_path[0] == "delegates" if len(parameters.subresource_path) == 2: raise jsonapi.UsageError("can't update specific delegate") delegates = jsonapi.convert(parameters, [api.user.User], data) else: converted = jsonapi.convert(parameters, {"delegates?": [api.user.User]}, data) delegates = converted.get("delegates") if value: repository_filters = [value] else: repository_filters = values with api.transaction.Transaction(critic) as transaction: for repository_filter in repository_filters: if delegates is not None: transaction \ .modifyUser(repository_filter.subject) \ .modifyFilter(repository_filter) \ .setDelegates(delegates) return value, values
def multiple(critic, parameters): """Retrieve all branches in the Git repositories. repository : REPOSITORY : - Include only branches in one repository, identified by the repository's unique numeric id or short-name. name : NAME : string Retrieve only the branch with the specified name. The name should <em>not</em> include the "refs/heads/" prefix. When this parameter is specified a repository must be specified as well, either in the resource path or using the <code>repository</code> parameter.""" repository = jsonapi.v1.repositories.Repositories.deduce( critic, parameters) name_parameter = parameters.getQueryParameter("name") if name_parameter: if repository is None: raise jsonapi.UsageError( "Named branch access must have repository specified.") return api.branch.fetch(critic, repository=repository, name=name_parameter) return api.branch.fetchAll(critic, repository=repository)
def update(parameters, value, values, data): critic = parameters.critic filechanges = [value] if value else values reviews = set(filechange.review for filechange in filechanges) if len(reviews) > 1: raise jsonapi.UsageError("Multiple reviews updated") review = reviews.pop() converted = jsonapi.convert(parameters, { "draft_changes": { "new_is_reviewed": bool, }, }, data) is_reviewed = converted["draft_changes"]["new_is_reviewed"] with api.transaction.Transaction(critic) as transaction: modifier = transaction \ .modifyReview(review) if is_reviewed: for filechange in filechanges: modifier.markChangeAsReviewed(filechange) else: for filechange in filechanges: modifier.markChangeAsPending(filechange)
def deduce(parameters): changeset = jsonapi.deduce("v1/changesets", parameters) if changeset is None: raise jsonapi.UsageError( "changeset needs to be specified, ex. &changeset=<id>") filechange = parameters.context.get(FileChanges.name) filechange_parameter = parameters.getQueryParameter("filechange") if filechange_parameter is not None: if filechange is not None: raise jsonapi.UsageError( "Redundant query parameter: filechange=%s" % filechange_parameter) filechange_id = jsonapi.numeric_id(filechange_parameter) filechange = api.filechange.fetch(parameters.critic, changeset, filechange_id) return filechange
def multiple(parameters): """Retrieve a single named repository or all repositories on this system. name : SHORT_NAME : string Retrieve a repository identified by its unique short-name. This is equivalent to accessing /api/v1/repositories/REPOSITORY_ID with that repository's numeric id. When used, any other parameters are ignored. filter : highlighted : - If specified, retrieve only "highlighted" repositories. These are repositories that are deemed of particular interest for the signed-in user. (If no user is signed in, no repositories are highlighted.)""" name_parameter = parameters.getQueryParameter("name") if name_parameter: return api.repository.fetch(parameters.critic, name=name_parameter) filter_parameter = parameters.getQueryParameter("filter") if filter_parameter is not None: if filter_parameter == "highlighted": repositories = api.repository.fetchHighlighted( parameters.critic) else: raise jsonapi.UsageError( "Invalid repository filter parameter: %r" % filter_parameter) else: repositories = api.repository.fetchAll(parameters.critic) return repositories
def multiple(critic, parameters): """Retrieve all reviews in this system. repository : REPOSITORY : - Include only reviews in one repository, identified by the repository's unique numeric id or short-name. state : STATE[,STATE,...] : - Include only reviews in the specified state. Valid values are: <code>open</code>, <code>closed</code>, <code>dropped</code>.""" repository = jsonapi.v1.repositories.Repositories.deduce( critic, parameters) state_parameter = parameters.getQueryParameter("state") if state_parameter: state = set(state_parameter.split(",")) invalid = state - api.review.Review.STATE_VALUES if invalid: raise jsonapi.UsageError("Invalid review state values: %s" % ", ".join(map(repr, sorted(invalid)))) else: state = None return api.review.fetchAll(critic, repository=repository, state=state)
def delete(parameters, value, values): critic = parameters.critic path = parameters.subresource_path if value: profiles = [value] else: profiles = values if len(path) in (2, 3) \ and path[0] in CATEGORIES \ and path[1] == "exceptions": exception_id = path[2] if len(path) == 3 else None with api.transaction.Transaction(critic) as transaction: for profile in profiles: modifier = transaction.modifyAccessControlProfile(profile) \ .modifyProfile() \ .modifyExceptions(path[0]) if exception_id is None: modifier.deleteAll() else: modifier.delete(exception_id) return value, values if path: raise jsonapi.UsageError("Invalid DELETE request") with api.transaction.Transaction(critic) as transaction: for profile in profiles: transaction.modifyAccessControlProfile(profile) \ .delete()
def deduce(parameters): repository = jsonapi.deduce("v1/repositories", parameters) changeset = parameters.context.get(Changesets.name) changeset_parameter = parameters.getQueryParameter("changeset") if changeset_parameter is not None: if changeset is not None: raise jsonapi.UsageError( "Redundant query parameter: changeset=%s" % changeset_parameter) if repository is None: raise jsonapi.UsageError( "repository needs to be specified, ex. &repository=<id>") changeset_id = jsonapi.numeric_id(changeset_parameter) changeset = api.changeset.fetch( parameters.critic, repository, changeset_id=changeset_id) return changeset
def create(parameters, value, values, data): critic = parameters.critic user = parameters.context.get("users", critic.actual_user) if parameters.subresource_path: raise jsonapi.UsageError("Invalid POST request") # Create a labeled access control profile selector. assert not (value or values) converted = jsonapi.convert( parameters, { "labels": [str], "profile": api.accesscontrolprofile.AccessControlProfile }, data) result = [] def collectLabeledAccessControlProfile(labeled_profile): assert isinstance( labeled_profile, api.labeledaccesscontrolprofile.LabeledAccessControlProfile) result.append(labeled_profile) with api.transaction.Transaction(critic) as transaction: transaction.createLabeledAccessControlProfile( converted["labels"], converted["profile"], callback=collectLabeledAccessControlProfile) assert len(result) == 1 return result[0], None
def create(parameters, value, values, data): critic = parameters.critic user = critic.actual_user converted = jsonapi.convert(parameters, { "new_upstream?": str, "history_rewrite?": bool }, data) new_upstream = converted.get("new_upstream") history_rewrite = converted.get("history_rewrite") if (new_upstream is None) == (history_rewrite is None): raise jsonapi.UsageError( "Exactly one of the arguments new_upstream and history_rewrite " "must be specified.") if history_rewrite == False: raise jsonapi.UsageError( "history_rewrite must be true, or omitted.") review = jsonapi.deduce("v1/reviews", parameters) if review is None: raise jsonapi.UsageError( "review must be specified when preparing a rebase") if history_rewrite is not None: expected_type = api.log.rebase.HistoryRewrite else: expected_type = api.log.rebase.MoveRebase result = [] def collectRebase(rebase): assert isinstance(rebase, expected_type), repr(rebase) result.append(rebase) with api.transaction.Transaction(critic) as transaction: transaction \ .modifyReview(review) \ .prepareRebase( user, new_upstream, history_rewrite, callback=collectRebase) assert len(result) == 1, repr(result) return result[0], None
def create(parameters, value, values, data): critic = parameters.critic user = parameters.context.get("users", critic.actual_user) if value or values: raise jsonapi.UsageError("Invalid POST request") converted = jsonapi.convert(parameters, { "comment?": api.comment.Comment, "author?": api.user.User, "text": str }, data) comment = jsonapi.deduce("v1/comments", parameters) if not comment: if "comment" not in converted: raise jsonapi.UsageError("No comment specified") comment = converted["comment"] elif "comment" in converted and comment != converted["comment"]: raise jsonapi.UsageError("Conflicting comments specified") if "author" in converted: author = converted["author"] else: author = critic.actual_user if not converted["text"].strip(): raise jsonapi.UsageError("Empty reply") result = [] def collectReply(reply): assert isinstance(reply, api.reply.Reply) result.append(reply) with api.transaction.Transaction(critic) as transaction: transaction \ .modifyReview(comment.review) \ .modifyComment(comment) \ .addReply( author=author, text=converted["text"], callback=collectReply) assert len(result) == 1 return result[0], None
def multiple(parameters): """Retrieve all reviewable file changes in a review. review : REVIEW_ID : - Retrieve the reviewable changes in the specified review. changeset : CHANGESET_ID : - Retrieve the reviewable changes in the specified changeset. file : FILE : - Retrieve the reviewable changes in the specified file only. assignee : USER : - Retrieve reviewable changes assigned to the specified user only. state : STATE : "pending" or "reviewed" Retrieve reviewable changes in the specified state only.""" review = jsonapi.deduce("v1/reviews", parameters) changeset = jsonapi.deduce("v1/changesets", parameters) if not review: raise jsonapi.UsageError("Missing required parameter: review") file = jsonapi.from_parameter("v1/files", "file", parameters) assignee = jsonapi.from_parameter("v1/users", "assignee", parameters) state_parameter = parameters.getQueryParameter("state") if state_parameter is None: is_reviewed = None else: if state_parameter not in ("pending", "reviewed"): raise jsonapi.UsageError( "Invalid parameter value: state=%r " "(value values are 'pending' and 'reviewed')" % state_parameter) is_reviewed = state_parameter == "reviewed" return api.reviewablefilechange.fetchAll(parameters.critic, review, changeset, file, assignee, is_reviewed)
def deduce(parameters): user = parameters.context.get("users") user_parameter = parameters.getQueryParameter("user") if user_parameter is not None: if user is not None: raise jsonapi.UsageError("Redundant query parameter: user=%s" % user_parameter) user = Users.fromParameter(user_parameter, parameters) return user
def deduce(parameters): commit = parameters.context.get(Commits.name) commit_parameter = parameters.getQueryParameter("commit") if commit_parameter is not None: if commit is not None: raise jsonapi.UsageError( "Redundant query parameter: commit=%s" % commit_parameter) commit = Commits.fromParameter(commit_parameter, parameters) return commit
def single(parameters, argument): """TODO: add documentation""" changeset = jsonapi.deduce("v1/changesets", parameters) if changeset is None: raise jsonapi.UsageError( "changeset needs to be specified, ex. &changeset=<id>") repository = jsonapi.deduce("v1/repositories", parameters) if repository is None: raise jsonapi.UsageError( "repository needs to be specified, " "ex. &repository=<id or name>") file = api.file.fetch(parameters.critic, jsonapi.numeric_id(argument)) filechange = api.filechange.fetch(parameters.critic, changeset, file) return api.filediff.fetch(parameters.critic, filechange)
def multiple(parameters): """Retrieve a single named user or all users of this system. name : NAME : string Retrieve only the user with the given name. This is equivalent to accessing /api/v1/users/USER_ID with that user's numeric id. When used, any other parameters are ignored. status : USER_STATUS[,USER_STATUS,...] : string Include only users whose status is one of the specified. Valid values are: <code>current</code>, <code>absent</code>, <code>retired</code>. sort : SORT_KEY : string Sort the returned users by the specified key. Valid values are: <code>id</code>, <code>name</code>, <code>fullname</code>, <code>email</code>.""" name_parameter = parameters.getQueryParameter("name") if name_parameter: return api.user.fetch(parameters.critic, name=name_parameter) status_parameter = parameters.getQueryParameter("status") if status_parameter: status = set(status_parameter.split(",")) invalid = status - api.user.User.STATUS_VALUES if invalid: raise jsonapi.UsageError("Invalid user status values: %s" % ", ".join(map(repr, sorted(invalid)))) else: status = None sort_parameter = parameters.getQueryParameter("sort") if sort_parameter: if sort_parameter not in ("id", "name", "fullname", "email"): raise jsonapi.UsageError("Invalid user sort parameter: %r" % sort_parameter) sort_key = lambda user: getattr(user, sort_parameter) else: sort_key = lambda user: user.id return sorted(api.user.fetchAll(parameters.critic, status=status), key=sort_key)
def deduce(critic, parameters): review = parameters.context.get("reviews") review_parameter = parameters.getQueryParameter("review") if review_parameter is not None: if review is not None: raise jsonapi.UsageError( "Redundant query parameter: review=%s" % review_parameter) review = api.review.fetch( critic, review_id=jsonapi.numeric_id(review_parameter)) return review
def deduce(critic, parameters): repository = parameters.context.get("repositories") repository_parameter = parameters.getQueryParameter("repository") if repository_parameter is not None: if repository is not None: raise jsonapi.UsageError( "Redundant query parameter: repository=%s" % repository_parameter) repository = from_argument(critic, repository_parameter) return repository
def deduce(parameters): batch = parameters.context.get("batches") batch_parameter = parameters.getQueryParameter("batch") if batch_parameter is not None: if batch is not None: raise jsonapi.UsageError( "Redundant query parameter: batch=%s" % batch_parameter) batch = api.batch.fetch( parameters.critic, jsonapi.numeric_id(batch_parameter)) return batch
def deduce(parameters): file_obj = parameters.context.get((Files.name)) file_parameter = parameters.getQueryParameter("file") if file_parameter is not None: if file_obj is not None: raise jsonapi.UsageError( "Redundant query parameter: file=%s" % file_parameter) file_id = Files.fromParameter(file_parameter, parameters) file_obj = api.file.fetch(parameters.critic, file_id) return file_obj
def deduce(parameters): profile = parameters.context.get("accesscontrolprofiles") profile_parameter = parameters.getQueryParameter("profile") if profile_parameter is not None: if profile is not None: raise jsonapi.UsageError( "Redundant query parameter: profile=%s" % profile_parameter) profile_id = jsonapi.numeric_id(profile_parameter) profile = api.accesscontrolprofile.fetch(parameters.critic, profile_id=profile_id) return profile
def delete(parameters, value, values): critic = parameters.critic if value is None: raise jsonapi.UsageError( "Only one rebase can currently be deleted per request") rebase = value with api.transaction.Transaction(critic) as transaction: transaction \ .modifyReview(rebase.review) \ .cancelRebase(rebase)
def deduce(parameters): comment = parameters.context.get("comments") comment_parameter = parameters.getQueryParameter("comment") if comment_parameter is not None: if comment is not None: raise jsonapi.UsageError( "Redundant query parameter: comment=%s" % comment_parameter) comment = api.comment.fetch( parameters.critic, comment_id=jsonapi.numeric_id(comment_parameter)) return comment
def multiple(parameters): """Retrieve replies to a comment. comment : COMMENT_ID : integer Retrieve all replies to the specified comment.""" comment = jsonapi.deduce("v1/comments", parameters) if not comment: raise jsonapi.UsageError("A comment must be identified.") return comment.replies
def multiple(parameters): """Retrieve all batches in the system (or review.) review : REVIEW_ID : integer Retrieve only batches in the specified review. Can only be used if a review is not specified in the resource path. author : AUTHOR : integer or string Retrieve only batches authored by the specified user, identified by the user's unique numeric id or user name. unpublished : UNPUBLISHED : 'yes' Retrieve a single batch representing the current user's unpublished changes to a review. Must be combined with `review` and cannot be combined with `author`.""" critic = parameters.critic review = jsonapi.deduce("v1/reviews", parameters) author = jsonapi.from_parameter("v1/users", "author", parameters) unpublished_parameter = parameters.getQueryParameter("unpublished") if unpublished_parameter is not None: if unpublished_parameter == "yes": if author is not None: raise jsonapi.UsageError( "Parameters 'author' and 'unpublished' cannot be " "combined") return api.batch.fetchUnpublished(critic, review) else: raise jsonapi.UsageError( "Invalid 'unpublished' parameter: %r (must be 'yes')" % unpublished_parameter) return api.batch.fetchAll(critic, review=review, author=author)
def create(parameters, value, values, data): critic = parameters.critic user = parameters.context.get("users", critic.actual_user) profiles = [value] if value else values path = parameters.subresource_path if 0 < len(path) < 2: raise jsonapi.UsageError("Invalid POST request") if len(path) == 2 \ and path[0] in CATEGORIES \ and path[1] == "exceptions": # Create an rule exception. if path[0] == "http": exception_type = HTTP_EXCEPTION elif path[0] == "repositories": exception_type = REPOSITORIES_EXCEPTION else: exception_type = EXTENSION_EXCEPTION converted = jsonapi.convert(parameters, exception_type, data) with api.transaction.Transaction(critic) as transaction: for profile in profiles: modifier = transaction.modifyAccessControlProfile(profile) \ .modifyExceptions(path[0]) \ .add(**converted) return value, values # Create an access control profile. assert not profiles converted = jsonapi.convert(parameters, PROFILE_WITH_TITLE, data) result = [] def collectAccessControlProfile(profile): assert isinstance(profile, api.accesscontrolprofile.AccessControlProfile) result.append(profile) with api.transaction.Transaction(critic) as transaction: modifier = transaction.createAccessControlProfile( callback=collectAccessControlProfile) updateProfile(modifier, converted) assert len(result) == 1 return result[0], None
def multiple(parameters): """TODO: add documentation""" commit = jsonapi.deduce("v1/commits", parameters) if commit is None: raise jsonapi.UsageError( "commit must be specified, ex. &commit=<sha1>") file_obj = jsonapi.deduce("v1/files", parameters) blob_sha1 = commit.getFileInformation(file_obj).sha1 return api.filecontent.fetch( parameters.critic, commit.repository, blob_sha1, file_obj)