Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .allowed-licenses
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Allowed licenses for git-sync
# One license type per line
# Comments start with #

MIT
BSD-2-Clause
BSD-3-Clause
Apache-2.0
MPL-2.0
CC0-1.0
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Tests
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1
- name: Tests
run: mise run test:ci
12 changes: 12 additions & 0 deletions .github/workflows/license-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: License Check

on:
workflow_dispatch:
pull_request:
push:
branches:
- main

jobs:
check-licenses:
uses: entireio/shared/.github/workflows/license-check-reusable.yml@main
34 changes: 34 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Lint
on:
workflow_dispatch:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: 'stable'

- uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1

- name: Run linters
run: mise run lint

# Uses the same config as `mise run lint:go`, but with special sauce to
# create inline feedback on GitHub's UI. On local dev, the same issues
# should be surfaced by mise-tasks/lint/go
- name: Run golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: 'v2.11.4'
debug: 'clean'
118 changes: 118 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
version: "2"
issues:
max-issues-per-linter: 0
max-same-issues: 0
linters:
default: standard
enable:
- asciicheck
- bidichk
- bodyclose
- canonicalheader
- copyloopvar
- decorder
- durationcheck
- embeddedstructfieldcheck
- errchkjson
- errname
- errorlint
- exhaustive
- exptostd
- forcetypeassert
- gocheckcompilerdirectives
- gochecknoinits
- gochecksumtype
- goconst
- gocritic
- gosec
- govet
- grouper
- iface
- importas
- inamedparam
- ineffassign
- intrange
- ireturn
- loggercheck
- maintidx
- makezero
- mirror
- misspell
- musttag
- nakedret
- nilerr
- nilnesserr
- nilnil
- noctx
- nolintlint
- nosprintfhostport
- perfsprint
- promlinter
- protogetter
- reassign
- recvcheck
- revive
- sloglint
- spancheck
- staticcheck
- tagalign
- testableexamples
- testifylint
- tparallel
- unconvert
- unparam
- unused
- usestdlibvars
- usetesting
- wastedassign
- whitespace
- wrapcheck
settings:
gosec:
excludes:
- G104 # errors are handled at appropriate levels, checked by errcheck linter
- G115 # integer overflow in flock fd conversion is safe on all platforms
- G204 # subprocess with variables is expected for git credential helpers
- G301 # directory permissions 0755 are fine for local data dirs
- G304 # file paths from variables are expected in token store and config readers
- G703 # path traversal via taint is expected when reading user config files
dupl:
threshold: 75
errcheck:
check-type-assertions: true
check-blank: true
govet:
enable-all: true
disable:
- fieldalignment
- shadow
ireturn:
allow:
- anon
- error
- empty
- stdlib
- github.com/go-git/go-git/v6/plumbing/storer.ReferenceIter
- github.com/go-git/go-git/v6/plumbing.EncodedObject
- github.com/go-git/go-git/v6/storage.Storer
- github.com/go-git/go-git/v6/plumbing/storer.EncodedObjectIter
- github.com/go-git/go-billy/v6.Filesystem
- github.com/go-git/go-git/v6/plumbing/transport.AuthMethod
nolintlint:
require-explanation: true
require-specific: true
sloglint:
attr-only: true
testifylint:
enable-all: true
unparam:
check-exported: true
exclusions:
presets:
- comments
- std-error-handling
rules:
- path: _test\.go
linters:
- gosec
- wrapcheck
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,13 @@ Add `--json` to `probe`, `fetch`, `bootstrap`, `plan`, or `sync` to emit machine

The JSON interface is intentionally stable:

