Example #1
0
def pull_requests_scanned(owner, repo, requestor_id=None):
    """
    Update the timestamp on the repository object,
    and delete old pull request that weren't updated.
    """
    repo_name = repo
    repo = Repository.get(owner, repo_name)
    prev_scan_at = repo.pull_requests_last_scanned_at
    repo.pull_requests_last_scanned_at = datetime.now()
    db.session.add(repo)

    if prev_scan_at:
        # delete any PRs that were not updated since the previous scan --
        # they have been removed from Github
        query = (
            PullRequest.query.filter_by(base_repo_id=repo.id)
            .filter(PullRequest.last_replicated_at < prev_scan_at)
        )
        query.delete()

    # delete the mutex
    lock_name = LOCK_TEMPLATE.format(owner=owner, repo=repo_name)
    Mutex.query.filter_by(name=lock_name).delete()
    logger.info("Lock {name} deleted".format(name=lock_name))

    db.session.commit()
Example #2
0
def issues_scanned(owner, repo, requestor_id=None):
    """
    Update the timestamp on the repository object,
    and delete old issues that weren't updated.
    """
    repo_name = repo
    repo = Repository.get(owner, repo_name)
    prev_scan_at = repo.issues_last_scanned_at
    repo.issues_last_scanned_at = datetime.now()
    db.session.add(repo)

    if prev_scan_at:
        # delete any issues that were not updated since the previous scan --
        # they have been removed from Github
        query = (
            Issue.query.filter_by(repo_id=repo.id)
            .filter(Issue.last_replicated_at < prev_scan_at)
        )
        query.delete()

    # delete the mutex
    lock_name = LOCK_TEMPLATE.format(owner=owner, repo=repo_name)
    Mutex.query.filter_by(name=lock_name).delete()
    logger.info("Lock {name} deleted".format(name=lock_name))

    db.session.commit()
Example #3
0
def process_repository(repo_data, via="webhook", fetched_at=None, commit=True,
                       requestor_id=None):
    repo_id = repo_data.get("id")
    if not repo_id:
        raise MissingData("no repo ID")

    # fetch the object from the database,
    # or create it if it doesn't exist in the DB
    repo = Repository.query.get(repo_id)
    if not repo:
        repo = Repository(id=repo_id)

    # should we update the object?
    fetched_at = fetched_at or datetime.now()
    if repo.last_replicated_at > fetched_at:
        raise StaleData()

    # update the object
    fields = (
        "name", "private", "description", "fork", "homepage", "size",
        "stargazers_count", "watchers_count", "language", "has_issues",
        "has_downloads", "has_wiki", "has_pages", "forks_count",
        "open_issues_count", "default_branch",
    )
    for field in fields:
        if field in repo_data:
            setattr(repo, field, repo_data[field])
    dt_fields = ("created_at", "updated_at", "pushed_at")
    for field in dt_fields:
        if repo_data.get(field):
            dt = parse_date(repo_data[field]).replace(tzinfo=None)
            setattr(repo, field, dt)

    # user references
    user_fields = ("owner", "organization")
    for user_field in user_fields:
        if user_field not in repo_data:
            continue
        user_data = repo_data[user_field]
        id_field = "{}_id".format(user_field)
        login_field = "{}_login".format(user_field)
        if user_data:
            setattr(repo, id_field, user_data["id"])
            if hasattr(repo, login_field):
                setattr(repo, login_field, user_data["login"])
            try:
                process_user(user_data, via=via, fetched_at=fetched_at)
            except StaleData:
                pass
        else:
            setattr(repo, id_field, None)
            if hasattr(repo, login_field):
                setattr(repo, login_field, None)

    # update replication timestamp
    replicated_dt_field = "last_replicated_via_{}_at".format(via)
    if hasattr(repo, replicated_dt_field):
        setattr(repo, replicated_dt_field, fetched_at)

    # add to DB session, so that it will be committed
    db.session.add(repo)

    # if we have requestor_id and permissions, update the permissions object
    if requestor_id and repo_data.get("permissions"):
        permissions_data = repo_data["permissions"]
        assoc = UserRepoAssociation.query.get((requestor_id, repo_id))
        if not assoc:
            assoc = UserRepoAssociation(user_id=requestor_id, repo_id=repo_id)
        for perm in ("admin", "push", "pull"):
            if perm in permissions_data:
                perm_attr = "can_{perm}".format(perm=perm)
                setattr(assoc, perm_attr, permissions_data[perm])
        db.session.add(assoc)

    if commit:
        db.session.commit()

    return repo
