devops

package
v0.9.855 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2026 License: MIT Imports: 14 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 (
	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

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.

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"`
}

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

type RepoResolution struct {
	Repo   string
	Source string
	Reason string
}

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) 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, 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

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) 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

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