-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
615 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: CI | ||
on: | ||
- push | ||
- pull_request | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
name: Test | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
- name: Cache Go modules | ||
uses: actions/cache@v4 | ||
with: | ||
path: | | ||
~/go/pkg/mod | ||
~/.cache/go-build | ||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | ||
restore-keys: | | ||
${{ runner.os }}-go- | ||
- name: Install Go stable version | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version: "1.22" | ||
- name: Run tests | ||
run: go test ./... | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
name: lint | ||
on: [push] | ||
jobs: | ||
golangci: | ||
name: lint | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-go@v5 | ||
with: | ||
go-version: stable | ||
- uses: golangci/golangci-lint-action@v6 | ||
with: | ||
version: v1.60 | ||
args: --timeout=5m |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
run: | ||
|
||
linters-settings: | ||
govet: | ||
enable-all: true | ||
disable: | ||
- shadow | ||
- fieldalignment | ||
|
||
linters: | ||
enable-all: true | ||
disable: | ||
- contextcheck | ||
- cyclop | ||
- depguard | ||
- dupl | ||
- exhaustive | ||
- exhaustruct | ||
- err113 | ||
- errorlint | ||
- funlen | ||
- gci | ||
- gochecknoglobals | ||
- gochecknoinits | ||
- gocognit | ||
- gocritic | ||
- gocyclo | ||
- godot | ||
- godox | ||
- gofumpt | ||
- gomnd | ||
- gomoddirectives # I think it's broken | ||
- gosec | ||
- gosmopolitan | ||
- govet | ||
- inamedparam # oh, sod off | ||
- interfacebloat | ||
- ireturn # No, I _LIKE_ returning interfaces | ||
- lll | ||
- maintidx # Do this in code review | ||
- makezero | ||
- mnd # TODO: re-enable when we can check again | ||
- nonamedreturns | ||
- nakedret | ||
- nestif | ||
- nlreturn | ||
- paralleltest | ||
- perfsprint | ||
- testifylint # TODO: re-enable when we can check again | ||
- tagliatelle | ||
- testpackage | ||
- thelper # Tests are fine | ||
- varnamelen # Short names are ok | ||
- wrapcheck | ||
- wsl | ||
|
||
issues: | ||
exclude-rules: | ||
# not needed | ||
- path: /*.go | ||
text: "ST1003: should not use underscores in package names" | ||
linters: | ||
- stylecheck | ||
- path: /*.go | ||
text: "don't use an underscore in package name" | ||
linters: | ||
- revive | ||
- path: /main.go | ||
linters: | ||
- errcheck | ||
- path: /*_test.go | ||
linters: | ||
- errcheck | ||
- errchkjson | ||
- forcetypeassert | ||
- path: /*_example_test.go | ||
linters: | ||
- forbidigo | ||
- path: /*_test.go | ||
text: "var-naming: " | ||
linters: | ||
- revive | ||
|
||
# Maximum issues count per one linter. Set to 0 to disable. Default is 50. | ||
max-issues-per-linter: 0 | ||
|
||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3. | ||
max-same-issues: 0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# scriptor | ||
|
||
A "scripting" framework, to coordinate actions: For example, this can be useful to construct testing sequences in Go. | ||
|
||
# HOW TO USE | ||
|
||
## 1. Create a `scene.Scene` object | ||
|
||
```go | ||
s := scene.New() | ||
``` | ||
|
||
## 2. Add `scene.Action` objects to `scene.Scene` | ||
|
||
```go | ||
// inline Action | ||
s.Add(scene.ActionFunc(func(ctx context.Context) error { | ||
// .. do something ... | ||
return nil | ||
})) | ||
|
||
// built-in Action | ||
s.Add(actions.Delay(5*time.Second)) | ||
|
||
// custom Action object | ||
s.Add(myCustomAction{}) | ||
``` | ||
|
||
## 3. Prepare a `context.Context` object | ||
|
||
All transient data in this tool is expected to be passed down along with a `context.Context` object. | ||
|
||
For example, logging is done through a `slog.Logger` passed down with the context. This means that the `context.Context` object must be primed with the logger object before the `Action`s are fired. | ||
|
||
To do this, you can manually create a context object using the appropriate injector functions, such as `log.InjectContext()`: | ||
|
||
```go | ||
ctx := log.InjectContext(context.Background(), slog.New(....)) | ||
``` | ||
|
||
Or, to get the default set of values injected, you can use `scriptor.DefaultContext()`: | ||
|
||
```go | ||
ctx := scriptor.DefaultContext(context.Background()) | ||
``` | ||
|
||
The values that need to be injected defer based on the actions that you provide. | ||
As of this writing the documentation is lacking, but in the future each component | ||
in this module should clearly state which values need to be injected into the | ||
`context.Context` object. | ||
|
||
As of this writing it is safest to just use `scriptor.DefaultContext()` for most everything. | ||
|
||
## 4. Execute the `scene.Scene` object | ||
|
||
Finally, put everything together and execute the scene. | ||
|
||
```go | ||
s.Execute(ctx) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package actions | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/lestrrat-go/scriptor/scene" | ||
) | ||
|
||
type delay time.Duration | ||
|
||
func (d delay) Execute(ctx context.Context) error { | ||
select { | ||
case <-time.After(time.Duration(d)): | ||
return nil | ||
case <-ctx.Done(): | ||
return ctx.Err() | ||
} | ||
} | ||
|
||
func Delay(d time.Duration) scene.Action { | ||
return delay(d) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package clock | ||
|
||
import ( | ||
"context" | ||
"time" | ||
) | ||
|
||
// Clock is an interface that provides the current time. | ||
type Clock interface { | ||
Now() time.Time | ||
} | ||
|
||
type static time.Time | ||
|
||
func Static(t time.Time) Clock { | ||
return static(t) | ||
} | ||
|
||
func (s static) Now() time.Time { | ||
return time.Time(s) | ||
} | ||
|
||
type realClock struct{} | ||
|
||
func (realClock) Now() time.Time { | ||
return time.Now() | ||
} | ||
|
||
func RealClock() Clock { | ||
return realClock{} | ||
} | ||
|
||
type clockKey struct{} | ||
|
||
func InjectContext(ctx context.Context, v Clock) context.Context { | ||
return context.WithValue(ctx, clockKey{}, v) | ||
} | ||
|
||
// FromContext returns the Clock from the context, if any. | ||
// Make sure to check the return value for nil. | ||
func FromContext(ctx context.Context) Clock { | ||
v := ctx.Value(clockKey{}) | ||
if v == nil { | ||
return nil | ||
} | ||
if c, ok := v.(Clock); ok { | ||
return c | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module github.com/lestrrat-go/scriptor | ||
|
||
go 1.22.6 | ||
|
||
require github.com/stretchr/testify v1.9.0 | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | ||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package httpactions | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log/slog" | ||
"net/http" | ||
|
||
"github.com/lestrrat-go/scriptor/log" | ||
"github.com/lestrrat-go/scriptor/scene" | ||
"github.com/lestrrat-go/scriptor/stash" | ||
) | ||
|
||
type prevRequestKey struct{} | ||
type prevResponseKey struct{} | ||
|
||
func PrevRequest(ctx context.Context) *http.Request { | ||
st := stash.FromContext(ctx) | ||
if st == nil { | ||
return nil | ||
} | ||
|
||
v, ok := st.Get(prevRequestKey{}) | ||
if !ok { | ||
return nil | ||
} | ||
|
||
if req, ok := v.(*http.Request); ok { | ||
return req | ||
} | ||
return nil | ||
} | ||
|
||
func PrevResponse(ctx context.Context) *http.Response { | ||
st := stash.FromContext(ctx) | ||
if st == nil { | ||
return nil | ||
} | ||
|
||
v, ok := st.Get(prevResponseKey{}) | ||
if !ok { | ||
return nil | ||
} | ||
|
||
if res, ok := v.(*http.Response); ok { | ||
return res | ||
} | ||
return nil | ||
} | ||
|
||
type Client struct { | ||
client *http.Client | ||
} | ||
|
||
func NewClient(client *http.Client) *Client { | ||
return &Client{client: client} | ||
} | ||
|
||
func (h *Client) GetAction(u string) scene.Action { | ||
r, err := http.NewRequest(http.MethodGet, u, nil) | ||
return &httpAction{client: h.client, req: r, err: err, name: "GetAction"} | ||
} | ||
|
||
type httpAction struct { | ||
client *http.Client | ||
req *http.Request | ||
err error | ||
name string | ||
} | ||
|
||
func (h *httpAction) Execute(ctx context.Context) error { | ||
logger := log.FromContext(ctx) | ||
if err := h.err; err != nil { | ||
logger.LogAttrs(ctx, slog.LevelInfo, "actions.httpAction", slog.String("error", err.Error())) | ||
return fmt.Errorf("actions.httpAction: error during setup: %w", err) | ||
} | ||
|
||
req := h.req.WithContext(ctx) | ||
//nolint:bodyclose | ||
res, err := h.client.Do(req) | ||
if err != nil { | ||
return fmt.Errorf("actions.httpAction: error during request: %w", err) | ||
} | ||
|
||
st := stash.FromContext(ctx) | ||
|
||
logger.DebugContext(ctx, "actions.httpAction", slog.Any("request", req)) | ||
logger.DebugContext(ctx, "actions.httpAction", slog.Any("response", res)) | ||
st.Set(prevRequestKey{}, req) | ||
st.Set(prevResponseKey{}, res) | ||
return nil | ||
} |
Oops, something went wrong.