Example #4
0
def process_milestone(milestone_data,
                      via="webhook",
                      fetched_at=None,
                      commit=True,
                      repo_id=None):
    number = milestone_data.get("number")
    if not number:
        raise MissingData("no milestone number")

    if not repo_id:
        url = milestone_data.get("url")
        if not url:
            raise MissingData("no milestone url")

        # parse repo info from url
        path = URLObject(url).path
        assert path.segments[0] == "repos"
        repo_owner = path.segments[1]
        repo_name = path.segments[2]

        # fetch repo from database
        try:
            repo = Repository.get(repo_owner, repo_name)
        except MultipleResultsFound:
            msg = "Repo {owner}/{repo} found multiple times!".format(
                owner=repo_owner,
                repo=repo_name,
            )
            raise DatabaseError(msg, {
                "type": "milestone",
                "owner": repo_owner,
                "repo": repo_name,
            })
        if not repo:
            msg = "Repo {owner}/{repo} not loaded in webhookdb".format(
                owner=repo_owner,
                repo=repo_name,
            )
            raise NotFound(msg, {
                "type": "milestone",
                "owner": repo_owner,
                "repo": repo_name,
            })
        repo_id = repo.id

    # fetch the object from the database,
    # or create it if it doesn't exist in the DB
    milestone = Milestone.query.get((repo_id, number))
    if not milestone:
        milestone = Milestone(repo_id=repo_id, number=number)

    # should we update the object?
    fetched_at = fetched_at or datetime.now()
    if milestone.last_replicated_at > fetched_at:
        raise StaleData()

    # Most fields have the same name in our model as they do in Github's API.
    # However, some are different. This mapping contains just the differences.
    field_to_model = {
        "open_issues": "open_issues_count",
        "closed_issues": "closed_issues_count",
        "due_on": "due_at",
    }

    # update the object
    fields = (
        "state",
        "title",
        "description",
        "open_issues",
        "closed_issues",
    )
    for field in fields:
        if field in milestone_data:
            mfield = field_to_model.get(field, field)
            setattr(milestone, mfield, milestone_data[field])
    dt_fields = ("created_at", "updated_at", "closed_at", "due_on")
    for field in dt_fields:
        if milestone_data.get(field):
            dt = parse_date(milestone_data[field]).replace(tzinfo=None)
            mfield = field_to_model.get(field, field)
            setattr(milestone, mfield, dt)

    # user references
    user_fields = ("creator", )
    for user_field in user_fields:
        if user_field not in milestone_data:
            continue
        user_data = milestone_data[user_field]
        id_field = "{}_id".format(user_field)
        login_field = "{}_login".format(user_field)
        if user_data:
            setattr(milestone, id_field, user_data["id"])
            if hasattr(milestone, login_field):
                setattr(milestone, login_field, user_data["login"])
            try:
                process_user(user_data, via=via, fetched_at=fetched_at)
            except StaleData:
                pass
        else:
            setattr(milestone, id_field, None)
            if hasattr(milestone, login_field):
                setattr(milestone, login_field, None)

    # update replication timestamp
    replicated_dt_field = "last_replicated_via_{}_at".format(via)
    if hasattr(milestone, replicated_dt_field):
        setattr(milestone, replicated_dt_field, fetched_at)

    # add to DB session, so that it will be committed
    db.session.add(milestone)
    if commit:
        db.session.commit()

    return milestone
Example #5
0
def process_label(label_data,
                  via="webhook",
                  fetched_at=None,
                  commit=True,
                  repo_id=None):
    name = label_data.get("name")
    if not name:
        raise MissingData("no label name")

    if not repo_id:
        url = label_data.get("url")
        if not url:
            raise MissingData("no label url")

        # parse repo info from url
        path = URLObject(url).path
        assert path.segments[0] == "repos"
        repo_owner = path.segments[1]
        repo_name = path.segments[2]

        # fetch repo from database
        try:
            repo = Repository.get(repo_owner, repo_name)
        except MultipleResultsFound:
            msg = "Repo {owner}/{repo} found multiple times!".format(
                owner=repo_owner,
                repo=repo_name,
            )
            raise DatabaseError(msg, {
                "type": "label",
                "owner": repo_owner,
                "repo": repo_name,
            })
        if not repo:
            msg = "Repo {owner}/{repo} not loaded in webhookdb".format(
                owner=repo_owner,
                repo=repo_name,
            )
            raise NotFound(msg, {
                "type": "label",
                "owner": repo_owner,
                "repo": repo_name,
            })
        repo_id = repo.id

    # fetch the object from the database,
    # or create it if it doesn't exist in the DB
    label = IssueLabel.query.get((repo_id, name))
    if not label:
        label = IssueLabel(repo_id=repo_id, name=name)

    # should we update the object?
    fetched_at = fetched_at or datetime.now()
    if label.last_replicated_at > fetched_at:
        raise StaleData()

    # color reference
    if "color" in label_data:
        color_hex = label_data["color"]
        if color_hex:
            label.color = Color("#{hex}".format(hex=color_hex))
        else:
            label.color = None

    # update replication timestamp
    replicated_dt_field = "last_replicated_via_{}_at".format(via)
    if hasattr(label, replicated_dt_field):
        setattr(label, replicated_dt_field, fetched_at)

    # add to DB session, so that it will be committed
    db.session.add(label)
    if commit:
        db.session.commit()

    return label