devops

package
v0.10.30 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package devops implements a read-only client for an on-prem Azure DevOps Server / TFS collection (v0.9.829).

DELIBERATELY NARROW: this is the connection layer only — settings persistence, an authenticated HTTP client, and a "does it answer?" probe. There is no repo mapping, no stack- frame → source resolution and no Copilot integration yet; those land in a later slice once the operator's repo-naming pattern is known. Nothing in Coremetry consumes this package today, so wiring it up changes no existing behaviour.

The secret contract is the tempo.Service one, verbatim: the PAT lives in Settings, never in Snapshot, never in an error string and never in an audit entry.

Index

Constants

View Source
const (
	FlavorAuto   = "auto"
	FlavorServer = "azure-devops-server"
	FlavorTFS    = "tfs"
)

Flavor values. On-prem installs differ in which api-version they will answer: Azure DevOps Server (2019+) speaks 6.0, the older TFS line (2015-2018) tops out around 4.1 and 400s on a 6.0 request. "auto" probes rather than making the operator know which box they inherited.

View Source
const (
	RepoRungExact = "exact"
	RepoRungFold  = "fold"  // yalnız harf yazımı farklı
	RepoRungLoose = "loose" // ayraçlar da soyulduktan sonra
)

Eşleşme basamakları — testler ve hata mesajları bunları okur.

View Source
const (
	RepoSourcePin        = "pin"        // service_metadata.repository
	RepoSourceConvention = "convention" // önek + ortam eki soyma
	RepoSourceNone       = ""           // çözülemedi
)

Repo çözüm kaynakları — yanıtın altındaki kaynak satırı ve testler bunları okur.

View Source
const (
	DryRunStepConnection = "connection"
	DryRunStepPin        = "pin"
	DryRunStepRepo       = "repo"
	DryRunStepProject    = "project"
	DryRunStepBranch     = chainStepBranch
	DryRunStepTree       = chainStepTree
)

Adım anahtarları — frontend rozetleri ve testler bunları okur.

View Source
const ProjectSourceSettings = "settings"

ProjectSourceSettings — projenin Ayarlar'daki açık alandan geldiğini söyleyen kaynak etiketi (v0.9.1242). Öbür iki değer RepoSourcePin / RepoSourceConvention; üçü birlikte "bu proje adı NEREDEN geldi" sorusunun tüm cevap kümesi.

Variables

This section is empty.

Functions

func BestPathForFrame added in v0.9.830

func BestPathForFrame(paths []string, f stackparse.Frame) string

BestPathForFrame — depo ağacındaki yollar arasından frame'in dosyasına en iyi eşleşen. Eşleşme yoksa "".

Kural: yol, "/" + dosya adı ile BİTMELİ (sonek eşleşmesi) — böylece CardService.java, MyCardService.java'yı yakalamaz. Birden çok aday varsa frame'in PAKET YOLUNA en çok benzeyen kazanır; eşitlikte KISA yol (üretilmiş/gölge kopyalar genelde daha derinde durur), o da eşitse alfabetik — sonuç deterministik olmak zorunda, yoksa aynı exception iki tıkta iki farklı dosya gösterir.

func DefaultBranchOrder added in v0.9.830

func DefaultBranchOrder() []string

func DefaultRepoPrefixes added in v0.9.830

func DefaultRepoPrefixes() []string

DefaultRepoPrefixes / DefaultBranchOrder — ayar boşken kullanılan varsayılanlar. Ayarın kendisi devops_connection blob'unda.

func FormatCodeMissNote added in v0.9.1243

func FormatCodeMissNote(class CodeOutcome, reason string) string

FormatCodeMissNote — ıska işaretinin TEK yazımı. Saf; tablo-testli.

Sınıf varsa sınıf yazılır: taksonomi sabit bir sözlük, kayıtlar üzerinde gruplanabilir. Sınıf yoksa (çıkmaz FetchCode taksonomisinin dışında — ör. bağlam taşmasında kod bloğunun düşürülmesi) gerekçe metni tavanlanarak yazılır; ikisi de yoksa sessiz kalmak yerine "bilinmiyor" denir — işaretin YOKLUĞU "hiç istenmedi" demektir ve tam olarak bu karışıklığı kapatmaya çalışıyoruz.

func MaskCodeInPrompt added in v0.9.830

func MaskCodeInPrompt(full, block, summary string) string

MaskCodeInPrompt — prompt'un LOG KOPYASINDA kod bloğunu özetiyle değiştirir. Saf.

