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
- func BestPathForFrame(paths []string, f stackparse.Frame) string
- func DefaultBranchOrder() []string
- func DefaultRepoPrefixes() []string
- func MaskCodeInPrompt(full, block, summary string) string
- func PickBranch(available []string, order []string) string
- func ShortBranch(ref string) string
- type CodeContext
- type CodeWindow
- type RepoResolution
- type ResolveConfig
- type Service
- func (s *Service) Configure(cfg Settings)
- func (s *Service) Configured() bool
- func (s *Service) CurrentSettings() Settings
- func (s *Service) FetchCode(ctx context.Context, repo string, frames []stackparse.Frame) CodeContext
- func (s *Service) LoadPersisted(ctx context.Context, store settingsStore) error
- func (s *Service) ResolveConfig() ResolveConfig
- func (s *Service) SavePersisted(ctx context.Context, store settingsStore, cfg Settings) error
- func (s *Service) Snapshot() Snapshot
- func (s *Service) StartConfigRefresh(ctx context.Context, store settingsStore, interval time.Duration)
- func (s *Service) Test(ctx context.Context, cfg Settings) TestResult
- func (s *Service) TestConnection(ctx context.Context) TestResult
- type Settings
- type Snapshot
- type TestResult
Constants ¶
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.
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.
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 MaskCodeInPrompt ¶ added in v0.9.830
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
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.
func ShortBranch ¶ added in v0.9.830
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"`
}
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.
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).
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
}
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 frame hataya en yakın olandır, bütçe daralınca düşecek olan SON frame'dir. Kesme rune bazlı ve pencere içindeki SATIR sınırında yapılır — yarım satır kod, kod değildir.
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 RepoResolution ¶ added in v0.9.830
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
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 (*Service) Configure ¶
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 ¶
Configured reports whether a server URL has been set.
func (*Service) CurrentSettings ¶
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, frames []stackparse.Frame) 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).
func (*Service) LoadPersisted ¶
LoadPersisted hydrates the in-memory config from system_settings. Missing blob = empty config (Configured reports false).
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) SavePersisted ¶
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) 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.