Skip to content
Open
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
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ updates:
- /
- /exp
- /tutorial/whatsup
- /api/prometheus/v1/paritytest
schedule:
interval: "monthly"
groups:
Expand Down
143 changes: 143 additions & 0 deletions .github/workflows/parity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
name: Parity
# The parity tests compile the pinned prometheus/prometheus release
# against the in-tree client_golang main module (see
# api/prometheus/v1/paritytest). They run as their own workflow, rather
# than inside `make test`, so that unrelated PRs don't pay the cost of
# building Prometheus and a parity failure is clearly labeled as such
# instead of surfacing as an unrelated red test job.
#
# The path filters cover the inputs most likely to change parity
# behavior. Because of the module's replace directive, any in-tree
# package that prometheus imports (prometheus/, promauto/, ...) can in
# principle break this build too; those paths are deliberately not
# filtered on, to avoid re-coupling most of CI to the pinned version.
# Breakage sneaking in through them is caught by the weekly scheduled
# run and by the next PR that does match the filters.
on:
pull_request:
paths:
- "api/prometheus/v1/**"
- "go.mod"
- "go.sum"
- "Makefile"
- "Makefile.common"
- "supported_go_versions.json"
- ".github/workflows/parity.yml"
push:
branches:
- main
- "release-*"
paths:
- "api/prometheus/v1/**"
- "go.mod"
- "go.sum"
- "Makefile"
- "Makefile.common"
- "supported_go_versions.json"
- ".github/workflows/parity.yml"
schedule:
# Weekly drift check against the newest prometheus/prometheus
# release (see parity-latest below), so upstream type changes are
# noticed even if the dependabot bump of the pinned version fails
# to materialize.
- cron: "42 7 * * 1"

concurrency:
# github.event_name is part of the key because push-to-main and
# schedule runs otherwise share a group (both resolve to
# refs/heads/main) and would cancel each other, silently dropping
# either the weekly drift check or the post-merge parity run.
group: ${{ github.workflow }}-${{ github.event_name }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read

jobs:
supported_versions:
name: Fetch supported Go versions
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.versions.outputs.matrix }}
stable: ${{ steps.versions.outputs.stable }}
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Get supported Go versions JSON
id: versions
run: |
echo "matrix=$(cat supported_go_versions.json | jq -c .)" >> "$GITHUB_OUTPUT"
echo "stable=$(jq -r '.versions[] | select(.label == "stable") | .version' supported_go_versions.json)" >> "$GITHUB_OUTPUT"

parity:
name: Parity (${{ matrix.label }})
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
needs: supported_versions
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.supported_versions.outputs.matrix).versions }}
concurrency:
group: ${{ github.workflow }}-parity-${{ matrix.label }}-${{ (github.event.pull_request && github.event.pull_request.number) || github.ref || github.run_id }}
cancel-in-progress: true

steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Go ${{ matrix.version }}
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: ${{ matrix.version }}
check-latest: true
# The parity module's replace directive resolves client_golang
# requirements from the root go.mod, so both sums shape its
# build.
cache-dependency-path: |
go.sum
api/prometheus/v1/paritytest/go.sum

- name: Run parity tests
run: make test-parity
env:
CI: true

parity-latest:
name: Parity vs latest prometheus
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
needs: supported_versions
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
# Selected by label rather than positionally: nothing
# guarantees the stable entry is listed first in
# supported_go_versions.json.
go-version: ${{ needs.supported_versions.outputs.stable }}
check-latest: true
cache-dependency-path: |
go.sum
api/prometheus/v1/paritytest/go.sum

- name: Bump prometheus to latest release
run: |
cd api/prometheus/v1/paritytest
go get github.com/prometheus/prometheus@latest
go mod tidy

- name: Run parity tests
run: make test-parity
env:
CI: true
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

* [CHANGE] **breaking** api/prometheus/v1: Fix `TSDBBlocks` so it can decode real server responses; fixes issues with data enveloping and aligns the TSDB Blocks struct types to match the upstream Prometheus counterpart. #1928

## 1.24.1 / 2026-07-23

* [BUGFIX] promhttp: Fix panic on requests with nil URL. #2065
Expand Down
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ test-exp:
test-exp-short:
cd exp && $(GOTEST) -short $(GOOPTS) $(pkgs)

# Download-only on purpose: running `go mod tidy` here would silently
# rewrite the tracked go.mod/go.sum whenever main-module dependencies
# change, because the module's replace directive resolves client_golang's
# requirements from the root go.mod. A stale go.sum should instead fail
# test-parity loudly ("missing go.sum entry"); the fix is to run
# `go mod tidy` in api/prometheus/v1/paritytest and commit the result.
.PHONY: parity-deps
parity-deps:
cd api/prometheus/v1/paritytest && $(GO) mod download