Sağlayıcıya giden gerçek prompt'a DOKUNMAZ — çağıran bunu yalnız ai_calls kaydı için üretir. block prompt'un içinde bulunamazsa prompt aynen döner: maskeleme bir "en iyi çaba" değil, bir sözleşmedir; bulunamadığında sessizce yanlış bir şey yazmaktansa hiçbir şey değiştirmemek doğrudur (çağıran zaten bloğu kendi eklemiştir).

func PickBranch added in v0.9.830

func PickBranch(available []string, order []string) string

PickBranch — sunucudan gelen branş adları arasından ayardaki SIRAYA göre ilk VAR OLANI seçer. Saf; tablo-testli.

available "refs/heads/master" ya da düz "master" olabilir — refs API tam ref adı döner, karşılaştırma son parça üzerinden yapılır. Hiçbiri yoksa "" döner ve çağıran deponun VARSAYILAN branşına düşer: "release yok, master yok" bir hata değil, farklı bir konvansiyondur.

v0.9.1236 — eşleşme HARF DUYARSIZ. Eskiden bayt-bayt eşleşiyordu ve "refs/heads/Release" taşıyan bir depo, ayardaki "release" ile hiç tutmuyordu: PickBranch "" dönüyor, çağıran sessizce deponun VARSAYILAN branşına (çoğunlukla Master/Develop) düşüyordu. Sonuç en kötü sınıftan bir hataydı — kod pencereleri YANLIŞ BRANŞTAN, yani yanlış satırlardan kesiliyor ve operatöre kanıt diye gösteriliyordu; hiçbir yerde bir uyarı yoktu.

Basamak sırası: aynı `want` için ÖNCE birebir, sonra harf duyarsız. Sunucunun KANONİK yazımı döner — git ref URL'i harf duyarlıdır, operatörün ayardaki yazımını geri vermek 404 üretirdi. Ayardaki SIRA semantiği korunur: dış döngü order, iç döngü basamak.

func ShortBranch added in v0.9.830

func ShortBranch(ref string) string

ShortBranch — "refs/heads/master" → "master". Zaten kısaysa aynen.

Types

type CodeContext added in v0.9.830

type CodeContext struct {
	Repo    string       `json:"repo,omitempty"`
	Branch  string       `json:"branch,omitempty"`
	Source  string       `json:"source,omitempty"` // pin | convention
	Windows []CodeWindow `json:"windows,omitempty"`
	Reason  string       `json:"reason,omitempty"`
	// Outcome — bu denemenin SINIFI (v0.9.1243), sayaçlarla BİREBİR
	// aynı taksonomi. v0.9.1241'de sınıf yalnız sayaca gidiyordu; tek
	// bir çağrının kaydına (ai_calls maskeli kopyası) hangi çıkmaza
	// düşüldüğü yazılamıyordu. Sınıfı Reason METNİNDEN çıkarmak
	// alternatifti ve reddedildi: metin operatöre hitap eden, serbestçe
	// değişen bir cümle; sınıf bir sözleşme.
	Outcome CodeOutcome `json:"outcome,omitempty"`
}

CodeContext — bir stacktrace için toplanan tüm kod bağlamı.

Windows boşsa Reason DOLU olmalı: "kod yok" cevabının yanında "neden yok" olmadan operatör entegrasyonun bozuk mu yoksa sadece eşleşme mi bulamadığını ayırt edemez.

func (CodeContext) Empty added in v0.9.830

func (c CodeContext) Empty() bool

Empty — kod bağlamı yok mu?

func (CodeContext) Halved added in v0.9.831

func (c CodeContext) Halved() CodeContext

Halved — kod bütçesini YARIYA indirir (v0.9.831).

Sağlayıcı bağlam taşması 400'ü döndüğünde çağıran BİR kez bununla yeniden dener. Kod, prompt'a en son eklenen ve tek başına en büyük parçadır; taşmada ilk küçültülecek şey odur — exception bağlamının kendisi (stack, trace, loglar) kod olmadan da cevap üretebilir, tersi doğru değil.

Yeni bir ağ isteği YOK: eldeki pencereler kırpılır. v0.9.1243 — küçültme KAYIPTIR ve kayda öyle yazılır. Öncesinde yeniden denemenin maskeli kopyası, ilk denemeninkiyle aynı dilde "kod geldi" diyordu; oysa modele giden pencereler kırpılmış ya da düşmüştü. Not BAŞA yazılıyor: gerekçe tavana çarparsa kesilecek olan eski kuyruk olsun, yeni kayıp değil.

func (CodeContext) LogMissSummary added in v0.9.1243

func (c CodeContext) LogMissSummary() string

