Skip to content

Commit e4332d7

Browse files
committed
Merge branch 'main' into dk/prebuilds-docs
2 parents 6439616 + 6b4d3f8 commit e4332d7

Some content is hidden

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

64 files changed

+4788
-169
lines changed

.github/actions/setup-go/action.yaml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,42 @@ inputs:
55
version:
66
description: "The Go version to use."
77
default: "1.24.2"
8+
use-preinstalled-go:
9+
description: "Whether to use preinstalled Go."
10+
default: "false"
11+
use-temp-cache-dirs:
12+
description: "Whether to use temporary GOCACHE and GOMODCACHE directories."
13+
default: "false"
814
runs:
915
using: "composite"
1016
steps:
17+
- name: Override GOCACHE and GOMODCACHE
18+
shell: bash
19+
if: inputs.use-temp-cache-dirs == 'true'
20+
run: |
21+
# cd to another directory to ensure we're not inside a Go project.
22+
# That'd trigger Go to download the toolchain for that project.
23+
cd "$RUNNER_TEMP"
24+
# RUNNER_TEMP should be backed by a RAM disk on Windows if
25+
# coder/setup-ramdisk-action was used
26+
export GOCACHE_DIR="$RUNNER_TEMP""\go-cache"
27+
export GOMODCACHE_DIR="$RUNNER_TEMP""\go-mod-cache"
28+
export GOPATH_DIR="$RUNNER_TEMP""\go-path"
29+
mkdir -p "$GOCACHE_DIR"
30+
mkdir -p "$GOMODCACHE_DIR"
31+
mkdir -p "$GOPATH_DIR"
32+
go env -w GOCACHE="$GOCACHE_DIR"
33+
go env -w GOMODCACHE="$GOMODCACHE_DIR"
34+
go env -w GOPATH="$GOPATH_DIR"
35+
1136
- name: Setup Go
1237
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
1338
with:
14-
go-version: ${{ inputs.version }}
39+
go-version: ${{ inputs.use-preinstalled-go == 'false' && inputs.version || '' }}
1540

1641
- name: Install gotestsum
1742
shell: bash
18-
run: go install gotest.tools/gotestsum@latest
43+
run: go install gotest.tools/gotestsum@3f7ff0ec4aeb6f95f5d67c998b71f272aa8a8b41 # v1.12.1
1944

2045
# It isn't necessary that we ever do this, but it helps
2146
# separate the "setup" from the "run" times.

.github/actions/upload-datadog/action.yaml

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ runs:
1010
steps:
1111
- shell: bash
1212
run: |
13+
set -e
14+
1315
owner=${{ github.repository_owner }}
1416
echo "owner: $owner"
1517
if [[ $owner != "coder" ]]; then
@@ -21,8 +23,45 @@ runs:
2123
echo "No API key provided, skipping..."
2224
exit 0
2325
fi
24-
npm install -g @datadog/datadog-ci@2.21.0
25-
datadog-ci junit upload --service coder ./gotests.xml \
26+
27+
BINARY_VERSION="v2.48.0"
28+
BINARY_HASH_WINDOWS="b7bebb8212403fddb1563bae84ce5e69a70dac11e35eb07a00c9ef7ac9ed65ea"
29+
BINARY_HASH_MACOS="e87c808638fddb21a87a5c4584b68ba802965eb0a593d43959c81f67246bd9eb"
30+
BINARY_HASH_LINUX="5e700c465728fff8313e77c2d5ba1ce19a736168735137e1ddc7c6346ed48208"
31+
32+
TMP_DIR=$(mktemp -d)
33+
34+
if [[ "${{ runner.os }}" == "Windows" ]]; then
35+
BINARY_PATH="${TMP_DIR}/datadog-ci.exe"
36+
BINARY_URL="https://github.com/DataDog/datadog-ci/releases/download/${BINARY_VERSION}/datadog-ci_win-x64"
37+
elif [[ "${{ runner.os }}" == "macOS" ]]; then
38+
BINARY_PATH="${TMP_DIR}/datadog-ci"
39+
BINARY_URL="https://github.com/DataDog/datadog-ci/releases/download/${BINARY_VERSION}/datadog-ci_darwin-arm64"
40+
elif [[ "${{ runner.os }}" == "Linux" ]]; then
41+
BINARY_PATH="${TMP_DIR}/datadog-ci"
42+
BINARY_URL="https://github.com/DataDog/datadog-ci/releases/download/${BINARY_VERSION}/datadog-ci_linux-x64"
43+
else
44+
echo "Unsupported OS: ${{ runner.os }}"
45+
exit 1
46+
fi
47+
48+
echo "Downloading DataDog CI binary version ${BINARY_VERSION} for ${{ runner.os }}..."
49+
curl -sSL "$BINARY_URL" -o "$BINARY_PATH"
50+
51+
if [[ "${{ runner.os }}" == "Windows" ]]; then
52+
echo "$BINARY_HASH_WINDOWS $BINARY_PATH" | sha256sum --check
53+
elif [[ "${{ runner.os }}" == "macOS" ]]; then
54+
echo "$BINARY_HASH_MACOS $BINARY_PATH" | shasum -a 256 --check
55+
elif [[ "${{ runner.os }}" == "Linux" ]]; then
56+
echo "$BINARY_HASH_LINUX $BINARY_PATH" | sha256sum --check
57+
fi
58+
59+
# Make binary executable (not needed for Windows)
60+
if [[ "${{ runner.os }}" != "Windows" ]]; then
61+
chmod +x "$BINARY_PATH"
62+
fi
63+
64+
"$BINARY_PATH" junit upload --service coder ./gotests.xml \
2665
--tags os:${{runner.os}} --tags runner_name:${{runner.name}}
2766
env:
2867
DATADOG_API_KEY: ${{ inputs.api-key }}

