summaryrefslogtreecommitdiff
path: root/buildscripts/patch_builds/change_data.py
blob: 0ecab81cb3960aa3950c1e1c54cfce0ea73d1600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""Tools for detecting changes in a commit."""
from typing import Any, Set
import os

from git import Repo, DiffIndex
import structlog
from structlog.stdlib import LoggerFactory

structlog.configure(logger_factory=LoggerFactory())
LOGGER = structlog.get_logger(__name__)


def _paths_for_iter(diff, iter_type):
    """
    Get the set for all the files in the given diff for the specified type.

    :param diff: git diff to query.
    :param iter_type: Iter type ['M', 'A', 'R', 'D'].
    :return: set of changed files.
    """
    a_path_changes = {change.a_path for change in diff.iter_change_type(iter_type)}
    b_path_changes = {change.b_path for change in diff.iter_change_type(iter_type)}
    return a_path_changes.union(b_path_changes)


def _modified_files_for_diff(diff: DiffIndex, log: Any) -> Set:
    """
    Get the set of files modified in the given git diff.

    :param diff: Git diff information.
    :param log: Logger for logging.
    :return: Set of files that were modified in diff.
    """
    modified_files = _paths_for_iter(diff, 'M')
    log.debug("modified files", files=modified_files)

    added_files = _paths_for_iter(diff, 'A')
    log.debug("added files", files=added_files)

    renamed_files = _paths_for_iter(diff, 'R')
    log.debug("renamed files", files=renamed_files)

    deleted_files = _paths_for_iter(diff, 'D')
    log.debug("deleted files", files=deleted_files)

    return modified_files.union(added_files).union(renamed_files).union(deleted_files)


def find_changed_files(repo: Repo) -> Set[str]:
    """
    Find files that were new or added to the repository between commits.

    :param repo: Git repository.

    :return: Set of changed files.
    """
    diff = repo.index.diff(None)
    work_tree_files = _modified_files_for_diff(diff, LOGGER.bind(diff="working tree diff"))

    commit = repo.index
    diff = commit.diff(repo.head.commit)
    index_files = _modified_files_for_diff(diff, LOGGER.bind(diff="index diff"))

    untracked_files = set(repo.untracked_files)
    LOGGER.info("untracked files", files=untracked_files, diff="untracked diff")

    paths = work_tree_files.union(index_files).union(untracked_files)

    return [
        os.path.relpath(f"{repo.working_dir}/{os.path.normpath(path)}", os.getcwd())
        for path in paths
    ]