- keys use `snake_case`
- keys use `camelCase`
- refs and hashes are serialized as strings, not raw byte arrays
- `probe` returns top-level keys such as `source_url`, `target_url`, `protocol`, `ref_prefixes`, `source_capabilities`, `target_capabilities`, `refs`, and `stats`
- `fetch` returns top-level keys such as `source_url`, `protocol`, `wants`, `haves`, `fetched_objects`, and `stats`
- `bootstrap`, `plan`, and `sync` return top-level keys such as `plans`, `pushed`, `skipped`, `blocked`, `deleted`, `dry_run`, `protocol`, and `stats`
- `bootstrap`, `plan`, and `sync` also expose `relay`, `relay_mode`, `relay_reason`, `batching`, `batch_count`, `planned_batch_count`, and `temp_refs`
- each item in `plans` includes stable string fields such as `branch`, `source_ref`, `target_ref`, `source_hash`, `target_hash`, `kind`, `action`, and `reason`
- `probe` returns top-level keys such as `sourceUrl`, `targetUrl`, `protocol`, `refPrefixes`, `sourceCapabilities`, `targetCapabilities`, `refs`, and `stats`
- `fetch` returns top-level keys such as `sourceUrl`, `protocol`, `wants`, `haves`, `fetchedObjects`, and `stats`
- `bootstrap`, `plan`, and `sync` return top-level keys such as `plans`, `pushed`, `skipped`, `blocked`, `deleted`, `dryRun`, `protocol`, and `stats`
- `bootstrap`, `plan`, and `sync` also expose `relay`, `relayMode`, `relayReason`, `batching`, `batchCount`, `plannedBatchCount`, and `tempRefs`
- each item in `plans` includes stable string fields such as `branch`, `sourceRef`, `targetRef`, `sourceHash`, `targetHash`, `kind`, `action`, and `reason`

## Auth

