diff --git a/.github/workflows/1_helloworld.yml b/.github/workflows/1_helloworld.yml new file mode 100644 index 0000000..9e9fda2 --- /dev/null +++ b/.github/workflows/1_helloworld.yml @@ -0,0 +1,31 @@ +name: "1. Согласована и сформулирована тема курсовой" + +on: + push: + branches: + - main + +jobs: + check_hello_world_dir_not_empty: + name: "Проверка наличия каталога ./hello_world/" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Check out current commit + + - name: check + run: | + dir="./hello_world/" + if [ -d "${dir}" ]; then + if [ "$(ls -A ${dir})" ]; then + echo "::notice::Предварительная проверка пройдена - каталог ${dir} создан и не пуст" + exit 0 + else + echo "::error::Предварительная проверка не пройдена - каталог ${dir} пуст" + exit 1 + fi + + else + echo "::error::Предварительная проверка не пройдена - каталог не найден ${dir}" + exit 1 + fi diff --git a/.github/workflows/2_usecase.yml b/.github/workflows/2_usecase.yml new file mode 100644 index 0000000..b7d2deb --- /dev/null +++ b/.github/workflows/2_usecase.yml @@ -0,0 +1,65 @@ +name: "2. Usecase" + +on: + push: + branches: + - main + gollum: + +jobs: + check_mockup_uc_wiki: + name: "Проверка наличия вики-страницы \"Макет и сценарий использования\" и разделов \"Макет UI\" \"Сценарий использования\" в ней" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Check wiki + with: + repository: ${{github.repository}}.wiki + - name: check + run: | + page="Макет-и-сценарий-использования.md" + mockup_header="Макет UI" + uc_header="Сценарий использования" + + if ! [[ -f "${page}" ]]; then + echo "::error::Предварительная проверка не пройдена - не найдена вики-страница \"Макет и сценарий использования\"" + exit 1 + fi + + if ! cat "${page}" | grep -q "${mockup_header}"; then + echo "::error::Предварительная проверка не пройдена - не найден заголовок ${mockup_header}" + exit 1 + fi + + + if ! cat "${page}" | grep -q "${uc_header}"; then + echo "::error::Предварительная проверка не пройдена - не найден заголовок ${uc_header}" + exit 1 + fi + + if ! cat "${page}" | grep -iq "импорт"; then + echo "::error::Предварительная проверка не пройдена - не найден сценарий, связанный с импортом данных в систему" + exit 1 + fi + + if ! cat "${page}" | grep -iq "экспорт"; then + echo "::error::Предварительная проверка не пройдена - не найден сценарий, связанный с экспортом данных в систему" + exit 1 + fi + + if ! cat "${page}" | grep -iq "статистик"; then + echo "::error::Предварительная проверка не пройдена - не найден сценарий, связанный с подсчетом статистики в системе" + exit 1 + fi + + if ! cat "${page}" | grep -iq '](https\:\/\/github.com\/moevm\/[^/]\+\/assets[^\)]\+)'; then + echo "::error::Предварительная проверка не пройдена - не найдены изображения макета из репозитория. Вставьте их через \![Название картинки](полная ссылка вида https://github.com/moevm/ВАШ РЕПО/assets/34864759/8f850ef1-fc3d-4adb-a7aa-81598cc7794c) . Если вы храните изображение макета где-то ВНЕ репозитория, то, пожалуйста, разместите файлы в репо - иначе потом очень сложно собирать материалы вашей проекта." + exit 1 + fi + + if cat "${page}" | grep 'https\:\/\/' | grep -qv github; then + echo "::error::Предварительная проверка не пройдена - найдены ссылки на сторонние сервисы. Если части вашего макета и сценария размещены где-то еще, то, пожалуйста 1) соберите их на вики 2) если у вас сложный макет с figma и тд - положите в репо качественную схему в виде графа. Иначе потом очень сложно собирать материалы вашего проекта." + exit 1 + fi + + echo "::notice::Предварительная проверка пройдена - вики-страница найдена, нужные заголовки присутствуют" diff --git a/.github/workflows/3_data_model.yml b/.github/workflows/3_data_model.yml new file mode 100644 index 0000000..1538cdb --- /dev/null +++ b/.github/workflows/3_data_model.yml @@ -0,0 +1,78 @@ +name: "3. Модель данных" + +on: + push: + branches: + - main + gollum: + +jobs: + check_data_model: + name: "Проверка наличия вики-страницы \"Модель данных\" и разделов \"Нереляционная модель\", \"Реляционная модель\", \"Сравнение моделей\", \"Вывод\" в ней" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Check wiki + with: + repository: ${{github.repository}}.wiki + - name: check + run: | + page="Модель-данных.md" + nosql_model="Нереляционная модель" + sql_model="Реляционная модель" + comparison="Сравнение моделей" + conclusion="Вывод" + query_examples="Примеры запросов" + data_examples="Примеры данных" + redundancy="Избыточность данных" + + if ! [[ -f "${page}" ]]; then + echo "::error::Предварительная проверка не пройдена - не найдена вики-страница \"Модель данных\"" + exit 1 + fi + + if ! cat "${page}" | grep -q "${nosql_model}"; then + echo "::error::Предварительная проверка не пройдена - не найден заголовок ${nosql_model}" + exit 1 + fi + + + if ! cat "${page}" | grep -q "${sql_model}"; then + echo "::error::Предварительная проверка не пройдена - не найден заголовок ${sql_model}" + exit 1 + fi + + image_count=`cat "${page}" | grep '](https\:\/\/github.com\/moevm\/[^/]\+\/assets[^\)]\+)' | wc -l` + if [[ ${image_count} -lt 2 ]]; then + echo "::error::Предварительная проверка не пройдена - не найдены изображения для схем моделей данных. Для реляционной и нереляционной модели необходимо разместить изображения схем моделей данных. Вставьте их через \![Название картинки](полная ссылка вида https://github.com/moevm/ВАШ РЕПО/assets/34864759/8f850ef1-fc3d-4adb-a7aa-81598cc7794c) . Если вы храните изображение макета где-то ВНЕ репозитория, то, пожалуйста, разместите файлы в репо - иначе потом очень сложно собирать материалы вашей проекта. " + exit 1 + fi + + query_examples_count=`cat "${page}" | grep "${query_examples}" | wc -l` + if [[ "${query_examples_count}" != "2" ]]; then + echo "::error::Предварительная проверка не пройдена - не найдены заголовоки ${query_examples} (соответствующие подразделы должны быть в разделах с нереляционной и реляционной моделями)." + exit 1 + fi + + data_examples_count=`cat "${page}" | grep "${data_examples}" | wc -l` + if [[ "${data_examples_count}" != "2" ]]; then + echo "::error::Предварительная проверка не пройдена - не найдены заголовоки ${data_examples} (соответствующие подразделы должны быть в разделах с нереляционной и реляционной моделями)." + exit 1 + fi + + redundancy_count=`cat "${page}" | grep "${redundancy}" | wc -l` + if [[ "${redundancy_count}" != "2" ]]; then + echo "::error::Предварительная проверка не пройдена - не найдены заголовоки ${redundancy} (соответствующие подразделы должны быть в разделах с нереляционной и реляционной моделями)." + exit 1 + fi + + if ! cat "${page}" | grep -q "${comparison}"; then + echo "::error::Предварительная проверка не пройдена - не найден заголовок ${comparison}" + exit 1 + fi + + if ! cat "${page}" | grep -q "${conclusion}"; then + echo "::error::Предварительная проверка не пройдена - не найден заголовок ${conclusion}" + exit 1 + fi + echo "::notice::Предварительная проверка пройдена - вики-страница найдена, нужные заголовки присутствуют " diff --git a/.github/workflows/4_prototype_store_and_view.yml b/.github/workflows/4_prototype_store_and_view.yml new file mode 100644 index 0000000..5f167ef --- /dev/null +++ b/.github/workflows/4_prototype_store_and_view.yml @@ -0,0 +1,26 @@ +name: "4. Прототип хранение и представление" + +on: + push: + branches: + - main + +jobs: + check_prototype_store_and_view: + name: "Проверка наличия тега 0.5" + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + name: Check out current commit + with: + fetch-depth: 0 + + - name: check + run: | + TAG="0.5" + if [ $(git tag -l "${TAG}") ]; then + echo "::notice::Тег ${TAG} найден" + else + echo "::error::Тег ${TAG} не найден" + exit 1 + fi diff --git a/.github/workflows/5_prototype_analysis.yml b/.github/workflows/5_prototype_analysis.yml new file mode 100644 index 0000000..36c0027 --- /dev/null +++ b/.github/workflows/5_prototype_analysis.yml @@ -0,0 +1,174 @@ +name: "5. Прототип анализ" + +on: + push: + branches: + - main + +jobs: + check_tag_08_docker_compose: + name: "Проверка наличия тега 0.8 и работоспособности docker-compose" + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + name: Check out current commit + with: + fetch-depth: 0 + + - name: There are at least one Dockerfile + run: | + if ! find ./ | grep -q 'Dockerfile$' + then + echo "::error:: Не найдены файлы с названием Dockerfile." + exit 1 + fi + + - name: Lint Dockerfile + uses: hadolint/hadolint-action@v3.1.0 + with: + dockerfile: Dockerfile + recursive: true + failure-threshold: error + override-error: DL3006, DL3000, DL3007, DL3008, DL3009, DL3013, DL3016, DL3018, DL3020, DL3028, DL3037, DL3047, DL4001, DL4003, DL4004 + + - name: Check docker-compose.yml + run: | + set -e + + dc_file=${1:-"./docker-compose.yml"} + + services_count=`yq '.services | length' ${dc_file}` + if [[ "${services_count}" < "2" ]]; + then + echo "::error:: Ошибка - слишком мало сервисов в конфигурации. У вас должно быть минимум два сервиса - приложение и СУБД." + exit 1 + fi + + db_service=`yq '.services.db' ${dc_file}` + if [[ "${db_service}" == "null" ]]; + then + echo "::error:: Ошибка - нет явно заданного сервиса для СУБД (с названием db)" + exit 1 + fi + + if [[ "`yq '.services.db.ports' ${dc_file}`" != "null" ]]; + then + echo "::error:: Ошибка - в сервисе db открыты сетевые порты через ports. Для работы приложения они не нужны, если вам требуется доступ для СУБД в отладочных целях, то можно или поднять веб-интерфейс (и ему открыть порты), или получать доступ по внутренней сети докера. " + exit 1 + fi + + if [[ "`yq '.services.db.volumes' ${dc_file}`" == "null" ]]; + then + echo "::error:: Ошибка - в сервисе db не организованы volumes. По заданию они требуются для того, чтобы сохранять данные БД между запусками вашей конфигурации" + exit 1 + fi + + if yq '.services.db.volumes' ${dc_file} | grep -q '^[^/a-zA-Z]*/' + then + echo "::error:: Ошибка - в сервисе db volumes использует монтирование каталогов. Используйте вместо этого именно volumes ( https://docs.docker.com/storage/volumes/#use-a-volume-with-docker-compose) - это гораздо удобнее и позволяет управлять таким хранилищем через докер." + exit 1 + fi + + if yq '.network' ${dc_file} | grep -q 'host' ; + then + echo "::error:: Ошибка - сеть типа host. Пожалуйста, не используйте данный тип сети: он максимально небезопасен (так как неглядя мапит все порты вашей конфигурации на адаптер хоста) и неудобен. Укажите вместо этого конкретные маппинги портов в соответствующих директивах ports" + exit 1 + fi + + # Проверка volumes + echo "::info:: Ниже будут все volumes всех сервисов" + yq '.services.*.volumes' ${dc_file} + if yq '.services.*.volumes' ${dc_file} | grep -v ':ro$' | grep -q '^[^/a-zA-Z]*/' + then + echo "::error:: Ошибка - у вас есть смонтированные в volumes файлы и/или каталоги без метки ro (read-only, https://docs.docker.com/compose/compose-file/05-services/#short-syntax-5). Монтируемый каталог или файл нужно или копировать на этапе сборки контейнера (если там данные, которые не предполагают изменение), или ставить опцию :ro ." + exit 1 + fi + + + # Проверка всех сервисов на общие ошибки + for i in $(seq 0 $(( services_count - 1 )) ); + do + service=`yq '.services | keys ['$i']' ${dc_file}` + echo "::info:: Проверка сервиса: ${service}" + yq '.services.'$service ${dc_file} + + image=`yq '.services.'$service'.image' ${dc_file}` + if [[ "${image}" != "null" ]]; + then + if echo ${image} | grep -qE ':latest|^[^:]*$'; + then + echo "::error:: Ошибка - отсутствие тега или использование тега latest. Обе эти ситуации означают, что вы не привязаны к опредлеленной версии образа и в случае его обновления работа приложения может нарушится (а вы об этом узнаете только постфактум). Укажите явно тег." + exit 1 + fi + fi + + ports=`yq '.services.'$service'.ports' ${dc_file}` + if [[ "${ports}" != "null" ]]; + then + if echo ${ports} | grep -qv '^[^0-9]*127.0.0.1:'; + then + echo "::error:: Ошибка - явно не указан интерфейс при маппинге портов. По умолчанию (если не указывать вот так 127.0.0.1:3000:80), докер мапит на все доступные интерфейсы и это нарушает безопасность. Добавьте 127.0.0.1: к содержимому директивы ports " + exit 1 + fi + fi + + external_ports=`echo $ports | grep '127.0.0.1' | sed 's/^[^1]*127.0.0.1:\([^:]*\):[^:]*$/\1/g'` + for port in $external_ports; + do + if [[ "$port" < 1025 ]]; + then + echo "::error:: Ошибка - использование внешних портов хоста <=1024. Данные порты зарезервированы под системные нужды, лучше использовать порты с номерами выше 8000 (чтобы не было коллизий). " + exit 1 + fi + done + + done + + + - name: Build docker-compose + run: | + docker-compose build --no-cache + + - name: Run docker-compose + run: | + docker-compose up -d + sleep 30 + + - name: Check containers are alive + run: | + echo "::notice:: docker ps --filter status=exited" + docker ps --filter status=exited + exited_count=`docker ps --filter status=exited | tail -n +2 | wc -l` + + echo "::notice:: docker ps --filter status=dead" + docker ps --filter status=dead + dead_count=`docker ps --filter status=dead | tail -n +2 | wc -l` + + echo "::notice:: docker ps --filter status=restarting" + docker ps --filter status=restarting + restarting_count=`docker ps --filter status=restarting | tail -n +2 | wc -l` + + echo "::notice:: docker ps --filter status=paused" + docker ps --filter status=paused + paused_count=`docker ps --filter status=paused | tail -n +2 | wc -l` + + echo "::notice:: docker ps --filter status=created" + docker ps --filter status=created + created_count=`docker ps --filter status=created | tail -n +2 | wc -l` + + if [[ "${exited_count}" != "0" ]] || [[ "${restarting_count}" != "0" ]] || [[ "${paused_count}" != "0" ]] || [[ "${created_count}" != "0" ]] || [[ "${created_count}" != "0" ]]; then + echo "::error::Часть контейнеров не находится в состоянии running (завершили или не начали свою работу корректно) " + exit 1 + fi + + + + - name: check_tag + run: | + TAG="0.8" + if [ $(git tag -l "${TAG}") ]; then + echo "::notice::Тег ${TAG} найден" + else + echo "::error::Тег ${TAG} не найден" + exit 1 + fi diff --git a/.github/workflows/6_report.yml b/.github/workflows/6_report.yml new file mode 100644 index 0000000..19de983 --- /dev/null +++ b/.github/workflows/6_report.yml @@ -0,0 +1,29 @@ +name: "6. Пояснительная записка" + +on: + push: + branches: + - main + +jobs: + check_reports: + name: "Проверка наличия пояснительной записки (report.doc / report.docx / report.odt + report.pdf в корне репо)" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + name: Check out current commit + + - name: check + run: | + + if ! ( [[ -f "./report.docx" ]] || [[ -f "./report.doc" ]] || [[ -f "./report.odt" ]] ) ; then + echo "::error::Предварительная проверка не пройдена - не найдены редактируемые версии пояснительной записки" + exit 1 + fi + + if ! [[ -f "./report.pdf" ]] ; then + echo "::error::Предварительная проверка не пройдена - не найдена pdf версия записки" + exit 1 + fi + + echo "::notice::Предварительная проверка пройдена - файлы записки найдены" diff --git a/.github/workflows/7_app_is_ready.yml b/.github/workflows/7_app_is_ready.yml new file mode 100644 index 0000000..c3f9655 --- /dev/null +++ b/.github/workflows/7_app_is_ready.yml @@ -0,0 +1,26 @@ +name: "7. App is ready" + +on: + push: + branches: + - main + +jobs: + check_app_is_ready: + name: "Проверка наличия тега 1.0" + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + name: Check out current commit + with: + fetch-depth: 0 + + - name: check + run: | + TAG="1.0" + if [ $(git tag -l "${TAG}") ]; then + echo "::notice::Тег ${TAG} найден" + else + echo "::error::Тег ${TAG} не найден" + exit 1 + fi diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e07660 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# nosql_template + + +## Предварительная проверка заданий + +![1. Согласована и сформулирована тема курсовой]( ./../../actions/workflows/1_helloworld.yml/badge.svg) + +![2. Usecase]( ./../../actions/workflows/2_usecase.yml/badge.svg) + +![3. Модель данных]( ./../../actions/workflows/3_data_model.yml/badge.svg) + +![4. Прототип хранение и представление]( ./../../actions/workflows/4_prototype_store_and_view.yml/badge.svg) + +![5. Прототип анализ]( ./../../actions/workflows/5_prototype_analysis.yml/badge.svg) + +![6. Пояснительная записка]( ./../../actions/workflows/6_report.yml/badge.svg) + +![7. App is ready]( ./../../actions/workflows/7_app_is_ready.yml/badge.svg)