Merge branch 'main' into feature/use-npm-workspace

Signed-off-by: Augustin Husson <husson.augustin@gmail.com>
This commit is contained in:
Augustin Husson 2021-09-14 19:27:44 +02:00
commit 1b740aeb6e
35 changed files with 36404 additions and 42163 deletions

29
.github/workflows/golangci-lint.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: golangci-lint
on:
push:
paths:
- "go.sum"
- "go.mod"
- "**.go"
- "scripts/errcheck_excludes.txt"
- ".github/workflows/golangci-lint.yml"
pull_request:
paths:
- "go.sum"
- "go.mod"
- "**.go"
- "scripts/errcheck_excludes.txt"
- ".github/workflows/golangci-lint.yml"
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.42.0

View File

@ -24,3 +24,4 @@ rules:
.github/workflows/funcbench.yml
.github/workflows/fuzzing.yml
.github/workflows/prombench.yml
.github/workflows/golangci-lint.yml

View File

@ -52,7 +52,7 @@ All our issues are regularly tagged so that you can also filter down the issues
* Commits should be as small as possible, while ensuring that each commit is correct independently (i.e., each commit should compile and pass tests).
* If your patch is not getting reviewed or you need a specific person to review it, you can @-reply a reviewer asking for a review in the pull request or a comment, or you can ask for a review on IRC channel [#prometheus](https://web.libera.chat/?channels=#prometheus) on irc.libera.chat (for the easiest start, [join via Riot](https://riot.im/app/#/room/#prometheus:matrix.org)).
* If your patch is not getting reviewed or you need a specific person to review it, you can @-reply a reviewer asking for a review in the pull request or a comment, or you can ask for a review on the IRC channel [#prometheus-dev](https://web.libera.chat/?channels=#prometheus-dev) on irc.libera.chat (for the easiest start, [join via Element](https://app.element.io/#/room/#prometheus-dev:matrix.org)).
* Add tests relevant to the fixed bug or new feature.
@ -64,10 +64,10 @@ To add or update a new dependency, use the `go get` command:
```bash
# Pick the latest tagged release.
go get example.com/some/module/pkg
go install example.com/some/module/pkg@latest
# Pick a specific version.
go get example.com/some/module/pkg@vX.Y.Z
go install example.com/some/module/pkg@vX.Y.Z
```
Tidy up the `go.mod` and `go.sum` files:

View File

@ -83,12 +83,18 @@ PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_
GOLANGCI_LINT :=
GOLANGCI_LINT_OPTS ?=
GOLANGCI_LINT_VERSION ?= v1.39.0
GOLANGCI_LINT_VERSION ?= v1.42.0
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
# windows isn't included here because of the path separator being different.
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
# If we're in CI and there is an Actions file, that means the linter
# is being run in Actions, so we don't need to run it here.
ifeq (,$(CIRCLE_JOB))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
else ifeq (,$(wildcard .github/workflows/golangci-lint.yml))
GOLANGCI_LINT := $(FIRST_GOPATH)/bin/golangci-lint
endif
endif
endif

View File

@ -27,7 +27,7 @@ replayed when the Prometheus server restarts. Write-ahead log files are stored
in the `wal` directory in 128MB segments. These files contain raw data that
has not yet been compacted; thus they are significantly larger than regular block
files. Prometheus will retain a minimum of three write-ahead log files.
High-traffic servers may retain more than three WAL files in order to to keep at
High-traffic servers may retain more than three WAL files in order to keep at
least two hours of raw data.
A Prometheus server's data directory looks something like this:

View File

@ -17,7 +17,6 @@ import (
"context"
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/prometheus/common/model"
@ -217,14 +216,7 @@ func TestGenerateTargetGroups(t *testing.T) {
for _, testCase := range testCases {
result := generateTargetGroups(testCase.targetGroup)
if !reflect.DeepEqual(result, testCase.expectedCustomSD) {
t.Errorf("%q failed\ngot: %#v\nexpected: %v",
testCase.title,
result,
testCase.expectedCustomSD)
}
require.Equal(t, testCase.expectedCustomSD, result)
}
}

View File

@ -17,6 +17,7 @@ import (
"testing"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
)
var (
@ -32,17 +33,13 @@ func TestEscape(t *testing.T) {
value := "abzABZ019(){},'\"\\"
expected := "abzABZ019\\(\\)\\{\\}\\,\\'\\\"\\\\"
actual := escape(model.LabelValue(value))
if expected != actual {
t.Errorf("Expected %s, got %s", expected, actual)
}
require.Equal(t, expected, actual)
// Test percent-encoding.
value = "é/|_;:%."
expected = "%C3%A9%2F|_;:%25%2E"
actual = escape(model.LabelValue(value))
if expected != actual {
t.Errorf("Expected %s, got %s", expected, actual)
}
require.Equal(t, expected, actual)
}
func TestPathFromMetric(t *testing.T) {
@ -51,7 +48,5 @@ func TestPathFromMetric(t *testing.T) {
".many_chars.abc!ABC:012-3!45%C3%B667~89%2E%2F\\(\\)\\{\\}\\,%3D%2E\\\"\\\\" +
".testlabel.test:value")
actual := pathFromMetric(metric, "prefix.")
if expected != actual {
t.Errorf("Expected %s, got %s", expected, actual)
}
require.Equal(t, expected, actual)
}

View File

@ -24,6 +24,7 @@ import (
influx "github.com/influxdata/influxdb/client/v2"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
)
func TestClient(t *testing.T) {
@ -73,28 +74,17 @@ testmetric,test_label=test_label_value2 value=5.1234 123456789123
server := httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
t.Fatalf("Unexpected method; expected POST, got %s", r.Method)
}
if r.URL.Path != "/write" {
t.Fatalf("Unexpected path; expected %s, got %s", "/write", r.URL.Path)
}
require.Equal(t, "POST", r.Method, "Unexpected method.")
require.Equal(t, "/write", r.URL.Path, "Unexpected path.")
b, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatalf("Error reading body: %s", err)
}
if string(b) != expectedBody {
t.Fatalf("Unexpected request body; expected:\n\n%s\n\ngot:\n\n%s", expectedBody, string(b))
}
require.NoError(t, err, "Error reading body.")
require.Equal(t, expectedBody, string(b), "Unexpected request body.")
},
))
defer server.Close()
serverURL, err := url.Parse(server.URL)
if err != nil {
t.Fatalf("Unable to parse server URL %s: %s", server.URL, err)
}
require.NoError(t, err, "Unable to parse server URL.")
conf := influx.HTTPConfig{
Addr: serverURL.String(),
@ -103,8 +93,6 @@ testmetric,test_label=test_label_value2 value=5.1234 123456789123
Timeout: time.Minute,
}
c := NewClient(nil, conf, "test_db", "default")
if err := c.Write(samples); err != nil {
t.Fatalf("Error sending samples: %s", err)
}
err = c.Write(samples)
require.NoError(t, err, "Error sending samples.")
}

