Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 590eb4e

Browse files
committed
Merge branch 'main' of github.com:coder/coder into dk/default-preset
2 parents 0d9d751 + 2afd1a2 commit 590eb4e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+922
-249
lines changed

.github/.linkspector.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ ignorePatterns:
2424
- pattern: "mutagen.io"
2525
- pattern: "docs.github.com"
2626
- pattern: "claude.ai"
27+
- pattern: "splunk.com"
2728
aliveStatusCodes:
2829
- 200

coderd/apidoc/docs.go

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/coderd.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ func New(options *Options) *API {
972972
})
973973
r.Route("/experiments", func(r chi.Router) {
974974
r.Use(apiKeyMiddleware)
975-
r.Get("/available", handleExperimentsSafe)
975+
r.Get("/available", handleExperimentsAvailable)
976976
r.Get("/", api.handleExperimentsGet)
977977
})
978978
r.Get("/updatecheck", api.updateCheck)
@@ -1895,7 +1895,9 @@ func ReadExperiments(log slog.Logger, raw []string) codersdk.Experiments {
18951895
exps = append(exps, codersdk.ExperimentsSafe...)
18961896
default:
18971897
ex := codersdk.Experiment(strings.ToLower(v))
1898-
if !slice.Contains(codersdk.ExperimentsSafe, ex) {
1898+
if !slice.Contains(codersdk.ExperimentsKnown, ex) {
1899+
log.Warn(context.Background(), "ignoring unknown experiment", slog.F("experiment", ex))
1900+
} else if !slice.Contains(codersdk.ExperimentsSafe, ex) {
18991901
log.Warn(context.Background(), "🐉 HERE BE DRAGONS: opting into hidden experiment", slog.F("experiment", ex))
19001902
}
19011903
exps = append(exps, ex)

coderd/devtunnel/tunnel_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"net/http"
1212
"net/http/httptest"
1313
"net/url"
14+
"runtime"
1415
"strconv"
1516
"strings"
1617
"testing"
@@ -33,6 +34,10 @@ import (
3334
func TestTunnel(t *testing.T) {
3435
t.Parallel()
3536

37+
if runtime.GOOS == "windows" {
38+
t.Skip("these tests are flaky on windows and cause the tests to fail with '(unknown)' and no output, see https://github.com/coder/internal/issues/579")
39+
}
40+
3641
cases := []struct {
3742
name string
3843
version tunnelsdk.TunnelVersion
@@ -173,6 +178,7 @@ func newTunnelServer(t *testing.T) *tunnelServer {
173178
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
174179
if handler != nil {
175180
handler.ServeHTTP(w, r)
181+
return
176182
}
177183

178184
w.WriteHeader(http.StatusBadGateway)
@@ -207,6 +213,7 @@ func newTunnelServer(t *testing.T) *tunnelServer {
207213
if err == nil {
208214
break
209215
}
216+
td = nil
210217
t.Logf("failed to create tunnel server on port %d: %s", wireguardPort, err)
211218
}
212219
if td == nil {

coderd/dynamicparameters/resolver.go

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,45 @@ type parameterValue struct {
2626
Source parameterValueSource
2727
}
2828

29+
type ResolverError struct {
30+
Diagnostics hcl.Diagnostics
31+
Parameter map[string]hcl.Diagnostics
32+
}
33+
34+
// Error is a pretty bad format for these errors. Try to avoid using this.
35+
func (e *ResolverError) Error() string {
36+
var diags hcl.Diagnostics
37+
diags = diags.Extend(e.Diagnostics)
38+
for _, d := range e.Parameter {
39+
diags = diags.Extend(d)
40+
}
41+
42+
return diags.Error()
43+
}
44+
45+
func (e *ResolverError) HasError() bool {
46+
if e.Diagnostics.HasErrors() {
47+
return true
48+
}
49+
50+
for _, diags := range e.Parameter {
51+
if diags.HasErrors() {
52+
return true
53+
}
54+
}
55+
return false
56+
}
57+
58+
func (e *ResolverError) Extend(parameterName string, diag hcl.Diagnostics) {
59+
if e.Parameter == nil {
60+
e.Parameter = make(map[string]hcl.Diagnostics)
61+
}
62+
if _, ok := e.Parameter[parameterName]; !ok {
63+
e.Parameter[parameterName] = hcl.Diagnostics{}
64+
}
65+
e.Parameter[parameterName] = e.Parameter[parameterName].Extend(diag)
66+
}
67+
2968
//nolint:revive // firstbuild is a control flag to turn on immutable validation
3069
func ResolveParameters(
3170
ctx context.Context,
@@ -35,7 +74,7 @@ func ResolveParameters(
3574
previousValues []database.WorkspaceBuildParameter,
3675
buildValues []codersdk.WorkspaceBuildParameter,
3776
presetValues []database.TemplateVersionPresetParameter,
38-
) (map[string]string, hcl.Diagnostics) {
77+
) (map[string]string, error) {
3978
previousValuesMap := slice.ToMapFunc(previousValues, func(p database.WorkspaceBuildParameter) (string, string) {
4079
return p.Name, p.Value
4180
})
@@ -73,7 +112,10 @@ func ResolveParameters(
73112
// always be valid. If there is a case where this is not true, then this has to
74113
// be changed to allow the build to continue with a different set of values.
75114

76-
return nil, diags
115+
return nil, &ResolverError{
116+
Diagnostics: diags,
117+
Parameter: nil,
118+
}
77119
}
78120

79121
// The user's input now needs to be validated against the parameters.
@@ -113,12 +155,16 @@ func ResolveParameters(
113155
// are fatal. Additional validation for immutability has to be done manually.
114156
output, diags = renderer.Render(ctx, ownerID, values.ValuesMap())
115157
if diags.HasErrors() {
116-
return nil, diags
158+
return nil, &ResolverError{
159+
Diagnostics: diags,
160+
Parameter: nil,
161+
}
117162
}
118163

119164
// parameterNames is going to be used to remove any excess values that were left
120165
// around without a parameter.
121166
parameterNames := make(map[string]struct{}, len(output.Parameters))
167+
parameterError := &ResolverError{}
122168
for _, parameter := range output.Parameters {
123169
parameterNames[parameter.Name] = struct{}{}
124170

@@ -132,20 +178,22 @@ func ResolveParameters(
132178
}
133179

134180
// An immutable parameter was changed, which is not allowed.
135-
// Add the failed diagnostic to the output.
136-
diags = diags.Append(&hcl.Diagnostic{
137-
Severity: hcl.DiagError,
138-
Summary: "Immutable parameter changed",
139-
Detail: fmt.Sprintf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", parameter.Name),
140-
Subject: src,
181+
// Add a failed diagnostic to the output.
182+
parameterError.Extend(parameter.Name, hcl.Diagnostics{
183+
&hcl.Diagnostic{
184+
Severity: hcl.DiagError,
185+
Summary: "Immutable parameter changed",
186+
Detail: fmt.Sprintf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", parameter.Name),
187+
Subject: src,
188+
},
141189
})
142190
}
143191
}
144192

145193
// TODO: Fix the `hcl.Diagnostics(...)` type casting. It should not be needed.
146194
if hcl.Diagnostics(parameter.Diagnostics).HasErrors() {
147-
// All validation errors are raised here.
148-
diags = diags.Extend(hcl.Diagnostics(parameter.Diagnostics))
195+
// All validation errors are raised here for each parameter.
196+
parameterError.Extend(parameter.Name, hcl.Diagnostics(parameter.Diagnostics))
149197
}
150198

151199
// If the parameter has a value, but it was not set explicitly by the user at any
@@ -174,8 +222,13 @@ func ResolveParameters(
174222
}
175223
}
176224

225+
if parameterError.HasError() {
226+
// If there are any errors, return them.
227+
return nil, parameterError
228+
}
229+
177230
// Return the values to be saved for the build.
178-
return values.ValuesMap(), diags
231+
return values.ValuesMap(), nil
179232
}
180233

181234
type parameterValueMap map[string]parameterValue

coderd/experiments.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (api *API) handleExperimentsGet(rw http.ResponseWriter, r *http.Request) {
2626
// @Tags General
2727
// @Success 200 {array} codersdk.Experiment
2828
// @Router /experiments/available [get]
29-
func handleExperimentsSafe(rw http.ResponseWriter, r *http.Request) {
29+
func handleExperimentsAvailable(rw http.ResponseWriter, r *http.Request) {
3030
ctx := r.Context()
3131
httpapi.Write(ctx, rw, http.StatusOK, codersdk.AvailableExperiments{
3232
Safe: codersdk.ExperimentsSafe,

coderd/httpapi/httperror/doc.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Package httperror handles formatting and writing some sentinel errors returned
2+
// within coder to the API.
3+
// This package exists outside httpapi to avoid some cyclic dependencies
4+
package httperror

coderd/httpapi/httperror/wsbuild.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package httperror
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
"sort"
9+
10+
"github.com/hashicorp/hcl/v2"
11+
12+
"github.com/coder/coder/v2/coderd/dynamicparameters"
13+
"github.com/coder/coder/v2/coderd/httpapi"
14+
"github.com/coder/coder/v2/coderd/wsbuilder"
15+
"github.com/coder/coder/v2/codersdk"
16+
)
17+
18+
func WriteWorkspaceBuildError(ctx context.Context, rw http.ResponseWriter, err error) {
19+
var buildErr wsbuilder.BuildError
20+
if errors.As(err, &buildErr) {
21+
if httpapi.IsUnauthorizedError(err) {
22+
buildErr.Status = http.StatusForbidden
23+
}
24+
25+
httpapi.Write(ctx, rw, buildErr.Status, codersdk.Response{
26+
Message: buildErr.Message,
27+
Detail: buildErr.Error(),
28+
})
29+
return
30+
}
31+
32+
var parameterErr *dynamicparameters.ResolverError
33+
if errors.As(err, &parameterErr) {
34+
resp := codersdk.Response{
35+
Message: "Unable to validate parameters",
36+
Validations: nil,
37+
}
38+
39+
// Sort the parameter names so that the order is consistent.
40+
sortedNames := make([]string, 0, len(parameterErr.Parameter))
41+
for name := range parameterErr.Parameter {
42+
sortedNames = append(sortedNames, name)
43+
}
44+
sort.Strings(sortedNames)
45+
46+
for _, name := range sortedNames {
47+
diag := parameterErr.Parameter[name]
48+
resp.Validations = append(resp.Validations, codersdk.ValidationError{
49+
Field: name,
50+
Detail: DiagnosticsErrorString(diag),
51+
})
52+
}
53+
54+
if parameterErr.Diagnostics.HasErrors() {
55+
resp.Detail = DiagnosticsErrorString(parameterErr.Diagnostics)
56+
}
57+
58+
httpapi.Write(ctx, rw, http.StatusBadRequest, resp)
59+
return
60+
}
61+
62+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
63+
Message: "Internal error creating workspace build.",
64+
Detail: err.Error(),
65+
})
66+
}
67+
68+
func DiagnosticError(d *hcl.Diagnostic) string {
69+
return fmt.Sprintf("%s; %s", d.Summary, d.Detail)
70+
}
71+
72+
func DiagnosticsErrorString(d hcl.Diagnostics) string {
73+
count := len(d)
74+
switch {
75+
case count == 0:
76+
return "no diagnostics"
77+
case count == 1:
78+
return DiagnosticError(d[0])
79+
default:
80+
for _, d := range d {
81+
// Render the first error diag.
82+
// If there are warnings, do not priority them over errors.
83+
if d.Severity == hcl.DiagError {
84+
return fmt.Sprintf("%s, and %d other diagnostic(s)", DiagnosticError(d), count-1)
85+
}
86+
}
87+
88+
// All warnings? ok...
89+
return fmt.Sprintf("%s, and %d other diagnostic(s)", DiagnosticError(d[0]), count-1)
90+
}
91+
}

coderd/parameters_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"github.com/coder/coder/v2/coderd/database/dbtestutil"
1616
"github.com/coder/coder/v2/coderd/database/pubsub"
1717
"github.com/coder/coder/v2/coderd/rbac"
18-
"github.com/coder/coder/v2/coderd/util/ptr"
1918
"github.com/coder/coder/v2/codersdk"
2019
"github.com/coder/coder/v2/codersdk/wsjson"
2120
"github.com/coder/coder/v2/provisioner/echo"
@@ -260,7 +259,6 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) {
260259
Value: "eu",
261260
},
262261
}
263-
request.EnableDynamicParameters = true
264262
})
265263
coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, wrk.LatestBuild.ID)
266264

@@ -285,7 +283,6 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) {
285283
RichParameterValues: []codersdk.WorkspaceBuildParameter{
286284
{Name: "region", Value: regionVal},
287285
},
288-
EnableDynamicParameters: ptr.Ref(true),
289286
})
290287
require.NoError(t, err)
291288
coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, bld.ID)

0 commit comments

Comments
 (0)