.github/workflows/ci.yaml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ jobs:
313313
run: ./scripts/check_unstaged.sh
314314

315315
test-go:
316-
runs-on: ${{ matrix.os == 'ubuntu-latest' && github.repository_owner == 'coder' && 'depot-ubuntu-22.04-4' || matrix.os == 'macos-latest' && github.repository_owner == 'coder' && 'depot-macos-latest' || matrix.os == 'windows-2022' && github.repository_owner == 'coder' && 'windows-latest-16-cores' || matrix.os }}
316+
runs-on: ${{ matrix.os == 'ubuntu-latest' && github.repository_owner == 'coder' && 'depot-ubuntu-22.04-4' || matrix.os == 'macos-latest' && github.repository_owner == 'coder' && 'depot-macos-latest' || matrix.os == 'windows-2022' && github.repository_owner == 'coder' && 'depot-windows-2022-16' || matrix.os }}
317317
needs: changes
318318
if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main'
319319
timeout-minutes: 20
@@ -326,17 +326,31 @@ jobs:
326326
- windows-2022
327327
steps:
328328
- name: Harden Runner
329+
# Harden Runner is only supported on Ubuntu runners.
330+
if: runner.os == 'Linux'
329331
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
330332
with:
331333
egress-policy: audit
332334

335+
# Set up RAM disks to speed up the rest of the job. This action is in
336+
# a separate repository to allow its use before actions/checkout.
337+
- name: Setup RAM Disks
338+
if: runner.os == 'Windows'
339+
uses: coder/setup-ramdisk-action@79dacfe70c47ad6d6c0dd7f45412368802641439
340+
333341
- name: Checkout
334342
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
335343
with:
336344
fetch-depth: 1
337345

338346
- name: Setup Go
339347
uses: ./.github/actions/setup-go
348+
with:
349+
# Runners have Go baked-in and Go will automatically
350+
# download the toolchain configured in go.mod, so we don't
351+
# need to reinstall it. It's faster on Windows runners.
352+
use-preinstalled-go: ${{ runner.os == 'Windows' }}
353+
use-temp-cache-dirs: ${{ runner.os == 'Windows' }}
340354

341355
- name: Setup Terraform
342356
uses: ./.github/actions/setup-tf

cli/server.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import (
6161
"github.com/coder/serpent"
6262
"github.com/coder/wgtunnel/tunnelsdk"
6363

64+
"github.com/coder/coder/v2/coderd/ai"
6465
"github.com/coder/coder/v2/coderd/entitlements"
6566
"github.com/coder/coder/v2/coderd/notifications/reports"
6667
"github.com/coder/coder/v2/coderd/runtimeconfig"
@@ -610,6 +611,22 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
610611
)
611612
}
612613

