From ac08a2fc8b3896f128c26d9226a71283e06ff749 Mon Sep 17 00:00:00 2001 From: gohy <134211235+gohy907@users.noreply.github.com> Date: Fri, 24 Apr 2026 23:42:04 +0400 Subject: [PATCH 1/7] docs: create guide for contributing --- README.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/README.md b/README.md index c00dda4..50da7a0 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,131 @@ git-trainer — это образовательная платформа д Попытки решить конкретное задание можно посмотреть в менеджере попыток. В нём вы можете увидеть дату создания попытки и тесты, запущенные на ней, вместе с их результатами. + +# Как контрибьютить? + +## Задания + +### Миграции + +Чтобы добавить задание, придумайте для него сначала название (`name`), рабочее название (`work_name`), описание (`description`) и развёрнутое описание (`extended_description`). + +- `name` будет использоваться в меню выбора задания и должен быть в человеко-читаемом виде. По названию человек должен суметь понять его суть, приветствуется оригинальность. +- `work_name` используется для названия Docker-контейнера и образов и должен быть переводом `name` на английский. Приветствуется стиль kebab-case в названии. +- `description` будет показываться в меню выбора задания и должен быть очень кратким, но ёмким описанием задания, которое может поместиться в небольшое место на экране. +- `extended_description` используется внутри контейнера, он показывается с помощью `git-trainer task` и должен быть довольно подробным описанием задания, в нём должна быть поставлена проблематика задания и вся информация для его корректного решения. + +Описания заданий хранятся в базе данных, поэтому создайте в папке [migrations](migrations) миграцию с вашим заданием в виде папки, в названии которой находится дата миграции и название задания, можете посмотреть на уже существующие задания. Такое чёткое наименование не обязательно, но приветствуется. + +В этой папке должны находиться два файла, up.sql и down.sql, для принятия и отзыва миграции соответственно. + +up.sql должен выглядеть вот так: + +```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 выглядит же вот так: + +```sql +DELETE FROM tasks WHERE work_name = 'hello-world'; +``` + +### Docker-образ + +Для начала, вам нужен сам git-репозиторий, с которым пользователь будет работать при запуске задания. Основные требования к репозиторию такие: +- Репозиторий должен имитировать работу над каким-то осмысленным проектом, в идеале это может быть настоящий проект, в котором появилась освещаемая проблема +- Задание не должно требовать от студента владение стеком технологий, кроме того, который изучается по программе на 1 курсе программной инженерии (т.е. базовый C++). Это требование относится именно к тем технологиям, без которых задание не выполнить — то есть если в качестве задания студент будет работать с проектом, написанным на незнакомом ему языке (допустим, Haskell), но оно решается грамотной работой с Git или другими известными технологиями, то такое задание более чем приветствуется. + +Этот git-репозиторий вы можете создать на каком угодно удалённом хранилище репозиториев, но будет очень хорошо, если вы сделаете его в организации [git-trainer-tasks](https://github.com/git-trainer-tasks). Для получения доступа к этой организации, напишите [вот ему](https://t.me/gohy279). + +> [!NOTE] +> Кстати говоря, не обязательно иметь репозиторий для задания, например в уже существующем задании "hello-world" его не предполагается, у вас может быть так же. + +Задания как таковые хранятся в папке [tasks](tasks) по своим названиям. Внутри них должна находиться папка src c Dockerfile в ней и файл justfile: +- В папке src должны находиться все пререквизиты, которые не могут и не должны находиться в репозитории-шаблоне. Например, это могут быть файлы, которые в задании должны будут находиться как незаиндексированные изменения, такие файлы никак не засунешь в репозиторий-шаблон. +- justfile — это скрипт, описывающий как задание преобразуется в Docker-образ. Он может выглядеть вот так: + +```just +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-образа. + +[Пример](tasks/branching/src/Dockerfile): + +```Dockerfile +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 main +``` + +> [!IMPORTANT] +> **Самое главное, что при создании образа вы должны написать копию `extended_description` в файл /etc/git-trainer/description.** Также вы должны заменить в нём все переносы строк на "\n" [#2](https://github.com/dsc-sgu/git-trainer/issues/2). + +### Тесты + +Тесты для задания хранятся в папке [tests](tests) по своим названиям. В них должны находиться скрипты .sh с названиями вида "test[n].sh", где "n" — номер теста. + +Каждый отдельный тест должен проверять отдельную степень свободы в сданном решении. По окончании своей работы он должен выдать какой-либо текст, оповещающий либо об успешном прохождении, либо об ошибке, и exit-code: 0 для успешного прохождения и 1 для ошибки. + +[Пример](tests/merge-conflict/test2.sh): + +```sh +#!/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](https://github.com/casey/just) и сделайте `just run`. Вы можете отдельно сделать `just build-images` для сборки только образов и `just release` для деплоя приложения. + + + From 57d9f809ef2502f096eb61dd709ba065caba4b8d Mon Sep 17 00:00:00 2001 From: gohy <134211235+gohy907@users.noreply.github.com> Date: Sat, 25 Apr 2026 00:26:03 +0400 Subject: [PATCH 2/7] chore: create CI for building git-trainer and task images --- .github/workflows/build.yml | 20 ++++++++++++++++++++ .github/workflows/build_images.yml | 23 +++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/build_images.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..286188e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,20 @@ +name: Build + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose diff --git a/.github/workflows/build_images.yml b/.github/workflows/build_images.yml new file mode 100644 index 0000000..57446bf --- /dev/null +++ b/.github/workflows/build_images.yml @@ -0,0 +1,23 @@ +name: Build images + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: extractions/setup-just@v4 + with: + just-version: '1.46.0' + - name: Build images + run: just build-images From d37e9959eafba59de242d885422c7684811fdc34 Mon Sep 17 00:00:00 2001 From: Maxim Brett Date: Sun, 26 Apr 2026 19:21:53 +0400 Subject: [PATCH 3/7] feat(new task): add 'fix-the-past' task and tests --- migrations/23042026_fix_the_past/down.sql | 1 + migrations/23042026_fix_the_past/up.sql | 19 +++++++++++ tasks/fix-the-past/justfile | 3 ++ tasks/fix-the-past/src/Dockerfile | 17 ++++++++++ tests/fix-the-past/test1.sh | 16 +++++++++ tests/fix-the-past/test2.sh | 30 +++++++++++++++++ tests/fix-the-past/test3.sh | 22 ++++++++++++ tests/fix-the-past/test4.sh | 41 +++++++++++++++++++++++ tests/fix-the-past/test5.sh | 24 +++++++++++++ 9 files changed, 173 insertions(+) create mode 100644 migrations/23042026_fix_the_past/down.sql create mode 100644 migrations/23042026_fix_the_past/up.sql create mode 100644 tasks/fix-the-past/justfile create mode 100644 tasks/fix-the-past/src/Dockerfile create mode 100755 tests/fix-the-past/test1.sh create mode 100755 tests/fix-the-past/test2.sh create mode 100755 tests/fix-the-past/test3.sh create mode 100755 tests/fix-the-past/test4.sh create mode 100755 tests/fix-the-past/test5.sh diff --git a/migrations/23042026_fix_the_past/down.sql b/migrations/23042026_fix_the_past/down.sql new file mode 100644 index 0000000..4088c1b --- /dev/null +++ b/migrations/23042026_fix_the_past/down.sql @@ -0,0 +1 @@ +DELETE FROM tasks WHERE work_name = 'fix-the-past'; \ No newline at end of file diff --git a/migrations/23042026_fix_the_past/up.sql b/migrations/23042026_fix_the_past/up.sql new file mode 100644 index 0000000..4f554c1 --- /dev/null +++ b/migrations/23042026_fix_the_past/up.sql @@ -0,0 +1,19 @@ +INSERT INTO tasks ( + id, + name, + work_name, + description, + extended_description +) VALUES ( + 5, + 'Назад в будущее', + 'fix-the-past', + 'Спасите сломанный проект, найдя правильный код в истории и создав новую спасательную ветку.', + 'Вы находитесь в ветке main, где последний коммит (№5) полностью ломает проект.' || + 'В истории есть коммит №4. Если туда откатиться, то видно, что автор написал правильную функцию,' || + ' но случайно снес половину других файлов. Есть коммит №3 — стабильная версия. ' || + 'Ваша задача: Через git log найдите хэш 4-го коммита, перейдите на него и скопируйте' || + ' функцию triangleArea. Переключитесь на стабильный 3-й коммит. Создайте новую ветку, ' || + 'Вставьте скопированную строчку,' || + ' сохраните файл и сделайте git commit.' + ); \ No newline at end of file diff --git a/tasks/fix-the-past/justfile b/tasks/fix-the-past/justfile new file mode 100644 index 0000000..6d8c41c --- /dev/null +++ b/tasks/fix-the-past/justfile @@ -0,0 +1,3 @@ +default: + -git clone https://github.com/git-trainer-tasks/fix-the-past.git tasks/fix-the-past/src/repo + docker build -f tasks/fix-the-past/src/Dockerfile -t git-trainer:fix-the-past . \ No newline at end of file diff --git a/tasks/fix-the-past/src/Dockerfile b/tasks/fix-the-past/src/Dockerfile new file mode 100644 index 0000000..ddf4df6 --- /dev/null +++ b/tasks/fix-the-past/src/Dockerfile @@ -0,0 +1,17 @@ +FROM git-trainer:base-task-image + +ARG USERNAME=student +ARG GIT_USERNAME=student +ARG GIT_EMAIL=student@alivetech.com +ENV DESCRIPTION="Проект сломался при последнем коммите. Найдите новую функцию в истории (№4) и cout, относящийся к ней, вернитесь в стабильное состояние (№3), создайте ветку, добавьте недостающую функцию и cout, относящийся к ней (аргументы любой функции в этой задачи должны быть 4,5). Сделайте коммит и введите git-trainer submit. Сливать ветку с main пока НЕ нужно!" + +RUN echo -n $DESCRIPTION > /etc/git-trainer/description +COPY ./tasks/fix-the-past/src/repo /home/${USERNAME}/fix-the-past + + +RUN sudo chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/fix-the-past +USER $USERNAME +RUN git config --global --add safe.directory /home/${USERNAME}/fix-the-past +WORKDIR /home/${USERNAME}/fix-the-past + + diff --git a/tests/fix-the-past/test1.sh b/tests/fix-the-past/test1.sh new file mode 100755 index 0000000..f3b8faf --- /dev/null +++ b/tests/fix-the-past/test1.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +cd /home/student/fix-the-past + +CURRENT_BRANCH=$(git branch --show-current) + +if [ -z "$CURRENT_BRANCH" ]; then + echo "1. Вы находитесь в состоянии Detached HEAD! Создайте ветку: git checkout -b <имя_ветки>." + exit 1 +elif [ "$CURRENT_BRANCH" == "main" ]; then + echo "1. Вы всё ещё в ветке main. Вам нужно найти стабильный коммит и создать ветку от него." + exit 1 +else + echo "1. Отлично! Вы работаете в новой ветке: $CURRENT_BRANCH." + exit 0 +fi diff --git a/tests/fix-the-past/test2.sh b/tests/fix-the-past/test2.sh new file mode 100755 index 0000000..9ff5a0e --- /dev/null +++ b/tests/fix-the-past/test2.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +cd /home/student/fix-the-past || exit 1 + + +TARGET_COMMIT_MSG="feat(main): implement rectangle area calculation" +TARGET_HASH=$(git log --all --grep="$TARGET_COMMIT_MSG" --format="%H" -n 1) + +if [ -z "$TARGET_HASH" ]; then + echo "Системная ошибка: Целевой стабильный коммит не найден в репозитории." + echo "Пожалуйста, сбросьте задание." + exit 1 +fi + + + +BASE_HASH=$(git merge-base HEAD main) + +if [ -z "$BASE_HASH" ]; then + echo "Системная ошибка: Не удалось вычислить общего предка с main." + exit 1 +fi + +if [ "$BASE_HASH" == "$TARGET_HASH" ]; then + echo "2. Супер! Ваша ветка отпочковалась от правильной стабильной версии." + exit 0 +else + echo "2. Вы взяли за основу не тот коммит! Найдите в логах коммит с rectangleArea и создайте ветку именно от него." + exit 1 +fi diff --git a/tests/fix-the-past/test3.sh b/tests/fix-the-past/test3.sh new file mode 100755 index 0000000..627a0c8 --- /dev/null +++ b/tests/fix-the-past/test3.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +cd /home/student/fix-the-past || exit 1 + +if [ ! -f main.cpp ]; then + echo "3. Ошибка: Файл main.cpp вообще не найден! Вы его случайно не удалили?" + exit 1 +fi + +grep -q "[A-Za-z_]* *rectangleArea" main.cpp +HAS_RECTANGLE=$? + +grep -q "[A-Za-z_]* *triangleArea" main.cpp +HAS_TRIANGLE=$? + +if [ "$HAS_RECTANGLE" -eq 0 ] && [ "$HAS_TRIANGLE" -eq 0 ]; then + echo "3. В файле присутствуют обе нужные функции. Отличная работа!" + exit 0 +else + echo "3. В файле main.cpp не хватает кода! Вы точно перенесли triangleArea и сохранили rectangleArea?" + exit 1 +fi diff --git a/tests/fix-the-past/test4.sh b/tests/fix-the-past/test4.sh new file mode 100755 index 0000000..fbb9f4a --- /dev/null +++ b/tests/fix-the-past/test4.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +cd /home/student/fix-the-past || exit 1 + +if [ ! -f main.cpp ]; then + echo "4. Ошибка: Файл main.cpp вообще не найден! Вы его случайно не удалили?" + exit 1 +fi + +# delete предыдущего на всякий +rm -f app +g++ main.cpp -o app > /dev/null 2>&1 +COMPILE_COMPLETED=$? + +if [ "$COMPILE_COMPLETED" -ne 0 ]; then + echo "4. Ошибка: Программа не скомпилировалась, проверьте правильно ли вы ее исправили." + exit 1 +fi + +PROGRAM_OUTPUT=$(./app) +STATUS_RUN=$? + +if [ "$STATUS_RUN" -ne 0 ]; then + echo "4. Ошибка во время runtime! Проверьте на правильность вашу программу" + exit 1 +fi + +echo "$PROGRAM_OUTPUT" | grep -q "Площадь прямоугольника (4x5): 20" +RECTANGLE_AREA=$? + +echo "$PROGRAM_OUTPUT" | grep -q "Площадь треугольника (4x5): 10" +TRIANGLE_AREA=$? + +if [ "$RECTANGLE_AREA" -eq 0 ] && [ "$TRIANGLE_AREA" -eq 0 ]; then + echo "4. Отличная работа! Программа скомпилировалась и успешно решила поставленную задачу" + exit 0 +else + echo "4. Ошибка: вывод программы не совпадает с требуемым в условии задачи, Проверьте, есть ли в выводе строки: Площадь прямоугольника (4x5): <возвращаемое значение из соответствующей функции> / Площадь треугольника (4x5): <возвращаемое значение из соответствующей функции>" + exit 1 +fi + diff --git a/tests/fix-the-past/test5.sh b/tests/fix-the-past/test5.sh new file mode 100755 index 0000000..a504e39 --- /dev/null +++ b/tests/fix-the-past/test5.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +cd /home/student/fix-the-past + +rm -f app + +git status --porcelain | grep -q "^" +HAS_CHANGES=$? + +if [ "$HAS_CHANGES" -eq 0 ]; then + echo "5. Почти готово! У вас есть несохраненные изменения, сделайте git commit." + exit 1 +fi + +BASE_HASH=$(git merge-base HEAD main) +CURRENT_HASH=$(git rev-parse HEAD) + +if [ "$BASE_HASH" == "$CURRENT_HASH" ]; then + echo "5. Вы не зафиксировали изменения. Создайте коммит со спасенным кодом!" + exit 1 +else + echo "5. Победа! Вы спасли проект из истории и зафиксировали результат." + exit 0 +fi From 0e46e442ca0ac6b027690a4215f084cb41f9bd9b Mon Sep 17 00:00:00 2001 From: Maxim Brett Date: Sun, 26 Apr 2026 19:22:54 +0400 Subject: [PATCH 4/7] feat(new task): add 'Where Am I' task and tests --- migrations/23062026_where-am-i/down.sql | 1 + migrations/23062026_where-am-i/up.sql | 10 ++++++++++ tasks/where-am-i/justfile | 3 +++ tasks/where-am-i/src/Dockerfile | 15 +++++++++++++++ tests/where-am-i/test1.sh | 22 ++++++++++++++++++++++ tests/where-am-i/test2.sh | 22 ++++++++++++++++++++++ tests/where-am-i/test3.sh | 11 +++++++++++ 7 files changed, 84 insertions(+) create mode 100644 migrations/23062026_where-am-i/down.sql create mode 100644 migrations/23062026_where-am-i/up.sql create mode 100644 tasks/where-am-i/justfile create mode 100644 tasks/where-am-i/src/Dockerfile create mode 100755 tests/where-am-i/test1.sh create mode 100755 tests/where-am-i/test2.sh create mode 100755 tests/where-am-i/test3.sh diff --git a/migrations/23062026_where-am-i/down.sql b/migrations/23062026_where-am-i/down.sql new file mode 100644 index 0000000..34d7b63 --- /dev/null +++ b/migrations/23062026_where-am-i/down.sql @@ -0,0 +1 @@ +DELETE FROM tasks WHERE work_name = 'where-am-i'; diff --git a/migrations/23062026_where-am-i/up.sql b/migrations/23062026_where-am-i/up.sql new file mode 100644 index 0000000..6417f9e --- /dev/null +++ b/migrations/23062026_where-am-i/up.sql @@ -0,0 +1,10 @@ +INSERT INTO tasks (id, + name, + work_name, + description, + extended_description) +VALUES (6, + 'Где Я?', + 'where-am-i', + 'Программа падает из-за пропавшей константы. Научитесь заглядывать в прошлые коммиты, не ломая текущую ветку.', + 'Студент дописывает программу для физических расчетов. Код не компилируется: удалено значение гравитационной постоянной. Найдите код в истории без checkout и закоммитьте исправление.'); \ No newline at end of file diff --git a/tasks/where-am-i/justfile b/tasks/where-am-i/justfile new file mode 100644 index 0000000..1caa216 --- /dev/null +++ b/tasks/where-am-i/justfile @@ -0,0 +1,3 @@ +default: + -git clone https://github.com/git-trainer-tasks/where-am-i.git tasks/where-am-i/src/repo + docker build -f tasks/where-am-i/src/Dockerfile -t git-trainer:where-am-i . \ No newline at end of file diff --git a/tasks/where-am-i/src/Dockerfile b/tasks/where-am-i/src/Dockerfile new file mode 100644 index 0000000..618918f --- /dev/null +++ b/tasks/where-am-i/src/Dockerfile @@ -0,0 +1,15 @@ +FROM git-trainer:base-task-image + +ARG USERNAME=student +ARG GIT_USERNAME=student +ARG GIT_EMAIL=student@alivetech.com +ENV DESCRIPTION="Программа для физических расчетов (src/physics.cpp) не компилируется: кто-то удалил из кода точное значение важной константы, которая участвует в рассчетах. Известно, что недавно эту константу добавляли, но в каком именно коммите никто не знает. Сейчас в проекте 7 коммитов. Ваша задача: Найти коммит, в котором присутствует эта константа. Скопируйте точное значение константы из вывода, вставьте его в physics.cpp и сделайте новый коммит с правильно работающей программой. ВАЖНО: в этом задании нельзя использовать git checkout . Вам нужно просто заглянуть в прошлое — найти команду Git, которая позволяет ПОКАЗАТЬ содержимое коммита и изменения в нем прямо в терминале" + +RUN echo -n $DESCRIPTION > /etc/git-trainer/description +COPY ./tasks/where-am-i/src/repo /home/${USERNAME}/where-am-i + + +RUN sudo chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/where-am-i +USER $USERNAME +RUN git config --global --add safe.directory /home/${USERNAME}/where-am-i +WORKDIR /home/${USERNAME}/where-am-i \ No newline at end of file diff --git a/tests/where-am-i/test1.sh b/tests/where-am-i/test1.sh new file mode 100755 index 0000000..b487d37 --- /dev/null +++ b/tests/where-am-i/test1.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +cd /home/student/where-am-i + +rm -f sim +g++ src/main.cpp src/physics.cpp -o sim 2>/dev/null + +if [ $? -ne 0 ]; then + echo "1. Ошибка компиляции! Вы точно вернули константу и правильно её назвали?" + exit 1 +fi + + + +OUTPUT=$(./sim) +if echo "$OUTPUT" | grep -q "0.0066743"; then + echo "1. Компиляция успешна! Чиселки сходятся." + exit 0 +else + echo "1. Код компилируется, но расчеты неверны. Убедитесь точное ли значение нужной константы вы нашли?" + exit 1 +fi \ No newline at end of file diff --git a/tests/where-am-i/test2.sh b/tests/where-am-i/test2.sh new file mode 100755 index 0000000..6aa97fb --- /dev/null +++ b/tests/where-am-i/test2.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +cd /home/student/where-am-i + +rm -f sim + +git status --porcelain | grep -q "^" +HAS_CHANGES=$? + +if [ "$HAS_CHANGES" -eq 0 ]; then + echo "2. У вас остались незакоммиченные изменения! Сделайте git add и git commit." + exit 1 +fi + +if ! git show HEAD:src/physics.cpp | grep -q "UNIVERSAL_G"; then + echo "2. В вашем последнем коммите нет нужной константы." + exit 1 +else + echo "2. Изменения успешно сохранены в историю Git!" + exit 0 +fi + diff --git a/tests/where-am-i/test3.sh b/tests/where-am-i/test3.sh new file mode 100755 index 0000000..46e904b --- /dev/null +++ b/tests/where-am-i/test3.sh @@ -0,0 +1,11 @@ +#!/bin/bash +cd /home/student/where-am-i + +if git reflog | grep -qi "checkout: moving from"; then + echo "3. Ага! Кто-то использовал git checkout! Это запрещено в данном задании. Вам нужно было использовать другую команду. Начните задание заново (клавиша 'r')." + exit 1 +else + echo "3. Отличная работа! Вы использовали безопасные методы чтения истории." + exit 0 +fi + From 5e40b98aa838801b6e6a9afdd9468b79c5038a19 Mon Sep 17 00:00:00 2001 From: Maxim Brett Date: Sun, 26 Apr 2026 20:16:08 +0400 Subject: [PATCH 5/7] fix(path): fix hardcode path of working directory --- migrations/23042026_fix_the_past/up.sql | 2 +- tasks/fix-the-past/src/Dockerfile | 8 ++++---- tasks/where-am-i/src/Dockerfile | 7 +++---- tests/fix-the-past/test1.sh | 2 +- tests/fix-the-past/test2.sh | 2 +- tests/fix-the-past/test3.sh | 2 +- tests/fix-the-past/test4.sh | 2 +- tests/fix-the-past/test5.sh | 2 +- tests/where-am-i/test1.sh | 2 +- tests/where-am-i/test2.sh | 2 +- tests/where-am-i/test3.sh | 4 ++-- 11 files changed, 17 insertions(+), 18 deletions(-) diff --git a/migrations/23042026_fix_the_past/up.sql b/migrations/23042026_fix_the_past/up.sql index 4f554c1..0ce2125 100644 --- a/migrations/23042026_fix_the_past/up.sql +++ b/migrations/23042026_fix_the_past/up.sql @@ -9,7 +9,7 @@ INSERT INTO tasks ( 'Назад в будущее', 'fix-the-past', 'Спасите сломанный проект, найдя правильный код в истории и создав новую спасательную ветку.', - 'Вы находитесь в ветке main, где последний коммит (№5) полностью ломает проект.' || + 'Вы находитесь в ветке main, где последний коммит (№5) полностью ломает проект. ' || 'В истории есть коммит №4. Если туда откатиться, то видно, что автор написал правильную функцию,' || ' но случайно снес половину других файлов. Есть коммит №3 — стабильная версия. ' || 'Ваша задача: Через git log найдите хэш 4-го коммита, перейдите на него и скопируйте' || diff --git a/tasks/fix-the-past/src/Dockerfile b/tasks/fix-the-past/src/Dockerfile index ddf4df6..babcb1e 100644 --- a/tasks/fix-the-past/src/Dockerfile +++ b/tasks/fix-the-past/src/Dockerfile @@ -3,15 +3,15 @@ FROM git-trainer:base-task-image ARG USERNAME=student ARG GIT_USERNAME=student ARG GIT_EMAIL=student@alivetech.com -ENV DESCRIPTION="Проект сломался при последнем коммите. Найдите новую функцию в истории (№4) и cout, относящийся к ней, вернитесь в стабильное состояние (№3), создайте ветку, добавьте недостающую функцию и cout, относящийся к ней (аргументы любой функции в этой задачи должны быть 4,5). Сделайте коммит и введите git-trainer submit. Сливать ветку с main пока НЕ нужно!" +ENV DESCRIPTION="Проект сломался при последнем коммите. Найдите новую функцию в истории (№4) и cout, относящийся к ней, вернитесь в стабильное состояние (№3), создайте ветку, добавьте недостающую функцию и cout, относящийся к ней (аргументы любой функции в этой задаче должны быть 4,5). Сделайте коммит и введите git-trainer submit. Сливать ветку с main пока НЕ нужно!" RUN echo -n $DESCRIPTION > /etc/git-trainer/description COPY ./tasks/fix-the-past/src/repo /home/${USERNAME}/fix-the-past - +WORKDIR /home/${USERNAME}/fix-the-past RUN sudo chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/fix-the-past USER $USERNAME -RUN git config --global --add safe.directory /home/${USERNAME}/fix-the-past -WORKDIR /home/${USERNAME}/fix-the-past +RUN git config --global --add safe.directory /home/${USERNAME}/fix-the-past && git switch main + diff --git a/tasks/where-am-i/src/Dockerfile b/tasks/where-am-i/src/Dockerfile index 618918f..ff47adb 100644 --- a/tasks/where-am-i/src/Dockerfile +++ b/tasks/where-am-i/src/Dockerfile @@ -3,13 +3,12 @@ FROM git-trainer:base-task-image ARG USERNAME=student ARG GIT_USERNAME=student ARG GIT_EMAIL=student@alivetech.com -ENV DESCRIPTION="Программа для физических расчетов (src/physics.cpp) не компилируется: кто-то удалил из кода точное значение важной константы, которая участвует в рассчетах. Известно, что недавно эту константу добавляли, но в каком именно коммите никто не знает. Сейчас в проекте 7 коммитов. Ваша задача: Найти коммит, в котором присутствует эта константа. Скопируйте точное значение константы из вывода, вставьте его в physics.cpp и сделайте новый коммит с правильно работающей программой. ВАЖНО: в этом задании нельзя использовать git checkout . Вам нужно просто заглянуть в прошлое — найти команду Git, которая позволяет ПОКАЗАТЬ содержимое коммита и изменения в нем прямо в терминале" +ENV DESCRIPTION="Программа для физических расчетов (src/physics.cpp) не компилируется: кто-то удалил из кода точное значение важной константы, которая участвует в расчетах. Известно, что недавно эту константу добавляли, но в каком именно коммите никто не знает. Сейчас в проекте 7 коммитов. Ваша задача: Найти коммит, в котором присутствует эта константа. Скопируйте точное значение константы из вывода, вставьте его в physics.cpp и сделайте новый коммит с правильно работающей программой. ВАЖНО: в этом задании нельзя использовать git checkout . Вам нужно просто заглянуть в прошлое — найти команду Git, которая позволяет ПОКАЗАТЬ содержимое коммита и изменения в нем прямо в терминале" RUN echo -n $DESCRIPTION > /etc/git-trainer/description COPY ./tasks/where-am-i/src/repo /home/${USERNAME}/where-am-i - +WORKDIR /home/${USERNAME}/where-am-i RUN sudo chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/where-am-i USER $USERNAME -RUN git config --global --add safe.directory /home/${USERNAME}/where-am-i -WORKDIR /home/${USERNAME}/where-am-i \ No newline at end of file +RUN git config --global --add safe.directory /home/${USERNAME}/where-am-i && git switch main diff --git a/tests/fix-the-past/test1.sh b/tests/fix-the-past/test1.sh index f3b8faf..d652b4e 100755 --- a/tests/fix-the-past/test1.sh +++ b/tests/fix-the-past/test1.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/fix-the-past +cd "$HOME/fix-the-past" || exit 1 CURRENT_BRANCH=$(git branch --show-current) diff --git a/tests/fix-the-past/test2.sh b/tests/fix-the-past/test2.sh index 9ff5a0e..d25eab1 100755 --- a/tests/fix-the-past/test2.sh +++ b/tests/fix-the-past/test2.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/fix-the-past || exit 1 +cd "$HOME/fix-the-past" || exit 1 TARGET_COMMIT_MSG="feat(main): implement rectangle area calculation" diff --git a/tests/fix-the-past/test3.sh b/tests/fix-the-past/test3.sh index 627a0c8..16a6a27 100755 --- a/tests/fix-the-past/test3.sh +++ b/tests/fix-the-past/test3.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/fix-the-past || exit 1 +cd "$HOME/fix-the-past" || exit 1 if [ ! -f main.cpp ]; then echo "3. Ошибка: Файл main.cpp вообще не найден! Вы его случайно не удалили?" diff --git a/tests/fix-the-past/test4.sh b/tests/fix-the-past/test4.sh index fbb9f4a..81edefc 100755 --- a/tests/fix-the-past/test4.sh +++ b/tests/fix-the-past/test4.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/fix-the-past || exit 1 +cd "$HOME/fix-the-past" || exit 1 if [ ! -f main.cpp ]; then echo "4. Ошибка: Файл main.cpp вообще не найден! Вы его случайно не удалили?" diff --git a/tests/fix-the-past/test5.sh b/tests/fix-the-past/test5.sh index a504e39..2df37d0 100755 --- a/tests/fix-the-past/test5.sh +++ b/tests/fix-the-past/test5.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/fix-the-past +cd "$HOME/fix-the-past" || exit 1 rm -f app diff --git a/tests/where-am-i/test1.sh b/tests/where-am-i/test1.sh index b487d37..3af63b9 100755 --- a/tests/where-am-i/test1.sh +++ b/tests/where-am-i/test1.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/where-am-i +cd "$HOME/where-am-i" || exit 1 rm -f sim g++ src/main.cpp src/physics.cpp -o sim 2>/dev/null diff --git a/tests/where-am-i/test2.sh b/tests/where-am-i/test2.sh index 6aa97fb..c50e74a 100755 --- a/tests/where-am-i/test2.sh +++ b/tests/where-am-i/test2.sh @@ -1,6 +1,6 @@ #!/bin/bash -cd /home/student/where-am-i +cd "$HOME/where-am-i" || exit 1 rm -f sim diff --git a/tests/where-am-i/test3.sh b/tests/where-am-i/test3.sh index 46e904b..f3bdb35 100755 --- a/tests/where-am-i/test3.sh +++ b/tests/where-am-i/test3.sh @@ -1,7 +1,7 @@ #!/bin/bash -cd /home/student/where-am-i +cd "$HOME/where-am-i" || exit 1 -if git reflog | grep -qi "checkout: moving from"; then +if git reflog | grep -qiE "checkout: moving from .* to [0-9a-f]{7,}"; then echo "3. Ага! Кто-то использовал git checkout! Это запрещено в данном задании. Вам нужно было использовать другую команду. Начните задание заново (клавиша 'r')." exit 1 else From 4b5f605e6d876196d6815c416531ec83389f6e79 Mon Sep 17 00:00:00 2001 From: Maxim Brett Date: Tue, 28 Apr 2026 19:06:23 +0400 Subject: [PATCH 6/7] refactor(tests): refactor tests for 'where-am-i' to CMake building --- tests/where-am-i/test1.sh | 18 ++++++++++-------- tests/where-am-i/test2.sh | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/where-am-i/test1.sh b/tests/where-am-i/test1.sh index 3af63b9..4f0922e 100755 --- a/tests/where-am-i/test1.sh +++ b/tests/where-am-i/test1.sh @@ -2,21 +2,23 @@ cd "$HOME/where-am-i" || exit 1 -rm -f sim -g++ src/main.cpp src/physics.cpp -o sim 2>/dev/null +rm -rf build +mkdir build && cd build +cmake .. > /dev/null 2>&1 +make > /dev/null 2>&1 + if [ $? -ne 0 ]; then echo "1. Ошибка компиляции! Вы точно вернули константу и правильно её назвали?" exit 1 fi - - -OUTPUT=$(./sim) -if echo "$OUTPUT" | grep -q "0.0066743"; then - echo "1. Компиляция успешна! Чиселки сходятся." +cd .. +OUTPUT=$(./build/orbital_app) +if echo "$OUTPUT" | grep -q "7672"; then + echo "1. Сборка успешна! Орбитальная скорость рассчитана верно." exit 0 else - echo "1. Код компилируется, но расчеты неверны. Убедитесь точное ли значение нужной константы вы нашли?" + echo "1. Код компилируется, но расчеты неверны. Точное ли значение нужной константы вы нашли?" exit 1 fi \ No newline at end of file diff --git a/tests/where-am-i/test2.sh b/tests/where-am-i/test2.sh index c50e74a..6db7fde 100755 --- a/tests/where-am-i/test2.sh +++ b/tests/where-am-i/test2.sh @@ -2,7 +2,7 @@ cd "$HOME/where-am-i" || exit 1 -rm -f sim +rm -rf build git status --porcelain | grep -q "^" HAS_CHANGES=$? @@ -12,8 +12,8 @@ if [ "$HAS_CHANGES" -eq 0 ]; then exit 1 fi -if ! git show HEAD:src/physics.cpp | grep -q "UNIVERSAL_G"; then - echo "2. В вашем последнем коммите нет нужной константы." +if ! git show HEAD:src/orbital_calc.cpp | grep -q "6.6743015e-11"; then + echo "2. В вашем последнем коммите нет правильного значения константы в нужном файле." exit 1 else echo "2. Изменения успешно сохранены в историю Git!" From 55f3507c6cc89b2b528bf8e160297e8636c9f63f Mon Sep 17 00:00:00 2001 From: Maxim Brett Date: Tue, 28 Apr 2026 19:46:50 +0400 Subject: [PATCH 7/7] refactor(where-am-i): refactor old task --- tasks/fix-the-past/justfile | 2 +- tasks/where-am-i/justfile | 2 +- tasks/where-am-i/src/Dockerfile | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tasks/fix-the-past/justfile b/tasks/fix-the-past/justfile index 6d8c41c..11b9ca9 100644 --- a/tasks/fix-the-past/justfile +++ b/tasks/fix-the-past/justfile @@ -1,3 +1,3 @@ default: -git clone https://github.com/git-trainer-tasks/fix-the-past.git tasks/fix-the-past/src/repo - docker build -f tasks/fix-the-past/src/Dockerfile -t git-trainer:fix-the-past . \ No newline at end of file + docker build -f tasks/fix-the-past/src/Dockerfile -t git-trainer:fix-the-past . \ No newline at end of file diff --git a/tasks/where-am-i/justfile b/tasks/where-am-i/justfile index 1caa216..ea554a2 100644 --- a/tasks/where-am-i/justfile +++ b/tasks/where-am-i/justfile @@ -1,3 +1,3 @@ default: -git clone https://github.com/git-trainer-tasks/where-am-i.git tasks/where-am-i/src/repo - docker build -f tasks/where-am-i/src/Dockerfile -t git-trainer:where-am-i . \ No newline at end of file + docker build -f tasks/where-am-i/src/Dockerfile -t git-trainer:where-am-i . \ No newline at end of file diff --git a/tasks/where-am-i/src/Dockerfile b/tasks/where-am-i/src/Dockerfile index ff47adb..31ad41a 100644 --- a/tasks/where-am-i/src/Dockerfile +++ b/tasks/where-am-i/src/Dockerfile @@ -3,11 +3,13 @@ FROM git-trainer:base-task-image ARG USERNAME=student ARG GIT_USERNAME=student ARG GIT_EMAIL=student@alivetech.com -ENV DESCRIPTION="Программа для физических расчетов (src/physics.cpp) не компилируется: кто-то удалил из кода точное значение важной константы, которая участвует в расчетах. Известно, что недавно эту константу добавляли, но в каком именно коммите никто не знает. Сейчас в проекте 7 коммитов. Ваша задача: Найти коммит, в котором присутствует эта константа. Скопируйте точное значение константы из вывода, вставьте его в physics.cpp и сделайте новый коммит с правильно работающей программой. ВАЖНО: в этом задании нельзя использовать git checkout . Вам нужно просто заглянуть в прошлое — найти команду Git, которая позволяет ПОКАЗАТЬ содержимое коммита и изменения в нем прямо в терминале" - +ENV DESCRIPTION="Произошла авария на расчетном сервере! Наш модуль вычисления орбитальных маневров (src/orbital_calc.cpp) перестал работать и выдает нулевую скорость. Долгие попытки разобраться показали, что во время недавнего масштабного рефакторинга кто-то случайно стер точное значение одной из фундаментальных физических констант, заменив её на ноль. Точно известно, что правильное многозначное число внедрялось в одном из прошлых коммитов, но история проекта забита десятками других правок, добавлением телеметрии и удалением старого кода.\nВаша задача: Найти в истории изменений коммит, в котором добавлялось правильное значение этой константы и восстановить значение в коде и сделать спасительный коммит.\nВАЖНО: в этом задании нельзя использовать git checkout . Вам нужно просто заглянуть в прошлое - найти команду Git, которая позволяет ПОКАЗАТЬ содержимое коммита и изменения в нем прямо в терминале." RUN echo -n $DESCRIPTION > /etc/git-trainer/description COPY ./tasks/where-am-i/src/repo /home/${USERNAME}/where-am-i +# Есть вариант, что это лишнее +RUN sudo apt-get update && sudo apt-get install -y cmake build-essential + WORKDIR /home/${USERNAME}/where-am-i RUN sudo chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/where-am-i USER $USERNAME