Merge branch 'master' into alund/home-v1

This commit is contained in:
Stefan Ålund
2020-02-06 21:03:27 +01:00
116 changed files with 12431 additions and 989 deletions
+29
View File
@@ -0,0 +1,29 @@
name: Scaffolder CI
on:
push:
paths:
- 'backend/scaffolder/**'
- '.github/workflows/scaffolder.yml'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.12
- name: checkout code
uses: actions/checkout@v1
- name: setup env
run: |
echo "::set-env name=GOPATH::$(go env GOPATH)"
echo "::add-path::$(go env GOPATH)/bin"
shell: bash
- name: build
run: go build -v ./...
working-directory: ./backend/scaffolder
- name: test
run: go test ./... -short
working-directory: ./backend/scaffolder
+2
View File
@@ -0,0 +1,2 @@
secrets.env
.DS_Store
-1
View File
@@ -1 +0,0 @@
main
+2
View File
@@ -16,6 +16,8 @@ RUN go build .
FROM debian:buster
ARG service
RUN apt-get update && apt-get install -y ca-certificates
WORKDIR /app/
COPY --from=build /build/$service/$service /app/service
+85
View File
@@ -0,0 +1,85 @@
package ghactions
import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
)
type Client struct {
client *http.Client
baseURL string
accessToken string
}
func NewFromEnv() (*Client, error) {
accessToken := os.Getenv("BOSS_GH_ACCESS_TOKEN")
if accessToken == "" {
return nil, fmt.Errorf("BOSS_GH_ACCESS_TOKEN not set")
}
return New(http.DefaultClient, "https://api.github.com", accessToken), nil
}
func New(client *http.Client, baseURL, accessToken string) *Client {
return &Client{
client: client,
baseURL: baseURL,
accessToken: accessToken,
}
}
func (c *Client) createRequest(ctx context.Context, owner, repo, path string) (*http.Request, error) {
url := fmt.Sprintf("%s/repos/%s/%s/actions%s", c.baseURL, owner, repo, path)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", "Bearer "+c.accessToken)
return req.WithContext(ctx), nil
}
func (c *Client) ListWorkflowRuns(ctx context.Context, owner, repo string) (*WorkflowRunsListResponse, error) {
req, err := c.createRequest(ctx, owner, repo, "/runs")
if err != nil {
return nil, err
}
res, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var resData WorkflowRunsListResponse
if err := json.NewDecoder(res.Body).Decode(&resData); err != nil {
return nil, err
}
return &resData, nil
}
func (c *Client) GetWorkflowRun(ctx context.Context, owner, repo, runId string) (*WorkflowRunResponse, error) {
req, err := c.createRequest(ctx, owner, repo, fmt.Sprintf("/runs/%s", runId))
if err != nil {
return nil, err
}
res, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var resData WorkflowRunResponse
if err := json.NewDecoder(res.Body).Decode(&resData); err != nil {
return nil, err
}
return &resData, nil
}
+53
View File
@@ -0,0 +1,53 @@
package ghactions
type User struct {
Name string `json:"name"` // "Octo Cat"
Email string `json:"email"` // "octocat@github.com"
}
type Commit struct {
ID string `json:"id"` // "acb5820ced9479c074f688cc328bf03f341a511d"
TreeID string `json:"tree_id"` // "d23f6eedb1e1b9610bbc754ddb5197bfe7271223"
Message string `json:"message"` // "Create linter.yml"
Timestamp string `json:"timestamp"` // "2020-01-22T19:33:05Z"
Author User `json:"author"`
Committer User `json:"committer"`
}
type Repository struct {
ID int64 `json:"id"` // 217723378
NodeID string `json:"node_id"` // MDEwOlJlcG9zaXRvcnkyMTc3MjMzNzg="
Name string `json:"name"` // o-repo"
FullName string `json:"full_name"` // "octo-org/octo-repo"
HTMLURL string `json:"html_url"` // "https://github.com/octo-org/octo-repo"
}
type WorkflowRunResponse struct {
ID int64 `json:"id"` // 30433642
NodeID string `json:"node_id"` // "MDEyOldvcmtmbG93IFJ1bjI2OTI4OQ=="
HeadBranch string `json:"head_branch"` // "master"
HeadSha string `json:"head_sha"` // "acb5820ced9479c074f688cc328bf03f341a511d"
RunNumber int64 `json:"run_number"` // 562
CheckSuiteID int64 `json:"check_suite_id"` // 414944374
Event string `json:"event"` // "push"
Status string `json:"status"` // "queued"
Conclusion *string `json:"conclusion"` // null
URL string `json:"url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642"
HTMLURL string `json:"html_url"` // "https://github.com/octo-org/octo-repo/actions/runs/30433642"
CreatedAt string `json:"created_at"` // "2020-01-22T19:33:08Z"
UpdatedAt string `json:"updated_at"` // "2020-01-22T19:33:08Z"
JobsURL string `json:"jobs_url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/jobs"
LogsURL string `json:"logs_url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/logs"
ArtifactsURL string `json:"artifacts_url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/artifacts"
CancelURL string `json:"cancel_url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/cancel"
RerunURL string `json:"rerun_url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/runs/30433642/rerun"
WorkflowURL string `json:"workflow_url"` // "https://api.github.com/repos/octo-org/octo-repo/actions/workflows/30433642"
HeadCommit Commit `json:"head_commit"`
Repository Repository `json:"repository"`
HeadRepository Repository `json:"head_repository"`
}
type WorkflowRunsListResponse struct {
TotalCount int64 `json:"total_count"`
Runs []WorkflowRunResponse `json:"workflow_runs"`
}
+10
View File
@@ -0,0 +1,10 @@
module github.com/spotify/backstage/builds
go 1.12
replace github.com/spotify/backstage/proto => ../proto
require (
github.com/spotify/backstage/proto v0.0.0-00010101000000-000000000000
google.golang.org/grpc v1.27.1
)
+54
View File
@@ -0,0 +1,54 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+34
View File
@@ -0,0 +1,34 @@
package main
import (
"log"
"net"
"github.com/spotify/backstage/builds/ghactions"
"github.com/spotify/backstage/builds/service"
buildsv1 "github.com/spotify/backstage/proto/builds/v1"
"google.golang.org/grpc"
)
const (
port = ":50051"
)
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
ghClient, err := ghactions.NewFromEnv()
if err != nil {
log.Fatalf("Failed to create github client, %s", err)
}
buildsv1.RegisterBuildsServer(grpcServer, service.New(ghClient))
log.Println("Serving Builds Service")
grpcServer.Serve(lis)
}
+116
View File
@@ -0,0 +1,116 @@
package service
import (
"context"
"fmt"
"regexp"
"github.com/spotify/backstage/builds/ghactions"
buildsv1 "github.com/spotify/backstage/proto/builds/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type service struct {
ghClient *ghactions.Client
}
var _ buildsv1.BuildsServer = (*service)(nil)
// New creates a new identity data server
func New(ghClient *ghactions.Client) buildsv1.BuildsServer {
return &service{ghClient}
}
func (s *service) ListBuilds(ctx context.Context, req *buildsv1.ListBuildsRequest) (*buildsv1.ListBuildsReply, error) {
owner := "spotify"
repo := "backstage"
result, err := s.ghClient.ListWorkflowRuns(ctx, owner, repo)
if err != nil {
return nil, status.Errorf(codes.Internal, "Failed to fetch workflow runs for %s/%s, %s", owner, repo, err)
}
builds := make([]*buildsv1.Build, len(result.Runs))
for i, run := range result.Runs {
builds[i] = s.transformBuild(owner, repo, &run)
}
return &buildsv1.ListBuildsReply{
EntityUri: "",
Builds: builds,
}, nil
}
func (s *service) GetBuild(ctx context.Context, req *buildsv1.GetBuildRequest) (*buildsv1.GetBuildReply, error) {
uri := req.GetBuildUri()
owner, repo, runID, err := s.parseBuildURI(uri)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "Invalid build URI '%s', %s", uri, err)
}
run, err := s.ghClient.GetWorkflowRun(ctx, owner, repo, runID)
if err != nil {
return nil, status.Errorf(codes.Internal, "Failed to fetch workflow run for %s/%s/%s, %s", owner, repo, runID, err)
}
return &buildsv1.GetBuildReply{
Build: s.transformBuild(owner, repo, run),
Details: &buildsv1.BuildDetails{
Author: run.HeadCommit.Author.Name,
LogUrl: run.LogsURL,
OverviewUrl: run.HTMLURL,
},
}, nil
}
func (s *service) transformBuild(owner, repo string, run *ghactions.WorkflowRunResponse) *buildsv1.Build {
stat := buildsv1.BuildStatus_NULL
switch run.Status {
case "queued":
stat = buildsv1.BuildStatus_PENDING
case "in_progress":
stat = buildsv1.BuildStatus_RUNNING
case "completed":
if run.Conclusion != nil {
switch *run.Conclusion {
case "success":
stat = buildsv1.BuildStatus_SUCCESS
case "neutral":
stat = buildsv1.BuildStatus_SUCCESS
case "failure":
stat = buildsv1.BuildStatus_FAILURE
case "cancelled":
stat = buildsv1.BuildStatus_FAILURE
case "timed_out":
stat = buildsv1.BuildStatus_FAILURE
case "action_required":
stat = buildsv1.BuildStatus_RUNNING
}
}
}
return &buildsv1.Build{
Uri: fmt.Sprintf("entity:build:%s/%s/%d", owner, repo, run.ID),
CommitId: run.HeadCommit.ID,
Message: run.HeadCommit.Message,
Status: stat,
}
}
var entityURIRegex = regexp.MustCompile("^entity:build:([^/:]+)/([^/:]+)/([^/:]+)$")
func (s *service) parseBuildURI(uri string) (owner, repo, runID string, err error) {
if uri == "" {
return "", "", "", fmt.Errorf("uri is empty")
}
match := entityURIRegex.FindStringSubmatch(uri)
if err != nil {
return "", "", "", fmt.Errorf("uri does not match")
}
return match[1], match[2], match[3], nil
}
+37 -5
View File
@@ -3,6 +3,7 @@ package app
import (
"context"
"fmt"
"github.com/spotify/backstage/inventory/storage"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -15,27 +16,58 @@ type Server struct {
Storage *storage.Storage
}
func (s *Server) ListEntities(ctx context.Context, req *pb.ListEntitiesRequest) (*pb.ListEntitiesReply, error) {
entities, err := s.Storage.ListEntities(req.UriPrefix)
if err != nil {
return nil, status.Error(codes.Internal, "could not list entities")
}
result := make([]*pb.Entity, len(entities))
for i, v := range entities {
result[i] = &pb.Entity{Uri: v}
}
return &pb.ListEntitiesReply{Entities: result}, nil
}
func (s *Server) CreateEntity(ctx context.Context, req *pb.CreateEntityRequest) (*pb.CreateEntityReply, error) {
err := s.Storage.CreateEntity(req.GetEntity().GetUri())
if err != nil {
return nil, status.Error(codes.Internal, "could not create entity")
return nil, status.Error(codes.Internal, "could not create entity")
}
return &pb.CreateEntityReply{Entity: req.GetEntity()} , nil
return &pb.CreateEntityReply{Entity: req.GetEntity()}, nil
}
// GetEntity returns an inventory Entity with the selected facts
func (s *Server) GetEntity(ctx context.Context, req *pb.GetEntityRequest) (*pb.GetEntityReply, error) {
var facts []*pb.Fact
entityUri, err := s.Storage.GetEntity(req.GetEntity().GetUri())
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("could not get entity %v", err))
}
return &pb.GetEntityReply{Entity: &pb.Entity{Uri: entityUri}}, nil
for _, factName := range req.GetIncludeFacts() {
value, err := s.Storage.GetFact(entityUri, factName)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("could not get fact %v for %v", factName, entityUri))
}
facts = append(facts, &pb.Fact{Name: factName, Value: value})
}
return &pb.GetEntityReply{Entity: &pb.Entity{Uri: entityUri}, Facts: facts}, nil
}
func (s *Server) SetFact(ctx context.Context, req *pb.SetFactRequest) (*pb.SetFactReply, error) {
factUri, err := s.Storage.SetFact(req.EntityUri, req.Name, req.Value)
err := s.Storage.SetFact(req.EntityUri, req.Name, req.Value)
if err != nil {
return nil, status.Error(codes.Internal, "could not set fact")
}
return &pb.SetFactReply{FactUri: factUri} , nil
return &pb.SetFactReply{Fact: &pb.Fact{Name: req.GetName(), Value: req.GetValue()}}, nil
}
func (s *Server) GetFact(ctx context.Context, req *pb.GetFactRequest) (*pb.GetFactReply, error) {
val, err := s.Storage.GetFact(req.EntityUri, req.Name)
if err != nil {
return nil, status.Error(codes.Internal, "could not set fact")
}
return &pb.GetFactReply{Fact: &pb.Fact{Name: req.GetName(), Value: val}}, nil
}
+69 -8
View File
@@ -3,14 +3,48 @@ package app
import (
"context"
"fmt"
"github.com/spotify/backstage/inventory/storage"
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/spotify/backstage/inventory/storage"
pb "github.com/spotify/backstage/proto/inventory/v1"
)
func TestServerListEntities(t *testing.T) {
testStorage := NewTestStorage()
defer testStorage.Close()
s := Server{Storage: testStorage.Storage}
entity := &pb.Entity{Uri: "boss://test/test"}
_, err := s.CreateEntity(context.Background(), &pb.CreateEntityRequest{Entity: entity})
if err != nil {
t.Errorf("ServerTest(TestServerListEntities) could not create: %v", err)
}
list, err := s.ListEntities(context.Background(), &pb.ListEntitiesRequest{UriPrefix: ""})
if err != nil {
t.Errorf("ServerTest(TestServerListEntities) could not list: %v", err)
}
if len(list.GetEntities()) != 1 {
t.Errorf("ServerTest(TestServerListEntities) expected %v items, got %v", 1, len(list.GetEntities()))
}
if list.GetEntities()[0].GetUri() != "boss://test/test" {
t.Errorf("ServerTest(TestServerListEntities) expected uri %v, got %v", "boss://test/test", list.GetEntities()[0].GetUri())
}
list, err = s.ListEntities(context.Background(), &pb.ListEntitiesRequest{UriPrefix: "boss://test2"})
if err != nil {
t.Errorf("ServerTest(TestServerListEntities) could not list: %v", err)
}
if len(list.GetEntities()) != 0 {
t.Errorf("ServerTest(TestServerListEntities) expected %v items, got %v", 0, len(list.GetEntities()))
}
}
func TestServerCreateEntity(t *testing.T) {
testStorage := NewTestStorage()
defer testStorage.Close()
@@ -22,7 +56,7 @@ func TestServerCreateEntity(t *testing.T) {
if err != nil {
t.Errorf("ServerTest(CreateEntity) got unexpected error %v", err)
}
if resp.GetEntity().GetUri() != entity.GetUri() {
if resp.GetEntity().GetUri() != entity.GetUri() {
t.Errorf("ServerTest(CreateEntity) expected %v, but got %v", entity.GetUri(), resp.GetEntity().GetUri())
}
}
@@ -49,6 +83,31 @@ func TestServerGetEntity(t *testing.T) {
}
}
func TestServerGetEntityWithIncludedFacts(t *testing.T) {
testStorage := NewTestStorage()
defer testStorage.Close()
s := Server{Storage: testStorage.Storage}
entityUri := "boss://test/test"
setFactReq := &pb.SetFactRequest{EntityUri: entityUri, Name: "test-name", Value: "test-value"}
s.SetFact(context.Background(), setFactReq)
entity := &pb.Entity{Uri: entityUri}
req := &pb.GetEntityRequest{Entity: entity, IncludeFacts: []string{"test-name"}}
resp, err := s.GetEntity(context.Background(), req)
if err != nil {
t.Errorf("ServerTest(GetEntity) got unexpected error %v", err)
}
if resp == nil {
t.Errorf("ServerTest(GetEntity) returned nil")
}
expectedFacts := []*pb.Fact{{Name: "test-name", Value: "test-value"}}
if !reflect.DeepEqual(resp.GetFacts(), expectedFacts) {
t.Errorf("ServerTest(GetEntity) got %v, wanted %v", resp.GetFacts(), expectedFacts)
}
}
func TestServerSetFactForExistingEntity(t *testing.T) {
testStorage := NewTestStorage()
defer testStorage.Close()
@@ -66,8 +125,9 @@ func TestServerSetFactForExistingEntity(t *testing.T) {
if resp == nil {
t.Errorf("ServerTest(SetFact) returned nil")
}
if resp.GetFactUri() != entity.GetUri() + "/" + req.Name {
t.Errorf("ServerTest(SetFact) got %v, wanted %v", resp.GetFactUri(), entity.GetUri() + "/" + req.Name)
fact := &pb.Fact{Name: req.GetName(), Value: req.GetValue()}
if !reflect.DeepEqual(resp.GetFact(), fact) {
t.Errorf("ServerTest(SetFact) got %v, wanted %v", resp.GetFact(), fact)
}
}
@@ -85,14 +145,16 @@ func TestServerSetFactForNonExistingEntity(t *testing.T) {
if resp == nil {
t.Errorf("ServerTest(SetFact) returned nil")
}
if resp.GetFactUri() != entityUri + "/" + req.Name {
t.Errorf("ServerTest(SetFact) got %v, wanted %v", resp.GetFactUri(), entityUri + "/" + req.Name)
fact := &pb.Fact{Name: req.GetName(), Value: req.GetValue()}
if !reflect.DeepEqual(resp.GetFact(), fact) {
t.Errorf("ServerTest(SetFact) got %v, wanted %v", resp.GetFact(), fact)
}
}
type TestStorage struct {
Storage *storage.Storage
Path string
Path string
}
// NewTestStorage returns a TestStorage using a temporary path.
@@ -114,4 +176,3 @@ func (db *TestStorage) Close() {
defer os.Remove(db.Path)
db.Storage.Close()
}
-3
View File
@@ -8,8 +8,5 @@ require (
github.com/golang/protobuf v1.3.3
github.com/spotify/backstage/proto v0.0.0-00010101000000-000000000000
go.etcd.io/bbolt v1.3.3
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 // indirect
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 // indirect
google.golang.org/grpc v1.27.0
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc // indirect
)
+29 -7
View File
@@ -3,6 +3,7 @@ package storage
import (
"fmt"
"os"
"strings"
"go.etcd.io/bbolt"
)
@@ -37,8 +38,8 @@ func (s *Storage) Close() error {
return s.db.Close()
}
func (s *Storage) SetFact(entityUri, name, value string) (factUri string, err error) {
err = s.db.Update(func(tx *bbolt.Tx) error {
func (s *Storage) SetFact(entityUri, name, value string) (err error) {
return s.db.Update(func(tx *bbolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(entityUri))
if err != nil {
return err
@@ -49,11 +50,6 @@ func (s *Storage) SetFact(entityUri, name, value string) (factUri string, err er
}
return nil
})
if err != nil {
return "", err
}
return entityUri + "/" + name, nil
}
func (s *Storage) GetFact(entityUri, name string) (string, error) {
@@ -67,6 +63,7 @@ func (s *Storage) GetFact(entityUri, name string) (string, error) {
value = string(b.Get([]byte(name)))
return nil
})
if err != nil {
return "", err
}
@@ -74,6 +71,31 @@ func (s *Storage) GetFact(entityUri, name string) (string, error) {
return value, nil
}
func (s *Storage) ListEntities(uriPrefix string) ([]string, error) {
entities := []string{}
err := s.db.View(func(tx *bbolt.Tx) error {
err := tx.ForEach(func(name []byte, b *bbolt.Bucket) error {
namestring := string(name)
if uriPrefix == "" || strings.HasPrefix(namestring, uriPrefix) {
entities = append(entities, namestring)
}
return nil
})
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return entities, nil
}
func (s *Storage) CreateEntity(entityUri string) error {
return s.db.Update(func(tx *bbolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(entityUri))
+509
View File
@@ -0,0 +1,509 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: builds/v1/builds.proto
package buildsv1
import (
context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type BuildStatus int32
const (
BuildStatus_NULL BuildStatus = 0
BuildStatus_SUCCESS BuildStatus = 1
BuildStatus_FAILURE BuildStatus = 2
BuildStatus_PENDING BuildStatus = 3
BuildStatus_RUNNING BuildStatus = 4
)
var BuildStatus_name = map[int32]string{
0: "NULL",
1: "SUCCESS",
2: "FAILURE",
3: "PENDING",
4: "RUNNING",
}
var BuildStatus_value = map[string]int32{
"NULL": 0,
"SUCCESS": 1,
"FAILURE": 2,
"PENDING": 3,
"RUNNING": 4,
}
func (x BuildStatus) String() string {
return proto.EnumName(BuildStatus_name, int32(x))
}
func (BuildStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{0}
}
type ListBuildsRequest struct {
EntityUri string `protobuf:"bytes,1,opt,name=entity_uri,json=entityUri,proto3" json:"entity_uri,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListBuildsRequest) Reset() { *m = ListBuildsRequest{} }
func (m *ListBuildsRequest) String() string { return proto.CompactTextString(m) }
func (*ListBuildsRequest) ProtoMessage() {}
func (*ListBuildsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{0}
}
func (m *ListBuildsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListBuildsRequest.Unmarshal(m, b)
}
func (m *ListBuildsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListBuildsRequest.Marshal(b, m, deterministic)
}
func (m *ListBuildsRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListBuildsRequest.Merge(m, src)
}
func (m *ListBuildsRequest) XXX_Size() int {
return xxx_messageInfo_ListBuildsRequest.Size(m)
}
func (m *ListBuildsRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ListBuildsRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ListBuildsRequest proto.InternalMessageInfo
func (m *ListBuildsRequest) GetEntityUri() string {
if m != nil {
return m.EntityUri
}
return ""
}
type ListBuildsReply struct {
EntityUri string `protobuf:"bytes,1,opt,name=entity_uri,json=entityUri,proto3" json:"entity_uri,omitempty"`
Builds []*Build `protobuf:"bytes,2,rep,name=builds,proto3" json:"builds,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListBuildsReply) Reset() { *m = ListBuildsReply{} }
func (m *ListBuildsReply) String() string { return proto.CompactTextString(m) }
func (*ListBuildsReply) ProtoMessage() {}
func (*ListBuildsReply) Descriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{1}
}
func (m *ListBuildsReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListBuildsReply.Unmarshal(m, b)
}
func (m *ListBuildsReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListBuildsReply.Marshal(b, m, deterministic)
}
func (m *ListBuildsReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListBuildsReply.Merge(m, src)
}
func (m *ListBuildsReply) XXX_Size() int {
return xxx_messageInfo_ListBuildsReply.Size(m)
}
func (m *ListBuildsReply) XXX_DiscardUnknown() {
xxx_messageInfo_ListBuildsReply.DiscardUnknown(m)
}
var xxx_messageInfo_ListBuildsReply proto.InternalMessageInfo
func (m *ListBuildsReply) GetEntityUri() string {
if m != nil {
return m.EntityUri
}
return ""
}
func (m *ListBuildsReply) GetBuilds() []*Build {
if m != nil {
return m.Builds
}
return nil
}
type GetBuildRequest struct {
BuildUri string `protobuf:"bytes,1,opt,name=build_uri,json=buildUri,proto3" json:"build_uri,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetBuildRequest) Reset() { *m = GetBuildRequest{} }
func (m *GetBuildRequest) String() string { return proto.CompactTextString(m) }
func (*GetBuildRequest) ProtoMessage() {}
func (*GetBuildRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{2}
}
func (m *GetBuildRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetBuildRequest.Unmarshal(m, b)
}
func (m *GetBuildRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetBuildRequest.Marshal(b, m, deterministic)
}
func (m *GetBuildRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetBuildRequest.Merge(m, src)
}
func (m *GetBuildRequest) XXX_Size() int {
return xxx_messageInfo_GetBuildRequest.Size(m)
}
func (m *GetBuildRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetBuildRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetBuildRequest proto.InternalMessageInfo
func (m *GetBuildRequest) GetBuildUri() string {
if m != nil {
return m.BuildUri
}
return ""
}
type GetBuildReply struct {
Build *Build `protobuf:"bytes,1,opt,name=build,proto3" json:"build,omitempty"`
Details *BuildDetails `protobuf:"bytes,2,opt,name=details,proto3" json:"details,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetBuildReply) Reset() { *m = GetBuildReply{} }
func (m *GetBuildReply) String() string { return proto.CompactTextString(m) }
func (*GetBuildReply) ProtoMessage() {}
func (*GetBuildReply) Descriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{3}
}
func (m *GetBuildReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetBuildReply.Unmarshal(m, b)
}
func (m *GetBuildReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetBuildReply.Marshal(b, m, deterministic)
}
func (m *GetBuildReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetBuildReply.Merge(m, src)
}
func (m *GetBuildReply) XXX_Size() int {
return xxx_messageInfo_GetBuildReply.Size(m)
}
func (m *GetBuildReply) XXX_DiscardUnknown() {
xxx_messageInfo_GetBuildReply.DiscardUnknown(m)
}
var xxx_messageInfo_GetBuildReply proto.InternalMessageInfo
func (m *GetBuildReply) GetBuild() *Build {
if m != nil {
return m.Build
}
return nil
}
func (m *GetBuildReply) GetDetails() *BuildDetails {
if m != nil {
return m.Details
}
return nil
}
type Build struct {
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"`
CommitId string `protobuf:"bytes,2,opt,name=commit_id,json=commitId,proto3" json:"commit_id,omitempty"`
Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
Status BuildStatus `protobuf:"varint,4,opt,name=status,proto3,enum=spotify.backstage.builds.v1.BuildStatus" json:"status,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Build) Reset() { *m = Build{} }
func (m *Build) String() string { return proto.CompactTextString(m) }
func (*Build) ProtoMessage() {}
func (*Build) Descriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{4}
}
func (m *Build) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Build.Unmarshal(m, b)
}
func (m *Build) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Build.Marshal(b, m, deterministic)
}
func (m *Build) XXX_Merge(src proto.Message) {
xxx_messageInfo_Build.Merge(m, src)
}
func (m *Build) XXX_Size() int {
return xxx_messageInfo_Build.Size(m)
}
func (m *Build) XXX_DiscardUnknown() {
xxx_messageInfo_Build.DiscardUnknown(m)
}
var xxx_messageInfo_Build proto.InternalMessageInfo
func (m *Build) GetUri() string {
if m != nil {
return m.Uri
}
return ""
}
func (m *Build) GetCommitId() string {
if m != nil {
return m.CommitId
}
return ""
}
func (m *Build) GetMessage() string {
if m != nil {
return m.Message
}
return ""
}
func (m *Build) GetStatus() BuildStatus {
if m != nil {
return m.Status
}
return BuildStatus_NULL
}
type BuildDetails struct {
Author string `protobuf:"bytes,1,opt,name=author,proto3" json:"author,omitempty"`
OverviewUrl string `protobuf:"bytes,2,opt,name=overview_url,json=overviewUrl,proto3" json:"overview_url,omitempty"`
LogUrl string `protobuf:"bytes,3,opt,name=log_url,json=logUrl,proto3" json:"log_url,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BuildDetails) Reset() { *m = BuildDetails{} }
func (m *BuildDetails) String() string { return proto.CompactTextString(m) }
func (*BuildDetails) ProtoMessage() {}
func (*BuildDetails) Descriptor() ([]byte, []int) {
return fileDescriptor_05a627abb7f9adb4, []int{5}
}
func (m *BuildDetails) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BuildDetails.Unmarshal(m, b)
}
func (m *BuildDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BuildDetails.Marshal(b, m, deterministic)
}
func (m *BuildDetails) XXX_Merge(src proto.Message) {
xxx_messageInfo_BuildDetails.Merge(m, src)
}
func (m *BuildDetails) XXX_Size() int {
return xxx_messageInfo_BuildDetails.Size(m)
}
func (m *BuildDetails) XXX_DiscardUnknown() {
xxx_messageInfo_BuildDetails.DiscardUnknown(m)
}
var xxx_messageInfo_BuildDetails proto.InternalMessageInfo
func (m *BuildDetails) GetAuthor() string {
if m != nil {
return m.Author
}
return ""
}
func (m *BuildDetails) GetOverviewUrl() string {
if m != nil {
return m.OverviewUrl
}
return ""
}
func (m *BuildDetails) GetLogUrl() string {
if m != nil {
return m.LogUrl
}
return ""
}
func init() {
proto.RegisterEnum("spotify.backstage.builds.v1.BuildStatus", BuildStatus_name, BuildStatus_value)
proto.RegisterType((*ListBuildsRequest)(nil), "spotify.backstage.builds.v1.ListBuildsRequest")
proto.RegisterType((*ListBuildsReply)(nil), "spotify.backstage.builds.v1.ListBuildsReply")
proto.RegisterType((*GetBuildRequest)(nil), "spotify.backstage.builds.v1.GetBuildRequest")
proto.RegisterType((*GetBuildReply)(nil), "spotify.backstage.builds.v1.GetBuildReply")
proto.RegisterType((*Build)(nil), "spotify.backstage.builds.v1.Build")
proto.RegisterType((*BuildDetails)(nil), "spotify.backstage.builds.v1.BuildDetails")
}
func init() { proto.RegisterFile("builds/v1/builds.proto", fileDescriptor_05a627abb7f9adb4) }
var fileDescriptor_05a627abb7f9adb4 = []byte{
// 447 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x41, 0x6f, 0xd3, 0x30,
0x18, 0x25, 0x6b, 0x97, 0xb6, 0x5f, 0x07, 0x0b, 0x3e, 0x8c, 0x68, 0x13, 0x52, 0xc9, 0xa9, 0x4c,
0x28, 0x53, 0xcb, 0x05, 0x71, 0x82, 0x75, 0x65, 0xaa, 0xa8, 0x22, 0xe4, 0x2a, 0x17, 0x2e, 0x55,
0xda, 0x98, 0x62, 0x70, 0x71, 0xb0, 0x9d, 0xa0, 0xfc, 0x09, 0x0e, 0xfc, 0x3c, 0x7e, 0x0d, 0xb2,
0x9d, 0xa8, 0x11, 0x93, 0xda, 0xde, 0xfc, 0xbe, 0xf7, 0xbd, 0xbc, 0xf7, 0x49, 0x2f, 0x70, 0xb1,
0xca, 0x29, 0x4b, 0xe5, 0x4d, 0x31, 0xba, 0xb1, 0xaf, 0x30, 0x13, 0x5c, 0x71, 0x74, 0x25, 0x33,
0xae, 0xe8, 0x97, 0x32, 0x5c, 0x25, 0xeb, 0xef, 0x52, 0x25, 0x1b, 0x12, 0x56, 0x7c, 0x31, 0x0a,
0xc6, 0xf0, 0x74, 0x4e, 0xa5, 0xba, 0x35, 0x03, 0x4c, 0x7e, 0xe6, 0x44, 0x2a, 0xf4, 0x1c, 0x80,
0xfc, 0x50, 0x54, 0x95, 0xcb, 0x5c, 0x50, 0xdf, 0x19, 0x38, 0xc3, 0x1e, 0xee, 0xd9, 0x49, 0x2c,
0x68, 0xc0, 0xe0, 0xbc, 0xa9, 0xc9, 0x58, 0x79, 0x40, 0x81, 0xde, 0x82, 0x6b, 0x2d, 0xfd, 0x93,
0x41, 0x6b, 0xd8, 0x1f, 0x07, 0xe1, 0x9e, 0x4c, 0xa1, 0xf9, 0x30, 0xae, 0x14, 0x41, 0x08, 0xe7,
0xf7, 0xc4, 0x9a, 0xd5, 0xf9, 0xae, 0xa0, 0x67, 0xc8, 0x86, 0x59, 0xd7, 0x0c, 0x74, 0xba, 0xdf,
0x0e, 0x3c, 0xde, 0x09, 0x74, 0xb8, 0x37, 0x70, 0x6a, 0x58, 0xb3, 0x7a, 0x9c, 0xb9, 0x15, 0xa0,
0x09, 0x74, 0x52, 0xa2, 0x12, 0xca, 0x74, 0x70, 0xad, 0x7d, 0x79, 0x58, 0x7b, 0x67, 0x05, 0xb8,
0x56, 0x06, 0x7f, 0x1c, 0x38, 0x35, 0x0c, 0xf2, 0xa0, 0xb5, 0x4b, 0xac, 0x9f, 0xfa, 0x92, 0x35,
0xdf, 0x6e, 0xa9, 0x5a, 0xd2, 0xd4, 0x58, 0xf4, 0x70, 0xd7, 0x0e, 0x66, 0x29, 0xf2, 0xa1, 0xb3,
0x25, 0x52, 0x26, 0x1b, 0xe2, 0xb7, 0x0c, 0x55, 0x43, 0xf4, 0x0e, 0x5c, 0xa9, 0x12, 0x95, 0x4b,
0xbf, 0x3d, 0x70, 0x86, 0x4f, 0xc6, 0xc3, 0xc3, 0xb1, 0x16, 0x66, 0x1f, 0x57, 0xba, 0x60, 0x05,
0x67, 0xcd, 0xb4, 0xe8, 0x02, 0xdc, 0x24, 0x57, 0x5f, 0xb9, 0xa8, 0xd2, 0x55, 0x08, 0xbd, 0x80,
0x33, 0x5e, 0x10, 0x51, 0x50, 0xf2, 0x6b, 0x99, 0x0b, 0x56, 0x65, 0xec, 0xd7, 0xb3, 0x58, 0x30,
0xf4, 0x0c, 0x3a, 0x8c, 0x6f, 0x0c, 0x6b, 0x63, 0xba, 0x8c, 0x6f, 0x62, 0xc1, 0xae, 0x3f, 0x42,
0xbf, 0x61, 0x8d, 0xba, 0xd0, 0x8e, 0xe2, 0xf9, 0xdc, 0x7b, 0x84, 0xfa, 0xd0, 0x59, 0xc4, 0x93,
0xc9, 0x74, 0xb1, 0xf0, 0x1c, 0x0d, 0x3e, 0xbc, 0x9f, 0xcd, 0x63, 0x3c, 0xf5, 0x4e, 0x34, 0xf8,
0x34, 0x8d, 0xee, 0x66, 0xd1, 0xbd, 0xd7, 0xd2, 0x00, 0xc7, 0x51, 0xa4, 0x41, 0x7b, 0xfc, 0xd7,
0x01, 0xd7, 0x36, 0x0e, 0x7d, 0x03, 0xd8, 0xf5, 0x0f, 0x85, 0x7b, 0x6f, 0x7f, 0x50, 0xee, 0xcb,
0x57, 0x47, 0xef, 0xeb, 0xee, 0xa4, 0xd0, 0xad, 0xcb, 0x84, 0xf6, 0x2b, 0xff, 0x2b, 0xe9, 0xe5,
0xf5, 0x91, 0xdb, 0x19, 0x2b, 0x6f, 0xe1, 0xb3, 0xed, 0xaf, 0x2c, 0x46, 0x2b, 0xd7, 0xfc, 0xb5,
0xaf, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x40, 0xf3, 0x96, 0x0b, 0xcf, 0x03, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// BuildsClient is the client API for Builds service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type BuildsClient interface {
ListBuilds(ctx context.Context, in *ListBuildsRequest, opts ...grpc.CallOption) (*ListBuildsReply, error)
GetBuild(ctx context.Context, in *GetBuildRequest, opts ...grpc.CallOption) (*GetBuildReply, error)
}
type buildsClient struct {
cc grpc.ClientConnInterface
}
func NewBuildsClient(cc grpc.ClientConnInterface) BuildsClient {
return &buildsClient{cc}
}
func (c *buildsClient) ListBuilds(ctx context.Context, in *ListBuildsRequest, opts ...grpc.CallOption) (*ListBuildsReply, error) {
out := new(ListBuildsReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.builds.v1.Builds/ListBuilds", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *buildsClient) GetBuild(ctx context.Context, in *GetBuildRequest, opts ...grpc.CallOption) (*GetBuildReply, error) {
out := new(GetBuildReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.builds.v1.Builds/GetBuild", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// BuildsServer is the server API for Builds service.
type BuildsServer interface {
ListBuilds(context.Context, *ListBuildsRequest) (*ListBuildsReply, error)
GetBuild(context.Context, *GetBuildRequest) (*GetBuildReply, error)
}
// UnimplementedBuildsServer can be embedded to have forward compatible implementations.
type UnimplementedBuildsServer struct {
}
func (*UnimplementedBuildsServer) ListBuilds(ctx context.Context, req *ListBuildsRequest) (*ListBuildsReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListBuilds not implemented")
}
func (*UnimplementedBuildsServer) GetBuild(ctx context.Context, req *GetBuildRequest) (*GetBuildReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBuild not implemented")
}
func RegisterBuildsServer(s *grpc.Server, srv BuildsServer) {
s.RegisterService(&_Builds_serviceDesc, srv)
}
func _Builds_ListBuilds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListBuildsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BuildsServer).ListBuilds(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.builds.v1.Builds/ListBuilds",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BuildsServer).ListBuilds(ctx, req.(*ListBuildsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Builds_GetBuild_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBuildRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BuildsServer).GetBuild(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.builds.v1.Builds/GetBuild",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BuildsServer).GetBuild(ctx, req.(*GetBuildRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Builds_serviceDesc = grpc.ServiceDesc{
ServiceName: "spotify.backstage.builds.v1.Builds",
HandlerType: (*BuildsServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ListBuilds",
Handler: _Builds_ListBuilds_Handler,
},
{
MethodName: "GetBuild",
Handler: _Builds_GetBuild_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "builds/v1/builds.proto",
}
+319 -44
View File
@@ -24,6 +24,84 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ListEntitiesRequest struct {
UriPrefix string `protobuf:"bytes,1,opt,name=uriPrefix,proto3" json:"uriPrefix,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListEntitiesRequest) Reset() { *m = ListEntitiesRequest{} }
func (m *ListEntitiesRequest) String() string { return proto.CompactTextString(m) }
func (*ListEntitiesRequest) ProtoMessage() {}
func (*ListEntitiesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{0}
}
func (m *ListEntitiesRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListEntitiesRequest.Unmarshal(m, b)
}
func (m *ListEntitiesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListEntitiesRequest.Marshal(b, m, deterministic)
}
func (m *ListEntitiesRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListEntitiesRequest.Merge(m, src)
}
func (m *ListEntitiesRequest) XXX_Size() int {
return xxx_messageInfo_ListEntitiesRequest.Size(m)
}
func (m *ListEntitiesRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ListEntitiesRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ListEntitiesRequest proto.InternalMessageInfo
func (m *ListEntitiesRequest) GetUriPrefix() string {
if m != nil {
return m.UriPrefix
}
return ""
}
type ListEntitiesReply struct {
Entities []*Entity `protobuf:"bytes,1,rep,name=entities,proto3" json:"entities,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListEntitiesReply) Reset() { *m = ListEntitiesReply{} }
func (m *ListEntitiesReply) String() string { return proto.CompactTextString(m) }
func (*ListEntitiesReply) ProtoMessage() {}
func (*ListEntitiesReply) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{1}
}
func (m *ListEntitiesReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListEntitiesReply.Unmarshal(m, b)
}
func (m *ListEntitiesReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListEntitiesReply.Marshal(b, m, deterministic)
}
func (m *ListEntitiesReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListEntitiesReply.Merge(m, src)
}
func (m *ListEntitiesReply) XXX_Size() int {
return xxx_messageInfo_ListEntitiesReply.Size(m)
}
func (m *ListEntitiesReply) XXX_DiscardUnknown() {
xxx_messageInfo_ListEntitiesReply.DiscardUnknown(m)
}
var xxx_messageInfo_ListEntitiesReply proto.InternalMessageInfo
func (m *ListEntitiesReply) GetEntities() []*Entity {
if m != nil {
return m.Entities
}
return nil
}
type GetEntityRequest struct {
Entity *Entity `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"`
IncludeFacts []string `protobuf:"bytes,2,rep,name=include_facts,json=includeFacts,proto3" json:"include_facts,omitempty"`
@@ -36,7 +114,7 @@ func (m *GetEntityRequest) Reset() { *m = GetEntityRequest{} }
func (m *GetEntityRequest) String() string { return proto.CompactTextString(m) }
func (*GetEntityRequest) ProtoMessage() {}
func (*GetEntityRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{0}
return fileDescriptor_70be9028e322f9d8, []int{2}
}
func (m *GetEntityRequest) XXX_Unmarshal(b []byte) error {
@@ -83,7 +161,7 @@ func (m *GetEntityReply) Reset() { *m = GetEntityReply{} }
func (m *GetEntityReply) String() string { return proto.CompactTextString(m) }
func (*GetEntityReply) ProtoMessage() {}
func (*GetEntityReply) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{1}
return fileDescriptor_70be9028e322f9d8, []int{3}
}
func (m *GetEntityReply) XXX_Unmarshal(b []byte) error {
@@ -129,7 +207,7 @@ func (m *CreateEntityRequest) Reset() { *m = CreateEntityRequest{} }
func (m *CreateEntityRequest) String() string { return proto.CompactTextString(m) }
func (*CreateEntityRequest) ProtoMessage() {}
func (*CreateEntityRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{2}
return fileDescriptor_70be9028e322f9d8, []int{4}
}
func (m *CreateEntityRequest) XXX_Unmarshal(b []byte) error {
@@ -168,7 +246,7 @@ func (m *CreateEntityReply) Reset() { *m = CreateEntityReply{} }
func (m *CreateEntityReply) String() string { return proto.CompactTextString(m) }
func (*CreateEntityReply) ProtoMessage() {}
func (*CreateEntityReply) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{3}
return fileDescriptor_70be9028e322f9d8, []int{5}
}
func (m *CreateEntityReply) XXX_Unmarshal(b []byte) error {
@@ -209,7 +287,7 @@ func (m *SetFactRequest) Reset() { *m = SetFactRequest{} }
func (m *SetFactRequest) String() string { return proto.CompactTextString(m) }
func (*SetFactRequest) ProtoMessage() {}
func (*SetFactRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{4}
return fileDescriptor_70be9028e322f9d8, []int{6}
}
func (m *SetFactRequest) XXX_Unmarshal(b []byte) error {
@@ -252,7 +330,7 @@ func (m *SetFactRequest) GetValue() string {
}
type SetFactReply struct {
FactUri string `protobuf:"bytes,1,opt,name=factUri,proto3" json:"factUri,omitempty"`
Fact *Fact `protobuf:"bytes,1,opt,name=fact,proto3" json:"fact,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -262,7 +340,7 @@ func (m *SetFactReply) Reset() { *m = SetFactReply{} }
func (m *SetFactReply) String() string { return proto.CompactTextString(m) }
func (*SetFactReply) ProtoMessage() {}
func (*SetFactReply) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{5}
return fileDescriptor_70be9028e322f9d8, []int{7}
}
func (m *SetFactReply) XXX_Unmarshal(b []byte) error {
@@ -283,13 +361,99 @@ func (m *SetFactReply) XXX_DiscardUnknown() {
var xxx_messageInfo_SetFactReply proto.InternalMessageInfo
func (m *SetFactReply) GetFactUri() string {
func (m *SetFactReply) GetFact() *Fact {
if m != nil {
return m.FactUri
return m.Fact
}
return nil
}
type GetFactRequest struct {
EntityUri string `protobuf:"bytes,1,opt,name=entityUri,proto3" json:"entityUri,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetFactRequest) Reset() { *m = GetFactRequest{} }
func (m *GetFactRequest) String() string { return proto.CompactTextString(m) }
func (*GetFactRequest) ProtoMessage() {}
func (*GetFactRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{8}
}
func (m *GetFactRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetFactRequest.Unmarshal(m, b)
}
func (m *GetFactRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetFactRequest.Marshal(b, m, deterministic)
}
func (m *GetFactRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetFactRequest.Merge(m, src)
}
func (m *GetFactRequest) XXX_Size() int {
return xxx_messageInfo_GetFactRequest.Size(m)
}
func (m *GetFactRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetFactRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetFactRequest proto.InternalMessageInfo
func (m *GetFactRequest) GetEntityUri() string {
if m != nil {
return m.EntityUri
}
return ""
}
func (m *GetFactRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
type GetFactReply struct {
Fact *Fact `protobuf:"bytes,1,opt,name=fact,proto3" json:"fact,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetFactReply) Reset() { *m = GetFactReply{} }
func (m *GetFactReply) String() string { return proto.CompactTextString(m) }
func (*GetFactReply) ProtoMessage() {}
func (*GetFactReply) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{9}
}
func (m *GetFactReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetFactReply.Unmarshal(m, b)
}
func (m *GetFactReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetFactReply.Marshal(b, m, deterministic)
}
func (m *GetFactReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetFactReply.Merge(m, src)
}
func (m *GetFactReply) XXX_Size() int {
return xxx_messageInfo_GetFactReply.Size(m)
}
func (m *GetFactReply) XXX_DiscardUnknown() {
xxx_messageInfo_GetFactReply.DiscardUnknown(m)
}
var xxx_messageInfo_GetFactReply proto.InternalMessageInfo
func (m *GetFactReply) GetFact() *Fact {
if m != nil {
return m.Fact
}
return nil
}
type Entity struct {
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -301,7 +465,7 @@ func (m *Entity) Reset() { *m = Entity{} }
func (m *Entity) String() string { return proto.CompactTextString(m) }
func (*Entity) ProtoMessage() {}
func (*Entity) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{6}
return fileDescriptor_70be9028e322f9d8, []int{10}
}
func (m *Entity) XXX_Unmarshal(b []byte) error {
@@ -330,9 +494,8 @@ func (m *Entity) GetUri() string {
}
type Fact struct {
EntityUri string `protobuf:"bytes,1,opt,name=entityUri,proto3" json:"entityUri,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -342,7 +505,7 @@ func (m *Fact) Reset() { *m = Fact{} }
func (m *Fact) String() string { return proto.CompactTextString(m) }
func (*Fact) ProtoMessage() {}
func (*Fact) Descriptor() ([]byte, []int) {
return fileDescriptor_70be9028e322f9d8, []int{7}
return fileDescriptor_70be9028e322f9d8, []int{11}
}
func (m *Fact) XXX_Unmarshal(b []byte) error {
@@ -363,13 +526,6 @@ func (m *Fact) XXX_DiscardUnknown() {
var xxx_messageInfo_Fact proto.InternalMessageInfo
func (m *Fact) GetEntityUri() string {
if m != nil {
return m.EntityUri
}
return ""
}
func (m *Fact) GetName() string {
if m != nil {
return m.Name
@@ -385,12 +541,16 @@ func (m *Fact) GetValue() string {
}
func init() {
proto.RegisterType((*ListEntitiesRequest)(nil), "spotify.backstage.inventory.v1.ListEntitiesRequest")
proto.RegisterType((*ListEntitiesReply)(nil), "spotify.backstage.inventory.v1.ListEntitiesReply")
proto.RegisterType((*GetEntityRequest)(nil), "spotify.backstage.inventory.v1.GetEntityRequest")
proto.RegisterType((*GetEntityReply)(nil), "spotify.backstage.inventory.v1.GetEntityReply")
proto.RegisterType((*CreateEntityRequest)(nil), "spotify.backstage.inventory.v1.CreateEntityRequest")
proto.RegisterType((*CreateEntityReply)(nil), "spotify.backstage.inventory.v1.CreateEntityReply")
proto.RegisterType((*SetFactRequest)(nil), "spotify.backstage.inventory.v1.SetFactRequest")
proto.RegisterType((*SetFactReply)(nil), "spotify.backstage.inventory.v1.SetFactReply")
proto.RegisterType((*GetFactRequest)(nil), "spotify.backstage.inventory.v1.GetFactRequest")
proto.RegisterType((*GetFactReply)(nil), "spotify.backstage.inventory.v1.GetFactReply")
proto.RegisterType((*Entity)(nil), "spotify.backstage.inventory.v1.Entity")
proto.RegisterType((*Fact)(nil), "spotify.backstage.inventory.v1.Fact")
}
@@ -398,29 +558,36 @@ func init() {
func init() { proto.RegisterFile("inventory/v1/inventory.proto", fileDescriptor_70be9028e322f9d8) }
var fileDescriptor_70be9028e322f9d8 = []byte{
// 346 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0x4d, 0x4b, 0xc3, 0x40,
0x10, 0x25, 0xfd, 0x92, 0x4c, 0x3f, 0xa8, 0xab, 0x87, 0x50, 0x8a, 0x94, 0x55, 0xa4, 0xa7, 0xd4,
0xb4, 0x37, 0x0f, 0x1e, 0x14, 0x15, 0x2f, 0x1e, 0x52, 0x0a, 0xe2, 0x45, 0xb6, 0x75, 0x2a, 0xc1,
0x34, 0x89, 0xc9, 0x66, 0x25, 0xff, 0xc1, 0x5f, 0xeb, 0x2f, 0x90, 0xdd, 0xa4, 0x49, 0x15, 0xb1,
0x14, 0x73, 0xdb, 0x79, 0xb3, 0xef, 0xcd, 0xcb, 0xcb, 0x2c, 0xf4, 0x1d, 0x4f, 0xa0, 0xc7, 0xfd,
0x30, 0x19, 0x09, 0x6b, 0x94, 0x17, 0x66, 0x10, 0xfa, 0xdc, 0x27, 0x47, 0x51, 0xe0, 0x73, 0x67,
0x99, 0x98, 0x73, 0xb6, 0x78, 0x8d, 0x38, 0x7b, 0x41, 0xb3, 0xb8, 0x22, 0x2c, 0xfa, 0x0e, 0xdd,
0x5b, 0xe4, 0xd7, 0x1e, 0x77, 0x78, 0x62, 0xe3, 0x5b, 0x8c, 0x11, 0x27, 0x17, 0xd0, 0x40, 0x05,
0x18, 0xda, 0x40, 0x1b, 0x36, 0xc7, 0xa7, 0xe6, 0xdf, 0x22, 0x66, 0x46, 0xcf, 0x58, 0xe4, 0x18,
0xda, 0x8e, 0xb7, 0x70, 0xe3, 0x67, 0x7c, 0x5a, 0xb2, 0x05, 0x8f, 0x8c, 0xca, 0xa0, 0x3a, 0xd4,
0xed, 0x56, 0x06, 0xde, 0x48, 0x8c, 0x7e, 0x68, 0xd0, 0xd9, 0x98, 0x1c, 0xb8, 0xc9, 0xbf, 0xe7,
0x9e, 0x43, 0xbd, 0x98, 0xd7, 0x1c, 0x9f, 0x6c, 0xa3, 0x4b, 0x23, 0x76, 0x4a, 0xa1, 0x33, 0x38,
0xb8, 0x0a, 0x91, 0x71, 0x2c, 0x35, 0x0a, 0x3a, 0x85, 0xfd, 0xef, 0xb2, 0x25, 0x7c, 0x27, 0x7d,
0x80, 0xce, 0x14, 0xb9, 0x72, 0x9f, 0xd9, 0xec, 0x83, 0x9e, 0xf6, 0x66, 0xa1, 0xa3, 0x44, 0x75,
0xbb, 0x00, 0x08, 0x81, 0x9a, 0xc7, 0x56, 0x68, 0x54, 0x54, 0x43, 0x9d, 0xc9, 0x21, 0xd4, 0x05,
0x73, 0x63, 0x34, 0xaa, 0x0a, 0x4c, 0x0b, 0x3a, 0x84, 0x56, 0xae, 0x2c, 0x9d, 0x1a, 0xb0, 0x27,
0xe3, 0x29, 0x54, 0xd7, 0x25, 0xed, 0x41, 0x23, 0x75, 0x45, 0xba, 0x50, 0x8d, 0xf3, 0xbe, 0x3c,
0xd2, 0x7b, 0xa8, 0x49, 0x89, 0xb2, 0x5c, 0x8d, 0x3f, 0x35, 0xd0, 0xef, 0xd6, 0x79, 0x90, 0x15,
0xe8, 0xf9, 0xde, 0x90, 0xb3, 0x6d, 0xd1, 0xfd, 0x5c, 0xee, 0x9e, 0xb9, 0x03, 0x43, 0x46, 0x20,
0xa0, 0xb5, 0xf9, 0x07, 0xc9, 0x64, 0x1b, 0xff, 0x97, 0x35, 0xea, 0x59, 0xbb, 0x91, 0x02, 0x37,
0xb9, 0x6c, 0x3f, 0x36, 0xf3, 0x1b, 0xc2, 0x9a, 0x37, 0xd4, 0x73, 0x9e, 0x7c, 0x05, 0x00, 0x00,
0xff, 0xff, 0xae, 0xd9, 0x2b, 0x51, 0xee, 0x03, 0x00, 0x00,
// 457 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x41, 0x8f, 0x93, 0x40,
0x14, 0x0e, 0x85, 0xad, 0xf2, 0xca, 0x6e, 0x76, 0x67, 0x3d, 0x10, 0xb2, 0x31, 0xcd, 0x68, 0x4c,
0x0f, 0x86, 0x5d, 0xda, 0x8b, 0xf1, 0xe0, 0xa1, 0x46, 0xd1, 0xc4, 0x83, 0xa1, 0x69, 0x34, 0x5e,
0x0c, 0xad, 0xd3, 0x66, 0x62, 0x0b, 0x15, 0x06, 0x94, 0xff, 0xe0, 0x4f, 0xf2, 0xc7, 0x99, 0x19,
0xa6, 0x03, 0xd5, 0x66, 0xa1, 0x69, 0x6f, 0x33, 0xef, 0xcd, 0xf7, 0xbe, 0xef, 0x3d, 0xde, 0x17,
0xe0, 0x86, 0x46, 0x39, 0x89, 0x58, 0x9c, 0x14, 0xb7, 0xb9, 0x77, 0xab, 0x2e, 0xee, 0x26, 0x89,
0x59, 0x8c, 0x1e, 0xa7, 0x9b, 0x98, 0xd1, 0x45, 0xe1, 0xce, 0xc2, 0xf9, 0xf7, 0x94, 0x85, 0x4b,
0xe2, 0x56, 0x4f, 0x72, 0x0f, 0x8f, 0xe0, 0xfa, 0x03, 0x4d, 0xd9, 0x9b, 0x88, 0x51, 0x46, 0x49,
0x1a, 0x90, 0x1f, 0x19, 0x49, 0x19, 0xba, 0x01, 0x33, 0x4b, 0xe8, 0xc7, 0x84, 0x2c, 0xe8, 0x2f,
0x5b, 0xeb, 0x6b, 0x03, 0x33, 0xa8, 0x02, 0xf8, 0x13, 0x5c, 0xed, 0x82, 0x36, 0xab, 0x02, 0x8d,
0xe1, 0x21, 0x91, 0x01, 0x5b, 0xeb, 0xeb, 0x83, 0xde, 0xf0, 0x99, 0x7b, 0x3f, 0xb9, 0x2b, 0x0a,
0x14, 0x81, 0xc2, 0xe1, 0x9f, 0x70, 0xe9, 0x13, 0x26, 0xc3, 0x52, 0xca, 0x2b, 0xe8, 0x8a, 0x7c,
0x21, 0x74, 0xb4, 0xaf, 0x2a, 0x51, 0xe8, 0x09, 0x9c, 0xd3, 0x68, 0xbe, 0xca, 0xbe, 0x91, 0xaf,
0x8b, 0x70, 0xce, 0x52, 0xbb, 0xd3, 0xd7, 0x07, 0x66, 0x60, 0xc9, 0xe0, 0x5b, 0x1e, 0xc3, 0xbf,
0x35, 0xb8, 0xa8, 0x31, 0xf3, 0x7e, 0x8e, 0xe5, 0x7d, 0x09, 0x67, 0x15, 0x5f, 0x6f, 0xf8, 0xb4,
0x09, 0xce, 0x85, 0x04, 0x25, 0x04, 0x4f, 0xe1, 0xfa, 0x75, 0x42, 0x42, 0x46, 0x4e, 0x3a, 0x0a,
0x3c, 0x81, 0xab, 0xdd, 0xb2, 0x27, 0xe8, 0x13, 0x7f, 0x86, 0x8b, 0x09, 0x61, 0x42, 0x7d, 0xb5,
0x3c, 0x65, 0x6e, 0x9a, 0xd0, 0xed, 0xf2, 0xa8, 0x00, 0x42, 0x60, 0x44, 0xe1, 0x9a, 0xd8, 0x1d,
0x91, 0x10, 0x67, 0xf4, 0x08, 0xce, 0xf2, 0x70, 0x95, 0x11, 0x5b, 0x17, 0xc1, 0xf2, 0x82, 0xdf,
0x81, 0xa5, 0x2a, 0x73, 0xa5, 0x2f, 0xc0, 0xe0, 0xe3, 0x91, 0x3a, 0xdb, 0x0d, 0x54, 0x20, 0xf0,
0x58, 0x7c, 0xdd, 0xa3, 0x34, 0x72, 0x35, 0xfe, 0x69, 0xd4, 0x38, 0xd0, 0x2d, 0x67, 0x88, 0x2e,
0x41, 0xcf, 0x14, 0x3f, 0x3f, 0xe2, 0x3b, 0x30, 0xf8, 0x4b, 0xa5, 0x40, 0xdb, 0x37, 0xa5, 0x4e,
0x6d, 0x4a, 0xc3, 0x3f, 0x06, 0x98, 0xef, 0xb7, 0x4c, 0x28, 0x07, 0xab, 0x6e, 0x4d, 0x34, 0x6a,
0xd2, 0xb5, 0xc7, 0xfd, 0x8e, 0x77, 0x18, 0x88, 0x4f, 0x63, 0x0d, 0xa6, 0xf2, 0x0f, 0xba, 0x6b,
0xc2, 0xff, 0x6b, 0x72, 0xc7, 0x3d, 0x00, 0xc1, 0xe9, 0x72, 0xb0, 0xea, 0x9b, 0xdc, 0xdc, 0xe6,
0x1e, 0x3b, 0x35, 0xb7, 0xf9, 0xbf, 0x59, 0x96, 0xf0, 0x40, 0xae, 0x24, 0x6a, 0x94, 0xbc, 0xeb,
0x0a, 0xe7, 0x79, 0xeb, 0xf7, 0x92, 0xc8, 0x6f, 0x4b, 0xe4, 0x1f, 0x48, 0x54, 0x5f, 0xe3, 0xf1,
0xf9, 0x97, 0x9e, 0x4a, 0xe6, 0xde, 0xac, 0x2b, 0x7e, 0x1b, 0xa3, 0xbf, 0x01, 0x00, 0x00, 0xff,
0xff, 0x0f, 0x08, 0x7c, 0x37, 0x56, 0x06, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -435,8 +602,11 @@ const _ = grpc.SupportPackageIsVersion6
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type InventoryClient interface {
ListEntities(ctx context.Context, in *ListEntitiesRequest, opts ...grpc.CallOption) (*ListEntitiesReply, error)
GetEntity(ctx context.Context, in *GetEntityRequest, opts ...grpc.CallOption) (*GetEntityReply, error)
CreateEntity(ctx context.Context, in *CreateEntityRequest, opts ...grpc.CallOption) (*CreateEntityReply, error)
SetFact(ctx context.Context, in *SetFactRequest, opts ...grpc.CallOption) (*SetFactReply, error)
GetFact(ctx context.Context, in *GetFactRequest, opts ...grpc.CallOption) (*GetFactReply, error)
}
type inventoryClient struct {
@@ -447,6 +617,15 @@ func NewInventoryClient(cc grpc.ClientConnInterface) InventoryClient {
return &inventoryClient{cc}
}
func (c *inventoryClient) ListEntities(ctx context.Context, in *ListEntitiesRequest, opts ...grpc.CallOption) (*ListEntitiesReply, error) {
out := new(ListEntitiesReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.inventory.v1.Inventory/ListEntities", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *inventoryClient) GetEntity(ctx context.Context, in *GetEntityRequest, opts ...grpc.CallOption) (*GetEntityReply, error) {
out := new(GetEntityReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.inventory.v1.Inventory/GetEntity", in, out, opts...)
@@ -465,27 +644,75 @@ func (c *inventoryClient) CreateEntity(ctx context.Context, in *CreateEntityRequ
return out, nil
}
func (c *inventoryClient) SetFact(ctx context.Context, in *SetFactRequest, opts ...grpc.CallOption) (*SetFactReply, error) {
out := new(SetFactReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.inventory.v1.Inventory/SetFact", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *inventoryClient) GetFact(ctx context.Context, in *GetFactRequest, opts ...grpc.CallOption) (*GetFactReply, error) {
out := new(GetFactReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.inventory.v1.Inventory/GetFact", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// InventoryServer is the server API for Inventory service.
type InventoryServer interface {
ListEntities(context.Context, *ListEntitiesRequest) (*ListEntitiesReply, error)
GetEntity(context.Context, *GetEntityRequest) (*GetEntityReply, error)
CreateEntity(context.Context, *CreateEntityRequest) (*CreateEntityReply, error)
SetFact(context.Context, *SetFactRequest) (*SetFactReply, error)
GetFact(context.Context, *GetFactRequest) (*GetFactReply, error)
}
// UnimplementedInventoryServer can be embedded to have forward compatible implementations.
type UnimplementedInventoryServer struct {
}
func (*UnimplementedInventoryServer) ListEntities(ctx context.Context, req *ListEntitiesRequest) (*ListEntitiesReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListEntities not implemented")
}
func (*UnimplementedInventoryServer) GetEntity(ctx context.Context, req *GetEntityRequest) (*GetEntityReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetEntity not implemented")
}
func (*UnimplementedInventoryServer) CreateEntity(ctx context.Context, req *CreateEntityRequest) (*CreateEntityReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateEntity not implemented")
}
func (*UnimplementedInventoryServer) SetFact(ctx context.Context, req *SetFactRequest) (*SetFactReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetFact not implemented")
}
func (*UnimplementedInventoryServer) GetFact(ctx context.Context, req *GetFactRequest) (*GetFactReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetFact not implemented")
}
func RegisterInventoryServer(s *grpc.Server, srv InventoryServer) {
s.RegisterService(&_Inventory_serviceDesc, srv)
}
func _Inventory_ListEntities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListEntitiesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InventoryServer).ListEntities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.inventory.v1.Inventory/ListEntities",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InventoryServer).ListEntities(ctx, req.(*ListEntitiesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Inventory_GetEntity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetEntityRequest)
if err := dec(in); err != nil {
@@ -522,10 +749,50 @@ func _Inventory_CreateEntity_Handler(srv interface{}, ctx context.Context, dec f
return interceptor(ctx, in, info, handler)
}
func _Inventory_SetFact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SetFactRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InventoryServer).SetFact(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.inventory.v1.Inventory/SetFact",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InventoryServer).SetFact(ctx, req.(*SetFactRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Inventory_GetFact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetFactRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InventoryServer).GetFact(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.inventory.v1.Inventory/GetFact",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InventoryServer).GetFact(ctx, req.(*GetFactRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Inventory_serviceDesc = grpc.ServiceDesc{
ServiceName: "spotify.backstage.inventory.v1.Inventory",
HandlerType: (*InventoryServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ListEntities",
Handler: _Inventory_ListEntities_Handler,
},
{
MethodName: "GetEntity",
Handler: _Inventory_GetEntity_Handler,
@@ -534,6 +801,14 @@ var _Inventory_serviceDesc = grpc.ServiceDesc{
MethodName: "CreateEntity",
Handler: _Inventory_CreateEntity_Handler,
},
{
MethodName: "SetFact",
Handler: _Inventory_SetFact_Handler,
},
{
MethodName: "GetFact",
Handler: _Inventory_GetFact_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "inventory/v1/inventory.proto",
+211 -50
View File
@@ -7,6 +7,7 @@ import (
context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
_struct "github.com/golang/protobuf/ptypes/struct"
v1 "github.com/spotify/backstage/backend/proto/identity/v1"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
@@ -56,45 +57,158 @@ func (m *Empty) XXX_DiscardUnknown() {
var xxx_messageInfo_Empty proto.InternalMessageInfo
type GetAllTemplatesReply struct {
type ListTemplatesReply struct {
Templates []*Template `protobuf:"bytes,1,rep,name=templates,proto3" json:"templates,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetAllTemplatesReply) Reset() { *m = GetAllTemplatesReply{} }
func (m *GetAllTemplatesReply) String() string { return proto.CompactTextString(m) }
func (*GetAllTemplatesReply) ProtoMessage() {}
func (*GetAllTemplatesReply) Descriptor() ([]byte, []int) {
func (m *ListTemplatesReply) Reset() { *m = ListTemplatesReply{} }
func (m *ListTemplatesReply) String() string { return proto.CompactTextString(m) }
func (*ListTemplatesReply) ProtoMessage() {}
func (*ListTemplatesReply) Descriptor() ([]byte, []int) {
return fileDescriptor_6737326b433dc57d, []int{1}
}
func (m *GetAllTemplatesReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetAllTemplatesReply.Unmarshal(m, b)
func (m *ListTemplatesReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListTemplatesReply.Unmarshal(m, b)
}
func (m *GetAllTemplatesReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetAllTemplatesReply.Marshal(b, m, deterministic)
func (m *ListTemplatesReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListTemplatesReply.Marshal(b, m, deterministic)
}
func (m *GetAllTemplatesReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetAllTemplatesReply.Merge(m, src)
func (m *ListTemplatesReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListTemplatesReply.Merge(m, src)
}
func (m *GetAllTemplatesReply) XXX_Size() int {
return xxx_messageInfo_GetAllTemplatesReply.Size(m)
func (m *ListTemplatesReply) XXX_Size() int {
return xxx_messageInfo_ListTemplatesReply.Size(m)
}
func (m *GetAllTemplatesReply) XXX_DiscardUnknown() {
xxx_messageInfo_GetAllTemplatesReply.DiscardUnknown(m)
func (m *ListTemplatesReply) XXX_DiscardUnknown() {
xxx_messageInfo_ListTemplatesReply.DiscardUnknown(m)
}
var xxx_messageInfo_GetAllTemplatesReply proto.InternalMessageInfo
var xxx_messageInfo_ListTemplatesReply proto.InternalMessageInfo
func (m *GetAllTemplatesReply) GetTemplates() []*Template {
func (m *ListTemplatesReply) GetTemplates() []*Template {
if m != nil {
return m.Templates
}
return nil
}
type CreateReply struct {
ComponentId string `protobuf:"bytes,1,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateReply) Reset() { *m = CreateReply{} }
func (m *CreateReply) String() string { return proto.CompactTextString(m) }
func (*CreateReply) ProtoMessage() {}
func (*CreateReply) Descriptor() ([]byte, []int) {
return fileDescriptor_6737326b433dc57d, []int{2}
}
func (m *CreateReply) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CreateReply.Unmarshal(m, b)
}
func (m *CreateReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CreateReply.Marshal(b, m, deterministic)
}
func (m *CreateReply) XXX_Merge(src proto.Message) {
xxx_messageInfo_CreateReply.Merge(m, src)
}
func (m *CreateReply) XXX_Size() int {
return xxx_messageInfo_CreateReply.Size(m)
}
func (m *CreateReply) XXX_DiscardUnknown() {
xxx_messageInfo_CreateReply.DiscardUnknown(m)
}
var xxx_messageInfo_CreateReply proto.InternalMessageInfo
func (m *CreateReply) GetComponentId() string {
if m != nil {
return m.ComponentId
}
return ""
}
type CreateRequest struct {
TemplateId string `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"`
Org string `protobuf:"bytes,2,opt,name=org,proto3" json:"org,omitempty"`
ComponentId string `protobuf:"bytes,3,opt,name=component_id,json=componentId,proto3" json:"component_id,omitempty"`
Private bool `protobuf:"varint,4,opt,name=private,proto3" json:"private,omitempty"`
// here's the cookiecutter.json that is used for the request.
// make as a struct so that we can pass through the data in a nice way
// withouth having to mess around with stuff and special types.
Metadata *_struct.Struct `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
func (m *CreateRequest) String() string { return proto.CompactTextString(m) }
func (*CreateRequest) ProtoMessage() {}
func (*CreateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_6737326b433dc57d, []int{3}
}
func (m *CreateRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CreateRequest.Unmarshal(m, b)
}
func (m *CreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CreateRequest.Marshal(b, m, deterministic)
}
func (m *CreateRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_CreateRequest.Merge(m, src)
}
func (m *CreateRequest) XXX_Size() int {
return xxx_messageInfo_CreateRequest.Size(m)
}
func (m *CreateRequest) XXX_DiscardUnknown() {
xxx_messageInfo_CreateRequest.DiscardUnknown(m)
}
var xxx_messageInfo_CreateRequest proto.InternalMessageInfo
func (m *CreateRequest) GetTemplateId() string {
if m != nil {
return m.TemplateId
}
return ""
}
func (m *CreateRequest) GetOrg() string {
if m != nil {
return m.Org
}
return ""
}
func (m *CreateRequest) GetComponentId() string {
if m != nil {
return m.ComponentId
}
return ""
}
func (m *CreateRequest) GetPrivate() bool {
if m != nil {
return m.Private
}
return false
}
func (m *CreateRequest) GetMetadata() *_struct.Struct {
if m != nil {
return m.Metadata
}
return nil
}
type Template struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
@@ -109,7 +223,7 @@ func (m *Template) Reset() { *m = Template{} }
func (m *Template) String() string { return proto.CompactTextString(m) }
func (*Template) ProtoMessage() {}
func (*Template) Descriptor() ([]byte, []int) {
return fileDescriptor_6737326b433dc57d, []int{2}
return fileDescriptor_6737326b433dc57d, []int{4}
}
func (m *Template) XXX_Unmarshal(b []byte) error {
@@ -160,31 +274,42 @@ func (m *Template) GetUser() *v1.User {
func init() {
proto.RegisterType((*Empty)(nil), "spotify.backstage.scaffolder.v1.Empty")
proto.RegisterType((*GetAllTemplatesReply)(nil), "spotify.backstage.scaffolder.v1.GetAllTemplatesReply")
proto.RegisterType((*ListTemplatesReply)(nil), "spotify.backstage.scaffolder.v1.ListTemplatesReply")
proto.RegisterType((*CreateReply)(nil), "spotify.backstage.scaffolder.v1.CreateReply")
proto.RegisterType((*CreateRequest)(nil), "spotify.backstage.scaffolder.v1.CreateRequest")
proto.RegisterType((*Template)(nil), "spotify.backstage.scaffolder.v1.Template")
}
func init() { proto.RegisterFile("scaffolder/v1/scaffolder.proto", fileDescriptor_6737326b433dc57d) }
var fileDescriptor_6737326b433dc57d = []byte{
// 270 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0x4f, 0x4b, 0xc4, 0x30,
0x10, 0xc5, 0xe9, 0x6e, 0xfd, 0xb3, 0x53, 0x59, 0x21, 0x78, 0x28, 0x3d, 0x68, 0xa9, 0x20, 0xf5,
0x92, 0xa5, 0x15, 0xf1, 0xac, 0x20, 0x7b, 0xaf, 0x7a, 0xf1, 0x22, 0xdd, 0x76, 0x2a, 0xc1, 0xb6,
0x09, 0xc9, 0x58, 0xe8, 0xc5, 0xbb, 0xdf, 0x5a, 0x8c, 0x74, 0xbb, 0xc8, 0x42, 0x6f, 0x93, 0x97,
0xf7, 0x4b, 0xe6, 0xcd, 0xc0, 0xb9, 0x29, 0xf2, 0xaa, 0x92, 0x75, 0x89, 0x7a, 0xd5, 0x25, 0xab,
0xf1, 0xc4, 0x95, 0x96, 0x24, 0xd9, 0x85, 0x51, 0x92, 0x44, 0xd5, 0xf3, 0x4d, 0x5e, 0x7c, 0x18,
0xca, 0xdf, 0x91, 0xef, 0x78, 0xba, 0x24, 0x08, 0x44, 0x89, 0x2d, 0x09, 0xea, 0x7f, 0xf1, 0xa1,
0xfe, 0x83, 0xa3, 0x23, 0x38, 0x78, 0x6c, 0x14, 0xf5, 0xd1, 0x1b, 0x9c, 0xad, 0x91, 0xee, 0xeb,
0xfa, 0x19, 0x1b, 0x55, 0xe7, 0x84, 0x26, 0x43, 0x55, 0xf7, 0x6c, 0x0d, 0x0b, 0x1a, 0x14, 0xdf,
0x09, 0xe7, 0xb1, 0x97, 0x5e, 0xf3, 0x89, 0x1f, 0xf9, 0xf0, 0x46, 0x36, 0xb2, 0xd1, 0xb7, 0x03,
0xc7, 0x83, 0xce, 0x96, 0x30, 0x13, 0xa5, 0xef, 0x84, 0x4e, 0xbc, 0xc8, 0x66, 0xa2, 0x64, 0x0c,
0xdc, 0x36, 0x6f, 0xd0, 0x9f, 0x59, 0xc5, 0xd6, 0x2c, 0x04, 0xaf, 0x44, 0x53, 0x68, 0xa1, 0x48,
0xc8, 0xd6, 0x9f, 0xdb, 0xab, 0x5d, 0x89, 0xdd, 0x81, 0xfb, 0x69, 0x50, 0xfb, 0x6e, 0xe8, 0xc4,
0x5e, 0x7a, 0xb9, 0xa7, 0xad, 0x6d, 0xda, 0x2e, 0xe1, 0x2f, 0x06, 0x75, 0x66, 0x81, 0xf4, 0x0b,
0xe0, 0x69, 0xdb, 0x30, 0x53, 0x70, 0xfa, 0x2f, 0x3a, 0xbb, 0x9a, 0x8c, 0x68, 0xa7, 0x16, 0xdc,
0x4e, 0xfa, 0xf6, 0x0d, 0xf5, 0x61, 0xf9, 0x7a, 0x32, 0xba, 0xba, 0x64, 0x73, 0x68, 0x97, 0x71,
0xf3, 0x13, 0x00, 0x00, 0xff, 0xff, 0x5b, 0x4d, 0x79, 0x5e, 0xeb, 0x01, 0x00, 0x00,
// 411 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xd1, 0x8a, 0xd3, 0x40,
0x14, 0x25, 0x6d, 0x77, 0xb7, 0x7b, 0xb3, 0xbb, 0xc8, 0xbc, 0x18, 0x82, 0xb8, 0x31, 0x82, 0x54,
0x90, 0xa9, 0x6d, 0x1f, 0x7c, 0x57, 0x44, 0x16, 0x7c, 0xca, 0xea, 0x8b, 0x20, 0x32, 0x4d, 0x6e,
0xca, 0x60, 0x92, 0x19, 0x67, 0x6e, 0x03, 0xf9, 0x04, 0xff, 0xc7, 0x2f, 0xf2, 0x4b, 0xa4, 0x53,
0x27, 0xdd, 0x65, 0x0b, 0xd9, 0xb7, 0x7b, 0xcf, 0xbd, 0xe7, 0xce, 0xe1, 0x9c, 0x81, 0xe7, 0x36,
0x17, 0x65, 0xa9, 0xaa, 0x02, 0xcd, 0xbc, 0x5d, 0xcc, 0x0f, 0x1d, 0xd7, 0x46, 0x91, 0x62, 0xd7,
0x56, 0x2b, 0x92, 0x65, 0xc7, 0xd7, 0x22, 0xff, 0x69, 0x49, 0x6c, 0x90, 0xdf, 0xd9, 0x69, 0x17,
0x71, 0x2c, 0x0b, 0x6c, 0x48, 0x52, 0xb7, 0xa3, 0xfb, 0x7a, 0x4f, 0x8e, 0x9f, 0x6d, 0x94, 0xda,
0x54, 0x38, 0x77, 0xdd, 0x7a, 0x5b, 0xce, 0x2d, 0x99, 0x6d, 0x4e, 0xfb, 0x69, 0x7a, 0x06, 0x27,
0x1f, 0x6b, 0x4d, 0x5d, 0xfa, 0x1d, 0xd8, 0x67, 0x69, 0xe9, 0x0b, 0xd6, 0xba, 0x12, 0x84, 0x36,
0x43, 0x5d, 0x75, 0xec, 0x13, 0x9c, 0x93, 0x47, 0xa2, 0x20, 0x19, 0xcf, 0xc2, 0xe5, 0x6b, 0x3e,
0xa0, 0x86, 0xfb, 0x1b, 0xd9, 0x81, 0x9b, 0xbe, 0x85, 0xf0, 0x83, 0xc1, 0x1d, 0xe8, 0xee, 0xbe,
0x80, 0x8b, 0x5c, 0xd5, 0x5a, 0x35, 0xd8, 0xd0, 0x0f, 0x59, 0x44, 0x41, 0x12, 0xcc, 0xce, 0xb3,
0xb0, 0xc7, 0x6e, 0x8a, 0xf4, 0x4f, 0x00, 0x97, 0x9e, 0xf2, 0x6b, 0x8b, 0x96, 0xd8, 0x35, 0x84,
0xfe, 0xe0, 0x81, 0x03, 0x1e, 0xba, 0x29, 0xd8, 0x13, 0x18, 0x2b, 0xb3, 0x89, 0x46, 0x6e, 0xb0,
0x2b, 0x1f, 0xbc, 0x33, 0x7e, 0xf0, 0x0e, 0x8b, 0xe0, 0x4c, 0x1b, 0xd9, 0x0a, 0xc2, 0x68, 0x92,
0x04, 0xb3, 0x69, 0xe6, 0x5b, 0xb6, 0x82, 0x69, 0x8d, 0x24, 0x0a, 0x41, 0x22, 0x3a, 0x49, 0x82,
0x59, 0xb8, 0x7c, 0xca, 0xf7, 0x66, 0x72, 0x6f, 0x26, 0xbf, 0x75, 0x66, 0x66, 0xfd, 0x62, 0xfa,
0x3b, 0x80, 0xa9, 0x37, 0x80, 0x5d, 0xc1, 0xa8, 0x17, 0x3a, 0x92, 0x05, 0x63, 0x30, 0x69, 0x44,
0x8d, 0xff, 0x15, 0xba, 0x9a, 0x25, 0x10, 0x16, 0x68, 0x73, 0x23, 0x35, 0x49, 0xd5, 0x78, 0x85,
0x77, 0x20, 0xf6, 0x0e, 0x26, 0x5b, 0x8b, 0xc6, 0xc9, 0x0b, 0x97, 0x2f, 0x8f, 0xf8, 0xdf, 0x47,
0xde, 0x2e, 0xf8, 0x57, 0x8b, 0x26, 0x73, 0x84, 0xe5, 0xdf, 0x00, 0xe0, 0xb6, 0x8f, 0x86, 0x55,
0x70, 0x79, 0x2f, 0x62, 0xf6, 0x6a, 0x30, 0x4a, 0xf7, 0x37, 0xe2, 0xd5, 0xe0, 0xde, 0x91, 0xaf,
0x53, 0xc2, 0xe9, 0x3e, 0x3e, 0xc6, 0x07, 0xe9, 0xf7, 0x72, 0x8e, 0xdf, 0x3c, 0x7a, 0x5f, 0x57,
0xdd, 0xfb, 0xab, 0x6f, 0x17, 0x87, 0x61, 0xbb, 0x58, 0x9f, 0xba, 0x6c, 0x56, 0xff, 0x02, 0x00,
0x00, 0xff, 0xff, 0xfc, 0x1f, 0xfc, 0xf0, 0x55, 0x03, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -199,7 +324,8 @@ const _ = grpc.SupportPackageIsVersion6
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ScaffolderClient interface {
GetAllTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetAllTemplatesReply, error)
ListTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ListTemplatesReply, error)
Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateReply, error)
}
type scaffolderClient struct {
@@ -210,9 +336,18 @@ func NewScaffolderClient(cc grpc.ClientConnInterface) ScaffolderClient {
return &scaffolderClient{cc}
}
func (c *scaffolderClient) GetAllTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GetAllTemplatesReply, error) {
out := new(GetAllTemplatesReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.scaffolder.v1.Scaffolder/GetAllTemplates", in, out, opts...)
func (c *scaffolderClient) ListTemplates(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ListTemplatesReply, error) {
out := new(ListTemplatesReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.scaffolder.v1.Scaffolder/ListTemplates", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *scaffolderClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateReply, error) {
out := new(CreateReply)
err := c.cc.Invoke(ctx, "/spotify.backstage.scaffolder.v1.Scaffolder/Create", in, out, opts...)
if err != nil {
return nil, err
}
@@ -221,35 +356,57 @@ func (c *scaffolderClient) GetAllTemplates(ctx context.Context, in *Empty, opts
// ScaffolderServer is the server API for Scaffolder service.
type ScaffolderServer interface {
GetAllTemplates(context.Context, *Empty) (*GetAllTemplatesReply, error)
ListTemplates(context.Context, *Empty) (*ListTemplatesReply, error)
Create(context.Context, *CreateRequest) (*CreateReply, error)
}
// UnimplementedScaffolderServer can be embedded to have forward compatible implementations.
type UnimplementedScaffolderServer struct {
}
func (*UnimplementedScaffolderServer) GetAllTemplates(ctx context.Context, req *Empty) (*GetAllTemplatesReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetAllTemplates not implemented")
func (*UnimplementedScaffolderServer) ListTemplates(ctx context.Context, req *Empty) (*ListTemplatesReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListTemplates not implemented")
}
func (*UnimplementedScaffolderServer) Create(ctx context.Context, req *CreateRequest) (*CreateReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Create not implemented")
}
func RegisterScaffolderServer(s *grpc.Server, srv ScaffolderServer) {
s.RegisterService(&_Scaffolder_serviceDesc, srv)
}
func _Scaffolder_GetAllTemplates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Scaffolder_ListTemplates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ScaffolderServer).GetAllTemplates(ctx, in)
return srv.(ScaffolderServer).ListTemplates(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.scaffolder.v1.Scaffolder/GetAllTemplates",
FullMethod: "/spotify.backstage.scaffolder.v1.Scaffolder/ListTemplates",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ScaffolderServer).GetAllTemplates(ctx, req.(*Empty))
return srv.(ScaffolderServer).ListTemplates(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
func _Scaffolder_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ScaffolderServer).Create(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/spotify.backstage.scaffolder.v1.Scaffolder/Create",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ScaffolderServer).Create(ctx, req.(*CreateRequest))
}
return interceptor(ctx, in, info, handler)
}
@@ -259,8 +416,12 @@ var _Scaffolder_serviceDesc = grpc.ServiceDesc{
HandlerType: (*ScaffolderServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetAllTemplates",
Handler: _Scaffolder_GetAllTemplates_Handler,
MethodName: "ListTemplates",
Handler: _Scaffolder_ListTemplates_Handler,
},
{
MethodName: "Create",
Handler: _Scaffolder_Create_Handler,
},
},
Streams: []grpc.StreamDesc{},
+1 -1
View File
@@ -1,4 +1,4 @@
FROM envoyproxy/envoy:latest
FROM envoyproxy/envoy:v1.13.0
COPY ./envoy.yaml /etc/envoy/envoy.yaml
+13
View File
@@ -28,6 +28,10 @@ static_resources:
route:
cluster: identity_service
max_grpc_timeout: 0s
- match: { prefix: '/spotify.backstage.builds.v1.Builds/' }
route:
cluster: builds_service
max_grpc_timeout: 0s
- match: { prefix: '/inventory' }
route:
cluster: inventory_service
@@ -58,6 +62,15 @@ static_resources:
- socket_address:
address: identity
port_value: 50051
- name: builds_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts:
- socket_address:
address: builds
port_value: 50051
- name: inventory_service
connect_timeout: 0.25s
type: logical_dns
+42 -6
View File
@@ -2,20 +2,56 @@ package app
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
identity "github.com/spotify/backstage/backend/proto/identity/v1"
pb "github.com/spotify/backstage/proto/scaffolder/v1"
pb "github.com/spotify/backstage/backend/proto/scaffolder/v1"
"github.com/spotify/backstage/scaffolder/fs"
"github.com/spotify/backstage/scaffolder/remote"
"github.com/spotify/backstage/scaffolder/repository"
)
// Server is the inventory Grpc server
type Server struct {
Repository *repository.Repository
repository *repository.Repository
github *remote.Github
fs *fs.Filesystem
}
// GetAllTemplates returns the local templatess
func (s *Server) GetAllTemplates(ctx context.Context, req *pb.Empty) (*pb.GetAllTemplatesReply, error) {
// NewServer creates a new server for with all the things
func NewServer() *Server {
return &Server{
github: remote.NewGithubClient(),
}
}
// Create scaffolds the repo in github and then will create push to the repository
func (s *Server) Create(ctx context.Context, req *pb.CreateRequest) (*pb.CreateReply, error) {
// first create the repository with github
fmt.Sprintf("Creating repository for Component %s", req.ComponentId)
repo := remote.Repository{
Name: req.ComponentId,
Org: req.Org,
Private: req.Private,
}
if _, err := s.github.CreateRepository(repo); err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("Could not create repository %s/%s", req.Org, req.ComponentId))
}
// move the template into a temporary directory
tempFolder, _ := s.fs.PrepareTemplate(fs.Template{req.TemplateId})
fmt.Sprintf("Created temporary folder %s", tempFolder)
// use git bindings to add the remote with access token and push to the directory
return nil, nil
}
// ListTemplates returns the local templatess
func (s *Server) ListTemplates(ctx context.Context, req *pb.Empty) (*pb.ListTemplatesReply, error) {
// todo (blam): yes we currently read the disk on every load. but it's fine for now 🤷‍♂️
definitions, err := s.Repository.Load()
definitions, err := s.repository.Load()
var templates []*pb.Template
for _, definition := range definitions {
@@ -34,7 +70,7 @@ func (s *Server) GetAllTemplates(ctx context.Context, req *pb.Empty) (*pb.GetAll
templates = append(templates, template)
}
return &pb.GetAllTemplatesReply{
return &pb.ListTemplatesReply{
Templates: templates,
}, err
}
+8
View File
@@ -0,0 +1,8 @@
package app
import (
"testing"
)
func TestSample(t *testing.T) {
}
+87
View File
@@ -0,0 +1,87 @@
package fs
import (
"fmt"
"io"
"io/ioutil"
"os"
"path"
)
// Filesystem Repository
type Filesystem struct{}
func file(src, dst string) error {
var err error
var srcfd *os.File
var dstfd *os.File
var srcinfo os.FileInfo
if srcfd, err = os.Open(src); err != nil {
return err
}
defer srcfd.Close()
if dstfd, err = os.Create(dst); err != nil {
return err
}
defer dstfd.Close()
if _, err = io.Copy(dstfd, srcfd); err != nil {
return err
}
if srcinfo, err = os.Stat(src); err != nil {
return err
}
return os.Chmod(dst, srcinfo.Mode())
}
func dir(src string, dst string) error {
var err error
var fds []os.FileInfo
var srcinfo os.FileInfo
if srcinfo, err = os.Stat(src); err != nil {
return err
}
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err
}
if fds, err = ioutil.ReadDir(src); err != nil {
return err
}
for _, fd := range fds {
srcfp := path.Join(src, fd.Name())
dstfp := path.Join(dst, fd.Name())
if fd.IsDir() {
if err = dir(srcfp, dstfp); err != nil {
fmt.Println(err)
}
} else {
if err = file(srcfp, dstfp); err != nil {
fmt.Println(err)
}
}
}
return nil
}
// Template holds the template ID for copying
type Template struct {
ID string
}
// PrepareTemplate will copy the local template to temp folder
// and return the temp location
func (f *Filesystem) PrepareTemplate(template Template) (string, error) {
tempDirectory, _ := ioutil.TempDir(os.TempDir(), template.ID)
fmt.Println(tempDirectory)
if err := dir("./templates/"+template.ID, tempDirectory); err != nil {
return "", err
}
return tempDirectory, nil
}
+6 -3
View File
@@ -2,13 +2,16 @@ module github.com/spotify/backstage/scaffolder
go 1.13
replace github.com/spotify/backstage/proto => ../proto
replace github.com/spotify/backstage/backend/proto => ../proto
replace (
github.com/spotify/backstage/backend/proto => ./../proto
github.com/spotify/backstage/proto => ../proto
)
require (
github.com/golang/protobuf v1.3.3
github.com/google/go-github/v29 v29.0.2
github.com/spotify/backstage/backend/proto v0.0.0-00010101000000-000000000000
github.com/spotify/backstage/proto v0.0.0-00010101000000-000000000000
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
google.golang.org/grpc v1.27.0
)
+7
View File
@@ -14,7 +14,13 @@ github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts=
github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -25,6 +31,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+4 -3
View File
@@ -4,9 +4,8 @@ import (
"log"
"net"
pb "github.com/spotify/backstage/proto/scaffolder/v1"
pb "github.com/spotify/backstage/backend/proto/scaffolder/v1"
"github.com/spotify/backstage/scaffolder/app"
"google.golang.org/grpc"
)
@@ -21,7 +20,9 @@ func main() {
}
grpcServer := grpc.NewServer()
pb.RegisterScaffolderServer(grpcServer, &app.Server{})
serverHandler := app.NewServer()
pb.RegisterScaffolderServer(grpcServer, serverHandler)
log.Println("Serving Scaffolder Service")
grpcServer.Serve(lis)
}
+62
View File
@@ -0,0 +1,62 @@
package remote
import (
"context"
"fmt"
gh "github.com/google/go-github/v29/github"
"golang.org/x/oauth2"
"os"
)
// Github is the exported struct
type Github struct {
client *gh.Client
ctx *context.Context
}
// NewGithubClient returns a new client with the correct access token enabled
func NewGithubClient() *Github {
accessToken := os.Getenv("BOSS_GH_ACCESS_TOKEN")
if accessToken == "" {
fmt.Println("No BOSS_GH_ACCESS_TOKEN set. Cannot continue")
os.Exit(1)
}
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: accessToken},
)
tc := oauth2.NewClient(ctx, ts)
client := gh.NewClient(tc)
return &Github{
client: client,
ctx: &ctx,
}
}
// Repository holds the information of the created repo
type Repository struct {
Org string
Name string
Private bool
}
// CreateRepository will create the repository in Github ready for use by the scaffolder
func (g *Github) CreateRepository(repo Repository) (*gh.Repository, error) {
ghRepo := &gh.Repository{
Name: &repo.Name,
Private: &repo.Private,
}
var org string
if repo.Org != "" {
org = repo.Org
}
created, _, err := g.client.Repositories.Create(*g.ctx, org, ghRepo)
return created, err
}
+3 -2
View File
@@ -20,9 +20,10 @@ type TemplateDefinition struct {
// Load will return all the Repository templates
func (s *Repository) Load() ([]*TemplateDefinition, error) {
templateInfoFilePaths, err := filepath.Glob("templates/**/template-info.json")
var templateDefinitions []*TemplateDefinition
templateInfoFilePaths, err := filepath.Glob("templates/**/template-info.json")
if err != nil {
fmt.Errorf("failed to load template-info files")
return nil, err
@@ -45,5 +46,5 @@ func (s *Repository) Load() ([]*TemplateDefinition, error) {
templateDefinitions = append(templateDefinitions, &definition)
}
return templateDefinitions, err
return templateDefinitions, nil
}
@@ -0,0 +1,6 @@
{
"app_id": "com.example.app",
"app_name": "SampleApp",
"owner": "",
"description": "We promise to update this description /{{cookiecutter.owner}}"
}
@@ -0,0 +1,57 @@
{
"schema": [
{
"id": "app_name",
"title": "App name",
"type": "text",
"description": "App name used to generate Android Studio files and class names. CamelCase e.g. 'MyAndroidApp'",
"validators": [
{
"type": "required"
},
{
"type": "regex",
"match": "^[A-Z][A-Za-z]+$",
"message": "Project name must be CamelCase"
}
]
},
{
"id": "app_id",
"title": "App ID",
"type": "text",
"description": "App id used as package for the new app. FQDN e.g. 'com.example.app'",
"validators": [
{
"type": "required"
},
{
"type": "regex",
"match": "^[a-z][a-z.]+$",
"message": "App ID must be a fully qualified domain name"
}
]
},
{
"id": "owner",
"title": "owner",
"type": "text",
"description": "The owner name used to identify the owner of this component",
"validators": [
{
"type": "required"
},
{
"type": "string-range",
"min": 4,
"max": 33
},
{
"type": "regex",
"match": "^[a-z][a-z0-9]+$",
"message": "Owner names must consist only of lowercase letters"
}
]
}
]
}
@@ -0,0 +1,14 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
@@ -0,0 +1,37 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "{{cookiecutter.app_id}}"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -0,0 +1,24 @@
package {{cookiecutter.app_id}}
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.example.mytemplate", appContext.packageName)
}
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{cookiecutter.app_id}}">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,12 @@
package {{cookiecutter.app_id}}
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Backsage!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">{{cookiecutter.app_name}}</string>
</resources>
@@ -0,0 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
@@ -0,0 +1,17 @@
package {{cookiecutter.app_id}}
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
@@ -0,0 +1,29 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.0-rc01'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
@@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
@@ -0,0 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@@ -0,0 +1,2 @@
rootProject.name='{{cookiecutter.app_name}}'
include ':app'
+10
View File
@@ -21,6 +21,15 @@ services:
volumes:
- ./backend/identity/identity-data.json:/app/identity-data.json
builds:
container_name: boss-builds
build:
context: backend
args:
service: builds
restart: unless-stopped
env_file: secrets.env
scaffolder:
container_name: boss-scaffolder
build:
@@ -28,3 +37,4 @@ services:
args:
service: scaffolder
restart: unless-stopped
env_file: secrets.env
+4 -4
View File
@@ -1,7 +1,7 @@
import {
createEntityKind,
createWidgetView,
createEntityView,
createEntityPage,
} from '@backstage/core';
import ComputerIcon from '@material-ui/icons/Computer';
import MockEntityPage from './MockEntityPage';
@@ -13,10 +13,10 @@ const serviceOverviewPage = createWidgetView()
.addComponent(MockEntityCard)
.addComponent(MockEntityCard);
const serviceView = createEntityView()
.addPage('Overview', 'overview', serviceOverviewPage)
const serviceView = createEntityPage()
.addPage('Overview', '/overview', serviceOverviewPage)
.register(GithubActionsPlugin)
.addComponent('Deployment', 'deployment', MockEntityPage);
.addComponent('Deployment', '/deployment', MockEntityPage);
const serviceEntity = createEntityKind({
kind: 'service',
+3 -3
View File
@@ -1,7 +1,7 @@
import AppBuilder from './app/AppBuilder';
import EntityKind, { EntityConfig } from './entity/EntityKind';
import WidgetViewBuilder from './widgetView/WidgetViewBuilder';
import EntityViewBuilder from './entityView/EntityViewPageBuilder';
import EntityPageBuilder from './entityView/EntityPageBuilder';
import BackstagePlugin, { PluginConfig } from './plugin/Plugin';
export function createApp() {
@@ -16,8 +16,8 @@ export function createWidgetView() {
return new WidgetViewBuilder();
}
export function createEntityView() {
return new EntityViewBuilder();
export function createEntityPage() {
return new EntityPageBuilder();
}
export function createPlugin(config: PluginConfig): BackstagePlugin {
@@ -1,10 +1,10 @@
import React, { ComponentType, FC } from 'react';
import { Route, Switch, useParams } from 'react-router-dom';
import { Route, Switch, useParams, Redirect } from 'react-router-dom';
import { AppContextProvider } from './AppContext';
import { App, AppComponentBuilder } from './types';
import EntityKind, { EntityConfig } from '../entity/EntityKind';
import { EntityContextProvider } from '../entityView/EntityContext';
import BackstagePlugin, { registerSymbol } from '../plugin/Plugin';
import BackstagePlugin from '../plugin/Plugin';
class AppImpl implements App {
constructor(private readonly entities: Map<string, EntityKind>) {}
@@ -97,8 +97,31 @@ export default class AppBuilder {
const pluginRoutes = new Array<JSX.Element>();
for (const plugin of this.plugins.values()) {
const { routes = [] } = plugin[registerSymbol]();
pluginRoutes.push(...routes);
for (const output of plugin.output()) {
switch (output.type) {
case 'route': {
const { path, component, options = {} } = output;
const { exact = true } = options;
pluginRoutes.push(
<Route
key={path}
path={path}
component={component}
exact={exact}
/>,
);
break;
}
case 'redirect-route': {
const { path, target, options = {} } = output;
const { exact = true } = options;
pluginRoutes.push(
<Redirect key={path} path={path} to={target} exact={exact} />,
);
break;
}
}
}
}
const routes = [...pluginRoutes, ...entityRoutes];
@@ -5,8 +5,7 @@ import ListItem from '@material-ui/core/ListItem';
import { AppComponentBuilder, App } from '../app/types';
import { useEntity, useEntityUri, useEntityConfig } from './EntityContext';
import EntityLink from '../../components/EntityLink/EntityLink';
import BackstagePlugin, { outputSymbol } from '../plugin/Plugin';
import { entityViewPage } from '../plugin/outputs';
import BackstagePlugin from '../plugin/Plugin';
const EntityLayout: FC<{}> = ({ children }) => {
const config = useEntityConfig();
@@ -34,43 +33,48 @@ const EntitySidebarItem: FC<{ title: string; path: string }> = ({
);
};
type EntityViewPage = {
type EntityPageNavItem = {
title: string;
target: string;
};
type EntityPageView = {
path: string;
component: ComponentType<any>;
};
type Props = {
pages: EntityViewPage[];
navItems: EntityPageNavItem[];
views: EntityPageView[];
};
const EntityViewComponent: FC<Props> = ({ pages }) => {
const EntityPageComponent: FC<Props> = ({ navItems, views }) => {
const { kind, id } = useEntity();
const basePath = `/entity/${kind}/${id}`;
return (
<EntityLayout>
<EntitySidebar>
{pages.map(({ title, path }) => (
<EntitySidebarItem key={path} title={title} path={path} />
{navItems.map(({ title, target }) => (
<EntitySidebarItem key={target} title={title} path={target} />
))}
</EntitySidebar>
<Switch>
{pages.map(({ path, component }) => (
{views.map(({ path, component }) => (
<Route
key={path}
exact={false}
path={`${basePath}/${path}`}
exact
path={`${basePath}${path}`}
component={component}
/>
))}
<Redirect from={basePath} to={`${basePath}/${pages[0].path}`} />
<Redirect from={basePath} to={`${basePath}${views[0].path}`} />
</Switch>
</EntityLayout>
);
};
type EntityViewRegistration =
type EntityPageRegistration =
| {
type: 'page';
title: string;
@@ -88,14 +92,14 @@ type EntityViewRegistration =
component: ComponentType<any>;
};
export default class EntityViewBuilder extends AppComponentBuilder {
private readonly registrations = new Array<EntityViewRegistration>();
export default class EntityPageBuilder extends AppComponentBuilder {
private readonly registrations = new Array<EntityPageRegistration>();
addPage(
title: string,
path: string,
page: AppComponentBuilder,
): EntityViewBuilder {
): EntityPageBuilder {
this.registrations.push({ type: 'page', title, path, page });
return this;
}
@@ -104,42 +108,60 @@ export default class EntityViewBuilder extends AppComponentBuilder {
title: string,
path: string,
component: ComponentType<any>,
): EntityViewBuilder {
): EntityPageBuilder {
this.registrations.push({ type: 'component', title, path, component });
return this;
}
register(plugin: BackstagePlugin): EntityViewBuilder {
register(plugin: BackstagePlugin): EntityPageBuilder {
this.registrations.push({ type: 'plugin', plugin });
return this;
}
build(app: App): ComponentType<any> {
const pages = this.registrations.map(registration => {
switch (registration.type) {
const navItems = new Array<EntityPageNavItem>();
const views = new Array<EntityPageView>();
for (const reg of this.registrations) {
switch (reg.type) {
case 'page': {
const { title, path, page } = registration;
return { title, path, component: page.build(app) };
const { title, path, page } = reg;
navItems.push({ title, target: path });
views.push({ path, component: page.build(app) });
break;
}
case 'component': {
const { title, path, component } = registration;
return { title, path, component };
const { title, path, component } = reg;
navItems.push({ title, target: path });
views.push({ path, component });
break;
}
case 'plugin': {
const { plugin } = registration;
const output = plugin[outputSymbol](entityViewPage);
if (!output) {
let added = false;
for (const output of reg.plugin.output()) {
switch (output.type) {
case 'entity-page-nav-item':
const { title, target } = output;
navItems.push({ title, target });
added = true;
break;
case 'entity-page-view-route':
const { path, component } = output;
views.push({ path, component });
added = true;
break;
}
}
if (!added) {
throw new Error(
`Plugin ${plugin} was registered as entity view, but did not have any output`,
`Plugin ${reg.plugin} was registered as entity view, but did not provide any output`,
);
}
return output;
break;
}
default:
throw new Error(`Unknown EntityViewBuilder registration`);
}
});
}
return () => <EntityViewComponent pages={pages} />;
return () => <EntityPageComponent navItems={navItems} views={views} />;
}
}
@@ -1,6 +1,5 @@
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import PluginOutputHook from './PluginOutputHook';
import { ComponentType } from 'react';
import { PluginOutput, RoutePath, RouteOptions } from './types';
export type PluginConfig = {
id: string;
@@ -8,101 +7,98 @@ export type PluginConfig = {
};
export type PluginHooks = {
router: Router;
provide<T>(ref: PluginOutputHook<T>, value: T): void;
router: RouterHooks;
entityPage: EntityPageHooks;
};
export type RouteOptions = {
// Whether the route path must match exactly, defaults to true.
exact?: boolean;
};
export type RedirectOptions = {
// Whether the route path must match exactly, defaults to true.
exact?: boolean;
};
export type Router = {
export type RouterHooks = {
registerRoute(
path: string,
Component: React.ComponentType<any>,
path: RoutePath,
Component: ComponentType<any>,
options?: RouteOptions,
): void;
registerRedirect(
path: string,
target: string,
options?: RedirectOptions,
path: RoutePath,
target: RoutePath,
options?: RouteOptions,
): void;
};
export type PluginRegistrationResult = {
routes?: JSX.Element[];
outputs?: Map<PluginOutputHook<any>, any>;
type EntityPageSidebarItemOptions = {
title: string;
target: RoutePath;
};
export type EntityPageHooks = {
navItem(options: EntityPageSidebarItemOptions): void;
route(
path: RoutePath,
component: ComponentType<any>,
options?: RouteOptions,
): void;
};
export const registerSymbol = Symbol('plugin-register');
export const outputSymbol = Symbol('plugin-output');
export default class Plugin {
private result?: PluginRegistrationResult;
private storedOutput?: PluginOutput[];
constructor(private readonly config: PluginConfig) {}
[registerSymbol](): PluginRegistrationResult {
if (this.result) {
return this.result;
output(): PluginOutput[] {
if (this.storedOutput) {
return this.storedOutput;
}
if (!this.config.register) {
return {};
return [];
}
const { id } = this.config;
const routes = new Array<JSX.Element>();
const outputs = new Map<PluginOutputHook<any>, any>();
const outputs = new Array<PluginOutput>();
this.config.register({
router: {
registerRoute(path, component, options = {}) {
registerRoute(path, component, options) {
if (path.startsWith('/entity/')) {
throw new Error(
`Plugin ${id} tried to register forbidden route ${path}`,
);
}
const { exact = true } = options;
routes.push(
<Route
key={path}
path={path}
component={component}
exact={exact}
/>,
);
outputs.push({ type: 'route', path, component, options });
},
registerRedirect(path, target, options = {}) {
registerRedirect(path, target, options) {
if (path.startsWith('/entity/')) {
throw new Error(
`Plugin ${id} tried to register forbidden redirect ${path}`,
);
}
const { exact = true } = options;
routes.push(
<Redirect key={path} path={path} to={target} exact={exact} />,
);
outputs.push({ type: 'redirect-route', path, target, options });
},
},
provide(hook, value) {
outputs.set(hook, value);
entityPage: {
navItem({ title, target }) {
outputs.push({
type: 'entity-page-nav-item',
target,
title,
});
},
route(path, component, options) {
outputs.push({
type: 'entity-page-view-route',
path,
component,
options,
});
},
},
});
this.result = { routes, outputs };
return this.result;
}
[outputSymbol]<T>(outputHook: PluginOutputHook<T>): T | undefined {
const { outputs } = this[registerSymbol]();
return outputs?.get(outputHook) as T;
this.storedOutput = outputs;
return this.storedOutput;
}
toString() {
@@ -1,11 +0,0 @@
export default class PluginOutputHook<T> {
constructor(private readonly name: string) {}
get T(): T {
throw new Error('use typeof instead');
}
toString() {
return `pluginOutput{${this.name}}`;
}
}
@@ -1,8 +0,0 @@
import PluginOutputHook from './PluginOutputHook';
import { ComponentType } from 'react';
export const entityViewPage = new PluginOutputHook<{
title: string;
path: string;
component: ComponentType<any>;
}>('entity-view-page');
@@ -0,0 +1,41 @@
import { ComponentType } from 'react';
export type RouteOptions = {
// Whether the route path must match exactly, defaults to true.
exact?: boolean;
};
export type RoutePath = string;
export type RouteOutput = {
type: 'route';
path: RoutePath;
component: ComponentType<{}>;
options?: RouteOptions;
};
export type RedirectRouteOutput = {
type: 'redirect-route';
path: RoutePath;
target: RoutePath;
options?: RouteOptions;
};
export type EntityPageViewRouteOutput = {
type: 'entity-page-view-route';
path: RoutePath;
component: ComponentType<any>;
options?: RouteOptions;
};
export type EntityPageNavItemOutput = {
type: 'entity-page-nav-item';
title: string;
target: RoutePath;
};
export type PluginOutput =
| RouteOutput
| RedirectRouteOutput
| EntityPageViewRouteOutput
| EntityPageNavItemOutput;
@@ -16,7 +16,7 @@ type Props = {
export function buildPath(kind: string, id?: string, subPath?: string) {
if (id) {
if (subPath) {
return `/entity/${kind}/${id}/${subPath}`;
return `/entity/${kind}/${id}/${subPath.replace(/^\//, '')}`;
}
return `/entity/${kind}/${id}`;
}
@@ -5,6 +5,7 @@
"main:src": "src/index.ts",
"devDependencies": {
"@backstage/core": "0.0.0",
"@backstage/protobuf-definitions": "0.0.0",
"@spotify/web-scripts": "^6.0.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
@@ -0,0 +1,59 @@
import { buildsV1 } from '@backstage/protobuf-definitions';
import { BuildStatus, Build, BuildDetails } from './types';
const statusTable = {
[buildsV1.BuildStatus.NULL]: BuildStatus.Null,
[buildsV1.BuildStatus.SUCCESS]: BuildStatus.Success,
[buildsV1.BuildStatus.FAILURE]: BuildStatus.Failure,
[buildsV1.BuildStatus.PENDING]: BuildStatus.Pending,
[buildsV1.BuildStatus.RUNNING]: BuildStatus.Running,
};
export default class BuildsClient {
static create(grpcAddress: string): BuildsClient {
return new BuildsClient(new buildsV1.Client(grpcAddress));
}
constructor(private readonly client: buildsV1.Client) {}
async listBuilds(entityUri: string): Promise<Build[]> {
const req = new buildsV1.ListBuildsRequest();
req.setEntityUri(entityUri);
const res = await this.client.listBuilds(req);
return res.getBuildsList().map(this.transformBuild);
}
async getBuild(buildUri: string): Promise<BuildDetails> {
const req = new buildsV1.GetBuildRequest();
req.setBuildUri(buildUri);
const res = await this.client.getBuild(req);
const build = res.getBuild();
if (!build) {
throw new Error('No build in GetBuild response');
}
const details = res.getDetails();
if (!details) {
throw new Error('No details in GetBuild response');
}
return {
build: this.transformBuild(build),
author: details.getAuthor(),
logUrl: details.getLogUrl(),
overviewUrl: details.getOverviewUrl(),
};
}
private transformBuild = (build: buildsV1.Build): Build => {
return {
commitId: build.getCommitId(),
message: build.getMessage(),
status: statusTable[build.getStatus()] || BuildStatus.Null,
uri: build.getUri(),
};
};
}
@@ -0,0 +1,2 @@
export * from './types';
export { default as BuildsClient } from './BuildsClient';
@@ -0,0 +1,21 @@
export enum BuildStatus {
Null,
Success,
Failure,
Pending,
Running,
}
export type Build = {
commitId: string;
message: string;
status: BuildStatus;
uri: string;
};
export type BuildDetails = {
build: Build;
author: string;
logUrl: string;
overviewUrl: string;
};
@@ -1,19 +1,101 @@
import React, { FC } from 'react';
import Button from '@material-ui/core/Button';
import { BuildsClient } from '../../apis/builds';
import { useAsync } from 'react-use';
import { useRouteMatch } from 'react-router-dom';
import {
LinearProgress,
Typography,
TableContainer,
Paper,
Table,
TableBody,
TableRow,
TableCell,
Link,
makeStyles,
ButtonGroup,
Button,
} from '@material-ui/core';
type Props = {
buildId: string;
};
const useStyles = makeStyles({
root: {
maxWidth: 720,
},
});
type Props = {};
const client = BuildsClient.create('http://localhost:8080');
const BuildDetailsPage: FC<Props> = () => {
const classes = useStyles();
const match = useRouteMatch<{ buildUri: string }>();
const buildUri = decodeURIComponent(match.params.buildUri);
const status = useAsync(() => client.getBuild(buildUri), [buildUri]);
if (status.loading) {
return <LinearProgress />;
}
if (status.error) {
return (
<Typography variant="h4" color="error">
Failed to load build, {status.error}
</Typography>
);
}
const details = status.value;
const BuildDetailsPage: FC<Props> = ({ buildId }) => {
return (
<Button
variant="contained"
color="primary"
onClick={() => window.location.reload()}
>
Hello! Build details for {buildId}
</Button>
<TableContainer component={Paper} className={classes.root}>
<Table>
<TableBody>
<TableRow>
<TableCell>
<Typography noWrap>Message</Typography>
</TableCell>
<TableCell>{details?.build.message}</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Commit ID</Typography>
</TableCell>
<TableCell>{details?.build.commitId}</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Status</Typography>
</TableCell>
<TableCell>{details?.build.status}</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Author</Typography>
</TableCell>
<TableCell>{details?.author}</TableCell>
</TableRow>
<TableRow>
<TableCell>
<Typography noWrap>Links</Typography>
</TableCell>
<TableCell>
<ButtonGroup
variant="text"
color="primary"
aria-label="text primary button group"
>
<Button>
<Link href={details?.overviewUrl}>GitHub</Link>
</Button>
<Button>
<Link href={details?.logUrl}>Logs</Link>
</Button>
</ButtonGroup>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
);
};
@@ -7,39 +7,79 @@ import {
TableCell,
Paper,
TableBody,
LinearProgress,
Typography,
Tooltip,
} from '@material-ui/core';
import { RelativeEntityLink } from '@backstage/core';
import { BuildsClient } from '../../apis/builds';
import { useAsync } from 'react-use';
const client = BuildsClient.create('http://localhost:8080');
const LongText: FC<{ text: string; max: number }> = ({ text, max }) => {
if (text.length < max) {
return <span>{text}</span>;
}
return (
<Tooltip title={text}>
<span>{text.slice(0, max)}...</span>
</Tooltip>
);
};
const BuildListPage: FC<{}> = () => {
const rows = [
{ message: 'Fixed a Bar', commit: 'fb46ca3dfbd7af5bc43da', id: 165 },
{ message: 'Fixed a Foo', commit: 'd7af5bc43dafb46ca3dfb', id: 164 },
];
const status = useAsync(() => client.listBuilds('entity:spotify:backstage'));
if (status.loading) {
return <LinearProgress />;
}
if (status.error) {
return (
<Typography variant="h4" color="error">
Failed to load builds, {status.error}
</Typography>
);
}
return (
<TableContainer component={Paper}>
<Table aria-label="CI/CD builds table">
<TableHead>
<TableRow>
<TableCell>Message</TableCell>
<TableCell>Commit</TableCell>
<TableCell>Build ID</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map(row => (
<TableRow key={row.commit}>
<TableCell>{row.message}</TableCell>
<TableCell>{row.commit}</TableCell>
<TableCell>
<RelativeEntityLink view={`builds/${row.id}`}>
{row.commit}
</RelativeEntityLink>
</TableCell>
<>
<Typography variant="h4">CI/CD Builds</Typography>
<TableContainer component={Paper}>
<Table aria-label="CI/CD builds table">
<TableHead>
<TableRow>
<TableCell>Message</TableCell>
<TableCell>Commit</TableCell>
<TableCell>Status</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</TableHead>
<TableBody>
{status.value!.map(build => (
<TableRow key={build.uri}>
<TableCell>
<RelativeEntityLink
view={`builds/${encodeURIComponent(build.uri)}`}
>
<Typography color="primary">
<LongText text={build.message} max={60} />
</Typography>
</RelativeEntityLink>
</TableCell>
<TableCell>
<Tooltip title={build.commitId}>
<Typography noWrap>
{build.commitId.slice(0, 10)}
</Typography>
</Tooltip>
</TableCell>
<TableCell>{build.status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
};
@@ -1,22 +0,0 @@
import React, { FC } from 'react';
import { Switch, Route } from 'react-router-dom';
import BuildListPage from '../BuildListPage';
import BuildDetailsPage from '../BuildDetailsPage';
import { useRouteMatch } from 'react-router-dom';
const BuildPage: FC<{}> = () => {
const match = useRouteMatch();
return (
<Switch>
<Route
path={`${match.path}/:buildId`}
render={({ match }) => (
<BuildDetailsPage buildId={match.params.buildId} />
)}
/>
<Route path={match.path} component={BuildListPage} />
</Switch>
);
};
export default BuildPage;
@@ -1 +0,0 @@
export { default } from './BuildPage';
@@ -1,6 +1,6 @@
import { createPlugin } from '@backstage/core';
import { entityViewPage } from '@backstage/core/src/api/plugin/outputs';
import BuildPage from './components/BuildPage';
import BuildDetailsPage from './components/BuildDetailsPage';
import BuildListPage from './components/BuildListPage';
// export const buildListRoute = createEntityRoute<[]>('/builds')
// export const buildDetailsRoute = createEntityRoute<[number]>('/builds/:buildId')
@@ -8,11 +8,9 @@ import BuildPage from './components/BuildPage';
export default createPlugin({
id: 'github-actions',
register({ provide }) {
provide(entityViewPage, {
title: 'CI/CD',
path: 'builds',
component: BuildPage,
});
register({ entityPage }) {
entityPage.navItem({ title: 'CI/CD', target: '/builds' });
entityPage.route('/builds', BuildListPage);
entityPage.route('/builds/:buildUri', BuildDetailsPage);
},
});
+5 -2
View File
@@ -1,8 +1,11 @@
{
"private": true,
"name": "@backstage/protobuf-definitions",
"main": "src/index.ts",
"main:src": "src/index.ts",
"version": "0.0.0",
"devDependencies": {
"ts-protoc-gen": "^0.12.0"
"dependencies": {
"google-protobuf": "^3.11.2",
"grpc-web": "^1.0.7"
}
}
+2
View File
@@ -0,0 +1,2 @@
export { BuildsPromiseClient as Client } from './generated/builds/v1/builds_grpc_web_pb';
export * from './generated/builds/v1/builds_pb';
@@ -0,0 +1,46 @@
import * as grpcWeb from 'grpc-web';
import {
GetBuildReply,
GetBuildRequest,
ListBuildsReply,
ListBuildsRequest} from './builds_pb';
export class BuildsClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
listBuilds(
request: ListBuildsRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: ListBuildsReply) => void
): grpcWeb.ClientReadableStream<ListBuildsReply>;
getBuild(
request: GetBuildRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: GetBuildReply) => void
): grpcWeb.ClientReadableStream<GetBuildReply>;
}
export class BuildsPromiseClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
listBuilds(
request: ListBuildsRequest,
metadata?: grpcWeb.Metadata
): Promise<ListBuildsReply>;
getBuild(
request: GetBuildRequest,
metadata?: grpcWeb.Metadata
): Promise<GetBuildReply>;
}
@@ -0,0 +1,233 @@
/**
* @fileoverview gRPC-Web generated client stub for spotify.backstage.builds.v1
* @enhanceable
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
const grpc = {};
grpc.web = require('grpc-web');
const proto = {};
proto.spotify = {};
proto.spotify.backstage = {};
proto.spotify.backstage.builds = {};
proto.spotify.backstage.builds.v1 = require('./builds_pb.js');
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.spotify.backstage.builds.v1.BuildsClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.spotify.backstage.builds.v1.BuildsPromiseClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.builds.v1.ListBuildsRequest,
* !proto.spotify.backstage.builds.v1.ListBuildsReply>}
*/
const methodDescriptor_Builds_ListBuilds = new grpc.web.MethodDescriptor(
'/spotify.backstage.builds.v1.Builds/ListBuilds',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.builds.v1.ListBuildsRequest,
proto.spotify.backstage.builds.v1.ListBuildsReply,
/**
* @param {!proto.spotify.backstage.builds.v1.ListBuildsRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.builds.v1.ListBuildsReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.builds.v1.ListBuildsRequest,
* !proto.spotify.backstage.builds.v1.ListBuildsReply>}
*/
const methodInfo_Builds_ListBuilds = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.builds.v1.ListBuildsReply,
/**
* @param {!proto.spotify.backstage.builds.v1.ListBuildsRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.builds.v1.ListBuildsReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.builds.v1.ListBuildsRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.builds.v1.ListBuildsReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.builds.v1.ListBuildsReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.builds.v1.BuildsClient.prototype.listBuilds =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.builds.v1.Builds/ListBuilds',
request,
metadata || {},
methodDescriptor_Builds_ListBuilds,
callback);
};
/**
* @param {!proto.spotify.backstage.builds.v1.ListBuildsRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.builds.v1.ListBuildsReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.builds.v1.BuildsPromiseClient.prototype.listBuilds =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.builds.v1.Builds/ListBuilds',
request,
metadata || {},
methodDescriptor_Builds_ListBuilds);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.builds.v1.GetBuildRequest,
* !proto.spotify.backstage.builds.v1.GetBuildReply>}
*/
const methodDescriptor_Builds_GetBuild = new grpc.web.MethodDescriptor(
'/spotify.backstage.builds.v1.Builds/GetBuild',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.builds.v1.GetBuildRequest,
proto.spotify.backstage.builds.v1.GetBuildReply,
/**
* @param {!proto.spotify.backstage.builds.v1.GetBuildRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.builds.v1.GetBuildReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.builds.v1.GetBuildRequest,
* !proto.spotify.backstage.builds.v1.GetBuildReply>}
*/
const methodInfo_Builds_GetBuild = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.builds.v1.GetBuildReply,
/**
* @param {!proto.spotify.backstage.builds.v1.GetBuildRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.builds.v1.GetBuildReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.builds.v1.GetBuildRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.builds.v1.GetBuildReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.builds.v1.GetBuildReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.builds.v1.BuildsClient.prototype.getBuild =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.builds.v1.Builds/GetBuild',
request,
metadata || {},
methodDescriptor_Builds_GetBuild,
callback);
};
/**
* @param {!proto.spotify.backstage.builds.v1.GetBuildRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.builds.v1.GetBuildReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.builds.v1.BuildsPromiseClient.prototype.getBuild =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.builds.v1.Builds/GetBuild',
request,
metadata || {},
methodDescriptor_Builds_GetBuild);
};
module.exports = proto.spotify.backstage.builds.v1;
@@ -0,0 +1,151 @@
import * as jspb from "google-protobuf"
export class ListBuildsRequest extends jspb.Message {
getEntityUri(): string;
setEntityUri(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListBuildsRequest.AsObject;
static toObject(includeInstance: boolean, msg: ListBuildsRequest): ListBuildsRequest.AsObject;
static serializeBinaryToWriter(message: ListBuildsRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListBuildsRequest;
static deserializeBinaryFromReader(message: ListBuildsRequest, reader: jspb.BinaryReader): ListBuildsRequest;
}
export namespace ListBuildsRequest {
export type AsObject = {
entityUri: string,
}
}
export class ListBuildsReply extends jspb.Message {
getEntityUri(): string;
setEntityUri(value: string): void;
getBuildsList(): Array<Build>;
setBuildsList(value: Array<Build>): void;
clearBuildsList(): void;
addBuilds(value?: Build, index?: number): Build;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListBuildsReply.AsObject;
static toObject(includeInstance: boolean, msg: ListBuildsReply): ListBuildsReply.AsObject;
static serializeBinaryToWriter(message: ListBuildsReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListBuildsReply;
static deserializeBinaryFromReader(message: ListBuildsReply, reader: jspb.BinaryReader): ListBuildsReply;
}
export namespace ListBuildsReply {
export type AsObject = {
entityUri: string,
buildsList: Array<Build.AsObject>,
}
}
export class GetBuildRequest extends jspb.Message {
getBuildUri(): string;
setBuildUri(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetBuildRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetBuildRequest): GetBuildRequest.AsObject;
static serializeBinaryToWriter(message: GetBuildRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetBuildRequest;
static deserializeBinaryFromReader(message: GetBuildRequest, reader: jspb.BinaryReader): GetBuildRequest;
}
export namespace GetBuildRequest {
export type AsObject = {
buildUri: string,
}
}
export class GetBuildReply extends jspb.Message {
getBuild(): Build | undefined;
setBuild(value?: Build): void;
hasBuild(): boolean;
clearBuild(): void;
getDetails(): BuildDetails | undefined;
setDetails(value?: BuildDetails): void;
hasDetails(): boolean;
clearDetails(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetBuildReply.AsObject;
static toObject(includeInstance: boolean, msg: GetBuildReply): GetBuildReply.AsObject;
static serializeBinaryToWriter(message: GetBuildReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetBuildReply;
static deserializeBinaryFromReader(message: GetBuildReply, reader: jspb.BinaryReader): GetBuildReply;
}
export namespace GetBuildReply {
export type AsObject = {
build?: Build.AsObject,
details?: BuildDetails.AsObject,
}
}
export class Build extends jspb.Message {
getUri(): string;
setUri(value: string): void;
getCommitId(): string;
setCommitId(value: string): void;
getMessage(): string;
setMessage(value: string): void;
getStatus(): BuildStatus;
setStatus(value: BuildStatus): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Build.AsObject;
static toObject(includeInstance: boolean, msg: Build): Build.AsObject;
static serializeBinaryToWriter(message: Build, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Build;
static deserializeBinaryFromReader(message: Build, reader: jspb.BinaryReader): Build;
}
export namespace Build {
export type AsObject = {
uri: string,
commitId: string,
message: string,
status: BuildStatus,
}
}
export class BuildDetails extends jspb.Message {
getAuthor(): string;
setAuthor(value: string): void;
getOverviewUrl(): string;
setOverviewUrl(value: string): void;
getLogUrl(): string;
setLogUrl(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): BuildDetails.AsObject;
static toObject(includeInstance: boolean, msg: BuildDetails): BuildDetails.AsObject;
static serializeBinaryToWriter(message: BuildDetails, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): BuildDetails;
static deserializeBinaryFromReader(message: BuildDetails, reader: jspb.BinaryReader): BuildDetails;
}
export namespace BuildDetails {
export type AsObject = {
author: string,
overviewUrl: string,
logUrl: string,
}
}
export enum BuildStatus {
NULL = 0,
SUCCESS = 1,
FAILURE = 2,
PENDING = 3,
RUNNING = 4,
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,46 @@
import * as grpcWeb from 'grpc-web';
import {
GetGroupReply,
GetGroupRequest,
GetUserReply,
GetUserRequest} from './identity_pb';
export class IdentityClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
getUser(
request: GetUserRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: GetUserReply) => void
): grpcWeb.ClientReadableStream<GetUserReply>;
getGroup(
request: GetGroupRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: GetGroupReply) => void
): grpcWeb.ClientReadableStream<GetGroupReply>;
}
export class IdentityPromiseClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
getUser(
request: GetUserRequest,
metadata?: grpcWeb.Metadata
): Promise<GetUserReply>;
getGroup(
request: GetGroupRequest,
metadata?: grpcWeb.Metadata
): Promise<GetGroupReply>;
}
@@ -0,0 +1,233 @@
/**
* @fileoverview gRPC-Web generated client stub for spotify.backstage.identity.v1
* @enhanceable
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
const grpc = {};
grpc.web = require('grpc-web');
const proto = {};
proto.spotify = {};
proto.spotify.backstage = {};
proto.spotify.backstage.identity = {};
proto.spotify.backstage.identity.v1 = require('./identity_pb.js');
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.spotify.backstage.identity.v1.IdentityClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.spotify.backstage.identity.v1.IdentityPromiseClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.identity.v1.GetUserRequest,
* !proto.spotify.backstage.identity.v1.GetUserReply>}
*/
const methodDescriptor_Identity_GetUser = new grpc.web.MethodDescriptor(
'/spotify.backstage.identity.v1.Identity/GetUser',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.identity.v1.GetUserRequest,
proto.spotify.backstage.identity.v1.GetUserReply,
/**
* @param {!proto.spotify.backstage.identity.v1.GetUserRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.identity.v1.GetUserReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.identity.v1.GetUserRequest,
* !proto.spotify.backstage.identity.v1.GetUserReply>}
*/
const methodInfo_Identity_GetUser = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.identity.v1.GetUserReply,
/**
* @param {!proto.spotify.backstage.identity.v1.GetUserRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.identity.v1.GetUserReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.identity.v1.GetUserRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.identity.v1.GetUserReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.identity.v1.GetUserReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.identity.v1.IdentityClient.prototype.getUser =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.identity.v1.Identity/GetUser',
request,
metadata || {},
methodDescriptor_Identity_GetUser,
callback);
};
/**
* @param {!proto.spotify.backstage.identity.v1.GetUserRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.identity.v1.GetUserReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.identity.v1.IdentityPromiseClient.prototype.getUser =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.identity.v1.Identity/GetUser',
request,
metadata || {},
methodDescriptor_Identity_GetUser);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.identity.v1.GetGroupRequest,
* !proto.spotify.backstage.identity.v1.GetGroupReply>}
*/
const methodDescriptor_Identity_GetGroup = new grpc.web.MethodDescriptor(
'/spotify.backstage.identity.v1.Identity/GetGroup',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.identity.v1.GetGroupRequest,
proto.spotify.backstage.identity.v1.GetGroupReply,
/**
* @param {!proto.spotify.backstage.identity.v1.GetGroupRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.identity.v1.GetGroupReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.identity.v1.GetGroupRequest,
* !proto.spotify.backstage.identity.v1.GetGroupReply>}
*/
const methodInfo_Identity_GetGroup = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.identity.v1.GetGroupReply,
/**
* @param {!proto.spotify.backstage.identity.v1.GetGroupRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.identity.v1.GetGroupReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.identity.v1.GetGroupRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.identity.v1.GetGroupReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.identity.v1.GetGroupReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.identity.v1.IdentityClient.prototype.getGroup =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.identity.v1.Identity/GetGroup',
request,
metadata || {},
methodDescriptor_Identity_GetGroup,
callback);
};
/**
* @param {!proto.spotify.backstage.identity.v1.GetGroupRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.identity.v1.GetGroupReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.identity.v1.IdentityPromiseClient.prototype.getGroup =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.identity.v1.Identity/GetGroup',
request,
metadata || {},
methodDescriptor_Identity_GetGroup);
};
module.exports = proto.spotify.backstage.identity.v1;
@@ -1,7 +1,4 @@
// package: spotify.backstage.identity.v1
// file: identity/v1/identity.proto
import * as jspb from "google-protobuf";
import * as jspb from "google-protobuf"
export class GetUserRequest extends jspb.Message {
getId(): string;
@@ -10,8 +7,6 @@ export class GetUserRequest extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetUserRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetUserRequest): GetUserRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetUserRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetUserRequest;
static deserializeBinaryFromReader(message: GetUserRequest, reader: jspb.BinaryReader): GetUserRequest;
@@ -24,21 +19,19 @@ export namespace GetUserRequest {
}
export class GetUserReply extends jspb.Message {
hasUser(): boolean;
clearUser(): void;
getUser(): User | undefined;
setUser(value?: User): void;
hasUser(): boolean;
clearUser(): void;
clearGroupsList(): void;
getGroupsList(): Array<Group>;
setGroupsList(value: Array<Group>): void;
clearGroupsList(): void;
addGroups(value?: Group, index?: number): Group;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetUserReply.AsObject;
static toObject(includeInstance: boolean, msg: GetUserReply): GetUserReply.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetUserReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetUserReply;
static deserializeBinaryFromReader(message: GetUserReply, reader: jspb.BinaryReader): GetUserReply;
@@ -58,8 +51,6 @@ export class GetGroupRequest extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetGroupRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetGroupRequest): GetGroupRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetGroupRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetGroupRequest;
static deserializeBinaryFromReader(message: GetGroupRequest, reader: jspb.BinaryReader): GetGroupRequest;
@@ -72,16 +63,14 @@ export namespace GetGroupRequest {
}
export class GetGroupReply extends jspb.Message {
hasGroup(): boolean;
clearGroup(): void;
getGroup(): Group | undefined;
setGroup(value?: Group): void;
hasGroup(): boolean;
clearGroup(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetGroupReply.AsObject;
static toObject(includeInstance: boolean, msg: GetGroupReply): GetGroupReply.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetGroupReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetGroupReply;
static deserializeBinaryFromReader(message: GetGroupReply, reader: jspb.BinaryReader): GetGroupReply;
@@ -103,8 +92,6 @@ export class User extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): User.AsObject;
static toObject(includeInstance: boolean, msg: User): User.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: User, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): User;
static deserializeBinaryFromReader(message: User, reader: jspb.BinaryReader): User;
@@ -121,21 +108,19 @@ export class Group extends jspb.Message {
getId(): string;
setId(value: string): void;
clearUsersList(): void;
getUsersList(): Array<User>;
setUsersList(value: Array<User>): void;
clearUsersList(): void;
addUsers(value?: User, index?: number): User;
clearGroupsList(): void;
getGroupsList(): Array<Group>;
setGroupsList(value: Array<Group>): void;
clearGroupsList(): void;
addGroups(value?: Group, index?: number): Group;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Group.AsObject;
static toObject(includeInstance: boolean, msg: Group): Group.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Group, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Group;
static deserializeBinaryFromReader(message: Group, reader: jspb.BinaryReader): Group;
File diff suppressed because it is too large Load Diff
@@ -1,82 +0,0 @@
// package: spotify.backstage.identity.v1
// file: identity/v1/identity.proto
import * as identity_v1_identity_pb from "../../identity/v1/identity_pb";
import {grpc} from "@improbable-eng/grpc-web";
type IdentityGetUser = {
readonly methodName: string;
readonly service: typeof Identity;
readonly requestStream: false;
readonly responseStream: false;
readonly requestType: typeof identity_v1_identity_pb.GetUserRequest;
readonly responseType: typeof identity_v1_identity_pb.GetUserReply;
};
type IdentityGetGroup = {
readonly methodName: string;
readonly service: typeof Identity;
readonly requestStream: false;
readonly responseStream: false;
readonly requestType: typeof identity_v1_identity_pb.GetGroupRequest;
readonly responseType: typeof identity_v1_identity_pb.GetGroupReply;
};
export class Identity {
static readonly serviceName: string;
static readonly GetUser: IdentityGetUser;
static readonly GetGroup: IdentityGetGroup;
}
export type ServiceError = { message: string, code: number; metadata: grpc.Metadata }
export type Status = { details: string, code: number; metadata: grpc.Metadata }
interface UnaryResponse {
cancel(): void;
}
interface ResponseStream<T> {
cancel(): void;
on(type: 'data', handler: (message: T) => void): ResponseStream<T>;
on(type: 'end', handler: (status?: Status) => void): ResponseStream<T>;
on(type: 'status', handler: (status: Status) => void): ResponseStream<T>;
}
interface RequestStream<T> {
write(message: T): RequestStream<T>;
end(): void;
cancel(): void;
on(type: 'end', handler: (status?: Status) => void): RequestStream<T>;
on(type: 'status', handler: (status: Status) => void): RequestStream<T>;
}
interface BidirectionalStream<ReqT, ResT> {
write(message: ReqT): BidirectionalStream<ReqT, ResT>;
end(): void;
cancel(): void;
on(type: 'data', handler: (message: ResT) => void): BidirectionalStream<ReqT, ResT>;
on(type: 'end', handler: (status?: Status) => void): BidirectionalStream<ReqT, ResT>;
on(type: 'status', handler: (status: Status) => void): BidirectionalStream<ReqT, ResT>;
}
export class IdentityClient {
readonly serviceHost: string;
constructor(serviceHost: string, options?: grpc.RpcOptions);
getUser(
requestMessage: identity_v1_identity_pb.GetUserRequest,
metadata: grpc.Metadata,
callback: (error: ServiceError|null, responseMessage: identity_v1_identity_pb.GetUserReply|null) => void
): UnaryResponse;
getUser(
requestMessage: identity_v1_identity_pb.GetUserRequest,
callback: (error: ServiceError|null, responseMessage: identity_v1_identity_pb.GetUserReply|null) => void
): UnaryResponse;
getGroup(
requestMessage: identity_v1_identity_pb.GetGroupRequest,
metadata: grpc.Metadata,
callback: (error: ServiceError|null, responseMessage: identity_v1_identity_pb.GetGroupReply|null) => void
): UnaryResponse;
getGroup(
requestMessage: identity_v1_identity_pb.GetGroupRequest,
callback: (error: ServiceError|null, responseMessage: identity_v1_identity_pb.GetGroupReply|null) => void
): UnaryResponse;
}
@@ -1,101 +0,0 @@
// package: spotify.backstage.identity.v1
// file: identity/v1/identity.proto
var identity_v1_identity_pb = require("../../identity/v1/identity_pb");
var grpc = require("@improbable-eng/grpc-web").grpc;
var Identity = (function () {
function Identity() {}
Identity.serviceName = "spotify.backstage.identity.v1.Identity";
return Identity;
}());
Identity.GetUser = {
methodName: "GetUser",
service: Identity,
requestStream: false,
responseStream: false,
requestType: identity_v1_identity_pb.GetUserRequest,
responseType: identity_v1_identity_pb.GetUserReply
};
Identity.GetGroup = {
methodName: "GetGroup",
service: Identity,
requestStream: false,
responseStream: false,
requestType: identity_v1_identity_pb.GetGroupRequest,
responseType: identity_v1_identity_pb.GetGroupReply
};
exports.Identity = Identity;
function IdentityClient(serviceHost, options) {
this.serviceHost = serviceHost;
this.options = options || {};
}
IdentityClient.prototype.getUser = function getUser(requestMessage, metadata, callback) {
if (arguments.length === 2) {
callback = arguments[1];
}
var client = grpc.unary(Identity.GetUser, {
request: requestMessage,
host: this.serviceHost,
metadata: metadata,
transport: this.options.transport,
debug: this.options.debug,
onEnd: function (response) {
if (callback) {
if (response.status !== grpc.Code.OK) {
var err = new Error(response.statusMessage);
err.code = response.status;
err.metadata = response.trailers;
callback(err, null);
} else {
callback(null, response.message);
}
}
}
});
return {
cancel: function () {
callback = null;
client.close();
}
};
};
IdentityClient.prototype.getGroup = function getGroup(requestMessage, metadata, callback) {
if (arguments.length === 2) {
callback = arguments[1];
}
var client = grpc.unary(Identity.GetGroup, {
request: requestMessage,
host: this.serviceHost,
metadata: metadata,
transport: this.options.transport,
debug: this.options.debug,
onEnd: function (response) {
if (callback) {
if (response.status !== grpc.Code.OK) {
var err = new Error(response.statusMessage);
err.code = response.status;
err.metadata = response.trailers;
callback(err, null);
} else {
callback(null, response.message);
}
}
}
});
return {
cancel: function () {
callback = null;
client.close();
}
};
};
exports.IdentityClient = IdentityClient;
@@ -0,0 +1,88 @@
import * as grpcWeb from 'grpc-web';
import {
CreateEntityReply,
CreateEntityRequest,
GetEntityReply,
GetEntityRequest,
GetFactReply,
GetFactRequest,
ListEntitiesReply,
ListEntitiesRequest,
SetFactReply,
SetFactRequest} from './inventory_pb';
export class InventoryClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
listEntities(
request: ListEntitiesRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: ListEntitiesReply) => void
): grpcWeb.ClientReadableStream<ListEntitiesReply>;
getEntity(
request: GetEntityRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: GetEntityReply) => void
): grpcWeb.ClientReadableStream<GetEntityReply>;
createEntity(
request: CreateEntityRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: CreateEntityReply) => void
): grpcWeb.ClientReadableStream<CreateEntityReply>;
setFact(
request: SetFactRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: SetFactReply) => void
): grpcWeb.ClientReadableStream<SetFactReply>;
getFact(
request: GetFactRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: GetFactReply) => void
): grpcWeb.ClientReadableStream<GetFactReply>;
}
export class InventoryPromiseClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
listEntities(
request: ListEntitiesRequest,
metadata?: grpcWeb.Metadata
): Promise<ListEntitiesReply>;
getEntity(
request: GetEntityRequest,
metadata?: grpcWeb.Metadata
): Promise<GetEntityReply>;
createEntity(
request: CreateEntityRequest,
metadata?: grpcWeb.Metadata
): Promise<CreateEntityReply>;
setFact(
request: SetFactRequest,
metadata?: grpcWeb.Metadata
): Promise<SetFactReply>;
getFact(
request: GetFactRequest,
metadata?: grpcWeb.Metadata
): Promise<GetFactReply>;
}
@@ -0,0 +1,473 @@
/**
* @fileoverview gRPC-Web generated client stub for spotify.backstage.inventory.v1
* @enhanceable
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
const grpc = {};
grpc.web = require('grpc-web');
const proto = {};
proto.spotify = {};
proto.spotify.backstage = {};
proto.spotify.backstage.inventory = {};
proto.spotify.backstage.inventory.v1 = require('./inventory_pb.js');
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.spotify.backstage.inventory.v1.InventoryClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.spotify.backstage.inventory.v1.InventoryPromiseClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.inventory.v1.ListEntitiesRequest,
* !proto.spotify.backstage.inventory.v1.ListEntitiesReply>}
*/
const methodDescriptor_Inventory_ListEntities = new grpc.web.MethodDescriptor(
'/spotify.backstage.inventory.v1.Inventory/ListEntities',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.inventory.v1.ListEntitiesRequest,
proto.spotify.backstage.inventory.v1.ListEntitiesReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.ListEntitiesRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.ListEntitiesReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.inventory.v1.ListEntitiesRequest,
* !proto.spotify.backstage.inventory.v1.ListEntitiesReply>}
*/
const methodInfo_Inventory_ListEntities = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.inventory.v1.ListEntitiesReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.ListEntitiesRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.ListEntitiesReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.inventory.v1.ListEntitiesRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.inventory.v1.ListEntitiesReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.inventory.v1.ListEntitiesReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.inventory.v1.InventoryClient.prototype.listEntities =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/ListEntities',
request,
metadata || {},
methodDescriptor_Inventory_ListEntities,
callback);
};
/**
* @param {!proto.spotify.backstage.inventory.v1.ListEntitiesRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.inventory.v1.ListEntitiesReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.inventory.v1.InventoryPromiseClient.prototype.listEntities =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/ListEntities',
request,
metadata || {},
methodDescriptor_Inventory_ListEntities);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.inventory.v1.GetEntityRequest,
* !proto.spotify.backstage.inventory.v1.GetEntityReply>}
*/
const methodDescriptor_Inventory_GetEntity = new grpc.web.MethodDescriptor(
'/spotify.backstage.inventory.v1.Inventory/GetEntity',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.inventory.v1.GetEntityRequest,
proto.spotify.backstage.inventory.v1.GetEntityReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.GetEntityRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.GetEntityReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.inventory.v1.GetEntityRequest,
* !proto.spotify.backstage.inventory.v1.GetEntityReply>}
*/
const methodInfo_Inventory_GetEntity = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.inventory.v1.GetEntityReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.GetEntityRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.GetEntityReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.inventory.v1.GetEntityRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.inventory.v1.GetEntityReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.inventory.v1.GetEntityReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.inventory.v1.InventoryClient.prototype.getEntity =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/GetEntity',
request,
metadata || {},
methodDescriptor_Inventory_GetEntity,
callback);
};
/**
* @param {!proto.spotify.backstage.inventory.v1.GetEntityRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.inventory.v1.GetEntityReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.inventory.v1.InventoryPromiseClient.prototype.getEntity =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/GetEntity',
request,
metadata || {},
methodDescriptor_Inventory_GetEntity);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.inventory.v1.CreateEntityRequest,
* !proto.spotify.backstage.inventory.v1.CreateEntityReply>}
*/
const methodDescriptor_Inventory_CreateEntity = new grpc.web.MethodDescriptor(
'/spotify.backstage.inventory.v1.Inventory/CreateEntity',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.inventory.v1.CreateEntityRequest,
proto.spotify.backstage.inventory.v1.CreateEntityReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.CreateEntityRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.CreateEntityReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.inventory.v1.CreateEntityRequest,
* !proto.spotify.backstage.inventory.v1.CreateEntityReply>}
*/
const methodInfo_Inventory_CreateEntity = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.inventory.v1.CreateEntityReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.CreateEntityRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.CreateEntityReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.inventory.v1.CreateEntityRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.inventory.v1.CreateEntityReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.inventory.v1.CreateEntityReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.inventory.v1.InventoryClient.prototype.createEntity =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/CreateEntity',
request,
metadata || {},
methodDescriptor_Inventory_CreateEntity,
callback);
};
/**
* @param {!proto.spotify.backstage.inventory.v1.CreateEntityRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.inventory.v1.CreateEntityReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.inventory.v1.InventoryPromiseClient.prototype.createEntity =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/CreateEntity',
request,
metadata || {},
methodDescriptor_Inventory_CreateEntity);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.inventory.v1.SetFactRequest,
* !proto.spotify.backstage.inventory.v1.SetFactReply>}
*/
const methodDescriptor_Inventory_SetFact = new grpc.web.MethodDescriptor(
'/spotify.backstage.inventory.v1.Inventory/SetFact',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.inventory.v1.SetFactRequest,
proto.spotify.backstage.inventory.v1.SetFactReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.SetFactRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.SetFactReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.inventory.v1.SetFactRequest,
* !proto.spotify.backstage.inventory.v1.SetFactReply>}
*/
const methodInfo_Inventory_SetFact = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.inventory.v1.SetFactReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.SetFactRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.SetFactReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.inventory.v1.SetFactRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.inventory.v1.SetFactReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.inventory.v1.SetFactReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.inventory.v1.InventoryClient.prototype.setFact =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/SetFact',
request,
metadata || {},
methodDescriptor_Inventory_SetFact,
callback);
};
/**
* @param {!proto.spotify.backstage.inventory.v1.SetFactRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.inventory.v1.SetFactReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.inventory.v1.InventoryPromiseClient.prototype.setFact =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/SetFact',
request,
metadata || {},
methodDescriptor_Inventory_SetFact);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.spotify.backstage.inventory.v1.GetFactRequest,
* !proto.spotify.backstage.inventory.v1.GetFactReply>}
*/
const methodDescriptor_Inventory_GetFact = new grpc.web.MethodDescriptor(
'/spotify.backstage.inventory.v1.Inventory/GetFact',
grpc.web.MethodType.UNARY,
proto.spotify.backstage.inventory.v1.GetFactRequest,
proto.spotify.backstage.inventory.v1.GetFactReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.GetFactRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.GetFactReply.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.spotify.backstage.inventory.v1.GetFactRequest,
* !proto.spotify.backstage.inventory.v1.GetFactReply>}
*/
const methodInfo_Inventory_GetFact = new grpc.web.AbstractClientBase.MethodInfo(
proto.spotify.backstage.inventory.v1.GetFactReply,
/**
* @param {!proto.spotify.backstage.inventory.v1.GetFactRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.spotify.backstage.inventory.v1.GetFactReply.deserializeBinary
);
/**
* @param {!proto.spotify.backstage.inventory.v1.GetFactRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.spotify.backstage.inventory.v1.GetFactReply)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.spotify.backstage.inventory.v1.GetFactReply>|undefined}
* The XHR Node Readable Stream
*/
proto.spotify.backstage.inventory.v1.InventoryClient.prototype.getFact =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/GetFact',
request,
metadata || {},
methodDescriptor_Inventory_GetFact,
callback);
};
/**
* @param {!proto.spotify.backstage.inventory.v1.GetFactRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.spotify.backstage.inventory.v1.GetFactReply>}
* A native promise that resolves to the response
*/
proto.spotify.backstage.inventory.v1.InventoryPromiseClient.prototype.getFact =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/spotify.backstage.inventory.v1.Inventory/GetFact',
request,
metadata || {},
methodDescriptor_Inventory_GetFact);
};
module.exports = proto.spotify.backstage.inventory.v1;
@@ -1,24 +1,57 @@
// package: spotify.backstage.inventory.v1
// file: inventory/v1/inventory.proto
import * as jspb from "google-protobuf"
import * as jspb from "google-protobuf";
export class ListEntitiesRequest extends jspb.Message {
getUriprefix(): string;
setUriprefix(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListEntitiesRequest.AsObject;
static toObject(includeInstance: boolean, msg: ListEntitiesRequest): ListEntitiesRequest.AsObject;
static serializeBinaryToWriter(message: ListEntitiesRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListEntitiesRequest;
static deserializeBinaryFromReader(message: ListEntitiesRequest, reader: jspb.BinaryReader): ListEntitiesRequest;
}
export namespace ListEntitiesRequest {
export type AsObject = {
uriprefix: string,
}
}
export class ListEntitiesReply extends jspb.Message {
getEntitiesList(): Array<Entity>;
setEntitiesList(value: Array<Entity>): void;
clearEntitiesList(): void;
addEntities(value?: Entity, index?: number): Entity;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListEntitiesReply.AsObject;
static toObject(includeInstance: boolean, msg: ListEntitiesReply): ListEntitiesReply.AsObject;
static serializeBinaryToWriter(message: ListEntitiesReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListEntitiesReply;
static deserializeBinaryFromReader(message: ListEntitiesReply, reader: jspb.BinaryReader): ListEntitiesReply;
}
export namespace ListEntitiesReply {
export type AsObject = {
entitiesList: Array<Entity.AsObject>,
}
}
export class GetEntityRequest extends jspb.Message {
hasEntity(): boolean;
clearEntity(): void;
getEntity(): Entity | undefined;
setEntity(value?: Entity): void;
hasEntity(): boolean;
clearEntity(): void;
clearIncludeFactsList(): void;
getIncludeFactsList(): Array<string>;
setIncludeFactsList(value: Array<string>): void;
addIncludeFacts(value: string, index?: number): string;
clearIncludeFactsList(): void;
addIncludeFacts(value: string, index?: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetEntityRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetEntityRequest): GetEntityRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetEntityRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetEntityRequest;
static deserializeBinaryFromReader(message: GetEntityRequest, reader: jspb.BinaryReader): GetEntityRequest;
@@ -32,21 +65,19 @@ export namespace GetEntityRequest {
}
export class GetEntityReply extends jspb.Message {
hasEntity(): boolean;
clearEntity(): void;
getEntity(): Entity | undefined;
setEntity(value?: Entity): void;
hasEntity(): boolean;
clearEntity(): void;
clearFactsList(): void;
getFactsList(): Array<Fact>;
setFactsList(value: Array<Fact>): void;
clearFactsList(): void;
addFacts(value?: Fact, index?: number): Fact;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetEntityReply.AsObject;
static toObject(includeInstance: boolean, msg: GetEntityReply): GetEntityReply.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetEntityReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetEntityReply;
static deserializeBinaryFromReader(message: GetEntityReply, reader: jspb.BinaryReader): GetEntityReply;
@@ -60,16 +91,14 @@ export namespace GetEntityReply {
}
export class CreateEntityRequest extends jspb.Message {
hasEntity(): boolean;
clearEntity(): void;
getEntity(): Entity | undefined;
setEntity(value?: Entity): void;
hasEntity(): boolean;
clearEntity(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CreateEntityRequest.AsObject;
static toObject(includeInstance: boolean, msg: CreateEntityRequest): CreateEntityRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CreateEntityRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CreateEntityRequest;
static deserializeBinaryFromReader(message: CreateEntityRequest, reader: jspb.BinaryReader): CreateEntityRequest;
@@ -82,16 +111,14 @@ export namespace CreateEntityRequest {
}
export class CreateEntityReply extends jspb.Message {
hasEntity(): boolean;
clearEntity(): void;
getEntity(): Entity | undefined;
setEntity(value?: Entity): void;
hasEntity(): boolean;
clearEntity(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CreateEntityReply.AsObject;
static toObject(includeInstance: boolean, msg: CreateEntityReply): CreateEntityReply.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CreateEntityReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CreateEntityReply;
static deserializeBinaryFromReader(message: CreateEntityReply, reader: jspb.BinaryReader): CreateEntityReply;
@@ -103,6 +130,94 @@ export namespace CreateEntityReply {
}
}
export class SetFactRequest extends jspb.Message {
getEntityuri(): string;
setEntityuri(value: string): void;
getName(): string;
setName(value: string): void;
getValue(): string;
setValue(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): SetFactRequest.AsObject;
static toObject(includeInstance: boolean, msg: SetFactRequest): SetFactRequest.AsObject;
static serializeBinaryToWriter(message: SetFactRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): SetFactRequest;
static deserializeBinaryFromReader(message: SetFactRequest, reader: jspb.BinaryReader): SetFactRequest;
}
export namespace SetFactRequest {
export type AsObject = {
entityuri: string,
name: string,
value: string,
}
}
export class SetFactReply extends jspb.Message {
getFact(): Fact | undefined;
setFact(value?: Fact): void;
hasFact(): boolean;
clearFact(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): SetFactReply.AsObject;
static toObject(includeInstance: boolean, msg: SetFactReply): SetFactReply.AsObject;
static serializeBinaryToWriter(message: SetFactReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): SetFactReply;
static deserializeBinaryFromReader(message: SetFactReply, reader: jspb.BinaryReader): SetFactReply;
}
export namespace SetFactReply {
export type AsObject = {
fact?: Fact.AsObject,
}
}
export class GetFactRequest extends jspb.Message {
getEntityuri(): string;
setEntityuri(value: string): void;
getName(): string;
setName(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetFactRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetFactRequest): GetFactRequest.AsObject;
static serializeBinaryToWriter(message: GetFactRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetFactRequest;
static deserializeBinaryFromReader(message: GetFactRequest, reader: jspb.BinaryReader): GetFactRequest;
}
export namespace GetFactRequest {
export type AsObject = {
entityuri: string,
name: string,
}
}
export class GetFactReply extends jspb.Message {
getFact(): Fact | undefined;
setFact(value?: Fact): void;
hasFact(): boolean;
clearFact(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetFactReply.AsObject;
static toObject(includeInstance: boolean, msg: GetFactReply): GetFactReply.AsObject;
static serializeBinaryToWriter(message: GetFactReply, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetFactReply;
static deserializeBinaryFromReader(message: GetFactReply, reader: jspb.BinaryReader): GetFactReply;
}
export namespace GetFactReply {
export type AsObject = {
fact?: Fact.AsObject,
}
}
export class Entity extends jspb.Message {
getUri(): string;
setUri(value: string): void;
@@ -110,8 +225,6 @@ export class Entity extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Entity.AsObject;
static toObject(includeInstance: boolean, msg: Entity): Entity.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Entity, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Entity;
static deserializeBinaryFromReader(message: Entity, reader: jspb.BinaryReader): Entity;
@@ -133,8 +246,6 @@ export class Fact extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Fact.AsObject;
static toObject(includeInstance: boolean, msg: Fact): Fact.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Fact, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Fact;
static deserializeBinaryFromReader(message: Fact, reader: jspb.BinaryReader): Fact;
File diff suppressed because it is too large Load Diff
@@ -1,82 +0,0 @@
// package: spotify.backstage.inventory.v1
// file: inventory/v1/inventory.proto
import * as inventory_v1_inventory_pb from "../../inventory/v1/inventory_pb";
import {grpc} from "@improbable-eng/grpc-web";
type InventoryGetEntity = {
readonly methodName: string;
readonly service: typeof Inventory;
readonly requestStream: false;
readonly responseStream: false;
readonly requestType: typeof inventory_v1_inventory_pb.GetEntityRequest;
readonly responseType: typeof inventory_v1_inventory_pb.GetEntityReply;
};
type InventoryCreateEntity = {
readonly methodName: string;
readonly service: typeof Inventory;
readonly requestStream: false;
readonly responseStream: false;
readonly requestType: typeof inventory_v1_inventory_pb.CreateEntityRequest;
readonly responseType: typeof inventory_v1_inventory_pb.CreateEntityReply;
};
export class Inventory {
static readonly serviceName: string;
static readonly GetEntity: InventoryGetEntity;
static readonly CreateEntity: InventoryCreateEntity;
}
export type ServiceError = { message: string, code: number; metadata: grpc.Metadata }
export type Status = { details: string, code: number; metadata: grpc.Metadata }
interface UnaryResponse {
cancel(): void;
}
interface ResponseStream<T> {
cancel(): void;
on(type: 'data', handler: (message: T) => void): ResponseStream<T>;
on(type: 'end', handler: (status?: Status) => void): ResponseStream<T>;
on(type: 'status', handler: (status: Status) => void): ResponseStream<T>;
}
interface RequestStream<T> {
write(message: T): RequestStream<T>;
end(): void;
cancel(): void;
on(type: 'end', handler: (status?: Status) => void): RequestStream<T>;
on(type: 'status', handler: (status: Status) => void): RequestStream<T>;
}
interface BidirectionalStream<ReqT, ResT> {
write(message: ReqT): BidirectionalStream<ReqT, ResT>;
end(): void;
cancel(): void;
on(type: 'data', handler: (message: ResT) => void): BidirectionalStream<ReqT, ResT>;
on(type: 'end', handler: (status?: Status) => void): BidirectionalStream<ReqT, ResT>;
on(type: 'status', handler: (status: Status) => void): BidirectionalStream<ReqT, ResT>;
}
export class InventoryClient {
readonly serviceHost: string;
constructor(serviceHost: string, options?: grpc.RpcOptions);
getEntity(
requestMessage: inventory_v1_inventory_pb.GetEntityRequest,
metadata: grpc.Metadata,
callback: (error: ServiceError|null, responseMessage: inventory_v1_inventory_pb.GetEntityReply|null) => void
): UnaryResponse;
getEntity(
requestMessage: inventory_v1_inventory_pb.GetEntityRequest,
callback: (error: ServiceError|null, responseMessage: inventory_v1_inventory_pb.GetEntityReply|null) => void
): UnaryResponse;
createEntity(
requestMessage: inventory_v1_inventory_pb.CreateEntityRequest,
metadata: grpc.Metadata,
callback: (error: ServiceError|null, responseMessage: inventory_v1_inventory_pb.CreateEntityReply|null) => void
): UnaryResponse;
createEntity(
requestMessage: inventory_v1_inventory_pb.CreateEntityRequest,
callback: (error: ServiceError|null, responseMessage: inventory_v1_inventory_pb.CreateEntityReply|null) => void
): UnaryResponse;
}
@@ -1,101 +0,0 @@
// package: spotify.backstage.inventory.v1
// file: inventory/v1/inventory.proto
var inventory_v1_inventory_pb = require("../../inventory/v1/inventory_pb");
var grpc = require("@improbable-eng/grpc-web").grpc;
var Inventory = (function () {
function Inventory() {}
Inventory.serviceName = "spotify.backstage.inventory.v1.Inventory";
return Inventory;
}());
Inventory.GetEntity = {
methodName: "GetEntity",
service: Inventory,
requestStream: false,
responseStream: false,
requestType: inventory_v1_inventory_pb.GetEntityRequest,
responseType: inventory_v1_inventory_pb.GetEntityReply
};
Inventory.CreateEntity = {
methodName: "CreateEntity",
service: Inventory,
requestStream: false,
responseStream: false,
requestType: inventory_v1_inventory_pb.CreateEntityRequest,
responseType: inventory_v1_inventory_pb.CreateEntityReply
};
exports.Inventory = Inventory;
function InventoryClient(serviceHost, options) {
this.serviceHost = serviceHost;
this.options = options || {};
}
InventoryClient.prototype.getEntity = function getEntity(requestMessage, metadata, callback) {
if (arguments.length === 2) {
callback = arguments[1];
}
var client = grpc.unary(Inventory.GetEntity, {
request: requestMessage,
host: this.serviceHost,
metadata: metadata,
transport: this.options.transport,
debug: this.options.debug,
onEnd: function (response) {
if (callback) {
if (response.status !== grpc.Code.OK) {
var err = new Error(response.statusMessage);
err.code = response.status;
err.metadata = response.trailers;
callback(err, null);
} else {
callback(null, response.message);
}
}
}
});
return {
cancel: function () {
callback = null;
client.close();
}
};
};
InventoryClient.prototype.createEntity = function createEntity(requestMessage, metadata, callback) {
if (arguments.length === 2) {
callback = arguments[1];
}
var client = grpc.unary(Inventory.CreateEntity, {
request: requestMessage,
host: this.serviceHost,
metadata: metadata,
transport: this.options.transport,
debug: this.options.debug,
onEnd: function (response) {
if (callback) {
if (response.status !== grpc.Code.OK) {
var err = new Error(response.statusMessage);
err.code = response.status;
err.metadata = response.trailers;
callback(err, null);
} else {
callback(null, response.message);
}
}
}
});
return {
cancel: function () {
callback = null;
client.close();
}
};
};
exports.InventoryClient = InventoryClient;
@@ -0,0 +1,49 @@
import * as grpcWeb from 'grpc-web';
import * as identity_v1_identity_pb from '../../identity/v1/identity_pb';
import * as google_protobuf_struct_pb from 'google-protobuf/google/protobuf/struct_pb';
import {
CreateReply,
CreateRequest,
Empty,
ListTemplatesReply} from './scaffolder_pb';
export class ScaffolderClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
listTemplates(
request: Empty,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: ListTemplatesReply) => void
): grpcWeb.ClientReadableStream<ListTemplatesReply>;
create(
request: CreateRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: CreateReply) => void
): grpcWeb.ClientReadableStream<CreateReply>;
}
export class ScaffolderPromiseClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: string; });
listTemplates(
request: Empty,
metadata?: grpcWeb.Metadata
): Promise<ListTemplatesReply>;
create(
request: CreateRequest,
metadata?: grpcWeb.Metadata
): Promise<CreateReply>;
}

Some files were not shown because too many files have changed in this diff Show More