LogMissSummary — "kod İSTENDİ ama gelmedi" işareti (v0.9.1243).

Neden var: maskeli ai_calls kopyası, kod geldiğinde `[kod: …]` özetini taşıyor; gelmediğinde HİÇBİR ŞEY taşımıyordu. Yani bir ai_calls satırına bakan operatör "kod hiç istenmedi" ile "istendi, ıskaladı" hâllerini AYIRT EDEMİYORDU — /ai analizi ve her postmortem ıska yarısını sessizce eksik sayıyordu (isabet oranı olduğundan iyi görünüyordu; v0.9.1241 sayaçlarının çözdüğü sorunun satır-düzeyi ikizi).

Dolu bağlamda "" döner: işaret yalnız ıskanın işareti.

func (CodeContext) LogSummary added in v0.9.830

func (c CodeContext) LogSummary() string

LogSummary — maskeli ai_calls kaydına giren tek satırlık özet. Kod GÖVDESİ değil, yalnız nereden geldiği: `[kod: repo/dosya:aralık · N satır]`. Operatör hangi dosyanın modele gittiğini görür, kaynak kodun kendisi telemetri deposuna yazılmaz.

func (CodeContext) PromptBlock added in v0.9.830

func (c CodeContext) PromptBlock() string

PromptBlock — kod bağlamının prompt'a giren metni. Boş bağlam → "".

Blok bir BÜTÜN olarak taşınır: ai_calls maskeleyicisi bu metni prompt'un içinde tek parça bulup özetiyle değiştirir (emsal: clampDrawerEvidence'in LogsBlock'u aynı şekilde tek parça geçer). v0.9.1239 — pencere içi İŞARET + konum etiketi + dile göre çit. Üçü de aynı boşluğu kapatıyor: modelin pencerede NEYE bakacağı. Öncesinde her satır tıpatıp aynı ("246| kod") görünüyordu ve pencereler sırasız bir yığındı; 4B'lik bir modelden başlıktaki ":246" ile satır önekini kendi eşleştirmesi ve pencere sırasının kök-nedene göre kurulduğunu tahmin etmesi bekleniyordu.

type CodeMissCount added in v0.9.1241

type CodeMissCount struct {
	Class string `json:"class"`
	Count int64  `json:"count"`
}

CodeMissCount — bir çıkmaz kovası. Slice olarak dönüyor (map değil): ekrandaki sıra deterministik olmalı, JSON map'i değil.

type CodeOutcome added in v0.9.1241

type CodeOutcome string

CodeOutcome — bir kod-çekme denemesinin sonucu.

İki başarı hâli + on bir çıkmaz. Sınıflar FetchCode'un (ve ondan önceki buildCodeContext adımlarının) gerçek çıkışlarıyla BİREBİR; her birinin operatör için farklı bir eylemi vardır — karıştırmak "kod gelmiyor" cevabını tek bir çaresiz kutuya indirirdi.