# Runs the API parity tests, which live in their own module so that
# their prometheus/prometheus dependency stays out of the main module.
# Deliberately not part of test/test-short: the module compiles the
# pinned prometheus/prometheus release against the in-tree
# client_golang main module (the separate exp module resolves from the
# proxy), a build that exists to catch drift in the v1 API types, so
# CI runs it as the dedicated path-filtered Parity workflow
# (.github/workflows/parity.yml) instead of on every PR.
.PHONY: test-parity
test-parity: parity-deps
cd api/prometheus/v1/paritytest && $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs)

.PHONY: check-crlf
check-crlf:
@echo ">> checking for CRLF line endings"
Expand Down
84 changes: 53 additions & 31 deletions api/prometheus/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,38 +696,60 @@ type TSDBHeadStats struct {
MaxTime int `json:"maxTime"`
}

// TSDBBlocksResult contains the results from querying the tsdb blocks endpoint.
// TSDBBlocksResult contains the result from querying the tsdb blocks endpoint.
//
// Note: TSDB block types are defined locally rather than importing from
// prometheus/prometheus to avoid circular dependencies and minimize the
// dependency footprint. These types match the HTTP API wire format and use
// string for ULID fields (since JSON serializes ULIDs as strings). See the
// individual type comments for links to upstream Prometheus definitions.
type TSDBBlocksResult struct {
Status string `json:"status"`
Data TSDBBlocksData `json:"data"`
}

// TSDBBlocksData contains the metadata for the tsdb blocks.
type TSDBBlocksData struct {
Blocks []TSDBBlocksBlockMetadata `json:"blocks"`
}

// TSDBBlocksBlockMetadata contains the metadata for a single tsdb block.
type TSDBBlocksBlockMetadata struct {
Ulid string `json:"ulid"`
MinTime int64 `json:"minTime"`
MaxTime int64 `json:"maxTime"`
Stats TSDBBlocksStats `json:"stats"`
Compaction TSDBBlocksCompaction `json:"compaction"`
Version int `json:"version"`
}

// TSDBBlocksStats contains block stats for a single tsdb block.
type TSDBBlocksStats struct {
NumSamples int `json:"numSamples"`
NumSeries int `json:"numSeries"`
NumChunks int `json:"numChunks"`
}

// TSDBBlocksCompaction contains block compaction details for a single block.
type TSDBBlocksCompaction struct {
Level int `json:"level"`
Sources []string `json:"sources"`
Blocks []TSDBBlockMeta `json:"blocks"`
}

// TSDBBlockMeta contains the metadata for a single TSDB block.
// Counterpart to prometheus/prometheus tsdb.BlockMeta:
// https://github.com/prometheus/prometheus/blob/v0.313.2/tsdb/block.go#L164
type TSDBBlockMeta struct {
ULID string `json:"ulid"`
MinTime int64 `json:"minTime"`
MaxTime int64 `json:"maxTime"`
Stats TSDBBlockStats `json:"stats,omitempty"`
Compaction TSDBBlockMetaCompaction `json:"compaction"`
Version int `json:"version"`
}

// TSDBBlockStats contains block stats for a single TSDB block.
// Counterpart to prometheus/prometheus tsdb.BlockStats:
// https://github.com/prometheus/prometheus/blob/v0.313.2/tsdb/block.go#L184
type TSDBBlockStats struct {
NumSamples uint64 `json:"numSamples,omitempty"`
NumFloatSamples uint64 `json:"numFloatSamples,omitempty"`
NumHistogramSamples uint64 `json:"numHistogramSamples,omitempty"`
NumSeries uint64 `json:"numSeries,omitempty"`
NumChunks uint64 `json:"numChunks,omitempty"`
NumTombstones uint64 `json:"numTombstones,omitempty"`
}

// TSDBBlockDesc describes a TSDB block reference, used in compaction parent tracking.
// Counterpart to prometheus/prometheus tsdb.BlockDesc:
// https://github.com/prometheus/prometheus/blob/v0.313.2/tsdb/block.go#L194
type TSDBBlockDesc struct {
ULID string `json:"ulid"`
MinTime int64 `json:"minTime"`
MaxTime int64 `json:"maxTime"`
}

// TSDBBlockMetaCompaction contains block compaction details for a single TSDB block.
// Counterpart to prometheus/prometheus tsdb.BlockMetaCompaction:
// https://github.com/prometheus/prometheus/blob/v0.313.2/tsdb/block.go#L201
type TSDBBlockMetaCompaction struct {
Level int `json:"level"`
Sources []string `json:"sources,omitempty"`
Deletable bool `json:"deletable,omitempty"`
Parents []TSDBBlockDesc `json:"parents,omitempty"`
Failed bool `json:"failed,omitempty"`
Hints []string `json:"hints,omitempty"`
}

// WalReplayStatus represents the wal replay status.
Expand Down
Loading
Loading