git-trainer — это образовательная платформа для изучения git.
Новички в git часто сталкиваются с ситуациями, которые не могут или не знают как разрешать, а если и разрешают, то могут быстро забыть решение, а потом столкнуться с той же проблемой или требованием вновь. Так вот git-trainer призван помочь людям научиться решать такие частые ситуации в виде, максимально приближённым к настоящему.
Задачи представляют из себя какие-либо ситуации, когда надо перевести репозиторий из одного состояния в другое. Это может быть всё что угодно: как решение Merge конфликтов, исправление расхождения истории локального и удалённого репозиториев, исправление последнего коммита, так и просто запутанные и эзотерические сценарии.
Задания представляют из себя образ Docker контейнера, так что в него можно положить какой угодно репозиторий и сценарий для работы.
Про то, как эти задания создавать будет описано ниже.
В git-trainer рабочее окружение представляет собой окно терминала, привязанное к отдельному Docker контейнеру, в котором развёрнуто задание. Так как действия происходят в контейнере, процесс решения задания максимально повторяет опыт, который человек бы получил, решая эту ситуацию в реальной среде.
В контейнерах добавляется CLI-утилита git-trainer, с помощью которой можно получать сведения о текущем задании и отправлять его на проверку.
Проверка решения заданий производится автоматически несколькими тестами, специально описанными для этого задания. Решение считается принятым, если для него успешно выполнились все тесты. Подробнее о них и их создании ниже.
Попытки решить конкретное задание можно посмотреть в менеджере попыток. В нём вы можете увидеть дату создания попытки и тесты, запущенные на ней, вместе с их результатами.
Чтобы добавить задание, придумайте для него сначала название (name), рабочее название (work_name), описание (description) и развёрнутое описание (extended_description).
nameбудет использоваться в меню выбора задания и должен быть в человеко-читаемом виде. По названию человек должен суметь понять его суть, приветствуется оригинальность.work_nameиспользуется для названия Docker-контейнера и образов и должен быть переводомnameна английский. Приветствуется стиль kebab-case в названии.descriptionбудет показываться в меню выбора задания и должен быть очень кратким, но ёмким описанием задания, которое может поместиться в небольшое место на экране.extended_descriptionиспользуется внутри контейнера, он показывается с помощьюgit-trainer taskи должен быть довольно подробным описанием задания, в нём должна быть поставлена проблематика задания и вся информация для его корректного решения.
Описания заданий хранятся в базе данных, поэтому создайте в папке migrations миграцию с вашим заданием в виде папки, в названии которой находится дата миграции и название задания, можете посмотреть на уже существующие задания. Такое чёткое наименование не обязательно, но приветствуется.
В этой папке должны находиться два файла, up.sql и down.sql, для принятия и отзыва миграции соответственно.
up.sql должен выглядеть вот так:
INSERT INTO tasks (
id,
name,
work_name,
description,
extended_description
)
VALUES (
1,
'Привет, мир!',
'hello-world',
'В этой задаче Вам предстоит создать новый Git репозиторий и сделать в нём первый коммит.',
'Давайте начнём с чего-нибудь лёгкого.n
Создайте в папке "hello-world" новый Git репозиторий, в котором напишите код на C, выводящий на экран строчку "Hello, World!".n
После этого сделайте ровно один коммит, добавляющий этот код, с названием "Initial commit".'
);ID нового задания должен быть на 1 больше самого большого из существующих, (TODO: сделать с этим что-то...) а name, work_name, description и extended_description должны быть указаны в параметрах создания новой записи в базу.
down.sql выглядит же вот так:
DELETE FROM tasks WHERE work_name = 'hello-world';Для начала, вам нужен сам git-репозиторий, с которым пользователь будет работать при запуске задания. Основные требования к репозиторию такие:
- Репозиторий должен имитировать работу над каким-то осмысленным проектом, в идеале это может быть настоящий проект, в котором появилась освещаемая проблема
- Задание не должно требовать от студента владение стеком технологий, кроме того, который изучается по программе на 1 курсе программной инженерии (т.е. базовый C++). Это требование относится именно к тем технологиям, без которых задание не выполнить — то есть если в качестве задания студент будет работать с проектом, написанным на незнакомом ему языке (допустим, Haskell), но оно решается грамотной работой с Git или другими известными технологиями, то такое задание более чем приветствуется.
Этот git-репозиторий вы можете создать на каком угодно удалённом хранилище репозиториев, но будет очень хорошо, если вы сделаете его в организации git-trainer-tasks. Для получения доступа к этой организации, напишите вот ему.
Note
Кстати говоря, не обязательно иметь репозиторий для задания, например в уже существующем задании "hello-world" его не предполагается, у вас может быть так же.
Задания как таковые хранятся в папке tasks по своим названиям. Внутри них должна находиться папка src c Dockerfile в ней и файл justfile:
- В папке src должны находиться все пререквизиты, которые не могут и не должны находиться в репозитории-шаблоне. Например, это могут быть файлы, которые в задании должны будут находиться как незаиндексированные изменения, такие файлы никак не засунешь в репозиторий-шаблон.
- justfile — это скрипт, описывающий как задание преобразуется в Docker-образ. Он может выглядеть вот так:
default:
-git clone https://github.com/git-trainer-tasks/branching.git tasks/branching/src/repo
docker build -f tasks/branching/src/Dockerfile -t git-trainer:branching .- В Dockerfile должна быть описана сама сборка Docker-образа.
FROM git-trainer:base-task-image
ARG USERNAME=student
ARG GIT_USERNAME=student
ARG GIT_EMAIL=student@alivetech.com
ENV DESCRIPTION="В этом репозитории вы с другом пишете алгоритм сортировки подсчётом.\nВаш друг сделал отдельную ветку \"origin/counting_sort\", где имплементировал алгоритм, а вам досталась задача написать функцию вывода вектора на экран в другой ветке.\nНапишите эту функцию в ветке \"print_vector\" и объедините обе ваших ветки с главной веткой main."
COPY tasks/branching/src/repo counting-sort
RUN sudo chown -R $USERNAME:$USERNAME counting-sort/
RUN echo -n $DESCRIPTION > /etc/git-trainer/description
USER $USERNAME
RUN git config --global --add safe.directory /home/$USERNAME/counting-sort
RUN cd counting-sort && git switch mainImportant
Самое главное, что при создании образа вы должны написать копию extended_description в файл /etc/git-trainer/description. Также вы должны заменить в нём все переносы строк на "\n" #2.
Тесты для задания хранятся в папке tests по своим названиям. В них должны находиться скрипты .sh с названиями вида "test[n].sh", где "n" — номер теста.
Каждый отдельный тест должен проверять отдельную степень свободы в сданном решении. По окончании своей работы он должен выдать какой-либо текст, оповещающий либо об успешном прохождении, либо об ошибке, и exit-code: 0 для успешного прохождения и 1 для ошибки.
#!/bin/bash
cd "$HOME"
cd binary-addition && git status &>/dev/null
if [ "$?" -eq 0 ]; then
echo "2. Git-репозиторий существует."
exit 0
else
echo "2. Убедитесь, что в директории binary-addition существует Git-репозиторий."
exit 1
fiЭтот скрипт проверяет, что в папке "binary-addition" есть Git-репозиторий с помощью сравнения exit-code команды git status с 0.
Скрипты зависят от друг друга: если скрипт с номером n выдал ошибку или не запускался, то скрипт с номером n + 1 не будет запускаться. Так вы можете проверить в первом тесте, что существует, к примеру, Git-репозиторий, а остальные тесты писать будет намного удобнее, исходя из уверенности, что они будут проверять репозиторий тогда и только тогда, когда он действительно существует.
Заметьте, что с помощью shebang вы можете писать тесты на любом другом языке. У вас есть огромная свобода при написании тестов
Чтобы запустить git-trainer, установите just и сделайте just run. Вы можете отдельно сделать just build-images для сборки только образов и just release для деплоя приложения.