Add gitfame homework.
This commit is contained in:
parent
df097199bc
commit
7773e306d9
3 changed files with 3550 additions and 0 deletions
166
gitfame/README.md
Normal file
166
gitfame/README.md
Normal file
|
@ -0,0 +1,166 @@
|
|||
## gitfame
|
||||
|
||||
В этом задании нужно реализовать консольную утилиту для подсчёта статистик авторов git репозитория.
|
||||
|
||||
### Статистики
|
||||
|
||||
* Количество строк
|
||||
* Количество коммитов
|
||||
* Количество файлов
|
||||
|
||||
Все статистики считаются для состояния репозитория на момент конкретного коммита.
|
||||
|
||||
#### Расчёт
|
||||
|
||||
Каждой строке интересующего подмножества файлов репозитория сопоставляется последний коммит, модифицировавший эту строку.
|
||||
Пустым файлам сопоставляются последние менявшие их коммиты.
|
||||
|
||||
После этого для каждого уникального автора, получившегося множества коммитов,
|
||||
считается количество строк, уникальных коммитов и файлов, которые затрагивали коммиты автора.
|
||||
|
||||
Нужную информацию можно получить с помощью команды `git blame`:
|
||||
|
||||
```
|
||||
✗ git blame utf8/README.md
|
||||
f4640df4 (Fedor Korotkiy 2020-02-26 20:28:52 +0000 1) # utf8*
|
||||
f4640df4 (Fedor Korotkiy 2020-02-26 20:28:52 +0000 2)
|
||||
f4640df4 (Fedor Korotkiy 2020-02-26 20:28:52 +0000 3) Задача объединяет несколько задач на строки и unicode.
|
||||
f4640df4 (Fedor Korotkiy 2020-02-26 20:28:52 +0000 4)
|
||||
f4640df4 (Fedor Korotkiy 2020-02-26 20:28:52 +0000 5) Задача считается решённой, если все подзадачи решены.
|
||||
```
|
||||
|
||||
`git blame` с флагом `--porcelain` (см. `git blame --help`) возвращает информацию в машиночитаемом формате.
|
||||
Кроме того, этот формат схлопывает соседние строки относящиеся к одному коммиту,
|
||||
что может сильно сократить размер результата. Поэтому использовать нужно его.
|
||||
|
||||
### Флаги
|
||||
|
||||
Утилита должна поддерживать следующий набор флагов:
|
||||
|
||||
**--repository** — путь до Git репозитория; по умолчанию текущая директория
|
||||
|
||||
**--revision** — указатель на коммит; HEAD по умолчанию
|
||||
|
||||
**--order-by** — ключ сортировки результатов, один из `lines` (дефолт), `commits`, `files`.
|
||||
|
||||
По умолчанию результаты сортируются по убыванию ключа `(lines, commits, files)`.
|
||||
При равенстве ключей выше будет автор с лексикографически меньшим именем.
|
||||
При использовании флага соответствующей поле в ключе перемещается на первое место.
|
||||
|
||||
**--use-committer** — булев флаг, заменяющий в расчётах автора (дефолт) на коммиттера
|
||||
|
||||
**--format** — формат вывода; один из `tabular` (дефолт), `csv`, `json`, `json-lines`;
|
||||
|
||||
`tabular`:
|
||||
```
|
||||
Name Lines Commits Files
|
||||
Joe Tsai 64 3 2
|
||||
Ross Light 2 1 1
|
||||
ferhat elmas 1 1 1
|
||||
```
|
||||
Human-readable формат. Для паддинга используется пробел.
|
||||
см. [text/tabwriter](https://golang.org/pkg/text/tabwriter/).
|
||||
|
||||
`csv`:
|
||||
```
|
||||
Name,Lines,Commits,Files
|
||||
Joe Tsai,64,3,2
|
||||
Ross Light,2,1,1
|
||||
ferhat elmas,1,1,1
|
||||
```
|
||||
|
||||
`json`:
|
||||
```
|
||||
[{"name":"Joe Tsai","lines":64,"commits":3,"files":2},{"name":"Ross Light","lines":2,"commits":1,"files":1},{"name":"ferhat elmas","lines":1,"commits":1,"files":1}]
|
||||
```
|
||||
|
||||
`json-lines`:
|
||||
```
|
||||
{"name":"Joe Tsai","lines":64,"commits":3,"files":2}
|
||||
{"name":"Ross Light","lines":2,"commits":1,"files":1}
|
||||
{"name":"ferhat elmas","lines":1,"commits":1,"files":1}
|
||||
```
|
||||
|
||||
**--extensions** — список расширений, сужающий список файлов в расчёте; множество ограничений разделяется запятыми, например, `'.go,.md'`
|
||||
|
||||
**--languages** — список языков (программирования, разметки и др.), сужающий список файлов в расчёте; множество ограничений разделяется запятыми например `'go,markdown'`
|
||||
|
||||
Принадлежность файла к языку программирования определяется с помощью его расширения.
|
||||
В [configs/langauage_extensions.json](configs/language_extensions.json) лежит маппинг.
|
||||
Неизвестные языки никаких ограничений не накладывают. При их использовании можно написать warning в stderr.
|
||||
|
||||
**--exclude** — набор [Glob](https://en.wikipedia.org/wiki/Glob_(programming)) паттернов, исключающих файлы из расчёта
|
||||
|
||||
**--restrict-to** — набор Glob паттернов, исключающий все файлы, не удовлетворяющие ни одному из паттерну из набора
|
||||
|
||||
### Тесты
|
||||
|
||||
В [/tests/integration/testdata/bundles](test/integration/testdata/bundles) лежат запакованные git репозитории.
|
||||
Каждый интеграционный тест ссылается на какой-нибудь бандл.
|
||||
|
||||
Как создать bundle? Находясь в git репозитории выполнить
|
||||
```
|
||||
git bundle create my.bundle --all
|
||||
```
|
||||
|
||||
Как распаковать bundle? Находясь в пустой директории.
|
||||
```
|
||||
git clone /path/to/my.bundle .
|
||||
```
|
||||
|
||||
### Ненавязчивые предложения
|
||||
|
||||
#### Project layout
|
||||
|
||||
В go есть [набор рекомендаций](https://github.com/golang-standards/project-layout) по организации структуры проекта.
|
||||
И подпроект этого задания уже частично ему следует. Например, `main.go`, который вам нужно реализовать, лежит в [cmd/gitfame](./cmd/gitfame),
|
||||
интеграционные тесты в `/test`.
|
||||
|
||||
В небольших проектах нет ничего плохого в том, чтобы весь код лежал плоско в корне.
|
||||
Здесь же, для ознакомления предлагаем изучить общепринятый подход.
|
||||
|
||||
#### Cli
|
||||
|
||||
Можно познакомиться с [spf13/cobra](https://github.com/spf13/cobra),
|
||||
популярной библиотекой для написания [cli](https://en.wikipedia.org/wiki/Command-line_interface).
|
||||
В этой задаче cobra поможет распарсить аргументы, написать подробный help message, сделать алиасы для флагов.
|
||||
|
||||
### Git ликбез
|
||||
|
||||
Вся информация взята из [книги](https://github.com/pluralsight/git-internals-pdf/releases/download/v2.0/peepcode-git.pdf).
|
||||
|
||||
Смело советуем прочитать её всем, даже если в контексте задания вы знаете про Git достаточно.
|
||||
|
||||
---------
|
||||
|
||||
Объекты Git хранятся в специальной базе данных `Git Object Database` в директории .git.
|
||||
В базе в сжатом виде хранятся объекты разных типов.
|
||||
У каждого объекта есть SHA-1 хэш, а также небольшой header.
|
||||
|
||||
Несколько основных типов объектов:
|
||||
* **blob** — соответствует файлу; хранит его данные (только содержимое)
|
||||
* **tree** — соответствует директории; хранит список блобов и деревьев, а также их описание (имена файлов, типы, права доступа)
|
||||
* **commit** — соответствует истории изменения дерева; хранит указатель на дерево, автора изменений, субъекта, добавившего изменения (committer), сообщение с описанием изменений, ссылку на предыдущие (родительские) коммиты
|
||||
|
||||
**branch** (ветка) — это не объект `Git Object Database`, а всего лишь файл в директории `.git/refs/heads/` с хэшом последнего для этой ветки коммита.
|
||||
То есть ветка — это указатель на коммит.
|
||||
|
||||
**head** — это ссылка на коммит. В каждом репозитории по умолчанию есть **head** именем **master**.
|
||||
|
||||
**HEAD** — один выделенный **head**. Файл `.git/HEAD`. Родитель следующего коммита.
|
||||
|
||||
**HEAD** может ссылаться на коммит напрямую (**detached HEAD**).
|
||||
Следующий коммит в таком случае не будет принадлежать никакой ветке.
|
||||
|
||||
Гораздо чаще **HEAD** ссылается на ветку.
|
||||
В таком случае следующий коммит "попадёт" в ту же ветку и продвинет **HEAD**.
|
||||
**HEAD** определяет текущую активную ветку.
|
||||
|
||||
**revision** (ревизия) — способ сослаться на Git объект.
|
||||
Например, SHA-1 коммита — это ревизия на коммит,
|
||||
`HEAD@{5 minutes ago}` — это ревизия на последний коммит на момент 5 минут назад,
|
||||
`HEAD:README` — это ревизия на блоб.
|
||||
|
||||
### Критерии сдачи
|
||||
|
||||
Решение должно проходить все тесты, так же как и в обычной задаче.
|
7
gitfame/cmd/gitfame/main.go
Normal file
7
gitfame/cmd/gitfame/main.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build !solution
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
3377
gitfame/configs/language_extensions.json
Normal file
3377
gitfame/configs/language_extensions.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue