# DEV Guide

1. [Development types](#development-types)
   1. [Client modifications](#1-client-modifications)
   2. [Separate existing plugin](#2-separate-existing-plugin)
   3. [Separate new plugin](#3-separate-new-plugin)
   4. [Core implementations](#4-core-implementations)
2. [Development](#development)
3. [Code style](./CODE_STYLE.md)
4. [Common errors](./COMMON_ERRORS.md)
5. [Repositories](./REPOSITORIES.md)
6. [Testing](./TESTS.md)

## Definitions of terms

- **Easy Project plugins / Jádro:** Jsou všechny pluginy, které jsou vyvýjené interně Easy Software. Jsou tedy jádrem Easy Projectu.
- **Patch:** Úprava, která přímo ovlivňuje chování existující věci. Příklad je použití `alias_method_chain`, `.include`, `.preload`, definování callbacku jako `after_save` / `before_action` nebo použití monkey patchinkg.
- **Úprava jádra:** Patchování interních pluginu Easy Projectu nebo Redmine.

## Development types

Vývoj Easy Projektu je rozdělen na 4 úrovně s různým stupněm kontroly.

#### 1. Client modifications

Úpravy určené konkrétnímu klientovi dle jeho požadavku. Většinou se jedná o jednorázovou a menší úpravu. Vývoj probíha pouze ve složce vygenerované generátorem (`plugins/easyproject/easy_plugins/modification_*`). Úpravy by měli co nejvíce využívát vlastní controllery/view a volání hooku.

Je důležité, aby veškerý vývoj probíhal pouze ve uvedené složce, protože při aktualizace je vše ostatní smazáne a nahrazene aktuálním kódem.

Patche do jádra jsou povolené jen ve výjmečnýh případech po předchozím schválením. Jsou na **plnou odpovědnost autora**.

Funkčnost kontroluje především klient. U těchto modifikacíh většinou nejsou žádné zásahy do jádra a tudiž probíhají minimální kontroly.

[... pokračování](./1_CLIENT_MODIFICATIONS.md)

#### 2. Separate existing plugin

Vývoj/úprava existujicího pluginu pro Redmine, který bude distribuován v rámci Easy Projectu.

Plugin je určený více klientům a tudíž musí být otestován. Buď na úrovni kódu (RSpec, Minitest) nebo definováním scénařů a ručním otestováním.

V těchto pluginech je povoleno využívát pouze vlastní controllery/view. Úpravy jádra jsou povolené **pouze po předchozí domluvě**. V takovémto případě se kontrola patche mění na úroveň [core implementations](#4-core-implementations).

MR může být v opačném případě vráce k přepisu.

Příklad: Easy DMSF

[... pokračování](./2_SEPARATE_EXISTING_PLUGIN.md)

#### 3. Separate new plugin

Vývoj zcela nového pluginu pro Easy Project. Oproti předcházejíci úrovní je rozdíl, že se plugin vyvíji od začátku a v takovém případě jsou kladené přísnější požadavky.

[... pokračování](./3_SEPARATE_NEW_PLUGIN.md)

#### 4. Core implementations

Implementace a úpravy přímo interních pluginu Easy Project. Tedy je brán na kvalitu a předem stanové postupy největší důráz.

Nedodržení pravidel vede k vrácení kódu.

Tato úroveň také vyžaduje dodržování pravidel ohledně stylu kódu popsané v [sekci code style](./CODE_STYLE.md).

[... pokračování](./4_CORE_IMPLEMENTATIONS.md)

## Development

### Before the development

1. Vytvoření účtu na [git.easy.cz](https://git.easy.cz)

2. Přístup do repozitáře (či jeho vytvoření)

3. Seznámení s pravidly s vývoje

### Branches and commits

Všechny důležité větve (pro vydávání balíku nebo pro testování) jsou označené jako **protected** a je zakázano do nich posílat změny přímo. Z tohoto důvodu je nutné nějprve vytvořit větev, která bude obsahovat všechny změny.

Vždy vycházejte z nějnižší možné vývojové verze, aby bylo možné změny začlenit na více míst.

    $ git checkout stable

Větve mají definovaný tvar `ID_ÚKOLU-kratky-popis`.

    $ git checkout -b 1234-add_author_to_project

Změny se přidávají postupně ve tvaru `refs #ID_ÚKOLU kratky popis`.

    $ git commit -m "refs #1234 add migration for author_id"
    $ git commit -m "refs #1234 add select to projects form"

Vyhněte se krátkým a neurčitým pojmenovávání jako _fix_, _patch_ nebo _edit_. Správně pojmenovávání je důležité z důvodu prohlížení historie. Komit ve tvaru "refs #1234 fix author migration" řekne mnohem více než "fix".

V případě kdy úkol neexistuje je třeba psát podrobnější popisy.

### Merge requests

Pro začlenění úprav se vytváří merge (pull) request, kde proběhne diskuze na kódem a funkcionalitou. Stejně jako větve má MR své zásady.

#### 1. Název

By měl být krátký, stručný a zárověň popisovat co se děje. Pokud je úprava spojena s úkolem tak zároveň i referenci na něj `refs #ID_UKOLU`.

Správně:
- 500 na úpravě úkolu (refs #123456)
- Nová verze ganttu 2.0

Špatně:
- fix
- patch
- refs #123456

Mějte na paměti, že přiřazený úživatel vidí ve svém seznamu jen název MR. "Important project fix" bude jistě vyřízen dříve než jen "patch".

Pokud MR není dokončeny a němel by být začleněn můžete do názu přidat **WIP:** (wotk in progress).

#### 2. Popis

Detailnější popis problému a změn. Pokud na úpravu existuje úkol musí popis vždy obsahovat plný odkaz ně nej. V opačném případě musí obsahovat detailnější popis.

#### 3. Větve

Cílová větev vždy závísí na definovanách pravidel daného repozitáře. Více informací v sekci [Repozitíře](./REPOSITORIES.md)

#### 4. Přiřazení

Při vytvoření je vždy autor.

#### 5. Po vytvoření

Po vytvoření je nutné **VŽDY** MR zkontrolovat. Změny musejí sedět s úpravou a MR nemůže obsahovat konflikt.

V repozitář s nastaveným CI je nunté nejprve počkat na doběhnutí testu.

V případech, kdy MR obsahuje konflikty, neprošli testy nebo podpobné situace dojte ke vrácení MR a zbytečnému zdržování.

Pokud je vše v pořádku může se MR přeřadid na odpovědnou osobu nebo správce repozitáře. Pokud si nejste jistí lze u Easy Projectu zvolit @lukas nebo @ondra. U ostatních typů lze zvolit i @jaroslav.bohmer .

### Společné zásady pro všechny úrovně

##### Plugins intializing

Pluginy v Easy Projectu načítájí pluginy jiným způsobem než je to ve vanila Redmine. Ten pro nahrání plugin využívá pouze soubor `init.rb`. V Easy Projectu je inicialize rozdělena na 2.

- `init.rb` obsahuje pouze registraci pluginu
- `after_init.rb` obsahuje vše ostatní

V případě vývoje pluginu, který má běžet jak Redmine tak pro Easy Project může zajistit kompatibilitu pomoci následujícího kódu, který vložíte na konec souboru `init.rb`

```ruby
if Redmine::Plugin.registered_plugins[:easy_extensions].nil?
  require_relative 'after_init'
end
```

##### Prefixes

Aby se předešlo zbytečným konfliktům je dobré veřejné věci oprefixovat. Například název pluginu bude `AbcPlugin`  místo `Plugin`.

Veřejné věci jsou ty které se dají přímo volat ze všech míst programu.

```ruby
class AbcModel
  has_many :others     # vnitřní metoda, která nebude v konfliktu s ostatními věcmi
  has_many :abc_others # a tudíž jí není třeba prefixovat
end

AbcModel # => lze volat odkudkoliv
```

##### Languages

Předchozí sekce se vztahuje i na definování klíčů pro lang soubory. Například klíč `label_sum: Abc sum` se může dostat do konfliktu se stávajícím klíčem a proto je nutné udělat prefix na `label_abc_sum`.

Zároveň je **zakázano** měnit/přepisovat existující klíče z Redmine nebo Easy Projectu.

Všechny texty **musí využívát** systém I18n a minimálně **musí být** přeložené do angličtiny.

##### Syntax checking

Syntax error není tolerovaný na žádné úrovní. V takovém to případě dojde k okamžitému vracácení MR jelikož kód nemohl byt v žádném případě otestovaný.

Tyto chyby lze snad odhalit pomocí `ruby -wc CESTA_K_SOUBORU`. Pro kontrolu nad všemi soubory lze použít tento příklad:

```
find . -name "*.rb" -type f -exec ruby -wc {} \; | grep -v OK
```