const (
	// CodeOK — en az bir pencere geldi ve HİÇBİR kayıp yok.
	CodeOK CodeOutcome = "ok"
	// CodePartial — pencere geldi ama eksik: bütçe kesti, bir frame
	// ağaçta bulunamadı, süre/deneme tavanı doldu. Başarıyla aynı
	// kovaya koymak isabet oranını olduğundan iyi gösterirdi.
	CodePartial CodeOutcome = "partial"

	// CodeUnconfigured — DevOps bağlantısı yok/ayarlanmamış.
	// Eylem: Ayarlar → Kod entegrasyonu.
	CodeUnconfigured CodeOutcome = "unconfigured"
	// CodeRepoUnresolved — servis için depo ADI çözülemedi (katalogda
	// pin yok, konvansiyon tutmadı). Eylem: servis kataloğuna Repository.
	CodeRepoUnresolved CodeOutcome = "repo-unresolved"
	// CodeProjectDeadEnd — proje adı ne ayarda ne pinde ne de servis
	// önekinden türetilebiliyor (v0.9.1240 çıkmazı).
	CodeProjectDeadEnd CodeOutcome = "project-dead-end"
	// CodeNoStack — kayıtta stacktrace yok ya da dosya+satır taşıyan
	// uygulama frame'i yok. Eylem YOK: bu, entegrasyonun değil verinin
	// hâli. Ayrı kova olmasının tek sebebi bu — arıza sanılmasın.
	CodeNoStack CodeOutcome = "no-stack"
	// CodeCatalogError — servis kataloğu OKUNAMADI ve yanlış depoya
	// düşmemek için adım bilerek iptal edildi (fail-CLOSED, v0.9.1236).
	CodeCatalogError CodeOutcome = "catalog-error"
	// CodeEmptyTree — depo ağacı BOŞ döndü: proje/depo adı büyük
	// olasılıkla yanlış (ya da PAT'ın Code(Read) yetkisi yok).
	CodeEmptyTree CodeOutcome = "empty-tree"
	// CodeTreeMiss — ağaç geldi ama frame'lerin dosyası içinde yok.
	// Klasik sebep: yanlış depo ya da branş sürüm farkı.
	CodeTreeMiss CodeOutcome = "tree-miss"
	// CodeWindowFailed — dosya bulundu, okundu, ama pencere kurulamadı
	// (satır aralığı boş). Nadir; ayrı tutuluyor çünkü tree-miss'ten
	// TAMAMEN farklı bir hikâye.
	CodeWindowFailed CodeOutcome = "window-failed"
	// CodeDeadline — BİZİM süre tavanımız doldu (v0.9.1237). Suç
	// ayrımı korunuyor: çağıran vazgeçtiyse bu sınıf DEĞİL.
	CodeDeadline CodeOutcome = "deadline"
	// CodeCancelled — çağıran gitti (tarayıcı kapandı, üst ctx düştü).
	// DevOps'un yavaşlığı değil; deadline ile birleştirmek olmayan bir
	// yavaşlığın peşine düşürürdü.
	CodeCancelled CodeOutcome = "cancelled"
	// CodeBackendError — DevOps sunucusu hata döndü (401/404/5xx, ağ).
	// PAT süresi dolduğunda burası dolar: sessiz filo-çapında bozulmayı
	// gösteren TEK kova.
	CodeBackendError CodeOutcome = "backend-error"
	// CodeOther — sınıflandırılmamış çıkış. Sıfırdan farklı olması
	// KODDA bir eksik demek: FetchCode'a sınıf atamayan yeni bir çıkış
	// eklenmiş. Sessizce "ok" saymaktansa görünür bir kova.
	CodeOther CodeOutcome = "other"
)

type CodeStats added in v0.9.1241

type CodeStats struct {
	// Attempts — kod bağlamı İSTENEN her deneme (isabet + çıkmaz).
	Attempts int64 `json:"attempts"`
	// OK / Partial — tam ve kısmi isabet. İkisinin toplamı "kod geldi"
	// demektir; isabet oranı bu toplam / Attempts.
	OK      int64 `json:"ok"`
	Partial int64 `json:"partial"`
	// Misses — çıkmaz kovaları, ÇOKTAN AZA sıralı; sıfır olanlar hiç
	// yok. On bir boş kova göstermek asıl sinyali gömerdi.
	Misses []CodeMissCount `json:"misses,omitempty"`
	// LastUnix / LastOutcome — SON denemenin anı ve sınıfı.
	LastUnix    int64  `json:"lastUnix"`
	LastOutcome string `json:"lastOutcome,omitempty"`
	// LastError / LastErrorUnix — son BAŞARISIZ denemenin gerekçesi
	// (yapışkan, bkz. codeObs.lastErr).
	LastError     string `json:"lastError,omitempty"`
	LastErrorUnix int64  `json:"lastErrorUnix,omitempty"`
}

CodeStats — /admin/stats'ın gördüğü anlık görüntü. Tüm sayaçlar SÜREÇ BAŞLANGICINDAN beri; restart sıfırlar.

func (CodeStats) HitRate added in v0.9.1241

func (c CodeStats) HitRate() float64

