# Виды релизов

Релиз представляет из себя снимок файлов определенной версии.

## Решение

Релиз решения содержит перечень модулей и их версий.

## Конфигурация

Релиз конфигурации содержит данные и скрипты обновления конфигурации решения.
База выпуска релизов выбирается по согласованию с заказчиком.

## Сервер приложения

Содержит в себе ядровой функционал необходимый для запуска решения.
Использует [семантическое версионирование](https://semver.org/).
  
## Комплект сборки

Содержит скомпилированные прикладные модули.
Версия формируется по следующему правилу:

- `GENERATION` - модули должны содержать одно поколение.
- `MAJOR` - перещелкивается при любом изменении мажорной версии модуля в составе комплекта.
- `MINOR` - перещелкивается при любом изменении минорной версии модуля в составе комплекта.
- `BUILD` - перещелкивается при любом изменении билда версии модуля в составе комплекта.  
- `PATCH` - перещелкивается при любом изменении патч версии модуля в составе комплекта.

## Snapshot версия

Используется для распространения артефактов из ночной сборки или внеплановой сборки.
Разработчики могут повторно загружать артефакты snapshot-версий в репозиторий.

Для обновления Snapshot версий разработчику необходимо выполнить следующие команды sbt:

```text
sbt clean
sbt update
sbt updateClassifiers
sbt publishDevDependencies
```

## Релиз прикладного модуля

Исходный код, согласованный на момент выпуска релиза, а также скрипты необходимые для установки обновления модуля в базе данных.

### Версия модуля

Укажите версию модуля в формате: Поколение.МажорнаяВерсия.МинорнаяВерсия.Билд.Патч

### Типы релиза

- `Поколение` - крупные изменения, которые ломают обратную совместимость. Старшая версия может означать полное переписывание кода. Также в этом типе релиза происходит очистка миграционных скриптов предыдущей версии. Устанавливается только на предыдущее поколение.
- `Мажор` – крупные изменения, которые могут ломать обратную совместимость. К примеру переключение сервера приложений или обновление SBT плагина.
- `Минор` – плановые изменения в рамках развития модуля, а так же изменение конфигурации модулей проекта (добавление, удаление модулей).
- `Билд` – сквозная нумерация. Увеличивается при выпуске любой из версий, не считая патчей.
- `Патч` – изменения критических ошибок на уже выпущенных версиях. От патчей нельзя создавать другие версии, кроме последующих патчей.

#### Состав релиза

Релиз состоит из:

- исходного кода;
- первичных данных, указанных в `odm.xml` и `pkg.xml`;
- первичных и миграционных данных, указанных в пакетах миграции (`<Имя модуля>_MigratePkg`);
- `sql`-скриптов миграции.

##### Схема базы данных модуля

Схема базы данных, прикладного модуля создается в базе данных при установке модуля.

Объекты схемы, которые были сформированы ранее, и были удалены из исходного кода приложения, не удаляются из БД автоматически. Этим занимается администратор используя инструмент `Корзина удаленных объектов схемы`.

##### Доменная схема

Доменная схема, представляет из себя таблицы, индексы и последовательности создаваемые по описанию классов в `odm`-файлах.

##### Расширенная схема

Расширенная схема, может быть описана в `odm`-, `pkg`-файлах, в тэге `dbSchema`.

#### Поставочные данные модуля

Поставочные данные прикладного модуля устанавливаются в базу данных при установки модуля.

#### Миграционные данные

Миграционные данные делятся на 2 типа:
  - `Sql-скрипты` - используются для работы с изменением схемы напрямую в БД, без `eclipse-link`. Хранятся в структуре модуля в ветке `resource/migration/dbSchema`.
  - `Миграционные задачи` – скрипты, которые написаны с использованием `Api` и `Pkg`. Хранятся в миграционных пакетах модуля.

### Миграционные пакеты

#### Общие сведения

В каждом модуле может быть создан миграционный пакет с именем `<Имя модуля>_MigratePkg`. Пакет размещается в корневом `scala`-каталоге модуля. Например, полное имя миграционного пакета модуля `btk` имеет вид `ru.bitec.app.btk.Btk_MigratePkg`.

Миграционный пакет используется для установки первичных данных и миграции существующих данных с помощью `scala`-кода.

Миграционные пакеты выполняются после создания и обновления структуры базы данных и установки первичных данных (`dbData`), но до завершения процесса обновления. Поэтому в задачах `upTask` и `downTask` можно обращаться к таблицам и колонкам, созданным или изменённым в рамках текущего обновления.

#### Порядок вызова

Вызов миграционных пакетов осуществляется в 2 прохода:
  - Первый раз осуществляется вызов метода `upMigrate`, при обходе модулей от низкоуровневых (например, `gtk`), к высокоуровневым (например, `stk`). В этом методе можно писать логику по созданию новых данных.
  - При втором проходе вызывается метод `downMigrate`, при проходе модулей от высокоуровневых к низкоуровневым. В этом методе можно удалять данные.

#### Миграционные задачи

Задачи имеют имя и версию. Задача выполняется только один раз, для того чтобы выполнить задачу повторно, требуется изменить ее версию или имя.
Задачи делятся на 2 вида:
  - `upTask` - используется в `upMigrate`;
  - `downTask` – используется в `downMigrate`.

##### UpTask

Задачи метода `upMigrate`. Позволяют указывать зависимости от других задач, от скриптов `dbData` из `odm.xml` и `pkg.xml`. Могут содержать секцию, которая будет выполнена, если задача уже выполнялась на целевой базе. А также могут быть анонимными и не содержать тело.

###### Простая задача

Содержит только тело. Пример объявления задачи:

```scala
upTask("taskWOElse", 1){
  //Код задачи
}
```

###### Задача с секцией orElse

Если задача выполняет установку каких-то данных, например, типа объекта, то можно указать ей секцию `orElse`, которая будет вызвана, если тело задачи уже было выполнено, например, в этой секции можно вызвать метод поиска типа объекта по его системному имени.  
Пример объявления такой задачи:

```scala
upTask("installType", 1){
  Btk_AuditActionApi().register("someName", "someCaption", "SomeDesc")
}.orElse{
  Btk_AuditActionApi().findByMnemoCode("someName")
}
```

###### Анонимная задача

Задача без тела, выполняется для группировки зависимостей.  
Пример объявления:

```scala
upTask("dependencyGroup")
  .dependsOnDbData("Wf_Doc", "dataInstall", 25)
  .dependsOn(installStkTypeTask())
```

###### Зависимости

Для каждой задачи можно указать зависимость как от другой задачи, так и от данных, устанавливаемых секцией `dbData`.

Пример объявления зависимостей:

```scala
val someOtherTask = upTask("someOtherTask", 1){
  //Код задачи
}

upTask("taskWOElse", 1){
  //Код задачи
}
  .dependsOnDbData("Wf_Doc", "dataInstall", 25) //зависимость от dbData
  .dependsOn(someOtherTask) // зависимость от другой задачи
```

###### Зависимости между модулями.

Для того чтобы сделать зависимость задачи одного модуля (`module1`) от задачи другого (`module2`) требуется:

1. В `Module1_MigratePkg` задачу вынести в отдельный метод и вызывать его из `upMigrate.`:

    ```scala
    def someTask(): UpTask[NLong] = {
      upTask("someTask", 1){
        1.nl
      }
    }

    override def onUpMigrate(): Unit = {
      someTask()
    }
    ````

2. В `Module2_MigratePkg` для задачи указать зависимость от задачи из `module1`:

    ```scala
    override def onUpMigrate(): Unit = {
      val someTask = Module1_MigratePkg().someTask()
      upTask("someDepTask", 1){
        //Получаем значение, которое вернула задача, от которой зависим
        val someTaskValue = someTask.get() 
      }
        .dependsOn(someTask)
    }
    ```

##### DownTask

Задачи метода `downMigrate`. Содержат только тело задачи.  
Пример объявления задачи:

```scala
downTask("Task_Down", 1) {
  //код задачи
}
```

### Sql-скрипты миграции

#### Общие сведения

Используются для внесения изменений в схему БД, до инициализации `eclipse-link`. Позволяют гарантированно выполняться в схеме, идентичной той, что была на момент выпуска релиза.

#### Описание файла скриптов

Миграционные скрипты размещаются внутри файла `resource/migration/trunk.script.jexl`. А при выпуске релиза копируются в подкаталог `resource/migration/dbSchema`.

Скрипты пишутся в формате `jexl`-скрипта, и могут быть выполнены до обновления схемы или после.

Исполняются внутри специального `jexl`-контекста, который обладает функциями:

- `before` – скрипт будет выполнен до обновления схемы;
- `after` – скрипт будет выполнен после обновления схемы.

Если при выполнении скрипта миграции будет получена ошибка, то процесс установки релиза и обновления базы будет прерван. Для того, чтобы выполнить какой-либо скрипт с игнорированием ошибок нужно добавить к нему директиву `force()`.

#### Пример файла скриптов

```
//выполнение скрипта после обновления схемы
after("scriptName1", `
  delete from btk_class where 1=2 asd
`);

//выполнение скрипта перед обновлением схемы
before("scriptName2", `
  delete from btk_class where 1=2
`);

//выполнение скрипта с игнорированием ошибок.
//Если в таком скрипте произойдет ошибка, то обновление не будет остановлено

after("scriptName3", `
  delete from btk_class where 1=2
`).force();
```

## Инструкции

### Создание задачи миграции

1. Зайдите в IDE.
2. В нужном модуле в `scala`-ветки найдите или создайте пакет с именем `<Имя модуля>_MigratePkg`.
3. Создайте задачу миграции, используя методы `upTask` или `downTask`.

### Создание SQL-скрипта миграции

1. Зайдите в IDE.
2. В нужном модуле в ветке `resource/migration` найдите или создайте файл `trunk.script.jexl`.
3. Добавьте в него скрипт используя методе `before` или `after`.


### Выпуск новой версии

[Выпуск с помощью плагина для IDEA](https://help.globalerp.ru/books/G3ScalaEditionPlugin/SNAPSHOT/html/010_%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5.html).
[Выпуск с помощью GSF-CLI](https://help.globalerp.ru/books/GsfCli/SNAPSHOT/html/070_%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%BA%D0%B0_gsf_git.html).

### Установка релиза

1. Сервер приложений Global должен быть запущен.
2. Подключитесь к серверу `SSH`-клиентом. И выполните скрипт.

   ```console
   attach db {dbAlias} as sys
   upgrade 
   detach
   exit
   ```

   `dbAlias` – алиас базы данных. Если не указан, будет использоваться значение по умолчанию из `global3.config.xml`

Обновление будет выполняться под суперпользователем `SYS`

#### Алгоритм работы

1. `Shh`-команда `attach db as sys` переключает консоль в режим работы с обновлениями.
2. Команда `upgrade` запустит процесс обновления, состоящий из следующих действий:
   1. Формирование очереди выполнения `sql`-скриптов миграции.
   2. Последовательное обновление схемы с промежуточными выполнениями скриптов.
   3. Установка первичных данных (`dbData`).
   4. Выполнение задач миграции.
3. Отключение от базы.
4. Выход из SSH.

#### Сброс состояния обновления

Если требуется откатить информацию об установленных первичных данных или миграционных задачах, то используется `ssh`-команда: `reset upgrade`.

Если в нее не передан идентификатор обновления, то будет сброшено последнее выполненное обновление.

```console
attach db {dbAlias} as sys
reset upgrade
detach
exit
```

или

```console
attach db {dbAlias} as sys
reset upgrade 10202
detach
exit
```

### Создание нового тега
1. Выбираем проект, заходим в коммиты этого проекта.
![tag1.png](../img/tag1.png)
2. Выбираем коммит, от которого хотим создать тег, нажимаем на вкладку "Options" в правом верхнем углу,  выбираем "Tag".
![tag2.png](../img/tag2.png)
3. В поле "Tag name" вводим номер следующего тега. В поле "Message" то же, 
только перед этим слово "Release".
![tag3.png](../img/tag3.png)
4. Выбираем "Create tag".











