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

Skip to content

Commit c451f4e

Browse files
authored
feat: Add templates to create working release (#422)
* Add templates * Move API structs to codersdk * Back to green tests! * It all works, but now with tea! 🧋 * It works! * Add cancellation to provisionerd * Tests pass! * Add deletion of workspaces and projects * Fix agent lock * Add clog * Fix linting errors * Remove unused CLI tests * Rename daemon to start * Fix leaking command * Fix promptui test * Update agent connection frequency * Skip login tests on Windows * Increase tunnel connect timeout * Fix templater * Lower test requirements * Fix embed * Disable promptui tests for Windows * Fix write newline * Fix PTY write newline * Fix CloseReader * Fix compilation on Windows * Fix linting error * Remove bubbletea * Cleanup readwriter * Use embedded templates instead of serving over API * Move templates to examples * Improve workspace create flow * Fix Windows build * Fix tests * Fix linting errors * Fix untar with extracting max size * Fix newline char
1 parent 2818b3c commit c451f4e

File tree

138 files changed

+7285
-2302
lines changed

Some content is hidden

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

138 files changed

+7285
-2302
lines changed

.github/workflows/coder.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ jobs:
157157
- name: Test with Mock Database
158158
shell: bash
159159
env:
160-
GOCOUNT: ${{ runner.os == 'Windows' && 3 || 5 }}
160+
GOCOUNT: ${{ runner.os == 'Windows' && 1 || 2 }}
161161
GOMAXPROCS: ${{ runner.os == 'Windows' && 1 || 2 }}
162162
run: gotestsum --junitfile="gotests.xml" --packages="./..." --
163163
-covermode=atomic -coverprofile="gotests.coverage"
@@ -178,7 +178,7 @@ jobs:
178178
run: DB=true gotestsum --junitfile="gotests.xml" --packages="./..." --
179179
-covermode=atomic -coverprofile="gotests.coverage" -timeout=3m
180180
-coverpkg=./...,github.com/coder/coder/codersdk
181-
-count=1 -race -parallel=2 -failfast
181+
-count=1 -parallel=2 -failfast
182182

183183
- name: Upload DataDog Trace
184184
if: (success() || failure()) && github.actor != 'dependabot[bot]' && runner.os == 'Linux'

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ site/**/*.typegen.ts
2828
# Build
2929
dist/
3030
site/out/
31+
32+
*.tfstate
33+
*.tfplan
34+
*.lock.hcl
35+
.terraform/

.goreleaser.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
archives:
2-
- builds:
2+
- id: coder
3+
builds:
34
- coder
45
files:
56
- README.md
@@ -12,18 +13,18 @@ before:
1213
builds:
1314
- id: coder-slim
1415
dir: cmd/coder
15-
flags: [-tags=slim]
1616
ldflags: ["-s -w"]
1717
env: [CGO_ENABLED=0]
1818
goos: [darwin, linux, windows]
1919
goarch: [amd64, arm64]
2020
hooks:
2121
# The "trimprefix" appends ".exe" on Windows.
2222
post: |
23-
cp {{.Path}} site/out/bin/coder_{{ .Os }}_{{ .Arch }}{{ trimprefix .Name "coder" }}
23+
cp {{.Path}} site/out/bin/coder-{{ .Os }}-{{ .Arch }}{{ trimprefix .Name "coder" }}
2424
2525
- id: coder
2626
dir: cmd/coder
27+
flags: [-tags=embed]
2728
ldflags: ["-s -w"]
2829
env: [CGO_ENABLED=0]
2930
goos: [darwin, linux, windows]

.vscode/settings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"cSpell.words": [
3+
"cliui",
34
"coderd",
45
"coderdtest",
56
"codersdk",
@@ -12,8 +13,10 @@
1213
"goleak",
1314
"gossh",
1415
"hashicorp",
16+
"hclsyntax",
1517
"httpmw",
1618
"idtoken",
19+
"Iflag",
1720
"incpatch",
1821
"isatty",
1922
"Jobf",
@@ -40,11 +43,14 @@
4043
"retrier",
4144
"sdkproto",
4245
"stretchr",
46+
"TCGETS",
4347
"tcpip",
48+
"TCSETS",
4449
"tfexec",
4550
"tfstate",
4651
"trimprefix",
4752
"unconvert",
53+
"Untar",
4854
"webrtc",
4955
"xerrors",
5056
"yamux"
@@ -69,7 +75,7 @@
6975
"go.coverOnSave": true,
7076
// The codersdk is used by coderd another other packages extensively.
7177
// To reduce redundancy in tests, it's covered by other packages.
72-
"go.testFlags": ["-coverpkg=./.,github.com/coder/coder/codersdk"],
78+
"go.testFlags": ["-short", "-coverpkg=./.,github.com/coder/coder/codersdk"],
7379
"go.coverageDecorator": {
7480
"type": "gutter",
7581
"coveredHighlightColor": "rgba(64,128,128,0.5)",

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ install: bin
5555
@echo "-- CLI available at $(shell ls $(INSTALL_DIR)/coder*)"
5656
.PHONY: install
5757

58+
package:
59+
goreleaser release --snapshot --rm-dist
60+
.PHONY: package
61+
5862
peerbroker/proto: peerbroker/proto/peerbroker.proto
5963
protoc \
6064
--go_out=. \
@@ -89,7 +93,3 @@ site/out:
8993
# Restores GITKEEP files!
9094
git checkout HEAD site/out
9195
.PHONY: site/out
92-
93-
snapshot:
94-
goreleaser release --snapshot --rm-dist
95-
.PHONY: snapshot

agent/agent.go

Lines changed: 72 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"net"
11+
"os"
1112
"os/exec"
1213
"os/user"
1314
"sync"
@@ -85,6 +86,76 @@ type server struct {
8586
sshServer *ssh.Server
8687
}
8788

89+
func (s *server) run(ctx context.Context) {
90+
var peerListener *peerbroker.Listener
91+
var err error
92+
// An exponential back-off occurs when the connection is failing to dial.
93+
// This is to prevent server spam in case of a coderd outage.
94+
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(ctx); {
95+
peerListener, err = s.clientDialer(ctx, s.options)
96+
if err != nil {
97+
if errors.Is(err, context.Canceled) {
98+
return
99+
}
100+
if s.isClosed() {
101+
return
102+
}
103+
s.options.Logger.Warn(context.Background(), "failed to dial", slog.Error(err))
104+
continue
105+
}
106+
s.options.Logger.Debug(context.Background(), "connected")
107+
break
108+
}
109+
select {
110+
case <-ctx.Done():
111+
return
112+
default:
113+
}
114+
115+
for {
116+
conn, err := peerListener.Accept()
117+
if err != nil {
118+
if s.isClosed() {
119+
return
120+
}
121+
s.options.Logger.Debug(ctx, "peer listener accept exited; restarting connection", slog.Error(err))
122+
s.run(ctx)
123+
return
124+
}
125+
s.closeMutex.Lock()
126+
s.connCloseWait.Add(1)
127+
s.closeMutex.Unlock()
128+
go s.handlePeerConn(ctx, conn)
129+
}
130+
}
131+
132+
func (s *server) handlePeerConn(ctx context.Context, conn *peer.Conn) {
133+
go func() {
134+
<-conn.Closed()
135+
s.connCloseWait.Done()
136+
}()
137+
for {
138+
channel, err := conn.Accept(ctx)
139+
if err != nil {
140+
if errors.Is(err, peer.ErrClosed) || s.isClosed() {
141+
return
142+
}
143+
s.options.Logger.Debug(ctx, "accept channel from peer connection", slog.Error(err))
144+
return
145+
}
146+
147+
switch channel.Protocol() {
148+
case "ssh":
149+
s.sshServer.HandleConn(channel.NetConn())
150+
default:
151+
s.options.Logger.Warn(ctx, "unhandled protocol from channel",
152+
slog.F("protocol", channel.Protocol()),
153+
slog.F("label", channel.Label()),
154+
)
155+
}
156+
}
157+
}
158+
88159
func (s *server) init(ctx context.Context) {
89160
// Clients' should ignore the host key when connecting.
90161
// The agent needs to authenticate with coderd to SSH,
@@ -197,7 +268,7 @@ func (*server) handleSSHSession(session ssh.Session) error {
197268
}()
198269

199270
cmd := exec.CommandContext(session.Context(), command, args...)
200-
cmd.Env = session.Environ()
271+
cmd.Env = append(os.Environ(), session.Environ()...)
201272

202273
sshPty, windowSize, isPty := session.Pty()
203274
if isPty {
@@ -244,76 +315,6 @@ func (*server) handleSSHSession(session ssh.Session) error {
244315
return nil
245316
}
246317

247-
func (s *server) run(ctx context.Context) {
248-
var peerListener *peerbroker.Listener
249-
var err error
250-
// An exponential back-off occurs when the connection is failing to dial.
251-
// This is to prevent server spam in case of a coderd outage.
252-
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(ctx); {
253-
peerListener, err = s.clientDialer(ctx, s.options)
254-
if err != nil {
255-
if errors.Is(err, context.Canceled) {
256-
return
257-
}
258-
if s.isClosed() {
259-
return
260-
}
261-
s.options.Logger.Warn(context.Background(), "failed to dial", slog.Error(err))
262-
continue
263-
}
264-
s.options.Logger.Debug(context.Background(), "connected")
265-
break
266-
}
267-
select {
268-
case <-ctx.Done():
269-
return
270-
default:
271-
}
272-
273-
for {
274-
conn, err := peerListener.Accept()
275-
if err != nil {
276-
if s.isClosed() {
277-
return
278-
}
279-
s.options.Logger.Debug(ctx, "peer listener accept exited; restarting connection", slog.Error(err))
280-
s.run(ctx)
281-
return
282-
}
283-
s.closeMutex.Lock()
284-
s.connCloseWait.Add(1)
285-
s.closeMutex.Unlock()
286-
go s.handlePeerConn(ctx, conn)
287-
}
288-
}
289-
290-
func (s *server) handlePeerConn(ctx context.Context, conn *peer.Conn) {
291-
go func() {
292-
<-conn.Closed()
293-
s.connCloseWait.Done()
294-
}()
295-
for {
296-
channel, err := conn.Accept(ctx)
297-
if err != nil {
298-
if errors.Is(err, peer.ErrClosed) || s.isClosed() {
299-
return
300-
}
301-
s.options.Logger.Debug(ctx, "accept channel from peer connection", slog.Error(err))
302-
return
303-
}
304-
305-
switch channel.Protocol() {
306-
case "ssh":
307-
s.sshServer.HandleConn(channel.NetConn())
308-
default:
309-
s.options.Logger.Warn(ctx, "unhandled protocol from channel",
310-
slog.F("protocol", channel.Protocol()),
311-
slog.F("label", channel.Label()),
312-
)
313-
}
314-
}
315-
}
316-
317318
// isClosed returns whether the API is closed or not.
318319
func (s *server) isClosed() bool {
319320
select {

agent/usershell/usershell_windows.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package usershell
22

3+
import "os/exec"
4+
35
// Get returns the command prompt binary name.
46
func Get(username string) (string, error) {
7+
_, err := exec.LookPath("powershell.exe")
8+
if err == nil {
9+
return "powershell.exe", nil
10+
}
511
return "cmd.exe", nil
612
}

cli/cliui/cliui.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cliui
2+
3+
import (
4+
"github.com/charmbracelet/charm/ui/common"
5+
"github.com/charmbracelet/lipgloss"
6+
"golang.org/x/xerrors"
7+
)
8+
9+
var (
10+
Canceled = xerrors.New("canceled")
11+
12+
defaultStyles = common.DefaultStyles()
13+
)
14+
15+
// ValidateNotEmpty is a helper function to disallow empty inputs!
16+
func ValidateNotEmpty(s string) error {
17+
if s == "" {
18+
return xerrors.New("Must be provided!")
19+
}
20+
return nil
21+
}
22+
23+
// Styles compose visual elements of the UI!
24+
var Styles = struct {
25+
Bold,
26+
Code,
27+
Field,
28+
Keyword,
29+
Paragraph,
30+
Placeholder,
31+
Prompt,
32+
FocusedPrompt,
33+
Fuschia,
34+
Logo,
35+
Warn,
36+
Wrap lipgloss.Style
37+
}{
38+
Bold: lipgloss.NewStyle().Bold(true),
39+
Code: defaultStyles.Code,
40+
Field: defaultStyles.Code.Copy().Foreground(lipgloss.AdaptiveColor{Light: "#000000", Dark: "#FFFFFF"}),
41+
Keyword: defaultStyles.Keyword,
42+
Paragraph: defaultStyles.Paragraph,
43+
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
44+
Prompt: defaultStyles.Prompt.Foreground(lipgloss.AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"}),
45+
FocusedPrompt: defaultStyles.FocusedPrompt.Foreground(lipgloss.Color("#651fff")),
46+
Fuschia: defaultStyles.SelectedMenuItem.Copy(),
47+
Logo: defaultStyles.Logo.SetString("Coder"),
48+
Warn: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#ECFD65"}),
49+
Wrap: defaultStyles.Wrap,
50+
}

0 commit comments

Comments
 (0)