Skip to content

Commit f5fc8be

Browse files
mirkoCrobumirkoCrobualessio-perugini
authored
Add brick api-docs, and examples (#499)
Co-authored-by: mirkoCrobu <mirkocrobu@NB-0531.localdomain> Co-authored-by: Alessio Perugini <alessio@perugini.xyz>
1 parent 42f909a commit f5fc8be

File tree

7 files changed

+122
-39
lines changed

7 files changed

+122
-39
lines changed

internal/api/docs/openapi.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,10 +976,17 @@ components:
976976
type: object
977977
BrickDetailsResult:
978978
properties:
979+
api_docs_path:
980+
type: string
979981
author:
980982
type: string
981983
category:
982984
type: string
985+
code_examples:
986+
items:
987+
$ref: '#/components/schemas/CodeExample'
988+
nullable: true
989+
type: array
983990
description:
984991
type: string
985992
id:
@@ -1073,6 +1080,11 @@ components:
10731080
nullable: true
10741081
type: string
10751082
type: object
1083+
CodeExample:
1084+
properties:
1085+
path:
1086+
type: string
1087+
type: object
10761088
ConfigDirectories:
10771089
properties:
10781090
apps:

internal/api/handlers/bricks.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,15 +236,15 @@ func HandleBrickDelete(
236236
if err != nil {
237237
switch {
238238
case errors.Is(err, bricks.ErrBrickNotFound):
239-
details := fmt.Sprintf("brick not found for id %q", id)
240-
render.EncodeResponse(w, http.StatusNotFound, models.ErrorResponse{Details: details})
239+
slog.Error("brick not found", "id", id, "error", err)
240+
render.EncodeResponse(w, http.StatusNotFound, models.ErrorResponse{Details: "brick not found"})
241241

242242
case errors.Is(err, bricks.ErrCannotSaveBrick):
243-
log.Printf("Internal error saving brick instance %s: %v", id, err)
243+
slog.Error("Internal error saving brick instance", "id", id, "error", err)
244244
render.EncodeResponse(w, http.StatusInternalServerError, models.ErrorResponse{Details: "unable to delete the app"})
245245

246246
default:
247-
log.Printf("Unexpected error deleting brick %s: %v", id, err)
247+
slog.Error("Unexpected error deleting brick", "id", id, "error", err)
248248
render.EncodeResponse(w, http.StatusInternalServerError, models.ErrorResponse{Details: "A server error occurred while finalizing the deletion."})
249249
}
250250
return

internal/e2e/client/client.gen.go

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

internal/orchestrator/bricks/bricks.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"maps"
77
"slices"
88

9+
"github.com/arduino/go-paths-helper"
910
"go.bug.st/f"
1011

1112
"github.com/bcmi-labs/orchestrator/internal/orchestrator/app"
@@ -129,15 +130,32 @@ func (s *Service) BricksDetails(id string) (BrickDetailsResult, error) {
129130
return BrickDetailsResult{}, fmt.Errorf("cannot open docs for brick %s: %w", id, err)
130131
}
131132

133+
apiDocsPath, err := s.staticStore.GetBrickApiDocPathFromID(brick.ID)
134+
if err != nil {
135+
return BrickDetailsResult{}, fmt.Errorf("cannot open api-docs for brick %s: %w", id, err)
136+
}
137+
138+
examplePaths, err := s.staticStore.GetBrickCodeExamplesPathFromID(brick.ID)
139+
if err != nil {
140+
return BrickDetailsResult{}, fmt.Errorf("cannot open code examples for brick %s: %w", id, err)
141+
}
142+
codeExamples := f.Map(examplePaths, func(p *paths.Path) CodeExample {
143+
return CodeExample{
144+
Path: p.String(),
145+
}
146+
})
147+
132148
return BrickDetailsResult{
133-
ID: id,
134-
Name: brick.Name,
135-
Author: "Arduino", // TODO: for now we only support our bricks
136-
Description: brick.Description,
137-
Category: brick.Category,
138-
Status: "installed", // For now every Arduino brick are installed
139-
Variables: variables,
140-
Readme: readme,
149+
ID: id,
150+
Name: brick.Name,
151+
Author: "Arduino", // TODO: for now we only support our bricks
152+
Description: brick.Description,
153+
Category: brick.Category,
154+
Status: "installed", // For now every Arduino brick are installed
155+
Variables: variables,
156+
Readme: readme,
157+
ApiDocsPath: apiDocsPath,
158+
CodeExamples: codeExamples,
141159
}, nil
142160
}
143161

internal/orchestrator/bricks/types.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,25 @@ type BrickVariable struct {
3434
Required bool `json:"required"`
3535
}
3636

37+
type CodeExample struct {
38+
Path string `json:"path"`
39+
}
3740
type AppReference struct {
3841
ID string `json:"id"`
3942
Name string `json:"name"`
4043
Icon string `json:"icon"`
4144
}
4245

4346
type BrickDetailsResult struct {
44-
ID string `json:"id"`
45-
Name string `json:"name"`
46-
Author string `json:"author"`
47-
Description string `json:"description"`
48-
Category string `json:"category"`
49-
Status string `json:"status"`
50-
Variables map[string]BrickVariable `json:"variables,omitempty"`
51-
Readme string `json:"readme"`
52-
UsedByApps []AppReference `json:"used_by_apps"`
47+
ID string `json:"id"`
48+
Name string `json:"name"`
49+
Author string `json:"author"`
50+
Description string `json:"description"`
51+
Category string `json:"category"`
52+
Status string `json:"status"`
53+
Variables map[string]BrickVariable `json:"variables,omitempty"`
54+
Readme string `json:"readme"`
55+
ApiDocsPath string `json:"api_docs_path"`
56+
CodeExamples []CodeExample `json:"code_examples"`
57+
UsedByApps []AppReference `json:"used_by_apps"`
5358
}

internal/store/store.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,22 @@ import (
1111
)
1212

1313
type StaticStore struct {
14-
baseDir string
15-
composePath string
16-
docsPath string
17-
assetsPath *paths.Path
14+
baseDir string
15+
composePath string
16+
docsPath string
17+
assetsPath *paths.Path
18+
apiDocsPath string
19+
codeExamplesPath string
1820
}
1921

2022
func NewStaticStore(baseDir string) *StaticStore {
2123
return &StaticStore{
22-
baseDir: baseDir,
23-
composePath: filepath.Join(baseDir, "compose"),
24-
docsPath: filepath.Join(baseDir, "docs"),
25-
assetsPath: paths.New(baseDir),
24+
baseDir: baseDir,
25+
composePath: filepath.Join(baseDir, "compose"),
26+
docsPath: filepath.Join(baseDir, "docs"),
27+
apiDocsPath: filepath.Join(baseDir, "api-docs"),
28+
codeExamplesPath: filepath.Join(baseDir, "examples"),
29+
assetsPath: paths.New(baseDir),
2630
}
2731
}
2832

@@ -63,3 +67,24 @@ func (s *StaticStore) GetBrickComposeFilePathFromID(brickID string) (*paths.Path
6367
}
6468
return paths.New(s.composePath, namespace, brickName, "brick_compose.yaml"), nil
6569
}
70+
71+
func (s *StaticStore) GetBrickApiDocPathFromID(brickID string) (string, error) {
72+
namespace, brickName, ok := strings.Cut(brickID, ":")
73+
if !ok {
74+
return "", errors.New("invalid ID")
75+
}
76+
return filepath.Join(s.apiDocsPath, namespace, "app_bricks", brickName, "API.md"), nil
77+
}
78+
79+
func (s *StaticStore) GetBrickCodeExamplesPathFromID(brickID string) (paths.PathList, error) {
80+
namespace, brickName, ok := strings.Cut(brickID, ":")
81+
if !ok {
82+
return nil, errors.New("invalid ID")
83+
}
84+
targetDir := paths.New(s.codeExamplesPath, namespace, brickName)
85+
dirEntries, err := targetDir.ReadDir()
86+
if err != nil {
87+
return nil, fmt.Errorf("cannot read examples directory %q: %w", targetDir, err)
88+
}
89+
return dirEntries, nil
90+
}

internal/store/store_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,26 @@ import (
88

99
var s = NewStaticStore("0.1.16")
1010

11-
func BenchmarkNew(b *testing.B) {
11+
func BenchmarkGetBrickReadmeFromID(b *testing.B) {
1212
for b.Loop() {
1313
x, err := s.GetBrickReadmeFromID("arduino:dbstorage_sqlstore")
1414
require.NoError(b, err)
1515
require.NotEmpty(b, x)
1616
}
1717
}
18+
19+
func BenchmarkGetBrickApiDocsPathFromID(b *testing.B) {
20+
for b.Loop() {
21+
x, err := s.GetBrickApiDocPathFromID("arduino:dbstorage_sqlstore")
22+
require.NoError(b, err)
23+
require.NotEmpty(b, x)
24+
}
25+
}
26+
27+
func BenchmarkGetBrickCodeExamplesPathFromID(b *testing.B) {
28+
for b.Loop() {
29+
x, err := s.GetBrickCodeExamplesPathFromID("arduino:weather_forecast")
30+
require.NoError(b, err)
31+
require.NotEmpty(b, x)
32+
}
33+
}

0 commit comments

Comments
 (0)