---
title: "Zahtevi za izmene"
description: "Kako rad u sesiji stiže do podrazumevane grane kroz pregled."
---

Захтев за измену (CR) спаја једну Git грану са другом. Beeuni прави CR од гране сесије (`head_ref`) ка подразумеваној грани пројекта (`base_ref`, обично `main`). Ред CR-а садржи метаподатке; спајање, разлике и провере конфликата изводе се као стварне Git операције над репозиторијумом пројекта. CR је једини начин да рад из сесије стигне до подразумеване гране.

<a id="why-work-goes-through-a-cr"></a>

## Зашто се рад обавља путем CR-а

Сесија се извршава у изолованом окружењу на сопственој грани, названој по ID-ју сесије. Изоловано окружење не траје заувек, али грана траје: Git је једини трајни запис рада сесије. Свака нова сесија почиње од подразумеване гране. Док се CR не споји, рад остаје на сопственој грани, без прегледа и невидљив за све друге агенте, окидаче и сараднике. Ово важи за сваку измену: код, агенте, вештине и манифест (`beeuni.yaml`) — без изузетака.

<a id="the-agent-mandate"></a>

## Обавезе агента

Агент мора да отвори CR да би унео било какву измену у подразумевану грану пројекта. Агент не спаја сопствени CR — одлука о спајању припада кориснику. Придржавајте се следећих правила:

1. Направите комит на грани сесије (`$BEEUNI_BRANCH_NAME`). Правите мале комите који раде. Не преписујте историју нити користите force-push.
2. Пошаљите грану: `git push origin HEAD`.
3. Отворите CR: `beeuni cr open --title "..." --description "..."`. У изолованом окружењу сесије, `--head` и `--session` подразумевано имају вредности `$BEEUNI_BRANCH_NAME` и `$BEEUNI_SESSION_ID`. `--base` подразумевано има вредност подразумеване гране пројекта.
4. Реците кориснику број CR-а да би могао да га прегледа.
5. Зауставите се. Немојте сами да спајате CR.

<a id="anti-patterns"></a>

### Лоши обрасци

- **Коришћење force-push-а на подразумеваној грани.** Тиме се крше правила прегледа, чак и када позадински систем то дозвољава.
- **„На мојој је грани, сами је преузмите.“** Грана сесије нестаје када се изоловано окружење заустави, осим ако је CR претходно није спојио.
- **Слање измене као датотеке, налепљеног текста или архиве.** Систем CR-ова већ решава овај проблем.

<a id="data-model"></a>

## Модел података

CR-ови се чувају у табели `change_requests`.

| Колона | Тип | Напомене |
| --- | --- | --- |
| `cr_id` | uuid | Примарни кључ. Идентификатор REST API-ја. |
| `project_id` | uuid | Пројекат ком CR припада. |
| `number` | integer | Редни број за приказ у оквиру пројекта (`#1`, `#2`…). Јединствен у оквиру пројекта. Никада се поново не користи. |
| `title` | text | Обавезно. |
| `description` | text | Подразумевана вредност је празан стринг. |
| `base_ref` | text | Грана у коју се спаја. Обично `main`. |
| `head_ref` | text | Грана из које се спаја. У сесији, то је ID сесије (UUID). |
| `status` | enum | `open`, `merged` или `closed`. |
| `head_commit_sha` | text | За отворене CR-ове освежава се при сваком читању према тренутном врху гране `head_ref`. За спојене CR-ове бележи се у тренутку спајања. |
| `base_commit_sha` | text | Исто правило важи за `base_ref`. |
| `origin_session_id` | text | Сесија која је отворила CR. Поставља се на null ако се та сесија избрише. |
| `created_by` | uuid | Корисник који је направио CR. |
| `merged_at` / `merged_by` | timestamp / uuid | Када и ко је спојио CR. |
| `merge_commit_sha` | text | Комит спајања. За брзо премотавање унапред једнак је `head_commit_sha`. |
| `closed_at` / `closed_by` | timestamp / uuid | Када и ко је затворио CR без спајања. |
| `metadata` | jsonb | Садржи `requested_changes`, листу ставки `{text, by, at}` које је додао `POST /:crId/request-changes`. CR-ови немају посебну табелу коментара. |
| `created_at` / `updated_at` | timestamp | Поставља се при креирању. Ажурира се при свакој промени статуса или освежавању SHA вредности. |

Јединствени индекс на `(project_id, number)` омогућава да се CR пронађе по кратком броју уместо по UUID-у.

<a id="lifecycle"></a>

## Животни циклус

```
open ──(merge)──▶ merged      (terminal)
open ──(close)──▶ closed ──(reopen)──▶ open
```

- `open` је почетни статус.
- `closed` може да се поништи. `POST /:crId/reopen` га враћа на `open`.
- `merged` је коначан статус. Спојени CR не можете поново да отворите нити затворите. Уместо тога отворите нови CR на основу спојеног стања.

Beeuni одбија да направи CR ако грана нема комите испред подразумеване гране. То обично значи да је агент направио комит локално, али га није послао. Пошаљите комите, па поново направите CR.