View File

@ -14,12 +14,11 @@
package opentsdb
import (
"bytes"
"encoding/json"
"reflect"
"testing"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
)
var (
@ -36,9 +35,7 @@ func TestTagsFromMetric(t *testing.T) {
"many_chars": TagValue("abc!ABC:012-3!45ö67~89./"),
}
actual := tagsFromMetric(metric)
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected %#v, got %#v", expected, actual)
}
require.Equal(t, expected, actual)
}
func TestMarshalStoreSamplesRequest(t *testing.T) {
@ -51,25 +48,11 @@ func TestMarshalStoreSamplesRequest(t *testing.T) {
expectedJSON := []byte(`{"metric":"test_.metric","timestamp":4711,"value":3.1415,"tags":{"many_chars":"abc_21ABC_.012-3_2145_C3_B667_7E89./","testlabel":"test_.value"}}`)
resultingJSON, err := json.Marshal(request)
if err != nil {
t.Fatalf("Marshal(request) resulted in err: %s", err)
}
if !bytes.Equal(resultingJSON, expectedJSON) {
t.Errorf(
"Marshal(request) => %q, want %q",
resultingJSON, expectedJSON,
)
}
require.NoError(t, err, "Marshal(request) resulted in err.")
require.Equal(t, expectedJSON, resultingJSON)
var unmarshaledRequest StoreSamplesRequest
err = json.Unmarshal(expectedJSON, &unmarshaledRequest)
if err != nil {
t.Fatalf("Unmarshal(expectedJSON, &unmarshaledRequest) resulted in err: %s", err)
}
if !reflect.DeepEqual(unmarshaledRequest, request) {
t.Errorf(
"Unmarshal(expectedJSON, &unmarshaledRequest) => %#v, want %#v",
unmarshaledRequest, request,
)
}
require.NoError(t, err, "Unmarshal(expectedJSON, &unmarshaledRequest) resulted in err.")
require.Equal(t, request, unmarshaledRequest)
}

View File

@ -14,9 +14,10 @@
package opentsdb
import (
"bytes"
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
var stringtests = []struct {
@ -32,17 +33,9 @@ var stringtests = []struct {
func TestTagValueMarshaling(t *testing.T) {
for i, tt := range stringtests {
json, err := json.Marshal(tt.tv)
if err != nil {
t.Errorf("%d. Marshal(%q) returned err: %s", i, tt.tv, err)
} else {
if !bytes.Equal(json, tt.json) {
t.Errorf(
"%d. Marshal(%q) => %q, want %q",
i, tt.tv, json, tt.json,
)
}
}
got, err := json.Marshal(tt.tv)
require.NoError(t, err, "%d. Marshal(%q) returned error.", i, tt.tv)
require.Equal(t, tt.json, got, "%d. Marshal(%q) not equal.", i, tt.tv)
}
}
@ -50,15 +43,7 @@ func TestTagValueUnMarshaling(t *testing.T) {
for i, tt := range stringtests {
var tv TagValue
err := json.Unmarshal(tt.json, &tv)
if err != nil {
t.Errorf("%d. Unmarshal(%q, &str) returned err: %s", i, tt.json, err)
} else {
if tv != tt.tv {
t.Errorf(
"%d. Unmarshal(%q, &str) => str==%q, want %q",
i, tt.json, tv, tt.tv,
)
}
}
require.NoError(t, err, "%d. Unmarshal(%q, &str) returned error.", i, tt.json)
require.Equal(t, tt.tv, tv, "%d. Unmarshal(%q, &str) not equal.", i, tt.json)
}
}

View File

@ -392,7 +392,7 @@ func TestHandlerQueuing(t *testing.T) {
require.NoError(t, err)
return
case <-time.After(5 * time.Second):
t.Fatalf("Alerts were not pushed")
require.FailNow(t, "Alerts were not pushed.")
}
}
}
@ -424,7 +424,7 @@ func TestHandlerQueuing(t *testing.T) {
case err := <-errc:
require.NoError(t, err)
case <-time.After(5 * time.Second):
t.Fatalf("Alerts were not pushed")
require.FailNow(t, "Alerts were not pushed.")
}
// Verify that we receive the last 3 batches.
@ -480,14 +480,12 @@ alerting:
alertmanagers:
- static_configs:
`
if err := yaml.UnmarshalStrict([]byte(s), cfg); err != nil {
t.Fatalf("Unable to load YAML config: %s", err)
}
err := yaml.UnmarshalStrict([]byte(s), cfg)
require.NoError(t, err, "Unable to load YAML config.")
require.Equal(t, 1, len(cfg.AlertingConfig.AlertmanagerConfigs))
if err := n.ApplyConfig(cfg); err != nil {
t.Fatalf("Error Applying the config:%v", err)
}
err = n.ApplyConfig(cfg)
require.NoError(t, err, "Error applying the config.")
tgs := make(map[string][]*targetgroup.Group)
for _, tt := range tests {
@ -534,14 +532,12 @@ alerting:
regex: 'alertmanager:9093'
action: drop
`
if err := yaml.UnmarshalStrict([]byte(s), cfg); err != nil {
t.Fatalf("Unable to load YAML config: %s", err)
}
err := yaml.UnmarshalStrict([]byte(s), cfg)
require.NoError(t, err, "Unable to load YAML config.")
require.Equal(t, 1, len(cfg.AlertingConfig.AlertmanagerConfigs))
if err := n.ApplyConfig(cfg); err != nil {
t.Fatalf("Error Applying the config:%v", err)
}
err = n.ApplyConfig(cfg)
require.NoError(t, err, "Error applying the config.")
tgs := make(map[string][]*targetgroup.Group)
for _, tt := range tests {

View File

@ -239,6 +239,7 @@ func testTemplateParsing(rl *RuleNode) (errs []error) {
model.Time(timestamp.FromTime(time.Now())),
nil,
nil,
nil,
)
return tmpl.ParseTest()
}

View File

@ -15,19 +15,14 @@ package rulefmt
import (
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestParseFileSuccess(t *testing.T) {
if _, errs := ParseFile("testdata/test.yaml"); len(errs) > 0 {
t.Errorf("unexpected errors parsing file")
for _, err := range errs {
t.Error(err)
}
}
_, errs := ParseFile("testdata/test.yaml")
require.Empty(t, errs, "unexpected errors parsing file")
}
func TestParseFileFailure(t *testing.T) {
@ -79,15 +74,9 @@ func TestParseFileFailure(t *testing.T) {
for _, c := range table {
_, errs := ParseFile(filepath.Join("testdata", c.filename))
if errs == nil {
t.Errorf("Expected error parsing %s but got none", c.filename)
continue
}
if !strings.Contains(errs[0].Error(), c.errMsg) {
t.Errorf("Expected error for %s to contain %q but got: %s", c.filename, c.errMsg, errs)
}
require.NotNil(t, errs, "Expected error parsing %s but got none", c.filename)
require.Error(t, errs[0], c.errMsg, "Expected error for %s.", c.filename)
}
}
func TestTemplateParsing(t *testing.T) {

View File

@ -72,7 +72,7 @@ func TestQueryConcurrency(t *testing.T) {
case <-processing:
// Expected.
case <-time.After(20 * time.Millisecond):
t.Fatalf("Query within concurrency threshold not being executed")
require.Fail(t, "Query within concurrency threshold not being executed")
}
}
@ -81,7 +81,7 @@ func TestQueryConcurrency(t *testing.T) {
select {
case <-processing:
t.Fatalf("Query above concurrency threshold being executed")
require.Fail(t, "Query above concurrency threshold being executed")
case <-time.After(20 * time.Millisecond):
// Expected.
}
@ -93,7 +93,7 @@ func TestQueryConcurrency(t *testing.T) {
case <-processing:
// Expected.
case <-time.After(20 * time.Millisecond):
t.Fatalf("Query within concurrency threshold not being executed")
require.Fail(t, "Query within concurrency threshold not being executed")
}
// Terminate remaining queries.
@ -604,7 +604,7 @@ func TestEngineShutdown(t *testing.T) {
require.Equal(t, errQueryCanceled, res.Err)
query2 := engine.newTestQuery(func(context.Context) error {
t.Fatalf("reached query execution unexpectedly")
require.FailNow(t, "reached query execution unexpectedly")
return nil
})
@ -1121,9 +1121,7 @@ func TestRecoverEvaluatorRuntime(t *testing.T) {
//nolint:govet
a[123] = 1
if err.Error() != "unexpected error" {
t.Fatalf("wrong error message: %q, expected %q", err, "unexpected error")
}
require.EqualError(t, err, "unexpected error")
}
func TestRecoverEvaluatorError(t *testing.T) {
@ -1133,9 +1131,7 @@ func TestRecoverEvaluatorError(t *testing.T) {
e := errors.New("custom error")
defer func() {
if err.Error() != e.Error() {
t.Fatalf("wrong error message: %q, expected %q", err, e)
}
require.EqualError(t, err, e.Error())
}()
defer ev.recover(nil, &err)
@ -1154,12 +1150,8 @@ func TestRecoverEvaluatorErrorWithWarnings(t *testing.T) {
}
defer func() {
if err.Error() != e.Error() {
t.Fatalf("wrong error message: %q, expected %q", err, e)
}
if len(ws) != len(warnings) && ws[0] != warnings[0] {
t.Fatalf("wrong warning message: %q, expected %q", ws[0], warnings[0])
}
require.EqualError(t, err, e.Error())
require.Equal(t, warnings, ws, "wrong warning message")
}()
defer ev.recover(&ws, &err)

View File

@ -737,13 +737,13 @@ func TestLexer(t *testing.T) {
}
if !hasError {
t.Logf("%d: input %q", i, test.input)
t.Fatalf("expected lexing error but did not fail")
require.Fail(t, "expected lexing error but did not fail")
}
continue
}
if lastItem.Typ == ERROR {
t.Logf("%d: input %q", i, test.input)
t.Fatalf("unexpected lexing error at position %d: %s", lastItem.Pos, lastItem)
require.Fail(t, "unexpected lexing error at position %d: %s", lastItem.Pos, lastItem)
}
eofItem := Item{EOF, Pos(len(test.input)), ""}

View File

@ -55,18 +55,16 @@ func TestQueryLogging(t *testing.T) {
queryLogger.Insert(context.Background(), queries[i])
have := string(fileAsBytes[start:end])
if !regexp.MustCompile(want[i]).MatchString(have) {
t.Fatalf("Query not written correctly: %s.\nHave %s\nWant %s", queries[i], have, want[i])
}
require.True(t, regexp.MustCompile(want[i]).MatchString(have),
"Query not written correctly: %s", queries[i])
}
// Check if all queries have been deleted.
for i := 0; i < 4; i++ {
queryLogger.Delete(1 + i*entrySize)
}
if !regexp.MustCompile(`^\x00+$`).Match(fileAsBytes[1 : 1+entrySize*4]) {
t.Fatalf("All queries not deleted properly. Have %s\nWant only null bytes \\x00", string(fileAsBytes[1:1+entrySize*4]))
}
require.True(t, regexp.MustCompile(`^\x00+$`).Match(fileAsBytes[1:1+entrySize*4]),
"All queries not deleted properly. Want only null bytes \\x00")
}
func TestIndexReuse(t *testing.T) {
@ -101,9 +99,8 @@ func TestIndexReuse(t *testing.T) {
end := start + entrySize
have := queryBytes[start:end]
if !regexp.MustCompile(want[i]).Match(have) {
t.Fatalf("Index not reused properly:\nHave %s\nWant %s", string(queryBytes[start:end]), want[i])
}
require.True(t, regexp.MustCompile(want[i]).Match(have),
"Index not reused properly.")
}
}
@ -124,14 +121,10 @@ func TestMMapFile(t *testing.T) {
bytes := make([]byte, 4)
n, err := f.Read(bytes)
require.Equal(t, n, 2)
require.NoError(t, err, "Unexpected error while reading file.")
if n != 2 || err != nil {
t.Fatalf("Error reading file")
}
if string(bytes[:2]) != string(fileAsBytes) {
t.Fatalf("Mmap failed")
}
require.Equal(t, fileAsBytes, bytes[:2], "Mmap failed")
}
func TestParseBrokenJSON(t *testing.T) {
@ -163,12 +156,9 @@ func TestParseBrokenJSON(t *testing.T) {
} {
t.Run("", func(t *testing.T) {
out, ok := parseBrokenJSON(tc.b)
if tc.ok != ok {
t.Fatalf("expected %t, got %t", tc.ok, ok)
return
}
if ok && tc.out != out {
t.Fatalf("expected %s, got %s", tc.out, out)
require.Equal(t, tc.ok, ok)
if ok {
require.Equal(t, tc.out, out)
}
})
}

View File

@ -25,6 +25,7 @@ import (
"github.com/pkg/errors"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
"github.com/prometheus/prometheus/pkg/exemplar"
"github.com/prometheus/prometheus/pkg/labels"
@ -597,9 +598,8 @@ func (t *Test) exec(tc testCommand) error {
// clear the current test storage of all inserted samples.
func (t *Test) clear() {
if t.storage != nil {
if err := t.storage.Close(); err != nil {
t.T.Fatalf("closing test storage: %s", err)
}
err := t.storage.Close()
require.NoError(t.T, err, "Unexpected error while closing test storage.")
}
if t.cancelCtx != nil {
t.cancelCtx()
@ -623,9 +623,8 @@ func (t *Test) clear() {
func (t *Test) Close() {
t.cancelCtx()
if err := t.storage.Close(); err != nil {
t.T.Fatalf("closing test storage: %s", err)
}
err := t.storage.Close()
require.NoError(t.T, err, "Unexpected error while closing test storage.")
}
// samplesAlmostEqual returns true if the two sample lines only differ by a
@ -722,9 +721,8 @@ func (ll *LazyLoader) parse(input string) error {
// clear the current test storage of all inserted samples.
func (ll *LazyLoader) clear() {
if ll.storage != nil {
if err := ll.storage.Close(); err != nil {
ll.T.Fatalf("closing test storage: %s", err)
}
err := ll.storage.Close()
require.NoError(ll.T, err, "Unexpected error while closing test storage.")
}
if ll.cancelCtx != nil {
ll.cancelCtx()
@ -798,8 +796,6 @@ func (ll *LazyLoader) Storage() storage.Storage {
// Close closes resources associated with the LazyLoader.
func (ll *LazyLoader) Close() {
ll.cancelCtx()
if err := ll.storage.Close(); err != nil {
ll.T.Fatalf("closing test storage: %s", err)
}
err := ll.storage.Close()
require.NoError(ll.T, err, "Unexpected error while closing test storage.")
}

View File

@ -338,6 +338,7 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc,
model.Time(timestamp.FromTime(ts)),
template.QueryFunc(query),
externalURL,
nil,
)
result, err := tmpl.Expand()
if err != nil {

View File

@ -721,7 +721,7 @@ var errBodySizeLimit = errors.New("body size limit exceeded")
const acceptHeader = `application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1`
var userAgentHeader = fmt.Sprintf("Prometheus/%s", version.Version)
var UserAgent = fmt.Sprintf("Prometheus/%s", version.Version)
func (s *targetScraper) scrape(ctx context.Context, w io.Writer) (string, error) {
if s.req == nil {
@ -731,7 +731,7 @@ func (s *targetScraper) scrape(ctx context.Context, w io.Writer) (string, error)
}
req.Header.Add("Accept", acceptHeader)
req.Header.Add("Accept-Encoding", "gzip")
req.Header.Set("User-Agent", userAgentHeader)
req.Header.Set("User-Agent", UserAgent)
req.Header.Set("X-Prometheus-Scrape-Timeout-Seconds", strconv.FormatFloat(s.timeout.Seconds(), 'f', -1, 64))
s.req = req

View File

@ -37,7 +37,7 @@ if [ -z "${GITHUB_TOKEN}" ]; then
fi
# List of files that should be synced.
SYNC_FILES="CODE_OF_CONDUCT.md LICENSE Makefile.common SECURITY.md .yamllint"
SYNC_FILES="CODE_OF_CONDUCT.md LICENSE Makefile.common SECURITY.md .yamllint .github/workflows/golangci-lint.yml"
# Go to the root of the repo
cd "$(git rev-parse --show-cdup)" || exit 1
@ -96,6 +96,15 @@ check_license() {
echo "$1" | grep --quiet --no-messages --ignore-case 'Apache License'
}
check_go() {
local org_repo
local default_branch
org_repo="$1"
default_branch="$2"
curl -sLf -o /dev/null "https://raw.githubusercontent.com/${org_repo}/${default_branch}/go.mod"
}
check_circleci_orb() {
local org_repo
local default_branch
@ -136,10 +145,14 @@ process_repo() {
echo "LICENSE in ${org_repo} is not apache, skipping."
continue
fi
if [[ "${source_file}" == '.github/workflows/golangci-lint.yml' ]] && ! check_go "${org_repo}" "${default_branch}" ; then
echo "${org_repo} is not Go, skipping .github/workflows/golangci-lint.yml."
continue
fi
if [[ -z "${target_file}" ]]; then
echo "${source_file} doesn't exist in ${org_repo}"
case "${source_file}" in
CODE_OF_CONDUCT.md | SECURITY.md)
CODE_OF_CONDUCT.md | SECURITY.md | .github/workflows/golangci-lint.yml)
echo "${source_file} missing in ${org_repo}, force updating."
needs_update+=("${source_file}")
;;
@ -172,6 +185,9 @@ process_repo() {
cd "${tmp_dir}/${org_repo}" || return 1
git checkout -b "${branch}" || return 1
# If we need to add an Actions file this directory needs to be present.
mkdir -p "./.github/workflows"
# Update the files in target repo by one from prometheus/prometheus.
for source_file in "${needs_update[@]}"; do
case "${source_file}" in

View File

@ -111,9 +111,8 @@ func TestClientRetryAfter(t *testing.T) {
c := getClient(conf)
err = c.Store(context.Background(), []byte{})
if _, ok := err.(RecoverableError); ok {
t.Fatal("recoverable error not expected")
}
_, ok := err.(RecoverableError)
require.False(t, ok, "Recoverable error not expected.")
conf = &ClientConfig{
URL: &config_util.URL{URL: serverURL},
@ -123,9 +122,8 @@ func TestClientRetryAfter(t *testing.T) {
c = getClient(conf)
err = c.Store(context.Background(), []byte{})
if _, ok := err.(RecoverableError); !ok {
t.Fatal("recoverable error was expected")
}
_, ok = err.(RecoverableError)
require.True(t, ok, "Recoverable error was expected.")
}
func TestRetryAfterDuration(t *testing.T) {

View File

@ -78,9 +78,7 @@ func TestSampledReadEndpoint(t *testing.T) {
recorder := httptest.NewRecorder()
h.ServeHTTP(recorder, request)
if recorder.Code/100 != 2 {
t.Fatal(recorder.Code)
}
require.Equal(t, 2, recorder.Code/100)
require.Equal(t, "application/x-protobuf", recorder.Result().Header.Get("Content-Type"))
require.Equal(t, "snappy", recorder.Result().Header.Get("Content-Encoding"))
@ -96,9 +94,7 @@ func TestSampledReadEndpoint(t *testing.T) {
err = proto.Unmarshal(uncompressed, &resp)
require.NoError(t, err)
if len(resp.Results) != 1 {
t.Fatalf("Expected 1 result, got %d", len(resp.Results))
}
require.Equal(t, 1, len(resp.Results), "Expected 1 result.")
require.Equal(t, &prompb.QueryResult{
Timeseries: []*prompb.TimeSeries{
@ -189,9 +185,7 @@ func TestStreamReadEndpoint(t *testing.T) {
recorder := httptest.NewRecorder()
api.ServeHTTP(recorder, request)
if recorder.Code/100 != 2 {
t.Fatal(recorder.Code)
}
require.Equal(t, 2, recorder.Code/100)
require.Equal(t, "application/x-streamed-protobuf; proto=prometheus.ChunkedReadResponse", recorder.Result().Header.Get("Content-Type"))
require.Equal(t, "", recorder.Result().Header.Get("Content-Encoding"))
@ -208,9 +202,7 @@ func TestStreamReadEndpoint(t *testing.T) {
results = append(results, res)
}
if len(results) != 5 {
t.Fatalf("Expected 5 result, got %d", len(results))
}
require.Equal(t, 5, len(results), "Expected 5 results.")
require.Equal(t, []*prompb.ChunkedReadResponse{
{

View File

@ -115,6 +115,7 @@ type Expander struct {
name string
data interface{}
funcMap text_template.FuncMap
options []string
}
// NewTemplateExpander returns a template expander ready to use.
@ -126,7 +127,11 @@ func NewTemplateExpander(
timestamp model.Time,
queryFunc QueryFunc,
externalURL *url.URL,
options []string,
) *Expander {
if options == nil {
options = []string{"missingkey=zero"}
}
return &Expander{
text: text,
name: name,
@ -291,6 +296,7 @@ func NewTemplateExpander(
return externalURL.String()
},
},
options: options,
}
}
@ -336,7 +342,9 @@ func (te Expander) Expand() (result string, resultErr error) {
templateTextExpansionTotal.Inc()
tmpl, err := text_template.New(te.name).Funcs(te.funcMap).Option("missingkey=zero").Parse(te.text)
tmpl := text_template.New(te.name).Funcs(te.funcMap)
tmpl.Option(te.options...)
tmpl, err := tmpl.Parse(te.text)
if err != nil {
return "", errors.Wrapf(err, "error parsing template %v", te.name)
}
@ -361,7 +369,7 @@ func (te Expander) ExpandHTML(templateFiles []string) (result string, resultErr
}()
tmpl := html_template.New(te.name).Funcs(html_template.FuncMap(te.funcMap))
tmpl.Option("missingkey=zero")
tmpl.Option(te.options...)
tmpl.Funcs(html_template.FuncMap{
"tmpl": func(name string, data interface{}) (html_template.HTML, error) {
var buffer bytes.Buffer

View File

@ -31,6 +31,7 @@ func TestTemplateExpansion(t *testing.T) {
text string
output string
input interface{}
options []string
queryResult promql.Vector
shouldFail bool
html bool
@ -153,6 +154,45 @@ func TestTemplateExpansion(t *testing.T) {
}},
output: "a:11: b:21: ",
},
{
// Missing value is no value for nil options.
text: "{{ .Foo }}",
output: "<no value>",
},
{
// Missing value is no value for no options.
text: "{{ .Foo }}",
options: make([]string, 0),
output: "<no value>",
},
{
// Assert that missing value returns error with missingkey=error.
text: "{{ .Foo }}",
options: []string{"missingkey=error"},
shouldFail: true,
errorMsg: `error executing template test: template: test:1:3: executing "test" at <.Foo>: nil data; no entry for key "Foo"`,
},
{
// Missing value is "" for nil options in ExpandHTML.
text: "{{ .Foo }}",
output: "",
html: true,
},
{
// Missing value is "" for no options in ExpandHTML.
text: "{{ .Foo }}",
options: make([]string, 0),
output: "",
html: true,
},
{
// Assert that missing value returns error with missingkey=error in ExpandHTML.
text: "{{ .Foo }}",
options: []string{"missingkey=error"},
shouldFail: true,
errorMsg: `error executing template test: template: test:1:3: executing "test" at <.Foo>: nil data; no entry for key "Foo"`,
html: true,
},
{
// Unparsable template.
text: "{{",
@ -341,7 +381,7 @@ func TestTemplateExpansion(t *testing.T) {
}
var result string
var err error
expander := NewTemplateExpander(context.Background(), s.text, "test", s.input, 0, queryFunc, extURL)
expander := NewTemplateExpander(context.Background(), s.text, "test", s.input, 0, queryFunc, extURL, s.options)
if s.html {
result, err = expander.ExpandHTML(nil)
} else {
@ -356,7 +396,7 @@ func TestTemplateExpansion(t *testing.T) {
require.NoError(t, err)
if err == nil {
require.Equal(t, result, s.output)
require.Equal(t, s.output, result)
}
}
}

View File

@ -21,6 +21,8 @@ import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
)
var (
@ -60,22 +62,14 @@ func TestCompressionHandler_PlainText(t *testing.T) {
}
resp, err := client.Get(server.URL + "/foo_endpoint")
if err != nil {
t.Error("client get failed with unexpected error")
}
require.NoError(t, err, "client get failed with unexpected error")
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("unexpected error while reading the response body: %s", err.Error())
}
require.NoError(t, err, "unexpected error while creating the response body reader")
expected := "Hello World!"
actual := string(contents)
if expected != actual {
t.Errorf("expected response with content %s, but got %s", expected, actual)
}
require.Equal(t, expected, actual, "expected response with content")
}
func TestCompressionHandler_Gzip(t *testing.T) {
@ -95,34 +89,22 @@ func TestCompressionHandler_Gzip(t *testing.T) {
req.Header.Set(acceptEncodingHeader, gzipEncoding)
resp, err := client.Do(req)
if err != nil {
t.Error("client get failed with unexpected error")
}
require.NoError(t, err, "client get failed with unexpected error")
defer resp.Body.Close()
if err != nil {
t.Errorf("unexpected error while reading the response body: %s", err.Error())
}
actualHeader := resp.Header.Get(contentEncodingHeader)
if actualHeader != gzipEncoding {
t.Errorf("expected response with encoding header %s, but got %s", gzipEncoding, actualHeader)
}
require.Equal(t, gzipEncoding, actualHeader, "unexpected encoding header in response")
var buf bytes.Buffer
zr, _ := gzip.NewReader(resp.Body)
zr, err := gzip.NewReader(resp.Body)
require.NoError(t, err, "unexpected error while creating the response body reader")
_, err = buf.ReadFrom(zr)
if err != nil {
t.Error("unexpected error while reading from response body")
}
require.NoError(t, err, "unexpected error while reading the response body")
actual := buf.String()
expected := "Hello World!"
if expected != actual {
t.Errorf("expected response with content %s, but got %s", expected, actual)
}
require.Equal(t, expected, actual, "unexpected response content")
}
func TestCompressionHandler_Deflate(t *testing.T) {
@ -142,35 +124,20 @@ func TestCompressionHandler_Deflate(t *testing.T) {
req.Header.Set(acceptEncodingHeader, deflateEncoding)
resp, err := client.Do(req)
if err != nil {
t.Error("client get failed with unexpected error")
}
require.NoError(t, err, "client get failed with unexpected error")
defer resp.Body.Close()
if err != nil {
t.Errorf("unexpected error while reading the response body: %s", err.Error())
}
actualHeader := resp.Header.Get(contentEncodingHeader)
if actualHeader != deflateEncoding {
t.Errorf("expected response with encoding header %s, but got %s", deflateEncoding, actualHeader)
}
require.Equal(t, deflateEncoding, actualHeader, "expected response with encoding header")
var buf bytes.Buffer
dr, err := zlib.NewReader(resp.Body)
if err != nil {
t.Error("unexpected error while reading from response body")
}
require.NoError(t, err, "unexpected error while creating the response body reader")
_, err = buf.ReadFrom(dr)
if err != nil {
t.Error("unexpected error while reading from response body")
}
require.NoError(t, err, "unexpected error while reading the response body")
actual := buf.String()
expected := "Hello World!"
if expected != actual {
t.Errorf("expected response with content %s, but got %s", expected, actual)
}
require.Equal(t, expected, actual, "expected response with content")
}

View File

@ -17,6 +17,8 @@ import (
"net/http"
"regexp"
"testing"
"github.com/stretchr/testify/require"
)
func getCORSHandlerFunc() http.Handler {
@ -40,41 +42,24 @@ func TestCORSHandler(t *testing.T) {
// OPTIONS with legit origin
req, err := http.NewRequest("OPTIONS", server.URL+"/any_path", nil)
if err != nil {
t.Error("could not create request")
}
require.NoError(t, err, "could not create request")
req.Header.Set("Origin", dummyOrigin)
resp, err := client.Do(req)
if err != nil {
t.Error("client get failed with unexpected error")
}
require.NoError(t, err, "client get failed with unexpected error")
AccessControlAllowOrigin := resp.Header.Get("Access-Control-Allow-Origin")
if AccessControlAllowOrigin != dummyOrigin {
t.Fatalf("%q does not match %q", dummyOrigin, AccessControlAllowOrigin)
}
require.Equal(t, dummyOrigin, AccessControlAllowOrigin, "expected Access-Control-Allow-Origin header")
// OPTIONS with bad origin
req, err = http.NewRequest("OPTIONS", server.URL+"/any_path", nil)
if err != nil {
t.Error("could not create request")
}
require.NoError(t, err, "could not create request")
req.Header.Set("Origin", "https://not-foo.com")
resp, err = client.Do(req)
if err != nil {
t.Error("client get failed with unexpected error")
}
require.NoError(t, err, "client get failed with unexpected error")
AccessControlAllowOrigin = resp.Header.Get("Access-Control-Allow-Origin")
if AccessControlAllowOrigin != "" {
t.Fatalf("Access-Control-Allow-Origin should not exist but it was set to: %q", AccessControlAllowOrigin)
}
require.Empty(t, AccessControlAllowOrigin, "Access-Control-Allow-Origin header should not exist but it was set")
}

View File

@ -20,6 +20,7 @@ import (
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"
"github.com/prometheus/prometheus/util/testutil"
)
@ -27,19 +28,17 @@ import (
func TestTimerGroupNewTimer(t *testing.T) {
tg := NewTimerGroup()
timer := tg.GetTimer(ExecTotalTime)
if duration := timer.Duration(); duration != 0 {
t.Fatalf("Expected duration of 0, but it was %f instead.", duration)
}
duration := timer.Duration()
require.Equal(t, 0.0, duration, "Expected duration equal 0")
minimum := 2 * time.Millisecond
timer.Start()
time.Sleep(minimum)
timer.Stop()
if duration := timer.Duration(); duration == 0 {
t.Fatalf("Expected duration greater than 0, but it was %f instead.", duration)
}
if elapsed := timer.ElapsedTime(); elapsed < minimum {
t.Fatalf("Expected elapsed time to be greater than time slept, elapsed was %d, and time slept was %d.", elapsed.Nanoseconds(), minimum)
}
duration = timer.Duration()
require.Greater(t, duration, 0.0, "Expected duration greater than 0")
elapsed := timer.ElapsedTime()
require.GreaterOrEqual(t, elapsed, minimum,
"Expected elapsed time to be greater than time slept.")
}
func TestQueryStatsWithTimers(t *testing.T) {
@ -51,17 +50,11 @@ func TestQueryStatsWithTimers(t *testing.T) {
qs := NewQueryStats(qt)
actual, err := json.Marshal(qs)
if err != nil {
t.Fatalf("Unexpected error during serialization: %v", err)
}
require.NoError(t, err, "unexpected error during serialization")
// Timing value is one of multiple fields, unit is seconds (float).
match, err := regexp.MatchString(`[,{]"execTotalTime":\d+\.\d+[,}]`, string(actual))
if err != nil {
t.Fatalf("Unexpected error while matching string: %v", err)
}
if !match {
t.Fatalf("Expected timings with one non-zero entry, but got %s.", actual)
}
require.NoError(t, err, "unexpected error while matching string")
require.True(t, match, "Expected timings with one non-zero entry.")
}
func TestQueryStatsWithSpanTimers(t *testing.T) {
@ -72,51 +65,28 @@ func TestQueryStatsWithSpanTimers(t *testing.T) {
qst.Finish()
qs := NewQueryStats(qt)
actual, err := json.Marshal(qs)
if err != nil {
t.Fatalf("Unexpected error during serialization: %v", err)
}
require.NoError(t, err, "unexpected error during serialization")
// Timing value is one of multiple fields, unit is seconds (float).
match, err := regexp.MatchString(`[,{]"execQueueTime":\d+\.\d+[,}]`, string(actual))
if err != nil {
t.Fatalf("Unexpected error while matching string: %v", err)
}
if !match {
t.Fatalf("Expected timings with one non-zero entry, but got %s.", actual)
}
require.NoError(t, err, "unexpected error while matching string")
require.True(t, match, "Expected timings with one non-zero entry.")
}
func TestTimerGroup(t *testing.T) {
tg := NewTimerGroup()
execTotalTimer := tg.GetTimer(ExecTotalTime)
if tg.GetTimer(ExecTotalTime).String() != "Exec total time: 0s" {
t.Fatalf("Expected string %s, but got %s", "", execTotalTimer.String())
}
execQueueTimer := tg.GetTimer(ExecQueueTime)
if tg.GetTimer(ExecQueueTime).String() != "Exec queue wait time: 0s" {
t.Fatalf("Expected string %s, but got %s", "", execQueueTimer.String())
}
innerEvalTimer := tg.GetTimer(InnerEvalTime)
if tg.GetTimer(InnerEvalTime).String() != "Inner eval time: 0s" {
t.Fatalf("Expected string %s, but got %s", "", innerEvalTimer.String())
}
queryPreparationTimer := tg.GetTimer(QueryPreparationTime)
if tg.GetTimer(QueryPreparationTime).String() != "Query preparation time: 0s" {
t.Fatalf("Expected string %s, but got %s", "", queryPreparationTimer.String())
}
resultSortTimer := tg.GetTimer(ResultSortTime)
if tg.GetTimer(ResultSortTime).String() != "Result sorting time: 0s" {
t.Fatalf("Expected string %s, but got %s", "", resultSortTimer.String())
}
evalTotalTimer := tg.GetTimer(EvalTotalTime)
if tg.GetTimer(EvalTotalTime).String() != "Eval total time: 0s" {
t.Fatalf("Expected string %s, but got %s", "", evalTotalTimer.String())
}
require.Equal(t, "Exec total time: 0s", tg.GetTimer(ExecTotalTime).String())
require.Equal(t, "Exec queue wait time: 0s", tg.GetTimer(ExecQueueTime).String())
require.Equal(t, "Inner eval time: 0s", tg.GetTimer(InnerEvalTime).String())
require.Equal(t, "Query preparation time: 0s", tg.GetTimer(QueryPreparationTime).String())
require.Equal(t, "Result sorting time: 0s", tg.GetTimer(ResultSortTime).String())
require.Equal(t, "Eval total time: 0s", tg.GetTimer(EvalTotalTime).String())
actual := tg.String()
expected := "Exec total time: 0s\nExec queue wait time: 0s\nInner eval time: 0s\nQuery preparation time: 0s\nResult sorting time: 0s\nEval total time: 0s\n"
if actual != expected {
t.Fatalf("Expected timerGroup string %s, but got %s.", expected, actual)
}
require.Equal(t, expected, actual)
}

View File

@ -15,6 +15,8 @@ package strutil
import (
"testing"
"github.com/stretchr/testify/require"
)
var quotetests = []struct {
@ -107,21 +109,22 @@ var misquoted = []string{
func TestUnquote(t *testing.T) {
for _, tt := range unquotetests {
if out, err := Unquote(tt.in); err != nil && out != tt.out {
t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
out, err := Unquote(tt.in)
if err != nil {
require.Equal(t, tt.out, out, "Unquote(%#q)", tt.in)
}
}
// Run the quote tests too, backward.
for _, tt := range quotetests {
if in, err := Unquote(tt.out); in != tt.in {
t.Errorf("Unquote(%#q) = %q, %v, want %q, nil", tt.out, in, err, tt.in)
}
in, err := Unquote(tt.out)
require.Equal(t, tt.in, in, "Unquote(%#q)", tt.out)
require.NoError(t, err)
}
for _, s := range misquoted {
if out, err := Unquote(s); out != "" || err != ErrSyntax {
t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", ErrSyntax)
}
out, err := Unquote(s)
require.Empty(t, out, "Unquote(%#q)", s)
require.EqualError(t, err, ErrSyntax.Error(), "Unquote(%#q)", s)
}
}

View File

@ -15,6 +15,8 @@ package strutil
import (
"testing"
"github.com/stretchr/testify/require"
)
type linkTest struct {
@ -38,28 +40,22 @@ var linkTests = []linkTest{
func TestLink(t *testing.T) {
for _, tt := range linkTests {
if graphLink := GraphLinkForExpression(tt.expression); graphLink != tt.expectedGraphLink {
t.Errorf("GraphLinkForExpression failed for expression (%#q), want %q got %q", tt.expression, tt.expectedGraphLink, graphLink)
}
graphLink := GraphLinkForExpression(tt.expression)
require.Equal(t, tt.expectedGraphLink, graphLink,
"GraphLinkForExpression failed for expression (%#q)", tt.expression)
if tableLink := TableLinkForExpression(tt.expression); tableLink != tt.expectedTableLink {
t.Errorf("TableLinkForExpression failed for expression (%#q), want %q got %q", tt.expression, tt.expectedTableLink, tableLink)
}
tableLink := TableLinkForExpression(tt.expression)
require.Equal(t, tt.expectedTableLink, tableLink,
"TableLinkForExpression failed for expression (%#q)", tt.expression)
}
}
func TestSanitizeLabelName(t *testing.T) {
actual := SanitizeLabelName("fooClientLABEL")
expected := "fooClientLABEL"
if actual != expected {
t.Errorf("SanitizeLabelName failed for label (%s), want %s got %s", "fooClientLABEL", expected, actual)
}
require.Equal(t, expected, actual, "SanitizeLabelName failed for label (%s)", expected)
actual = SanitizeLabelName("barClient.LABEL$$##")
expected = "barClient_LABEL____"
if actual != expected {
t.Errorf("SanitizeLabelName failed for label (%s), want %s got %s", "barClient.LABEL$$##", expected, actual)
}
require.Equal(t, expected, actual, "SanitizeLabelName failed for label (%s)", expected)
}

View File

@ -19,6 +19,8 @@ import (
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"
"github.com/prometheus/prometheus/pkg/exemplar"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/storage"
@ -30,9 +32,7 @@ import (
// that removes all associated files on closing.
func New(t testutil.T) *TestStorage {
dir, err := ioutil.TempDir("", "test_storage")
if err != nil {
t.Fatalf("Opening test dir failed: %s", err)
}
require.NoError(t, err, "unexpected error while opening test directory")
// Tests just load data for a series sequentially. Thus we
// need a long appendable window.
@ -40,16 +40,12 @@ func New(t testutil.T) *TestStorage {
opts.MinBlockDuration = int64(24 * time.Hour / time.Millisecond)
opts.MaxBlockDuration = int64(24 * time.Hour / time.Millisecond)
db, err := tsdb.Open(dir, nil, nil, opts, tsdb.NewDBStats())
if err != nil {
t.Fatalf("Opening test storage failed: %s", err)
}
require.NoError(t, err, "unexpected error while opening test storage")
reg := prometheus.NewRegistry()
eMetrics := tsdb.NewExemplarMetrics(reg)
es, err := tsdb.NewCircularExemplarStorage(10, eMetrics)
if err != nil {
t.Fatalf("Opening test exemplar storage failed: %s", err)
}
require.NoError(t, err, "unexpected error while opening test exemplar storage")
return &TestStorage{DB: db, exemplarStorage: es, dir: dir}
}

View File

@ -73,8 +73,8 @@ type (
// the test flags, which we do not want in non-test binaries even if
// they make use of these utilities for some reason).
T interface {
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Errorf(format string, args ...interface{})
FailNow()
}
)
@ -105,9 +105,7 @@ func (t temporaryDirectory) Close() {
err = os.RemoveAll(t.path)
}
}
if err != nil {
t.tester.Fatal(err)
}
require.NoError(t.tester, err)
}
func (t temporaryDirectory) Path() string {
@ -123,9 +121,7 @@ func NewTemporaryDirectory(name string, t T) (handler TemporaryDirectory) {
)
directory, err = ioutil.TempDir(defaultDirectory, name)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
handler = temporaryDirectory{
path: directory,

77917
web/ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ describe('Graph', () => {
jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb: any) => cb());
});
// fix coming from https://github.com/maslianok/react-resize-detector#testing-with-enzyme-and-jest
// Source: https://github.com/maslianok/react-resize-detector#testing-with-enzyme-and-jest
beforeEach(() => {
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
@ -22,6 +22,7 @@ describe('Graph', () => {
afterEach(() => {
window.ResizeObserver = ResizeObserver;
});
describe('data is returned', () => {
const props: any = {
queryParams: {

View File

@ -135,8 +135,9 @@ input[type='checkbox']:checked + label {
flex-wrap: nowrap;
}
.alert.alert-danger {
margin-bottom: 10px;
.alert {
padding: 10px;
margin-bottom: .2rem;
}
.nav-tabs .nav-link {
@ -320,6 +321,7 @@ input[type='checkbox']:checked + label {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
margin-top: 10px;
padding: 10px;
}

View File

@ -709,6 +709,7 @@ func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
h.now(),
template.QueryFunc(rules.EngineQueryFunc(h.queryEngine, h.storage)),
h.options.ExternalURL,
nil,
)
filenames, err := filepath.Glob(h.options.ConsoleLibrariesPath + "/*.lib")
if err != nil {
@ -1113,6 +1114,7 @@ func (h *Handler) executeTemplate(w http.ResponseWriter, name string, data inter
h.now(),
template.QueryFunc(rules.EngineQueryFunc(h.queryEngine, h.storage)),
h.options.ExternalURL,
nil,
)
tmpl.Funcs(tmplFuncs(h.consolesPath(), h.options))