614+
aiProviders, err := ReadAIProvidersFromEnv(os.Environ())
615+
if err != nil {
616+
return xerrors.Errorf("read ai providers from env: %w", err)
617+
}
618+
vals.AI.Value.Providers = append(vals.AI.Value.Providers, aiProviders...)
619+
for _, provider := range aiProviders {
620+
logger.Debug(
621+
ctx, "loaded ai provider",
622+
slog.F("type", provider.Type),
623+
)
624+
}
625+
languageModels, err := ai.ModelsFromConfig(ctx, vals.AI.Value.Providers)
626+
if err != nil {
627+
return xerrors.Errorf("create language models: %w", err)
628+
}
629+
613630
realIPConfig, err := httpmw.ParseRealIPConfig(vals.ProxyTrustedHeaders, vals.ProxyTrustedOrigins)
614631
if err != nil {
615632
return xerrors.Errorf("parse real ip config: %w", err)
@@ -640,6 +657,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
640657
CacheDir: cacheDir,
641658
GoogleTokenValidator: googleTokenValidator,
642659
ExternalAuthConfigs: externalAuthConfigs,
660+
LanguageModels: languageModels,
643661
RealIPConfig: realIPConfig,
644662
SSHKeygenAlgorithm: sshKeygenAlgorithm,
645663
TracerProvider: tracerProvider,
@@ -2621,6 +2639,77 @@ func redirectHTTPToHTTPSDeprecation(ctx context.Context, logger slog.Logger, inv
26212639
}
26222640
}
26232641

2642+
func ReadAIProvidersFromEnv(environ []string) ([]codersdk.AIProviderConfig, error) {
2643+
// The index numbers must be in-order.
2644+
sort.Strings(environ)
2645+
2646+
var providers []codersdk.AIProviderConfig
2647+
for _, v := range serpent.ParseEnviron(environ, "CODER_AI_PROVIDER_") {
2648+
tokens := strings.SplitN(v.Name, "_", 2)
2649+
if len(tokens) != 2 {
2650+
return nil, xerrors.Errorf("invalid env var: %s", v.Name)
2651+
}
2652+
2653+
providerNum, err := strconv.Atoi(tokens[0])
2654+
if err != nil {
2655+
return nil, xerrors.Errorf("parse number: %s", v.Name)
2656+
}
2657+
2658+
var provider codersdk.AIProviderConfig
2659+
switch {
2660+
case len(providers) < providerNum:
2661+
return nil, xerrors.Errorf(
2662+
"provider num %v skipped: %s",
2663+
len(providers),
2664+
v.Name,
2665+
)
2666+
case len(providers) == providerNum:
2667+
// At the next next provider.
2668+
providers = append(providers, provider)
2669+
case len(providers) == providerNum+1:
2670+
// At the current provider.
2671+
provider = providers[providerNum]
2672+
}
2673+
2674+
key := tokens[1]
2675+
switch key {
2676+
case "TYPE":
2677+
provider.Type = v.Value
2678+
case "API_KEY":
2679+
provider.APIKey = v.Value
2680+
case "BASE_URL":
2681+
provider.BaseURL = v.Value
2682+
case "MODELS":
2683+
provider.Models = strings.Split(v.Value, ",")
2684+
}
2685+
providers[providerNum] = provider
2686+
}
2687+
for _, envVar := range environ {
2688+
tokens := strings.SplitN(envVar, "=", 2)
2689+
if len(tokens) != 2 {
2690+
continue
2691+
}
2692+
switch tokens[0] {
2693+
case "OPENAI_API_KEY":
2694+
providers = append(providers, codersdk.AIProviderConfig{
2695+
Type: "openai",
2696+
APIKey: tokens[1],
2697+
})
2698+
case "ANTHROPIC_API_KEY":
2699+
providers = append(providers, codersdk.AIProviderConfig{
2700+
Type: "anthropic",
2701+
APIKey: tokens[1],
2702+
})
2703+
case "GOOGLE_API_KEY":
2704+
providers = append(providers, codersdk.AIProviderConfig{
2705+
Type: "google",
2706+
APIKey: tokens[1],
2707+
})
2708+
}
2709+
}
2710+
return providers, nil
2711+
}
2712+
26242713
// ReadExternalAuthProvidersFromEnv is provided for compatibility purposes with
26252714
// the viper CLI.
26262715
func ReadExternalAuthProvidersFromEnv(environ []string) ([]codersdk.ExternalAuthConfig, error) {

cli/testdata/server-config.yaml.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,9 @@ client:
519519
# Support links to display in the top right drop down menu.
520520
# (default: <unset>, type: struct[[]codersdk.LinkConfig])
521521
supportLinks: []
522+
# Configure AI providers.
523+
# (default: <unset>, type: struct[codersdk.AIConfig])
524+
ai: {}
522525
# External Authentication providers.
523526
# (default: <unset>, type: struct[[]codersdk.ExternalAuthConfig])
524527
externalAuthProviders: []

0 commit comments

Comments
 (0)