Expand Down
74 changes: 41 additions & 33 deletions cmd/git-sync-bench/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,49 +29,49 @@ const (

type runSummary struct {
Index int `json:"index"`
TargetPath string `json:"target_path"`
TargetURL string `json:"target_url"`
WallMillis int64 `json:"wall_millis"`
TargetPath string `json:"targetPath"`
TargetURL string `json:"targetUrl"`
WallMillis int64 `json:"wallMillis"`
Result unstable.Result `json:"result"`
Error string `json:"error,omitempty"`
}

type aggregateSummary struct {
SuccessfulRuns int `json:"successful_runs"`
FailedRuns int `json:"failed_runs"`
BatchedRuns int `json:"batched_runs"`
MinWallMillis int64 `json:"min_wall_millis"`
MaxWallMillis int64 `json:"max_wall_millis"`
AvgWallMillis float64 `json:"avg_wall_millis"`
MinSyncElapsedMillis int64 `json:"min_sync_elapsed_millis"`
MaxSyncElapsedMillis int64 `json:"max_sync_elapsed_millis"`
AvgSyncElapsedMillis float64 `json:"avg_sync_elapsed_millis"`
MinBatchCount int `json:"min_batch_count,omitempty"`
MaxBatchCount int `json:"max_batch_count,omitempty"`
AvgBatchCount float64 `json:"avg_batch_count,omitempty"`
MinPlannedBatchCount int `json:"min_planned_batch_count,omitempty"`
MaxPlannedBatchCount int `json:"max_planned_batch_count,omitempty"`
AvgPlannedBatchCount float64 `json:"avg_planned_batch_count,omitempty"`
MaxPeakAllocBytes uint64 `json:"max_peak_alloc_bytes"`
MaxPeakHeapInuseBytes uint64 `json:"max_peak_heap_inuse_bytes"`
MaxTotalAllocBytes uint64 `json:"max_total_alloc_bytes"`
MaxGCCount uint32 `json:"max_gc_count"`
RelayModes []string `json:"relay_modes,omitempty"`
SuccessfulRuns int `json:"successfulRuns"`
FailedRuns int `json:"failedRuns"`
BatchedRuns int `json:"batchedRuns"`
MinWallMillis int64 `json:"minWallMillis"`
MaxWallMillis int64 `json:"maxWallMillis"`
AvgWallMillis float64 `json:"avgWallMillis"`
MinSyncElapsedMillis int64 `json:"minSyncElapsedMillis"`
MaxSyncElapsedMillis int64 `json:"maxSyncElapsedMillis"`
AvgSyncElapsedMillis float64 `json:"avgSyncElapsedMillis"`
MinBatchCount int `json:"minBatchCount,omitempty"`
MaxBatchCount int `json:"maxBatchCount,omitempty"`
AvgBatchCount float64 `json:"avgBatchCount,omitempty"`
MinPlannedBatchCount int `json:"minPlannedBatchCount,omitempty"`
MaxPlannedBatchCount int `json:"maxPlannedBatchCount,omitempty"`
AvgPlannedBatchCount float64 `json:"avgPlannedBatchCount,omitempty"`
MaxPeakAllocBytes uint64 `json:"maxPeakAllocBytes"`
MaxPeakHeapInuseBytes uint64 `json:"maxPeakHeapInuseBytes"`
MaxTotalAllocBytes uint64 `json:"maxTotalAllocBytes"`
MaxGCCount uint32 `json:"maxGcCount"`
RelayModes []string `json:"relayModes,omitempty"`
}

type benchmarkReport struct {
Scenario scenario `json:"scenario"`
SourceURL string `json:"source_url"`
SourceURL string `json:"sourceUrl"`
Repeat int `json:"repeat"`
KeepTargets bool `json:"keep_targets"`
WorkDir string `json:"work_dir"`
KeepTargets bool `json:"keepTargets"`
WorkDir string `json:"workDir"`
Config benchmarkConfig `json:"config"`
Aggregate aggregateSummary `json:"aggregate"`
Runs []runSummary `json:"runs"`
}

type benchmarkConfig struct {
SourceURL string `json:"source_url"`
SourceURL string `json:"sourceUrl"`
Scope gitsync.RefScope `json:"scope"`
Policy gitsync.SyncPolicy `json:"policy"`
Options unstable.AdvancedOptions `json:"options"`
Expand Down Expand Up @@ -117,7 +117,7 @@ func run(ctx context.Context, args []string) error {
fs.BoolVar(&cfg.Options.Verbose, "v", false, "verbose logging")

if err := fs.Parse(args); err != nil {
return err
return fmt.Errorf("parse flags: %w", err)
}
cfg.Policy.Protocol = gitsync.ProtocolMode(benchProtocol)
if len(fs.Args()) > 0 {
Expand All @@ -133,7 +133,7 @@ func run(ctx context.Context, args []string) error {
for _, raw := range mappings {
mapping, err := validation.ParseMapping(raw)
if err != nil {
return err
return fmt.Errorf("parse mapping %q: %w", raw, err)
}
cfg.Scope.Mappings = append(cfg.Scope.Mappings, gitsync.RefMapping{
Source: mapping.Source,
Expand Down Expand Up @@ -178,7 +178,7 @@ func run(ctx context.Context, args []string) error {
Runs: make([]runSummary, 0, repeat),
}

for i := 0; i < repeat; i++ {
for i := range repeat {
runCfg := cfg
targetPath := filepath.Join(workDir, fmt.Sprintf("%s-run-%03d.git", sc, i+1))
if err := os.RemoveAll(targetPath); err != nil {
Expand Down Expand Up @@ -231,22 +231,30 @@ func executeScenario(ctx context.Context, sc scenario, cfg benchmarkConfig, targ
client := unstable.New(unstable.Options{})
switch sc {
case scenarioBootstrap:
return client.Bootstrap(ctx, unstable.BootstrapRequest{
result, err := client.Bootstrap(ctx, unstable.BootstrapRequest{
Source: gitsync.Endpoint{URL: cfg.SourceURL},
Target: gitsync.Endpoint{URL: targetURL},
Scope: cfg.Scope,
IncludeTags: cfg.Policy.IncludeTags,
Protocol: cfg.Policy.Protocol,
Options: cfg.Options,
})
if err != nil {
return unstable.Result{}, fmt.Errorf("bootstrap: %w", err)
}
return result, nil
case scenarioSync:
return client.Sync(ctx, unstable.SyncRequest{
result, err := client.Sync(ctx, unstable.SyncRequest{
Source: gitsync.Endpoint{URL: cfg.SourceURL},
Target: gitsync.Endpoint{URL: targetURL},
Scope: cfg.Scope,
Policy: cfg.Policy,
Options: cfg.Options,
})
if err != nil {
return unstable.Result{}, fmt.Errorf("sync: %w", err)
}
return result, nil
default:
return unstable.Result{}, fmt.Errorf("unsupported scenario %q", sc)
}
Expand Down Expand Up @@ -460,7 +468,7 @@ func (p *benchProtocolModeFlag) String() string {
func (p *benchProtocolModeFlag) Set(value string) error {
mode, err := validation.NormalizeProtocolMode(value)
if err != nil {
return err
return fmt.Errorf("normalize protocol: %w", err)
}
*p = benchProtocolModeFlag(benchProtocolMode(gitsync.ProtocolMode(mode)))
return nil
Expand Down
Loading
Loading