<a id="sha-refresh"></a>

## Освежавање SHA вредности

За отворени CR, Beeuni освежава `head_commit_sha` и `base_commit_sha` према тренутним гранама при сваком `GET`. Ако репозиторијум није доступан или грана недостаје, Beeuni прескаче освежавање и враћа последње познате метаподатке CR-а. Спојени CR задржава SHA вредности забележене у тренутку спајања — Beeuni их више никада не освежава.

<a id="merge-mechanics"></a>

## Механизам спајања

`POST /v1/projects/:projectId/change-requests/:crId/merge` извршава следеће кораке.

1. Beeuni чита манифест (`beeuni.yaml`) из `head_ref` и проверава га према шеми манифеста. Грана без манифеста пролази проверу. Неисправан манифест враћа `422` са `code: "MANIFEST_INVALID"` и прекида спајање.
2. Beeuni брзо премотава `base_ref` унапред ако је `head_ref` строго испред њега.
3. У супротном, Beeuni прави комит спајања. Подразумевана порука је `Merge CR #<n>: <title>`, а можете је заменити помоћу `message` у телу захтева. Аутор комита је `Beeuni <noreply@beeuni.com>`.
4. У случају конфликта враћа се `409` са списком конфликата. Исти списак проверите помоћу `GET /:crId/merge-preview` пре спајања.
5. У случају успеха, Beeuni поставља `status` на `merged`, бележи `merged_at`, `merged_by` и `merge_commit_sha` и поништава кеш Git података пројекта.

Покушај спајања CR-а који није `open` враћа `409`.

<a id="merge-preview"></a>

### Преглед спајања

`GET /:crId/merge-preview` враћа:

| Поље | Тип | Значење |
| --- | --- | --- |
| `base_sha` | string | Тренутни врх гране `base_ref`. |
| `head_sha` | string | Тренутни врх гране `head_ref`. |
| `merge_base` | string \| null | Заједнички предак. Null ако историје нису повезане. |
| `is_up_to_date` | boolean | `head_ref` је у потпуности спојена у `base_ref`. |
| `can_merge` | boolean | Нема конфликата. |
| `can_fast_forward` | boolean | `head_ref` је строго испред `base_ref`. |
| `conflicts` | string[] | Путање до датотека које би биле у сукобу. |

## REST API

Све руте су под `/v1/projects/:projectId/change-requests`.

| Метод | Путања | Напомене |
| --- | --- | --- |
| GET | `/` | `?status=open\|merged\|closed\|all`. Без филтера враћа све статусе. |
| POST | `/` | Тело: `{title, description?, head_ref, base_ref?, session_id?}`. Враћа `201`. |
| GET | `/:crId` | Враћа CR. Узгред освежава SHA вредности. |
| PATCH | `/:crId` | Уређује `title` или `description`. `409` ако није `open`. |
| GET | `/:crId/diff` | Обједињена закрпа: списак датотека, додавања и брисања. |
| GET | `/:crId/merge-preview` | Погледајте одељак „Преглед спајања“ изнад. |
| POST | `/:crId/merge` | Тело: `{message?}`. `422` ако је манифест неисправан. `409` у случају конфликта или ако није `open`. |
| POST | `/:crId/close` | `409` ако је већ `merged`. |
| POST | `/:crId/reopen` | `409` ако није `closed`. |
| POST | `/:crId/request-changes` | Тело: `{feedback}`. Додаје у `metadata.requested_changes` и буди агента сесије која је покренула CR. `409` ако није `open`. |

`POST /` одбија `head_ref` без комита испред `base_ref`: `422 code: "CR_HEAD_NOT_AHEAD"`. Ову грешку види агент који отвори CR пре него што пошаље своју грану.

<a id="authorization"></a>

### Овлашћења

За руте за читање потребан је приступ пројекту за читање. За руте за писање потребан је приступ за писање. За сваку радњу писања потребна је и одговарајућа могућност, наведена испод за пун токен и ограничени токен сесије.

| Радња | Могућност |
| --- | --- |
| Отварање CR-а | `project.gitops.push` |
| Захтев за изменама | `project.review.act` |
| Спајање | `project.gitops.merge` |

За сваку радњу потребна је по једна могућност, како за пун токен тако и за ограничени токен сесије. Отварање и спајање су засебна овлашћења, па токен може да омогући отварање захтева за измену, али не и њихово спајање — то је механизам на коме се заснивају горенаведене обавезе агента.

`project.cr.open` и `project.cr.merge` били су називи за `project.gitops.push` и `project.gitops.merge` пре преласка — исто овлашћење под другим именом. `beeuni.yaml` који и даље наводи један од тих назива наставља да ради (овлашћење се при разрешавању преписује у важећи назив), али у свему новом користите назив `gitops`.

Сесија никада не може да споји захтев за измену који је сама отворила, без обзира на додељена јој овлашћења. То правило је структурно, а не засновано на овлашћењу.