HitRate — isabet oranı [0,1]. Deneme yoksa 0 (ve çağıran zaten Attempts==0'ı ayrı gösterir: "hiç denenmedi" ile "%0 isabet" aynı şey değil).

type CodeWindow added in v0.9.830

type CodeWindow struct {
	Path     string `json:"path"`     // depo içi tam yol
	Frame    string `json:"frame"`    // "com.x.Y.m(Y.java:246)"
	Line     int    `json:"line"`     // frame'in işaret ettiği satır
	FromLine int    `json:"fromLine"` // pencerenin ilk satırı (1-tabanlı)
	ToLine   int    `json:"toLine"`   // pencerenin son satırı
	Content  string `json:"content"`  // satır numarası ÖNEKLİ kaynak
	// Segment — frame'in "Caused by" zincirindeki derinliği
	// (stackparse.Frame.Segment, v0.9.1235). 0 = en dış wrapper
	// exception, 1+ = Caused by bölümleri. v0.9.1239'dan beri prompt
	// başlığına yazılıyor: pencere sırası kök-nedene göre kuruluyor
	// (AppFrames en derini başa alır) ama modele bu SIRA hiç
	// söylenmiyordu — üç pencereyi eşit ağırlıkta okuyordu.
	Segment int `json:"segment,omitempty"`
}

CodeWindow — tek frame için çekilen kaynak penceresi.

func ClampCodeWindows added in v0.9.830

func ClampCodeWindows(ws []CodeWindow, maxRunes int) ([]CodeWindow, bool)

ClampCodeWindows — pencereleri TOPLAM rune bütçesine sığdırır. trimmed=true: en az bir pencere kısaldı ya da tümüyle düştü.

Sıra korunur: ilk pencere kök nedene en yakın olandır (AppFrames v0.9.1235'ten beri en derin "Caused by" segmentini başa koyuyor), bütçe daralınca düşecek olan SON penceredir — yani dıştaki wrapper/yeniden-fırlatma kodu. Kesme rune bazlı ve pencere içindeki SATIR sınırında yapılır — yarım satır kod, kod değildir.

Kesme MERKEZDEN yapılır (v0.9.1239)

Pencere hata satırının ÜSTÜNDEN başlar (line-30). Kırpma baştan saymayla yapılırsa — v0.9.1239 öncesi hâli — kalan bütçe pencerenin yarısından azken korunan satırlar hata satırına VARMADAN biter: prompt başlığı hâlâ "… (Y.java:246)" diye satırı gösterir, o satır pencerede YOKTUR. Küçük model bunu "246 bu blokta bir yerde" diye okuyup gördüğü rastgele satırdan kök neden uydurur. Halved() bütçeyi 2000'e indirdiğinde ilk pencere bile merkezini kaybediyordu, yani taşma yeniden-denemesi tam da en çok kanıt gereken anda pencereyi işe yaramaz hâle getiriyordu.

Artık kırpma frame satırı MERKEZDE kalacak şekilde iki yandan daraltılır. Hata satırı tek başına bile bütçeye sığmıyorsa pencere DÜŞER: kullanılamaz bir pencere, hiç pencere olmamasından kötüdür (çağıran düşüşü Reason'a yazar). Line=0 olan pencerede (frame satırı bilinmiyor) eski baştan-kesme davranışı korunur.

func WindowAround added in v0.9.830

func WindowAround(content string, line, radius int) CodeWindow

WindowAround — dosya içeriğinden `line` merkezli ±radius satırlık pencere; satırlar numaralandırılır (" 246| kod"). Numaralar şart: modelin "246. satırdaki null kontrolü" diyebilmesi, operatörün de cevabı dosyada bulabilmesi için.

line dosyanın dışındaysa (kaynak stack'ten sonra değişmiş) pencere dosya sınırlarına kırpılır — boş dönmek yerine yakını göstermek daha faydalı, ve satır numaraları zaten gerçeği söylüyor.

type DryRunResult added in v0.9.1242

type DryRunResult struct {
	Service string `json:"service"`
	// OK — zincirin TAMAMI yürüdü mü (ağaç dahil).
	OK    bool         `json:"ok"`
	Steps []DryRunStep `json:"steps"`
	// Özet alanlar — ekranın başlık satırı. Adımlardan türer;
	// çözülemeyen alan boş kalır.
	Repo    string `json:"repo,omitempty"`
	Project string `json:"project,omitempty"`
	Branch  string `json:"branch,omitempty"`
	// Source — depo adının kaynağı (pin | convention).
	Source string `json:"source,omitempty"`
	// FileCount — ağaçtaki dosya sayısı. Yollar DÖNMEZ.
	FileCount int `json:"fileCount,omitempty"`
}

DryRunResult — provanın tamamı. Steps SIRALI ve zincir nerede durduysa orada biter: yarısı yeşil, biri kırmızı, gerisi YOK. Koşmamış bir adımı "başarısız" göstermek, operatörü olmayan bir arızanın peşine düşürürdü.

type DryRunStep added in v0.9.1242

type DryRunStep struct {
	Key    string `json:"key"`
	Label  string `json:"label"`
	OK     bool   `json:"ok"`
	Detail string `json:"detail"`
}

DryRunStep — tek adımın sonucu. Detail her iki hâlde de DOLU: başarıda ne bulunduğu, başarısızlıkta neden bulunamadığı.

type PinRead added in v0.9.1242

type PinRead struct {
	// Repo — katalogdaki `repository` alanı ("" = pin yok).
	Repo string
	// Abort — katalog OKUNAMADI, adım fail-CLOSED iptal edildi
	// (v0.9.1236). Doluysa zincir burada durur; gerçek yolda da
	// öyle durur.
	Abort string
}

PinRead — servis kataloğu okumasının SONUCU.

devops paketi CH'yi bilmiyor (paket doc'u), o yüzden okumayı internal/api yapar ve sonucu buraya taşır. Şekil, gerçek yoldaki pinReadDecision'ın dönüşüyle birebir: (pin, iptal).

type ProjectHint added in v0.9.1240

type ProjectHint struct {
	Value  string // önerilen proje ("" = öneri yok)
	Source string // RepoSourcePin | RepoSourceConvention | ""
	Reason string // Value=="" iken pin + önek kaynaklarının durumu
}

ProjectHint — proje adı ÖNERİSİ, kaynağı ve (boşsa) neden boş kaldığı.

v0.9.1240 — üçüncü alan Reason yeni: proje çözülemediğinde çıkmazın nedeni ÜÇ kaynağa dağılmış durumda (pinin proje bileşeni, Ayarlar'daki Project, önek türetimi) ve ikisini yalnız burası bilir. FetchCode yalnız Ayarlar'ı görüyor, o yüzden tek başına yazdığı cümle ("servis adı bilinen bir önekle başlamıyor") pin kısa devresi yüzünden düpedüz YANLIŞ olabiliyordu: önek tutuyor, türetim hiç koşmuyordu.

type RepoNameMatch added in v0.9.1236

type RepoNameMatch struct {
	Name string   // sunucudaki kanonik ad ("" = eşleşme yok)
	Rung string   // exact | fold | loose
	Alts []string // AYNI basamakta eşleşen diğer adaylar (deterministik)
	Near []string // eşleşme yoksa en yakın adlar (≤ repoNearMax)
}

RepoNameMatch — istenen ad ↔ sunucudaki kanonik adlar eşleşmesi.

Name boşsa eşleşme yok ve Near doludur (varsa). Rung hangi basamağın tuttuğunu söyler — düzeltme izini yazan taraf bunu okumaz ama test okur: "fold" beklenen yerde "loose" tutuyorsa normalizasyon çok gevşemiş demektir.

func MatchRepoName added in v0.9.1236

func MatchRepoName(want string, have []string) RepoNameMatch

MatchRepoName — SAF eşleştirici; tablo-testli, ağ yok.

Basamaklar SIRAYLA denenir ve ilk DOLU basamak kazanır: harf-yazımı eşleşmesi varken ayraç-soyulmuş bir adaya geçmek, daha zayıf kanıtı daha güçlüsüne tercih etmek olurdu.

Aynı basamakta birden çok aday varsa seçim DETERMİNİSTİK: adlar sıralanır, ilki kazanır, kalanlar Alts'a düşer. Sunucunun liste sırasına güvenmek, aynı sorgunun iki farklı depoyu açması demekti — yanlış depodan kod göstermek bu özelliğin en pahalı hatası.

type RepoResolution added in v0.9.830

type RepoResolution struct {
	Repo   string
	Source string
	Reason string
	// Project (v0.9.1183, operatör isteği: "service_name başında bsa-
	// yazıyorsa direkt project BSA olduğunu anlasın") — DevOps proje
	// ÖNERİSİ + önerinin kaynağı.
	//
	// Yalnız bir ÖNERİ: ayardaki açık Project her zaman kazanır (FetchCode
	// sırası). Önek zaten "bu servis şu projeye ait" bilgisini taşıyor
	// (kurulumun kendi adlandırma sözleşmesi), o yüzden aynı bilgiyi
	// ikinci bir alana daha yazdırmak gereksiz bir el işiydi — ve boş
	// bırakıldığında kod bağlamı sessizce hiç çalışmıyordu.
	Project ProjectHint
}

RepoResolution — çözüm sonucu + NEDEN. Reason boş bir sonuçta operatöre gösterilir ("neden kod yok" sorusunun cevabı).

func ResolveRepo added in v0.9.830

func ResolveRepo(service, metaRepository string, cfg ResolveConfig) RepoResolution

ResolveRepo — servis adı + service_metadata.repository → depo adı.

metaRepository tam bir URL de olabilir (operatörler katalog alanına çoğunlukla depo linkini yapıştırır); son yol parçası alınır ve ".git" eki atılır. "_git/" segmenti varsa ondan SONRASI alınır — Azure DevOps depo linklerinin kanonik şekli budur.

Saf. Branş seçimi ayrıdır (PickBranch + refs API): branş varlığı sunucuya sorulmadan bilinemez.

type ResolveConfig added in v0.9.830

type ResolveConfig struct {
	RepoPrefixes []string
	BranchOrder  []string
}

ResolveConfig — çözücünün ayarlanabilir kısmı. Boş alanlar varsayılana düşer, yani sıfır değer çalışır bir yapılandırmadır.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service holds the live config + a pooled HTTP client.

func New

func New() *Service

func (*Service) CodeObservability added in v0.9.1241

func (s *Service) CodeObservability() CodeStats

CodeObservability — sayaçların anlık görüntüsü; API sunucusu /admin/stats için çağırır (anomaly.BehaviorObservability muadili).

func (*Service) Configure

func (s *Service) Configure(cfg Settings)

Configure swaps the live config. Rebuilds the HTTP client when the TLS-verify flag flips so a connection pooled under the old certificate policy can't outlive the toggle. Any recorded detection is dropped — it described the PREVIOUS endpoint.

func (*Service) Configured

func (s *Service) Configured() bool

Configured reports whether a server URL has been set.

func (*Service) CurrentSettings

func (s *Service) CurrentSettings() Settings

CurrentSettings returns the full config INCLUDING the PAT. Only for the settings handler's stored-secret merge — never call this from a path that writes its return value to the wire.

func (*Service) FetchCode added in v0.9.830

func (s *Service) FetchCode(ctx context.Context, repo string, hint ProjectHint, frames []stackparse.Frame) (out CodeContext)

FetchCode — bir depodaki frame'ler için kod pencereleri toplar.

repo boşsa ya da bağlantı yapılandırılmamışsa boş + Reason döner; HATA DÖNDÜRMEZ (fail-open sözleşmesi — imzada error yok ki çağıran yanlışlıkla açıklamayı düşürmesin). hint (v0.9.1183, v0.9.1240'ta yapılandırıldı) — proje ÖNERİSİ + önerinin kaynağı, öneri boşsa çıkmazın nedeni. Ayardaki açık Project boşsa kullanılır. Operatör isteği: "service_name başında bsa- yazıyorsa direkt project BSA olduğunu anlasın."

v0.9.1241 — her çıkış SAYILIR. Dönüş DEĞERİ adlandırıldı ve sayaç tek bir defer'den geçiyor: on dört çıkışın her birine elle sayaç eklemek, on beşinci eklendiğinde sessizce eksik kalırdı. Sınıfı atamayan bir dal "other" kovasına düşer — görünür bir eksik, sessiz bir "ok" değil.

func (*Service) LoadPersisted

func (s *Service) LoadPersisted(ctx context.Context, store settingsStore) error

LoadPersisted hydrates the in-memory config from system_settings. Missing blob = empty config (Configured reports false).

func (*Service) RecordCodeOutcome added in v0.9.1241

func (s *Service) RecordCodeOutcome(class CodeOutcome, reason string)

RecordCodeOutcome — kod-çekme sonucunu sayar. FetchCode'dan ÖNCEKİ adımlar (katalog okuması, depo çözümü — internal/api) da buradan geçer: sayaç "operatör kod istedi" anını ölçmeli, yalnız işin FetchCode'a kadar gelebilen kısmını değil.

nil-Service güvenli: kod entegrasyonu hiç kurulmamış bir sürecte çağıran ekstra bir muhafız yazmak zorunda kalmasın.

func (*Service) ResolveConfig added in v0.9.830

func (s *Service) ResolveConfig() ResolveConfig

ResolveConfig returns the service→repo convention with defaults already folded in, so callers never have to know what the fallback is. Safe on a nil Service (returns the bundled defaults).

func (*Service) ResolveDryRun added in v0.9.1242

func (s *Service) ResolveDryRun(ctx context.Context, service string, pin PinRead) DryRunResult

ResolveDryRun — servis adı → depo/branş/ağaç, adım adım. LLM YOK, yazma YOK, sayaç YOK.

Zincir ilk kırmızıda DURUR. Bağlantı yoksa hiç başlamaz: türetilmiş bir depo adını sunucuya sormadan göstermek, doğrulanmamış bir tahmini cevap gibi sunmak olurdu — bu ekranın var olma sebebi tam da o yanılgıyı bitirmek.

func (*Service) SavePersisted

func (s *Service) SavePersisted(ctx context.Context, store settingsStore, cfg Settings) error

SavePersisted writes the typed config to system_settings and swaps the live client. The handler merges the stored PAT in before calling this — see api.mergeDevOpsSettings.

func (*Service) Snapshot

func (s *Service) Snapshot() Snapshot

Snapshot returns the public config view (no PAT).

func (*Service) StartConfigRefresh

func (s *Service) StartConfigRefresh(ctx context.Context, store settingsStore, interval time.Duration)

StartConfigRefresh keeps peer pods converged on the shared blob (tempo/thanos template). interval ≤ 0 → 30s.

func (*Service) Test

func (s *Service) Test(ctx context.Context, cfg Settings) TestResult

Test probes a CANDIDATE config without saving or swapping anything — the Settings tab's "Test connection" button. On success against the live endpoint it records the detected flavor so the Snapshot can report it.

func (*Service) TestConnection

func (s *Service) TestConnection(ctx context.Context) TestResult

TestConnection probes the LIVE config.

type Settings

type Settings struct {
	// BaseURL is the server root, with or without the collection.
	// e.g. https://devops.example.local/tfs
	BaseURL string `json:"baseUrl"`
	// Collection is the TFS collection / Azure DevOps organisation
	// segment, e.g. "DefaultCollection". Empty is allowed for
	// installs that already carry it inside BaseURL.
	Collection string `json:"collection,omitempty"`
	// Project is optional. When set, TestConnection verifies the
	// project resolves as well as the collection.
	Project string `json:"project,omitempty"`
	// Username is optional. PAT auth conventionally sends an EMPTY
	// username with the PAT as the password; NTLM-era TFS installs
	// sometimes want a real account name alongside it.
	Username string `json:"username,omitempty"`
	// PAT is the personal access token — the secret. Never echoed
	// in Snapshot(), never interpolated into an error string, never
	// written to audit_log.
	PAT string `json:"pat,omitempty"`
	// Flavor — auto | azure-devops-server | tfs.
	Flavor string `json:"flavor,omitempty"`
	// InsecureSkipVerify relaxes TLS chain verification, for the
	// internal CA / self-signed certs common on on-prem servers.
	InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
	// RepoPrefixes / BranchOrder (v0.9.830) — the service→repo naming
	// convention. Empty = the bundled defaults (see repo_resolve.go).
	//
	// These live in the SAME blob rather than a new settings key: one
	// integration, one row (invariant 5's spirit — no new schema per
	// surface). They are not secrets and DO round-trip through the
	// snapshot, unlike the PAT — the secret contract is unchanged.
	RepoPrefixes []string `json:"repoPrefixes,omitempty"`
	BranchOrder  []string `json:"branchOrder,omitempty"`
}

Settings is the persisted connection config, stored as a JSON blob under the system_settings key "devops_connection".

type Snapshot

type Snapshot struct {
	BaseURL            string `json:"baseUrl"`
	Collection         string `json:"collection,omitempty"`
	Project            string `json:"project,omitempty"`
	Username           string `json:"username,omitempty"`
	HasPAT             bool   `json:"hasPat"`
	Flavor             string `json:"flavor,omitempty"`
	InsecureSkipVerify bool   `json:"insecureSkipVerify,omitempty"`
	DetectedFlavor     string `json:"detectedFlavor,omitempty"`
	DetectedAPIVersion string `json:"detectedApiVersion,omitempty"`
	// RepoPrefixes / BranchOrder (v0.9.830) — echoed back RESOLVED, i.e.
	// the defaults appear when the operator saved nothing. The card
	// would otherwise render two empty boxes next to a resolver that is
	// quietly using "bsa-" and release→master, and the first question
	// out of a failed lookup would be "but what IS it stripping?".
	RepoPrefixes []string `json:"repoPrefixes,omitempty"`
	BranchOrder  []string `json:"branchOrder,omitempty"`
}

Snapshot is the public view returned by GET /api/settings/devops. Mirrors Settings with the PAT replaced by a HasPAT signal.

DetectedFlavor / DetectedAPIVersion report what the last successful probe of THIS config actually spoke. They are in-memory only and deliberately NOT persisted: re-detecting at boot costs one request and can never go stale, whereas a written-back guess survives a server upgrade and starts lying.

type TestResult

type TestResult struct {
	OK             bool   `json:"ok"`
	DetectedFlavor string `json:"detectedFlavor,omitempty"`
	APIVersion     string `json:"apiVersion,omitempty"`
	ProjectCount   int    `json:"projectCount"`
	// ProjectChecked is true when Settings.Project was set and the
	// project lookup ran, so the UI can say "collection + project OK"
	// rather than implying it verified something it didn't.
	ProjectChecked bool   `json:"projectChecked,omitempty"`
	Error          string `json:"error,omitempty"`
}

TestResult is the POST /api/settings/devops/test response. Either OK with a project count, or a sanitised error string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL