diff --git a/.gitignore b/.gitignore index c38fa4e..3ceb5a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .idea *.iml +.token_* +.repo_* diff --git a/DIRECTORY_TREE.md b/DIRECTORY_TREE.md new file mode 100644 index 0000000..9b19f28 --- /dev/null +++ b/DIRECTORY_TREE.md @@ -0,0 +1,44 @@ +## Дерево каталогов + +
+.
+├─ avatars
+│  ├─ README.md
+│  ├─ color-tomato-theme.jpg
+│  ├─ dispatcher.jpg
+│  ├─ older-tomato-theme.jpg
+│  ├─ pomodoro.jpg
+│  └─ website.jpg
+├─ bash_scripts
+│  ├─ archive_backup.sh
+│  ├─ archive_cleanup.sh
+│  ├─ archive_packaging.sh
+│  ├─ info_param.sh
+│  ├─ info_references.sh
+│  ├─ info_tree_license.sh
+│  ├─ repo_compose.sh
+│  ├─ repo_forgejo.tmpl.sh
+│  ├─ repo_forgejo2.tmpl.sh
+│  ├─ repo_gitlab.tmpl.sh
+│  ├─ repo_local.tmpl.sh
+│  ├─ repo_testing.smpl.sh
+│  ├─ suite_orchestrate.sh
+│  └─ suite_pages2.sh
+├─ print_screen
+│  ├─ LISTVIEW.md
+│  ├─ archive_cleanup.png
+│  ├─ archive_packaging.gif
+│  ├─ info_references.png
+│  ├─ info_tree_license.png
+│  ├─ repo_compose.png
+│  ├─ repo_testing.smpl.png
+│  ├─ suite_orchestrate.gif
+│  └─ suite_pages2.gif
+├─ .gitignore
+├─ CONTRIBUTING.md
+├─ DIRECTORY_TREE.md
+├─ LICENSE.md
+├─ OPEN_LICENSE.txt
+├─ README.en.md
+└─ README.md
+
diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..0979102 --- /dev/null +++ b/README.en.md @@ -0,0 +1,42 @@ +# [Dispatcher](README.md) + +Creating the archive, switching a domain, saving scripts in the directories of projects and publishing the repositories on to server. + +| № | Bash script | Actions performed | (+) | +|:-:|:--------------------------------------------------------------|:------------------------------------------------------------------------------------------------|:-----------------------------------------:| +| 1 | [**archive_backup.sh**](bash_scripts/archive_backup.sh) | Creating a common archive for the directories of projects on the current date. | | +| | [archive_cleanup.sh](bash_scripts/archive_cleanup.sh) | Deleting files and folders from the directories of projects before restoring the archive. | [png](print_screen/archive_cleanup.png) | +| | [archive_packaging.sh](bash_scripts/archive_packaging.sh) | Building websites, packaging and copying archives for deployment. | [gif](print_screen/archive_packaging.gif) | +| 2 | [**info_param.sh**](bash_scripts/info_param.sh) | Parameter for other scripts. Switching the domain of the remote repository. | | +| | [info_references.sh](bash_scripts/info_references.sh) | Updating the domain of a remote repository in cross-references in descriptions. | [png](print_screen/info_references.png) | +| | [info_tree_license.sh](bash_scripts/info_tree_license.sh) | Building a directory tree for each project and copying license files. | [png](print_screen/info_tree_license.png) | +| 3 | [**repo_compose.sh**](bash_scripts/repo_compose.sh) | Creating scripts from templates with parameters and saving them in the directories of projects. | [png](print_screen/repo_compose.png) | +| | [repo_forgejo.tmpl.sh](bash_scripts/repo_forgejo.tmpl.sh) | Template of a script without parameters to create a remote repository forgejo. | | +| | [repo_forgejo2.tmpl.sh](bash_scripts/repo_forgejo2.tmpl.sh) | Template of a script without parameters to deploy a website on the server codeberg. | | +| | [repo_gitlab.tmpl.sh](bash_scripts/repo_gitlab.tmpl.sh) | Template of a script without parameters to create a remote repository gitlab. | | +| | [repo_local.tmpl.sh](bash_scripts/repo_local.tmpl.sh) | Template of a script without parameters to create a local repository git. | | +| | [repo_testing.smpl.sh](bash_scripts/repo_testing.smpl.sh) | Sample of a script for testing the accessibility of pages in the web-interface on the server. | [png](print_screen/repo_testing.smpl.png) | +| 4 | [**suite_orchestrate.sh**](bash_scripts/suite_orchestrate.sh) | Parallel execution of scripts and publishing the repositories for the directories of projects. | [gif](print_screen/suite_orchestrate.gif) | +| | [suite_pages2.sh](bash_scripts/suite_pages2.sh) | Parallel execution of scripts and deploying the websites on the server codeberg. | [gif](print_screen/suite_pages2.gif) | + +## Directories of projects + +Local project directories are located on the same level. On the server, repositories with websites are moved to +a separate group, and the rest of the repositories remain with the user. The directory structure is the same for +[codeberg.org](https://codeberg.org/golovin), +[git.org.ru](https://git.org.ru/golovin) and +[hub.mos.ru](https://hub.mos.ru/golovin). + +
+.
+├─ color-tomato-theme
+├─ dispatcher
+├─ older-tomato-theme
+├─ pomodoro
+├─ pomodoro1
+├─ pomodoro2
+├─ pomodoro3
+├─ pomodoro4
+├─ pomodoro5
+└─ pomodoro6
+
diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7ce53c --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# [Диспетчер](README.en.md) + +Создание архива, переключение домена, сохранение скриптов в каталогах проектов и публикация репозиториев на сервере. + +| № | Скрипт Bash | Выполняемые действия | (+) | +|:-:|:--------------------------------------------------------------|:-----------------------------------------------------------------------------------|:-----------------------------------------:| +| 1 | [**archive_backup.sh**](bash_scripts/archive_backup.sh) | Создание общего архива для каталогов проектов на текущую дату. | | +| | [archive_cleanup.sh](bash_scripts/archive_cleanup.sh) | Удаление файлов и папок из каталогов проектов перед восстановлением архива. | [png](print_screen/archive_cleanup.png) | +| | [archive_packaging.sh](bash_scripts/archive_packaging.sh) | Сборка вёб-сайтов, упаковка и копирование архивов для развёртывания. | [gif](print_screen/archive_packaging.gif) | +| 2 | [**info_param.sh**](bash_scripts/info_param.sh) | Параметр для других скриптов. Переключение домена удалённого репозитория. | | +| | [info_references.sh](bash_scripts/info_references.sh) | Обновление домена удалённого репозитория в перекрёстных ссылках в описаниях. | [png](print_screen/info_references.png) | +| | [info_tree_license.sh](bash_scripts/info_tree_license.sh) | Построение дерева каталогов для каждого проекта и копирование файлов лицензии. | [png](print_screen/info_tree_license.png) | +| 3 | [**repo_compose.sh**](bash_scripts/repo_compose.sh) | Создание скриптов из шаблонов с параметрами и сохранение их в каталогах проектов. | [png](print_screen/repo_compose.png) | +| | [repo_forgejo.tmpl.sh](bash_scripts/repo_forgejo.tmpl.sh) | Шаблон скрипта без параметров для создания удалённого репозитория forgejo. | | +| | [repo_forgejo2.tmpl.sh](bash_scripts/repo_forgejo2.tmpl.sh) | Шаблон скрипта без параметров для развёртывания вёб-сайта на сервере codeberg. | | +| | [repo_gitlab.tmpl.sh](bash_scripts/repo_gitlab.tmpl.sh) | Шаблон скрипта без параметров для создания удалённого репозитория gitlab. | | +| | [repo_local.tmpl.sh](bash_scripts/repo_local.tmpl.sh) | Шаблон скрипта без параметров для создания локального репозитория git. | | +| | [repo_testing.smpl.sh](bash_scripts/repo_testing.smpl.sh) | Образец скрипта для тестирования доступности страниц в вёб-интерфейсе на сервере. | [png](print_screen/repo_testing.smpl.png) | +| 4 | [**suite_orchestrate.sh**](bash_scripts/suite_orchestrate.sh) | Параллельное выполнение скриптов и публикация репозиториев для каталогов проектов. | [gif](print_screen/suite_orchestrate.gif) | +| | [suite_pages2.sh](bash_scripts/suite_pages2.sh) | Параллельное выполнение скриптов и развёртывание вёб-сайтов на сервере codeberg. | [gif](print_screen/suite_pages2.gif) | + +## Каталоги проектов + +Локальные каталоги проектов расположены на одном уровне. На сервере репозитории с вёб-сайтами переходят +в отдельную группу, а остальные репозитории остаются у пользователя. Структура каталогов одинаковая для +[codeberg.org](https://codeberg.org/golovin), +[git.org.ru](https://git.org.ru/golovin) и +[hub.mos.ru](https://hub.mos.ru/golovin). + +
+.
+├─ color-tomato-theme
+├─ dispatcher
+├─ older-tomato-theme
+├─ pomodoro
+├─ pomodoro1
+├─ pomodoro2
+├─ pomodoro3
+├─ pomodoro4
+├─ pomodoro5
+└─ pomodoro6
+
diff --git a/avatars/README.md b/avatars/README.md new file mode 100644 index 0000000..623ba4d --- /dev/null +++ b/avatars/README.md @@ -0,0 +1,12 @@ + +| ![dispatcher](dispatcher.jpg) | +|:----------------------------------------------| +| dispatcher | +| ![color-tomato-theme](color-tomato-theme.jpg) | +| color-tomato-theme | +| ![older-tomato-theme](older-tomato-theme.jpg) | +| older-tomato-theme | +| ![pomodoro](pomodoro.jpg) | +| pomodoro | +| ![website](website.jpg) | +| website | diff --git a/avatars/color-tomato-theme.jpg b/avatars/color-tomato-theme.jpg new file mode 100644 index 0000000..4777099 Binary files /dev/null and b/avatars/color-tomato-theme.jpg differ diff --git a/avatars/dispatcher.jpg b/avatars/dispatcher.jpg new file mode 100644 index 0000000..84c8396 Binary files /dev/null and b/avatars/dispatcher.jpg differ diff --git a/avatars/older-tomato-theme.jpg b/avatars/older-tomato-theme.jpg new file mode 100644 index 0000000..bf1024d Binary files /dev/null and b/avatars/older-tomato-theme.jpg differ diff --git a/avatars/pomodoro.jpg b/avatars/pomodoro.jpg new file mode 100644 index 0000000..2301a85 Binary files /dev/null and b/avatars/pomodoro.jpg differ diff --git a/avatars/website.jpg b/avatars/website.jpg new file mode 100644 index 0000000..3d27162 Binary files /dev/null and b/avatars/website.jpg differ diff --git a/bash_scripts/archive_backup.sh b/bash_scripts/archive_backup.sh new file mode 100755 index 0000000..3e1b2bf --- /dev/null +++ b/bash_scripts/archive_backup.sh @@ -0,0 +1,9 @@ +#!/bin/bash +echo "Создание общего архива для каталогов проектов на текущую дату." +cd ../.. # выход из папки и из репозитория +filename="pomodoro-$(date '+%Y-%m-%d').zip" +# сводная строка исключений для всех проектов из файлов ".gitignore" +exclusions="$(find . -maxdepth 2 -type f -name '.gitignore' -exec \ + sed -E "s|^(.*)$|-xr!'\1'|" {} \; | sort | uniq | tr '\n' ' ')" +rm -f "$filename" +eval "7z a -tzip '$filename' . -xr!'.git' $exclusions" | grep -E '\S' diff --git a/bash_scripts/archive_cleanup.sh b/bash_scripts/archive_cleanup.sh new file mode 100755 index 0000000..250ac85 --- /dev/null +++ b/bash_scripts/archive_cleanup.sh @@ -0,0 +1,12 @@ +#!/bin/bash +echo "Удаление файлов и папок из каталогов проектов перед восстановлением архива." +echo "Предохранитель: ОТМЕНА" && exit 0 +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# обход всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea" +find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" | sort | while read -r dir; do + echo "Обработка: $dir" + # внутри репозитория — удаление всех вложенных файлов и папок, кроме папки ".git" + find "$dir" -mindepth 1 -maxdepth 1 -type f,d -not -name ".git" -exec rm -r {} \; +done +echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." diff --git a/bash_scripts/archive_packaging.sh b/bash_scripts/archive_packaging.sh new file mode 100755 index 0000000..186a2f8 --- /dev/null +++ b/bash_scripts/archive_packaging.sh @@ -0,0 +1,27 @@ +#!/bin/bash +echo "Сборка вёб-сайтов, упаковка и копирование архивов для развёртывания." +# обработка репозитория вёб-сайта +function packaging { + dir="pomodoro${1}" && red="\e[91m" && green="\e[92m" && norm="\e[0m" + # соответствующая строка для вывода сообщений по ходу выполнения функции + num="$((7 - ${1}))" && pre="\e[${num}A${dir}: " && aft="\e[K\e[${num}B\r" + printf "${pre}%s${aft}" "Обработка." + cd "./$dir" &>/dev/null || { printf "${pre}${red}%s${norm}${aft}" "Не найден каталог." && return; } + printf "${pre}%s${aft}" "Сборка." + ./build.sh &>/dev/null || { printf "${pre}${red}%s${norm}${aft}" "Ошибка сборки." && return; } + printf "${pre}%s${aft}" "Упаковка." + ./package.sh &>/dev/null || { printf "${pre}${red}%s${norm}${aft}" "Ошибка упаковки." && return; } + printf "${pre}%s${aft}" "Копирование." + cp "$dir".zip .. &>/dev/null || { printf "${pre}${red}%s${norm}${aft}" "Ошибка копирования." && return; } + printf "${pre}${green}%s${norm}${aft}" "Выполнено." +} +export -f packaging +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# смещение курсора вниз на соответствующее количество строк +printf 'pomodoro%s\n' {1..6} +# обход всех вёб-сайтов и параллельный запуск функции для каждого +printf 'packaging "%s"\0' {1..6} | xargs -n1 -0 -P0 bash -c +# замер продолжительности выполнения в миллисекундах, пересчёт в минуты, секунды и миллисекунды +tms="$(($(date '+%s%3N') - time_ms))" && min="$((tms / 1000 / 60))" && sec="$((tms / 1000 % 60))" +ms="$((tms % 1000))" && printf 'Общее время выполнения: %02d:%02d.%03d мс.\n' "$min" "$sec" "$ms" diff --git a/bash_scripts/info_param.sh b/bash_scripts/info_param.sh new file mode 100755 index 0000000..9489b95 --- /dev/null +++ b/bash_scripts/info_param.sh @@ -0,0 +1,5 @@ +#!/bin/false +#domain="codeberg.org" +domain="git.org.ru" +#domain="hub.mos.ru" +echo "Домен удалённого репозитория: $domain" diff --git a/bash_scripts/info_references.sh b/bash_scripts/info_references.sh new file mode 100755 index 0000000..758df1c --- /dev/null +++ b/bash_scripts/info_references.sh @@ -0,0 +1,23 @@ +#!/bin/bash +echo "Обновление домена удалённого репозитория в перекрёстных ссылках в описаниях." +domain="git.org.ru" && source info_param.sh +# название домена в верхнем регистре +DOMAIN="${domain^^}" +# шаблоны для подстановки +expr+=("s|codeberg\.org|$domain|g") +expr+=("s|CODEBERG\.ORG|$DOMAIN|g") +expr+=("s|git\.org\.ru|$domain|g") +expr+=("s|GIT\.ORG\.RU|$DOMAIN|g") +expr+=("s|hub\.mos\.ru|$domain|g") +expr+=("s|HUB\.MOS\.RU|$DOMAIN|g") +if [ "$domain" == "hub.mos.ru" ]; then + expr+=("s|src/branch|blob|g") +else + expr+=("s|blob|src/branch|g") +fi +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# поиск файлов "README" и параллельная подстановка значений по шаблонам для каждого +find . -type f -name "README*.md" -printf '%p\0' | xargs -I{} -n1 -0 -P0 bash -c \ + "echo '$domain => {}' && sed -i $(printf " -e '%s'" "${expr[@]}") '{}'" +echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." diff --git a/bash_scripts/info_tree_license.sh b/bash_scripts/info_tree_license.sh new file mode 100755 index 0000000..c29831c --- /dev/null +++ b/bash_scripts/info_tree_license.sh @@ -0,0 +1,58 @@ +#!/bin/bash +echo "Построение дерева каталогов для каждого проекта и копирование файлов лицензии." +# дерево каталогов со ссылками +function directory_tree { + # аргументы + local path="$1" + local head="$2" + local tail="$3" + # получить содержимое каталога + if [ -d "$path" ]; then + # сначала заглавные буквы, потом строчные, сначала каталоги, потом файлы + ls_sorted="LC_COLLATE=C ls -A --group-directories-first $exclusions $path" + # отсортированный массив файлов и каталогов + local list && readarray -t list < <(eval "$ls_sorted") + # длина массива + local size=${#list[@]} + # пропустить пустой каталог + [ "$size" == 0 ] && return + fi + # префикс текущего элемента, сворачивать синглтоны в одну строку + [ "$4" == "one" ] && printf '%s' "/" || printf '\n%s' "$head" + # текущий элемент дерева — относительная гиперссылка + printf '%s' "${path##*/}" + # рекурсивные вызовы для подкаталогов + if [ -d "$path" ]; then + local i # счётчик + for ((i = 0; i < size; i++)); do + if ((size == 1)); then + directory_tree "$path/${list[$i]}" "$tail" "$tail" "one" + elif ((i < size - 1)); then + directory_tree "$path/${list[$i]}" "$tail├─ " "$tail│ " + else + directory_tree "$path/${list[$i]}" "$tail└─ " "$tail " + fi + done + fi +} +# копирование файлов лицензии и построение дерева каталогов +function tree_license { + echo "Обработка: $1" + cd "$1" || return + # копирование файлов из этого репозитория во все остальные + if [ "$1" != "./dispatcher" ]; then + cp --remove-destination ../dispatcher/CONTRIBUTING.md . + cp --remove-destination ../dispatcher/*LICENSE* . + fi + # строка исключений для "ls" из списка неотслеживаемых файлов ".gitignore" + exclusions="-I'.git' $(sed -E "s|^(.*)$|-I'\1'|" .gitignore | tr '\n' ' ')" + # помещаем дерево в контейнер, добавляем заголовок и выводим в файл + printf '%s\n' "## Дерево каталогов" "" "
" \
+    "$(directory_tree . | grep '\S')" "
" >DIRECTORY_TREE.md +} +export -f tree_license directory_tree +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# поиск всех каталогов на одном уровне с текущим, кроме папки ".idea", и параллельный запуск функции для каждого +find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -printf 'tree_license "%p"\0' | xargs -n1 -0 -P0 bash -c +echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." diff --git a/bash_scripts/repo_compose.sh b/bash_scripts/repo_compose.sh new file mode 100755 index 0000000..78e3130 --- /dev/null +++ b/bash_scripts/repo_compose.sh @@ -0,0 +1,92 @@ +#!/bin/bash +echo "Создание скриптов из шаблонов с параметрами и сохранение их в каталогах проектов." +export domain="git.org.ru" && source info_param.sh +export basedir="$PWD" # текущая папка +# создание скриптов внутри каталога +function compose { + echo "Обработка: $1" + cd "$1" || return + # добавление скриптов в список неотслеживаемых файлов, если ещё не добавлено + if [[ ! -f ".gitignore" || "$(grep -cF ".repo_*" ".gitignore")" == 0 ]]; then + echo ".repo_*" >>".gitignore" && echo "Обновлён файл: $1/.gitignore" + fi + # подготовка значений для параметров + user="golovin" && owner="$user" && repo="$1" + case "$1" in + *[1-6]) owner="pomodoro" && repo="${1//$owner/}" ;;& + *1) description="Трёхмерная графика на JavaScript" ;;& + *2) description="Декартово произведение, комбинаторика" ;;& + *3) description="Умножение матриц и повороты" ;;& + *4) description="Практическая философия, поэзия и юмор" ;;& + *5) description="Рисуем картинки текстом" ;;& + *6) description="Пустой" ;;& + *[1-6]) description+=" — https://$owner$repo.mircloud.ru" ;; + dispatcher) description="Управление репозиториями" ;; + pomodoro) description="Описание и оглавление" ;; + color*) description="Тема оформления / Цветной помидор" ;; + older*) description="Тема оформления / Старый помидор" ;; + *) return ;; # шесть помидорных вёб-сайтов и три сопутствующих проекта + esac + file="DIRECTORY_TREE.md" + if [ "$domain" == "hub.mos.ru" ]; then + model="gitlab" && folder="blob" && wiki_home="-/wikis/home" + [ -f "WIKI.md" ] && wiki="$(uni2ascii -aU -qpsn "WIKI.md")" + else + model="forgejo" && folder="src/branch" && wiki_home="wiki" + [ -f "WIKI.md" ] && wiki="$(basenc "WIKI.md" --base64 -w0)" + fi + if [ "$domain" == "codeberg.org" ]; then + [[ "$1" =~ [1-6] ]] && description2="Исходные тексты вёб-сайта — https://$domain/$owner/$repo" + [ -f "WIKI.md" ] && wiki="$(sed 's|mircloud\.ru|codeberg.page|g' WIKI.md | basenc --base64 -w0)" + description="${description//mircloud.ru/codeberg.page}" + fi + # создание трёх скриптов в каталоге проекта с одинаковой шапкой для всех + echo "#!/bin/bash" | tee ".repo_remote.sh" ".repo_local.sh" >".repo_testing.sh" + chmod +x ".repo_remote.sh" ".repo_local.sh" ".repo_testing.sh" + # параметры для удалённого репозитория + param_remote+=("domain='$domain'") + param_remote+=("owner='$owner'") + param_remote+=("user='$user'") + param_remote+=("repo='$repo'") + param_remote+=("description='$description'") + param_remote+=("wiki='$wiki'") + param_remote+=("token='$(head -n+1 "$basedir/.token_$model")'") + # скрипт для создания удалённого репозитория + printf '%s\n' "${param_remote[@]}" >>".repo_remote.sh" + tail -n+2 "$basedir/repo_$model.tmpl.sh" >>".repo_remote.sh" + # параметры для локального репозитория + param_local+=("domain='$domain'") + param_local+=("owner='$owner'") + param_local+=("repo='$repo'") + param_local+=("dir='$1'") + # скрипт для создания локального репозитория + printf '%s\n' "${param_local[@]}" >>".repo_local.sh" + tail -n+2 "$basedir/repo_local.tmpl.sh" >>".repo_local.sh" + # параметры для тестирования вёб-интерфейса + param_testing+=("'https://$domain/$owner/$repo/$folder/master/$file' '$file'") + [ "$wiki" ] && param_testing+=("'https://$domain/$owner/$repo/$wiki_home' 'Home'") + # скрипт для тестирования вёб-интерфейса + printf 'pages+=("%s")\n' "${param_testing[@]}" >>".repo_testing.sh" + tail -n+21 "$basedir/repo_testing.smpl.sh" >>".repo_testing.sh" + # создание четвёртого скрипта в каталоге вёб-сайта + if [[ "$domain" == "codeberg.org" && "$1" =~ [1-6] ]]; then + # параметры для развёртывания вёб-сайта + param_pages+=("#!/bin/bash") + param_pages+=("domain='$domain'") + param_pages+=("owner='$owner$repo'") + param_pages+=("user='$user'") + param_pages+=("repo='pages'") + param_pages+=("description='$description2'") + param_pages+=("token='$(head -n+1 "$basedir/.token_forgejo")'") + # скрипт для развёртывания вёб-сайта + printf '%s\n' "${param_pages[@]}" >".repo_pages2.sh" + tail -n+2 "$basedir/repo_forgejo2.tmpl.sh" >>".repo_pages2.sh" + chmod +x ".repo_pages2.sh" + fi +} +export -f compose +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# поиск всех каталогов на одном уровне с текущим, кроме папки ".idea", и параллельный запуск функции для каждого +find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -printf 'compose "%f"\0' | xargs -n1 -0 -P0 bash -c +echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." diff --git a/bash_scripts/repo_forgejo.tmpl.sh b/bash_scripts/repo_forgejo.tmpl.sh new file mode 100644 index 0000000..18d43f5 --- /dev/null +++ b/bash_scripts/repo_forgejo.tmpl.sh @@ -0,0 +1,57 @@ +#!/bin/false +if [[ -z "$domain" || -z "$token" || -z "$owner" || -z "$repo" || -z "$description" || -z "$user" ]]; then + echo "Не указаны обязательные параметры." && exit 1 +fi +if [ -z "$1" ]; then + echo "Создание удалённого репозитория для текущего проекта." +fi +time_ms="$(date '+%s%3N')" +if [[ -z "$1" || "$1" == "delete" ]]; then + echo "Удаление старого репозитория." + curl -i -X DELETE "https://$domain/api/v1/repos/$owner/$repo" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" +fi +if [[ -z "$1" || "$1" == "create" ]]; then + echo "Создание нового репозитория пользователя." + curl -i -X POST "https://$domain/api/v1/user/repos" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ \"name\": \"$repo\", \"description\": \"$description\" }" + if [ "$user" != "$owner" ]; then + echo "Перемещение репозитория в группу." + curl -i -X POST "https://$domain/api/v1/repos/$user/$repo/transfer" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ \"new_owner\": \"$owner\" }" + fi +fi +if [[ -z "$1" || "$1" == "options" ]]; then + [ "$wiki" ] && has_wiki=true || has_wiki=false + echo "Изменение свойств репозитория / отключение ненужного." + curl -i -X PATCH "https://$domain/api/v1/repos/$owner/$repo" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ + \"has_projects\": false, \"has_issues\": false, + \"has_releases\": false, \"has_actions\": false, + \"has_packages\": false, \"has_pull_requests\": false, + \"has_wiki\": $has_wiki }" + if [ "$wiki" ]; then + echo "Добавление страницы wiki в репозиторий." + curl -i -X POST "https://$domain/api/v1/repos/$owner/$repo/wiki/new" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ \"content_base64\": \"$wiki\", \"title\": \"Home\" }" + fi + echo "Добавление аватарки для репозитория." + [ "$user" != "$owner" ] && picture="website" || picture="$repo" + avatar=$(basenc "../dispatcher/avatars/$picture.jpg" --base64 -w0) + curl -i -X POST "https://$domain/api/v1/repos/$owner/$repo/avatar" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ \"image\": \"$avatar\" }" +fi +if [ -z "$1" ]; then + echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." +fi diff --git a/bash_scripts/repo_forgejo2.tmpl.sh b/bash_scripts/repo_forgejo2.tmpl.sh new file mode 100644 index 0000000..be75494 --- /dev/null +++ b/bash_scripts/repo_forgejo2.tmpl.sh @@ -0,0 +1,60 @@ +#!/bin/false +if [[ -z "$domain" || -z "$token" || -z "$owner" || -z "$repo" || -z "$description" || -z "$user" ]]; then + echo "Не указаны обязательные параметры." && exit 1 +elif [ "$domain" != "codeberg.org" ]; then + echo "Некорректно указан сервер." && exit 1 +fi +cd _site || exit 1 +if [ -z "$1" ]; then + echo "Создание удалённого репозитория, локального репозитория, отправка данных и проверка их получения." +fi +time_ms="$(date '+%s%3N')" +if [[ -z "$1" || "$1" == "remote" ]]; then + echo "Удаление старого репозитория на сервере." + curl -i -X DELETE "https://$domain/api/v1/repos/$owner/$repo" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" + echo "Создание нового репозитория в группе на сервере." + curl -i -X POST "https://$domain/api/v1/orgs/$owner/repos" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ + \"name\": \"$repo\", \"description\": \"$description\" }" + echo "Изменение свойств репозитория / отключение ненужного." + curl -i -X PATCH "https://$domain/api/v1/repos/$owner/$repo" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ + \"has_projects\": false, \"has_issues\": false, + \"has_releases\": false, \"has_actions\": false, + \"has_packages\": false, \"has_pull_requests\": false, + \"has_wiki\": false }" + echo "Добавление аватарки для репозитория." + avatar=$(basenc "../../dispatcher/avatars/website.jpg" --base64 -w0) + curl -i -X POST "https://$domain/api/v1/repos/$owner/$repo/avatar" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" \ + -H "Content-Type: application/json" -d "{ \"image\": \"$avatar\" }" +fi +if [[ -z "$1" || "$1" == "local" ]]; then + echo "Пересоздание локального репозитория и отправка данных на сервер." + rm -rf ".git" # удаление старого репозитория + git init -b "master" + git remote add "$domain" "git@$domain:$owner/$repo.git" + git add --all + git commit -m "$(printf '%(%F %T)T' "$(stat . -c'%W')")" + git push -u "$domain" "master" +fi +if [ -z "$1" ]; then + echo "Ожидание 3 секунды." && sleep 3 +fi +if [[ -z "$1" || "$1" == "testing" ]]; then + echo "Получение списка коммитов для удалённого репозитория." + param="stat=false&verification=false&files=false" + curl -i -X GET "https://$domain/api/v1/repos/$owner/$repo/commits?$param" \ + -H "Authorization: token $token" \ + -H "Accept: application/json" +fi +if [ -z "$1" ]; then + echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." +fi diff --git a/bash_scripts/repo_gitlab.tmpl.sh b/bash_scripts/repo_gitlab.tmpl.sh new file mode 100644 index 0000000..fb69cac --- /dev/null +++ b/bash_scripts/repo_gitlab.tmpl.sh @@ -0,0 +1,68 @@ +#!/bin/false +if [[ -z "$domain" || -z "$token" || -z "$owner" || -z "$repo" || -z "$description" || -z "$user" ]]; then + echo "Не указаны обязательные параметры." && exit 1 +fi +if [ -z "$1" ]; then + echo "Создание удалённого репозитория для текущего проекта." +fi +time_ms="$(date '+%s%3N')" +if [[ -z "$1" || "$1" == "delete" ]]; then + echo "Удаление старого репозитория." + curl -i -X DELETE "https://$domain/api/v4/projects/$owner%2F$repo" \ + -H "PRIVATE-TOKEN: $token" \ + -H "Content-Type: application/json" -d "{ \"permanently_remove\": \"true\", \"full_path\": \"$owner/$repo\" }" + echo +fi +if [[ -z "$1" || "$1" == "create" ]]; then + echo "Создание нового репозитория пользователя." + curl -i -X POST "https://$domain/api/v4/projects" \ + -H "PRIVATE-TOKEN: $token" \ + -H "Content-Type: application/json" -d "{ \"name\": \"$repo\", \"description\": \"$description\" }" + echo + if [ "$user" != "$owner" ]; then + echo "Перемещение репозитория в группу." + curl -i -X PUT "https://$domain/api/v4/projects/$user%2F$repo/transfer?namespace=$owner" \ + -H "PRIVATE-TOKEN: $token" + echo + fi +fi +if [[ -z "$1" || "$1" == "options" ]]; then + [ "$wiki" ] && has_wiki="enabled" || has_wiki="disabled" + echo "Изменение свойств репозитория / отключение ненужного." + curl -i -X PUT "https://$domain/api/v4/projects/$owner%2F$repo" \ + -H "PRIVATE-TOKEN: $token" \ + -H "Content-Type: application/json" -d "{ + \"emails_disabled\": \"true\", \"issues_access_level\": \"disabled\", + \"merge_requests_access_level\": \"disabled\", \"operations_access_level\": \"disabled\", + \"builds_access_level\": \"disabled\", \"request_access_enabled\": \"false\", + \"keep_latest_artifact\": \"false\", \"ci_forward_deployment_enabled\": \"false\", + \"ci_separated_caches\": \"false\", \"ci_allow_fork_pipelines_to_run_in_parent_project\": \"false\", + \"jobs_enabled\": \"false\", \"public_builds\": \"false\", \"packages_enabled\": \"false\", + \"merge_requests_enabled\": \"false\", \"issues_enabled\": \"false\", \"lfs_enabled\": \"false\", + \"snippets_enabled\": \"false\", \"container_registry_enabled\": \"false\", + \"wiki_access_level\": \"$has_wiki\", \"container_registry_access_level\": \"disabled\", + \"security_and_compliance_access_level\": \"disabled\", \"pages_access_level\": \"disabled\", + \"analytics_access_level\": \"disabled\", \"forking_access_level\": \"disabled\", + \"releases_access_level\": \"disabled\", \"requirements_access_level\": \"disabled\", + \"environments_access_level\": \"disabled\", \"feature_flags_access_level\": \"private\", + \"infrastructure_access_level\": \"private\", \"monitor_access_level\": \"disabled\", + \"snippets_access_level\": \"disabled\", \"auto_devops_enabled\": \"false\", + \"shared_runners_enabled\": \"false\", \"group_runners_enabled\": \"false\" }" + echo + if [ "$wiki" ]; then + echo "Добавление страницы wiki в репозиторий." + curl -i -X POST "https://$domain/api/v4/projects/$owner%2F$repo/wikis" \ + -H "PRIVATE-TOKEN: $token" \ + -H "Content-Type: application/json" -d "{ \"content\": \"$wiki\", \"title\": \"Home\" }" + echo + fi + echo "Добавление аватарки для репозитория." + [ "$user" != "$owner" ] && picture="website" || picture="$repo" + curl -i -X PUT "https://$domain/api/v4/projects/$owner%2F$repo" \ + -H "PRIVATE-TOKEN: $token" \ + -F "avatar=@../dispatcher/avatars/$picture.jpg" + echo +fi +if [ -z "$1" ]; then + echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." +fi diff --git a/bash_scripts/repo_local.tmpl.sh b/bash_scripts/repo_local.tmpl.sh new file mode 100644 index 0000000..f81b093 --- /dev/null +++ b/bash_scripts/repo_local.tmpl.sh @@ -0,0 +1,38 @@ +#!/bin/false +if [[ -z "$domain" || -z "$owner" || -z "$repo" || -z "$dir" ]]; then + echo "Не указаны обязательные параметры." && exit 1 +fi +echo "Создание локального репозитория, подключение к удалённому и передача данных." +time_ms="$(date '+%s%3N')" +# строка исключений для "find" из списка неотслеживаемых файлов ".gitignore" +exclusions="-not -path '*/.git/*' $(sed -E "s|^(.*)$|-not -path '*/\1*'|" .gitignore | tr '\n' ' ')" +# перевести размеры файла в человеко-читаемую строку, отбросить нули из дробной части и добавить пробел +function BKM { numfmt --to=iec --format="%.2f" --suffix="B" "$1" | sed -r 's|,{,1}0{,2}([BKM])| \1|'; } +rm -rf .git +git init -b master +git remote add "$domain" "git@$domain:$owner/$repo.git" +git add .git* +git commit -m "Инициализация / $dir" +if [ "$domain" == "hub.mos.ru" ]; then + echo "Второй пуш, потому что лингвист с первого раза не срабатывает." + git push -u "$domain" master +fi +find . -type f | grep -E 'CONTRIBUTING|LICENSE' | xargs git add +git commit -m "Открытая лицензия РФ" +find . -type f -name '*.md' | grep -E 'TREE|WIKI|README|VIEW' | xargs git add +git commit -m "Описание проекта" +find . -type f | grep -E '(yml|Gemfile.*|gemspec|robots.txt)$' | xargs git add +git commit -m "Настройки" +git add \*.sh +git commit -m "Скрипты bash" +find . -type f | grep -E '(min.css|min.js|woff)$' | xargs git add +git commit -m "Сторонние материалы" +find . -type f | grep -E '(bmp|gif|ico|jpg|png|svg)$' | xargs git add +git commit -m "Картинки" +while read -r file size; do + echo "Обработка: $file" + git add "$file" + git commit -m "${file#*/} / $(BKM "$size")" +done < <(eval "find . -type f $exclusions -printf '%p %s\n'" | LC_COLLATE=C sort -r) +git push -u "$domain" master +echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." diff --git a/bash_scripts/repo_testing.smpl.sh b/bash_scripts/repo_testing.smpl.sh new file mode 100755 index 0000000..6446f6a --- /dev/null +++ b/bash_scripts/repo_testing.smpl.sh @@ -0,0 +1,35 @@ +#!/bin/bash +echo "Образец скрипта для тестирования доступности страниц в вёб-интерфейсе на сервере." +domain="git.org.ru" && source info_param.sh +# две страницы для тестирования +file="DIRECTORY_TREE.md" +if [ "$domain" == "hub.mos.ru" ]; then + folder="blob" && wiki_home="-/wikis/home" +else + folder="src/branch" && wiki_home="wiki" +fi +# подготовка массива строк — адрес страницы и название файла через пробел +for repo in {1..6}; do + #pages+=("'https://$domain/golovin/$repo/$folder/master/$file' '$file'") + pages+=("'https://$domain/pomodoro/$repo/$folder/master/$file' '$file'") + pages+=("'https://$domain/pomodoro/$repo/$wiki_home' 'Home'") +done +for repo in {pomodoro,older-tomato-theme,color-tomato-theme}; do + pages+=("'https://$domain/golovin/$repo/$folder/master/$file' '$file'") + pages+=("'https://$domain/golovin/$repo/$wiki_home' 'Home'") +done +# тестирование доступности страниц +function testing { + # название файла должно находиться в заголовке страницы, иначе сервер должен вернуть ошибку + case "$(curl "$1" 2>/dev/null | grep -oP '(?<=).*(?=)' | grep -cF "$2")" in + 0) color="91" ;; # светло-красный цвет для отсутствующих страниц + *) color="0" ;; # обычный цвет для всех остальных страниц + esac + # текст соответствующего цвета и адрес страницы + printf "\e[${color}m%s\e[0m %s\n" "Страница:" "$1" +} +export -f testing +time_ms="$(date '+%s%3N')" +# запуск параллельного тестирования строк массива и сортировка результатов +printf "testing %s\0" "${pages[@]}" | xargs -n1 -0 -P0 bash -c | sort -r -k2 +echo "Общее время выполнения: $(($(date '+%s%3N') - time_ms)) мс." diff --git a/bash_scripts/suite_orchestrate.sh b/bash_scripts/suite_orchestrate.sh new file mode 100755 index 0000000..dfc89a0 --- /dev/null +++ b/bash_scripts/suite_orchestrate.sh @@ -0,0 +1,54 @@ +#!/bin/bash +echo "Параллельное выполнение скриптов и публикация репозиториев для каталогов проектов." +# выполнение скриптов внутри каталога +function orchestrate { + dir="${1#*:}" && red="\e[91m" && green="\e[92m" && norm="\e[0m" + # соответствующая строка для вывода сообщений по ходу выполнения функции + num="${1%:*}" && pre="\e[${num}A${dir}: " && aft="\e[K\e[${num}B\r" + cd "$dir" || return + pattern="^HTTP/[1,2].{,2}? [4,5]" + printf "${pre}%s${aft}" "Создание репозитория на сервере." + for ((ms1 = "$(date '+%s%3N')"; $(date '+%s%3N') - ms1 < 60000; pass = 0)); do + # 1 Создание удалённого репозитория и проверка корректности ответов от сервера + for ((dot = 1, ms2 = "$(date '+%s%3N')"; $(date '+%s%3N') - ms2 < 10000; dot++, remote = 0)); do + ellipsis="$(seq -s '.' 0 "$dot" | tr -d '0-9')" + case "$(./.repo_remote.sh 2>/dev/null | tail -n+10 | grep -cE "$pattern")" in + 0) remote=1 && break ;; *) printf "${pre}%s${aft}" "Ошибка 400-500 при подключении к серверу${ellipsis}" ;; + esac + done + case "$remote" in + 1) printf "${pre}%s${aft}" "Создание локального репозитория." ;; + *) printf "${pre}%s${aft}" "Создание на сервере более 10 секунд." && continue ;; + esac + # 2 Создание локального репозитория и отправка данных на сервер + ./.repo_local.sh &>/dev/null + # 3 Проверка доступности данных в вёб-интерфейсе на сервере + printf "${pre}%s${aft}" "Проверка доступности данных." + for ((dot = 1, ms2 = "$(date '+%s%3N')"; $(date '+%s%3N') - ms2 < 10000; dot++, testing = 0)); do + ellipsis="$(seq -s '.' 0 "$dot" | tr -d '0-9')" + case "$(./.repo_testing.sh 2>/dev/null | grep -cF "[91m")" in + 0) testing=1 && break ;; *) printf "${pre}%s${aft}" "Ожидание данных на сервере${ellipsis}" ;; + esac + done + case "$testing" in + 1) pass=1 && break ;; + *) printf "${pre}%s${aft}" "Проверка данных более 10 секунд." ;; + esac + done + case "$pass" in + 1) printf "${pre}${green}%s${norm}${aft}" "Выполнено." ;; + *) printf "${pre}${red}%s${norm}${aft}" "Ожидание более 60 секунд." ;; + esac +} +export -f orchestrate +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# поиск всех каталогов на одном уровне с текущим, кроме папки ".idea", сортировка и добавление порядковых номеров для строк +readarray -t folders < <(find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -printf '%P\n' | sort -r | grep -n '\S') +# смещение курсора вниз на соответствующее количество строк +printf '%s\n' "${folders[@]#*:}" | sort +# вывод строк массива и параллельный запуск функции для каждого каталога +printf 'orchestrate "%s"\0' "${folders[@]}" | xargs -n1 -0 -P0 bash -c +# замер продолжительности выполнения в миллисекундах, пересчёт в минуты, секунды и миллисекунды +tms="$(($(date '+%s%3N') - time_ms))" && min="$((tms / 1000 / 60))" && sec="$((tms / 1000 % 60))" +ms="$((tms % 1000))" && printf 'Общее время выполнения: %02d:%02d.%03d мс.\n' "$min" "$sec" "$ms" diff --git a/bash_scripts/suite_pages2.sh b/bash_scripts/suite_pages2.sh new file mode 100755 index 0000000..f9ba27d --- /dev/null +++ b/bash_scripts/suite_pages2.sh @@ -0,0 +1,52 @@ +#!/bin/bash +echo "Параллельное выполнение скриптов и развёртывание вёб-сайтов на сервере codeberg." +# выполнение скрипта внутри каталога вёб-сайта +function pages2 { + dir="pomodoro${1}" && red="\e[91m" && green="\e[92m" && norm="\e[0m" + # соответствующая строка для вывода сообщений по ходу выполнения функции + num="$((7 - ${1}))" && pre="\e[${num}A${dir}: " && aft="\e[K\e[${num}B\r" + cd "$dir" || return + pattern="^HTTP/[1,2].{,2}? [4,5]" + printf "${pre}%s${aft}" "Создание репозитория на сервере." + for ((ms1 = "$(date '+%s%3N')"; $(date '+%s%3N') - ms1 < 60000; pass = 0)); do + # 1 Создание удалённого репозитория и проверка корректности ответов от сервера + for ((dot = 1, ms2 = "$(date '+%s%3N')"; $(date '+%s%3N') - ms2 < 10000; dot++, remote = 0)); do + ellipsis="$(seq -s '.' 0 "$dot" | tr -d '0-9')" + case "$(./.repo_pages2.sh "remote" 2>/dev/null | tail -n+10 | grep -cE "$pattern")" in + 0) remote=1 && break ;; *) printf "${pre}%s${aft}" "Ошибка 400-500 при подключении к серверу${ellipsis}" ;; + esac + done + case "$remote" in + 1) printf "${pre}%s${aft}" "Создание локального репозитория." ;; + *) printf "${pre}%s${aft}" "Создание на сервере более 10 секунд." && continue ;; + esac + # 2 Создание локального репозитория и отправка данных на сервер + ./.repo_pages2.sh "local" &>/dev/null + # 3 Проверка корректности получения данных на сервере + printf "${pre}%s${aft}" "Проверка доступности данных." + for ((dot = 1, ms2 = "$(date '+%s%3N')"; $(date '+%s%3N') - ms2 < 10000; dot++, testing = 0)); do + ellipsis="$(seq -s '.' 0 "$dot" | tr -d '0-9')" + case "$(./.repo_pages2.sh "testing" 2>/dev/null | grep -cE "$pattern")" in + 0) testing=1 && break ;; *) printf "${pre}%s${aft}" "Ожидание данных на сервере${ellipsis}" ;; + esac + done + case "$testing" in + 1) pass=1 && break ;; + *) printf "${pre}%s${aft}" "Проверка данных более 10 секунд." ;; + esac + done + case "$pass" in + 1) printf "${pre}${green}%s${norm}${aft}" "Выполнено." ;; + *) printf "${pre}${red}%s${norm}${aft}" "Ожидание более 60 секунд." ;; + esac +} +export -f pages2 +cd ../.. # выход из папки и из репозитория +time_ms="$(date '+%s%3N')" +# смещение курсора вниз на соответствующее количество строк +printf 'pomodoro%s\n' {1..6} +# обход всех вёб-сайтов и параллельный запуск функции для каждого +printf 'pages2 "%s"\0' {1..6} | xargs -n1 -0 -P0 bash -c +# замер продолжительности выполнения в миллисекундах, пересчёт в минуты, секунды и миллисекунды +tms="$(($(date '+%s%3N') - time_ms))" && min="$((tms / 1000 / 60))" && sec="$((tms / 1000 % 60))" +ms="$((tms % 1000))" && printf 'Общее время выполнения: %02d:%02d.%03d мс.\n' "$min" "$sec" "$ms" diff --git a/print_screen/LISTVIEW.md b/print_screen/LISTVIEW.md new file mode 100644 index 0000000..f95c084 --- /dev/null +++ b/print_screen/LISTVIEW.md @@ -0,0 +1,17 @@ +| ![archive_cleanup.png](archive_cleanup.png) | +|:------------------------------------------------| +| archive_cleanup.png | +| ![archive_packaging.gif](archive_packaging.gif) | +| archive_packaging.gif | +| ![info_references.png](info_references.png) | +| info_references.png | +| ![info_tree_license.png](info_tree_license.png) | +| info_tree_license.png | +| ![repo_compose.png](repo_compose.png) | +| repo_compose.png | +| ![repo_testing.smpl.png](repo_testing.smpl.png) | +| repo_testing.smpl.png | +| ![suite_orchestrate.gif](suite_orchestrate.gif) | +| suite_orchestrate.gif | +| ![suite_pages2.gif](suite_pages2.gif) | +| suite_pages2.gif | diff --git a/print_screen/archive_cleanup.png b/print_screen/archive_cleanup.png new file mode 100644 index 0000000..6832481 Binary files /dev/null and b/print_screen/archive_cleanup.png differ diff --git a/print_screen/archive_packaging.gif b/print_screen/archive_packaging.gif new file mode 100644 index 0000000..e2328df Binary files /dev/null and b/print_screen/archive_packaging.gif differ diff --git a/print_screen/info_references.png b/print_screen/info_references.png new file mode 100644 index 0000000..64332dc Binary files /dev/null and b/print_screen/info_references.png differ diff --git a/print_screen/info_tree_license.png b/print_screen/info_tree_license.png new file mode 100644 index 0000000..5e136f7 Binary files /dev/null and b/print_screen/info_tree_license.png differ diff --git a/print_screen/repo_compose.png b/print_screen/repo_compose.png new file mode 100644 index 0000000..c7bd482 Binary files /dev/null and b/print_screen/repo_compose.png differ diff --git a/print_screen/repo_testing.smpl.png b/print_screen/repo_testing.smpl.png new file mode 100644 index 0000000..0e0ad74 Binary files /dev/null and b/print_screen/repo_testing.smpl.png differ diff --git a/print_screen/suite_orchestrate.gif b/print_screen/suite_orchestrate.gif new file mode 100644 index 0000000..75831de Binary files /dev/null and b/print_screen/suite_orchestrate.gif differ diff --git a/print_screen/suite_pages2.gif b/print_screen/suite_pages2.gif new file mode 100644 index 0000000..6fb17e2 Binary files /dev/null and b/print_screen/suite_pages2.gif differ