diff --git a/.circleci/config.yml b/.circleci/config.yml index 8cf200b826..cea565fca2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,6 +14,11 @@ executors: resource_class: arm.medium jobs: + feature-gates: + executor: golang + steps: + - checkout + - run: make feature-gates-verify test: executor: golang steps: diff --git a/Makefile b/Makefile index 0edd9a125a..5c80340ed2 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ MACH ?= $(shell uname -m) STATICCHECK_IGNORE = +FEATURE_GATES_MANIFEST = featuregate/feature-gates.md + ifeq ($(GOHOSTOS), linux) test-e2e := test-e2e else @@ -145,3 +147,15 @@ promtool: $(PROMTOOL) $(PROMTOOL): mkdir -p $(FIRST_GOPATH)/bin curl -fsS -L $(PROMTOOL_URL) | tar -xvzf - -C $(FIRST_GOPATH)/bin --strip 1 "prometheus-$(PROMTOOL_VERSION).$(GO_BUILD_PLATFORM)/promtool" + +.PHONY: feature-gates +feature-gates: + @echo ">> checking feature gates" + ./feature-gates.sh + +.PHONY: feature-gates-verify +feature-gates-verify: feature-gates + @if [ $$(git diff --exit-code -- $(FEATURE_GATES_MANIFEST) &>/dev/null; echo $$?) -ne 0 ]; then \ + echo ">> feature gates have changed, needs staging"; \ + exit 1; \ + fi diff --git a/feature-gates.sh b/feature-gates.sh new file mode 100755 index 0000000000..1c23cb4cc1 --- /dev/null +++ b/feature-gates.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Fetch the feature-gates manifest from remote. This is the source of truth. +FEATURE_GATES_MANIFEST_PATH="featuregate/feature-gates.md" +FEATURE_GATES_REMOTE_MANIFEST_RAW_URL="https://raw.githubusercontent.com/rexagod/node_exporter/feature-gated/$FEATURE_GATES_MANIFEST_PATH" # TODO: Point to prometheus remote. +FEATURE_GATES_REMOTE_MANIFEST_RAW_STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}\n" "$FEATURE_GATES_REMOTE_MANIFEST_RAW_URL") +if [ "$FEATURE_GATES_REMOTE_MANIFEST_RAW_STATUS_CODE" -ne 200 ]; then + echo "Failed to fetch feature-gates data from remote, got $FEATURE_GATES_REMOTE_MANIFEST_RAW_STATUS_CODE." + exit 1 +fi +mkdir -p /tmp/featuregate +curl -s "$FEATURE_GATES_REMOTE_MANIFEST_RAW_URL" > "/tmp/$FEATURE_GATES_MANIFEST_PATH" + +# Generate the updated feature-gates manifest locally. This is the working copy. +echo -e " +# Feature gates +Below is the set of feature-gates currently present in the repository, along with the versions they were added and retired in. +| Name | Description | Adding Version | Retiring Version | +|------|-------------|----------------|------------------|" > "./$FEATURE_GATES_MANIFEST_PATH" +# For all non-test collector files, extract the feature-gates and their metadata. +find ./collector -type f ! -name "*_test.go" -exec cat {} \; | \ +# * -0777: Slurp the entire file into a single string. +# * -n: Process the input line by line. +# * -e: Provide the script as an argument instead of reading it from a file. +# * $args =~ s/\n/ /g: Replace all newlines in the arguments with spaces (for multi-line arguments). +perl -0777 -ne ' + while (m/featuregate\.NewFeatureGate\(\s*([^)]*?)\s*\)/sg) { + $args = $1; + $args =~ s/\n/ /g; + print "$args\n"; + } +' | \ +# Squeeze multiple spaces into a single space. +tr -s ' ' | \ +# Replace commas with pipes. +tr ',' '|' | \ +# Remove double quotes. +sed 's/\"//g' >> "./$FEATURE_GATES_MANIFEST_PATH" + +# Check for changes to existing feature-gates (instead of adding new ones) by comparing the local and remote feature-gates manifests. +if grep -Fxf "/tmp/$FEATURE_GATES_MANIFEST_PATH" "./$FEATURE_GATES_MANIFEST_PATH" > /dev/null; then + exit 0 +else + echo "Manifest modifications are not consistent with the remote. Ensure that no existing feature-gate version commitments were changed." +fi diff --git a/featuregate/feature-gates.md b/featuregate/feature-gates.md new file mode 100644 index 0000000000..1bd32c6be7 --- /dev/null +++ b/featuregate/feature-gates.md @@ -0,0 +1,5 @@ + +# Feature gates +Below is the set of feature-gates currently present in the repository, along with the versions they were added and retired in. +| Name | Description | Adding Version | Retiring Version | +|------|-------------|----------------|------------------|