From 268ac8f1e476aa70f9e19ccff59dbf77bf9456b8 Mon Sep 17 00:00:00 2001 From: restitux Date: Thu, 23 Feb 2023 22:15:39 -0700 Subject: [PATCH] Implement graphql api client and update gui to display data --- genqlient.graphql | 107 ++++++ genqlient.yaml | 8 + go.mod | 9 + go.sum | 97 ++++++ main.go | 16 +- queries/generated.go | 698 ++++++++++++++++++++++++++++++++++++++ schema.graphql | 162 +++++++++ screens/dashboard.go | 50 ++- screens/editserver.go | 1 + screens/error.go | 19 ++ widget/cloneCredential.go | 83 +++++ widget/common.go | 17 + widget/pipeline.go | 81 +++++ widget/runner.go | 79 +++++ widget/secrets.go | 82 +++++ 15 files changed, 1498 insertions(+), 11 deletions(-) create mode 100644 genqlient.graphql create mode 100644 genqlient.yaml create mode 100644 queries/generated.go create mode 100644 schema.graphql create mode 100644 screens/error.go create mode 100644 widget/cloneCredential.go create mode 100644 widget/common.go create mode 100644 widget/pipeline.go create mode 100644 widget/runner.go create mode 100644 widget/secrets.go diff --git a/genqlient.graphql b/genqlient.graphql new file mode 100644 index 0000000..12e2b80 --- /dev/null +++ b/genqlient.graphql @@ -0,0 +1,107 @@ +query GetPipelines { + Pipelines { + id, name + } +} + +query GetSecrets { + Secrets { + id, name + } +} + +query GetRunners { + Runners { + id, name + } +} + +query GetCloneCredentials { + CloneCredentials { + id, name, type + } +} + + +mutation CreatePipeline( + $name: String!, + $url: String!, + $pollInterval: Int, + $cloneCredentialId: String, +) { + createPipeline( + name: $name, + url: $url, + pollInterval: $pollInterval, + cloneCredentialId: $cloneCredentialId, + ) { + id, + name, + url, + pollInterval, + cloneCredential { + id, + name, + type, + } + } +} + +mutation CreateCloneCredential( + $credentialType: String!, + $username: String!, + $secret: String!, + $name: String!, +) { + createCloneCredential( + type: $credentialType, + username: $username, + secret: $secret, + name: $name, + ) { + type, + username, + secret, + name, + } +} + +mutation CreateSecret( + $name: String!, + $secret: String!, +) { + createSecret( + name: $name, + secret: $secret, + ) { + id, + name, + secret, + } +} + +mutation CreateWebhook( + $webhookType: String!, + $pipelineId: String!, +) { + createWebhook( + type: $webhookType, + pipelineId: $pipelineId, + ) { + id, + secret, + serverType, + } +} + +mutation CreateRunner( + $name: String!, +) { + createRunner( + name: $name, + ) { + id, + name, + token, + } +} diff --git a/genqlient.yaml b/genqlient.yaml new file mode 100644 index 0000000..f72591e --- /dev/null +++ b/genqlient.yaml @@ -0,0 +1,8 @@ +# Default genqlient config; for full documentation see: +# https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml +schema: schema.graphql +operations: +- genqlient.graphql +generated: queries/generated.go +package: queries +optional: pointer diff --git a/go.mod b/go.mod index 2ab671f..a29c87c 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,10 @@ require ( ) require ( + github.com/Khan/genqlient v0.5.0 // indirect + github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/alexflint/go-arg v1.4.2 // indirect + github.com/alexflint/go-scalar v1.0.0 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52 v1.2.1 // indirect github.com/containerd/console v1.0.3 // indirect @@ -22,8 +26,13 @@ require ( github.com/muesli/termenv v0.14.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/sahilm/fuzzy v0.1.0 // indirect + github.com/vektah/gqlparser/v2 v2.4.5 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 048eff9..5c4ba8d 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,23 @@ +github.com/99designs/gqlgen v0.17.2/go.mod h1:K5fzLKwtph+FFgh9j7nFbRUdBKvTcGnsta51fsMTn3o= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Khan/genqlient v0.5.0 h1:TMZJ+tl/BpbmGyIBiXzKzUftDhw4ZWxQZ+1ydn0gyII= +github.com/Khan/genqlient v0.5.0/go.mod h1:EpIvDVXYm01GP6AXzjA7dKriPTH6GmtpmvTAwUUqIX8= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/alexflint/go-arg v1.4.2 h1:lDWZAXxpAnZUq4qwb86p/3rIJJ2Li81EoMbTMujhVa0= +github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf2y2768kM= +github.com/alexflint/go-scalar v1.0.0 h1:NGupf1XV/Xb04wXskDFzS0KWOLH632W/EO4fAFi+A70= +github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/aymanbagabas/go-osc52 v1.2.1 h1:q2sWUyDcozPLcLabEMd+a+7Ea2DitxZVN9hTxab9L4E= github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= +github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= @@ -13,10 +28,26 @@ github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87ini github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= @@ -28,6 +59,7 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= @@ -39,21 +71,86 @@ github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= github.com/muesli/termenv v0.14.0 h1:8x9NFfOe8lmIWK4pgy3IfVEy47f+ppe3tUqdPZG2Uy0= github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/vektah/gqlparser/v2 v2.4.5 h1:C02NsyEsL4TXJB7ndonqTfuQOL4XPIu0aAWugdmTgmc= +github.com/vektah/gqlparser/v2 v2.4.5/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index a3bc750..ee76b17 100644 --- a/main.go +++ b/main.go @@ -37,6 +37,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { Height: m.height, } } + case error: + m.screen = screens.ErrorScreen{ + Err: msg, + } + return m, nil } var cmd tea.Cmd @@ -54,17 +59,22 @@ func main() { screen: screens.CreateLogin( // TODO: load from config file []screens.CursoriusServer{ - screens.CursoriusServer{ + { + Name: "local-test", + Url: "http://127.0.0.1:45421/graphql", + Token: "", + }, + { Name: "ohea", Url: "https://ci.cursorius.server", Token: "test", }, - screens.CursoriusServer{ + { Name: "nohea", Url: "https://ci.cursoriuspreview.server", Token: "test", }, - screens.CursoriusServer{ + { Name: "work", Url: "https://ci.acme.corp", Token: "test", diff --git a/queries/generated.go b/queries/generated.go new file mode 100644 index 0000000..31eb59c --- /dev/null +++ b/queries/generated.go @@ -0,0 +1,698 @@ +// Code generated by github.com/Khan/genqlient, DO NOT EDIT. + +package queries + +import ( + "context" + + "github.com/Khan/genqlient/graphql" +) + +// CreateCloneCredentialCreateCloneCredential includes the requested fields of the GraphQL type CloneCredential. +// The GraphQL type's documentation follows. +// +// A credential for authenticating with the pipeline source host. +type CreateCloneCredentialCreateCloneCredential struct { + // The credential type. + Type string `json:"type"` + // The username to user with the credential. + Username string `json:"username"` + // The secret for the credential. + Secret string `json:"secret"` + // The name of the credential. + Name string `json:"name"` +} + +// GetType returns CreateCloneCredentialCreateCloneCredential.Type, and is useful for accessing the field via an interface. +func (v *CreateCloneCredentialCreateCloneCredential) GetType() string { return v.Type } + +// GetUsername returns CreateCloneCredentialCreateCloneCredential.Username, and is useful for accessing the field via an interface. +func (v *CreateCloneCredentialCreateCloneCredential) GetUsername() string { return v.Username } + +// GetSecret returns CreateCloneCredentialCreateCloneCredential.Secret, and is useful for accessing the field via an interface. +func (v *CreateCloneCredentialCreateCloneCredential) GetSecret() string { return v.Secret } + +// GetName returns CreateCloneCredentialCreateCloneCredential.Name, and is useful for accessing the field via an interface. +func (v *CreateCloneCredentialCreateCloneCredential) GetName() string { return v.Name } + +// CreateCloneCredentialResponse is returned by CreateCloneCredential on success. +type CreateCloneCredentialResponse struct { + // Create a new CloneCredential + CreateCloneCredential *CreateCloneCredentialCreateCloneCredential `json:"createCloneCredential"` +} + +// GetCreateCloneCredential returns CreateCloneCredentialResponse.CreateCloneCredential, and is useful for accessing the field via an interface. +func (v *CreateCloneCredentialResponse) GetCreateCloneCredential() *CreateCloneCredentialCreateCloneCredential { + return v.CreateCloneCredential +} + +// CreatePipelineCreatePipeline includes the requested fields of the GraphQL type Pipeline. +// The GraphQL type's documentation follows. +// +// A pipeline for running ci jobs +type CreatePipelineCreatePipeline struct { + // The id of the pipeline. + Id string `json:"id"` + // The name of the pipeline. + Name string `json:"name"` + // The url of the pipeline. + Url string `json:"url"` + // The polling interval for the pipeline. + PollInterval int `json:"pollInterval"` + // The configured credential for cloning the pipeline source. + CloneCredential *CreatePipelineCreatePipelineCloneCredential `json:"cloneCredential"` +} + +// GetId returns CreatePipelineCreatePipeline.Id, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipeline) GetId() string { return v.Id } + +// GetName returns CreatePipelineCreatePipeline.Name, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipeline) GetName() string { return v.Name } + +// GetUrl returns CreatePipelineCreatePipeline.Url, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipeline) GetUrl() string { return v.Url } + +// GetPollInterval returns CreatePipelineCreatePipeline.PollInterval, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipeline) GetPollInterval() int { return v.PollInterval } + +// GetCloneCredential returns CreatePipelineCreatePipeline.CloneCredential, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipeline) GetCloneCredential() *CreatePipelineCreatePipelineCloneCredential { + return v.CloneCredential +} + +// CreatePipelineCreatePipelineCloneCredential includes the requested fields of the GraphQL type CloneCredential. +// The GraphQL type's documentation follows. +// +// A credential for authenticating with the pipeline source host. +type CreatePipelineCreatePipelineCloneCredential struct { + // The id of the credential. + Id string `json:"id"` + // The name of the credential. + Name string `json:"name"` + // The credential type. + Type string `json:"type"` +} + +// GetId returns CreatePipelineCreatePipelineCloneCredential.Id, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipelineCloneCredential) GetId() string { return v.Id } + +// GetName returns CreatePipelineCreatePipelineCloneCredential.Name, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipelineCloneCredential) GetName() string { return v.Name } + +// GetType returns CreatePipelineCreatePipelineCloneCredential.Type, and is useful for accessing the field via an interface. +func (v *CreatePipelineCreatePipelineCloneCredential) GetType() string { return v.Type } + +// CreatePipelineResponse is returned by CreatePipeline on success. +type CreatePipelineResponse struct { + // Create a new pipeline + CreatePipeline *CreatePipelineCreatePipeline `json:"createPipeline"` +} + +// GetCreatePipeline returns CreatePipelineResponse.CreatePipeline, and is useful for accessing the field via an interface. +func (v *CreatePipelineResponse) GetCreatePipeline() *CreatePipelineCreatePipeline { + return v.CreatePipeline +} + +// CreateRunnerCreateRunner includes the requested fields of the GraphQL type Runner. +// The GraphQL type's documentation follows. +// +// A runner available for use inside of a pipeline. +type CreateRunnerCreateRunner struct { + // The id of the runner. + Id string `json:"id"` + // The name of the runner. + Name string `json:"name"` + // The token. + Token string `json:"token"` +} + +// GetId returns CreateRunnerCreateRunner.Id, and is useful for accessing the field via an interface. +func (v *CreateRunnerCreateRunner) GetId() string { return v.Id } + +// GetName returns CreateRunnerCreateRunner.Name, and is useful for accessing the field via an interface. +func (v *CreateRunnerCreateRunner) GetName() string { return v.Name } + +// GetToken returns CreateRunnerCreateRunner.Token, and is useful for accessing the field via an interface. +func (v *CreateRunnerCreateRunner) GetToken() string { return v.Token } + +// CreateRunnerResponse is returned by CreateRunner on success. +type CreateRunnerResponse struct { + // Create a new runner + CreateRunner *CreateRunnerCreateRunner `json:"createRunner"` +} + +// GetCreateRunner returns CreateRunnerResponse.CreateRunner, and is useful for accessing the field via an interface. +func (v *CreateRunnerResponse) GetCreateRunner() *CreateRunnerCreateRunner { return v.CreateRunner } + +// CreateSecretCreateSecret includes the requested fields of the GraphQL type Secret. +// The GraphQL type's documentation follows. +// +// A secret available for use inside of a pipeline. +type CreateSecretCreateSecret struct { + // The id of the secret. + Id string `json:"id"` + // The name of the secret. + Name string `json:"name"` + // The secret. + Secret string `json:"secret"` +} + +// GetId returns CreateSecretCreateSecret.Id, and is useful for accessing the field via an interface. +func (v *CreateSecretCreateSecret) GetId() string { return v.Id } + +// GetName returns CreateSecretCreateSecret.Name, and is useful for accessing the field via an interface. +func (v *CreateSecretCreateSecret) GetName() string { return v.Name } + +// GetSecret returns CreateSecretCreateSecret.Secret, and is useful for accessing the field via an interface. +func (v *CreateSecretCreateSecret) GetSecret() string { return v.Secret } + +// CreateSecretResponse is returned by CreateSecret on success. +type CreateSecretResponse struct { + // Create a new secret + CreateSecret *CreateSecretCreateSecret `json:"createSecret"` +} + +// GetCreateSecret returns CreateSecretResponse.CreateSecret, and is useful for accessing the field via an interface. +func (v *CreateSecretResponse) GetCreateSecret() *CreateSecretCreateSecret { return v.CreateSecret } + +// CreateWebhookCreateWebhook includes the requested fields of the GraphQL type Webhook. +// The GraphQL type's documentation follows. +// +// A webhook for triggering pipelines +type CreateWebhookCreateWebhook struct { + // The id of the webhook. + Id string `json:"id"` + // The secret used to validate the webhook. + Secret string `json:"secret"` + // The format of the webhook. + ServerType string `json:"serverType"` +} + +// GetId returns CreateWebhookCreateWebhook.Id, and is useful for accessing the field via an interface. +func (v *CreateWebhookCreateWebhook) GetId() string { return v.Id } + +// GetSecret returns CreateWebhookCreateWebhook.Secret, and is useful for accessing the field via an interface. +func (v *CreateWebhookCreateWebhook) GetSecret() string { return v.Secret } + +// GetServerType returns CreateWebhookCreateWebhook.ServerType, and is useful for accessing the field via an interface. +func (v *CreateWebhookCreateWebhook) GetServerType() string { return v.ServerType } + +// CreateWebhookResponse is returned by CreateWebhook on success. +type CreateWebhookResponse struct { + // Create a new webhook + CreateWebhook *CreateWebhookCreateWebhook `json:"createWebhook"` +} + +// GetCreateWebhook returns CreateWebhookResponse.CreateWebhook, and is useful for accessing the field via an interface. +func (v *CreateWebhookResponse) GetCreateWebhook() *CreateWebhookCreateWebhook { + return v.CreateWebhook +} + +// GetCloneCredentialsCloneCredentialsCloneCredential includes the requested fields of the GraphQL type CloneCredential. +// The GraphQL type's documentation follows. +// +// A credential for authenticating with the pipeline source host. +type GetCloneCredentialsCloneCredentialsCloneCredential struct { + // The id of the credential. + Id string `json:"id"` + // The name of the credential. + Name string `json:"name"` + // The credential type. + Type string `json:"type"` +} + +// GetId returns GetCloneCredentialsCloneCredentialsCloneCredential.Id, and is useful for accessing the field via an interface. +func (v *GetCloneCredentialsCloneCredentialsCloneCredential) GetId() string { return v.Id } + +// GetName returns GetCloneCredentialsCloneCredentialsCloneCredential.Name, and is useful for accessing the field via an interface. +func (v *GetCloneCredentialsCloneCredentialsCloneCredential) GetName() string { return v.Name } + +// GetType returns GetCloneCredentialsCloneCredentialsCloneCredential.Type, and is useful for accessing the field via an interface. +func (v *GetCloneCredentialsCloneCredentialsCloneCredential) GetType() string { return v.Type } + +// GetCloneCredentialsResponse is returned by GetCloneCredentials on success. +type GetCloneCredentialsResponse struct { + CloneCredentials []*GetCloneCredentialsCloneCredentialsCloneCredential `json:"CloneCredentials"` +} + +// GetCloneCredentials returns GetCloneCredentialsResponse.CloneCredentials, and is useful for accessing the field via an interface. +func (v *GetCloneCredentialsResponse) GetCloneCredentials() []*GetCloneCredentialsCloneCredentialsCloneCredential { + return v.CloneCredentials +} + +// GetPipelinesPipelinesPipeline includes the requested fields of the GraphQL type Pipeline. +// The GraphQL type's documentation follows. +// +// A pipeline for running ci jobs +type GetPipelinesPipelinesPipeline struct { + // The id of the pipeline. + Id string `json:"id"` + // The name of the pipeline. + Name string `json:"name"` +} + +// GetId returns GetPipelinesPipelinesPipeline.Id, and is useful for accessing the field via an interface. +func (v *GetPipelinesPipelinesPipeline) GetId() string { return v.Id } + +// GetName returns GetPipelinesPipelinesPipeline.Name, and is useful for accessing the field via an interface. +func (v *GetPipelinesPipelinesPipeline) GetName() string { return v.Name } + +// GetPipelinesResponse is returned by GetPipelines on success. +type GetPipelinesResponse struct { + Pipelines []*GetPipelinesPipelinesPipeline `json:"Pipelines"` +} + +// GetPipelines returns GetPipelinesResponse.Pipelines, and is useful for accessing the field via an interface. +func (v *GetPipelinesResponse) GetPipelines() []*GetPipelinesPipelinesPipeline { return v.Pipelines } + +// GetRunnersResponse is returned by GetRunners on success. +type GetRunnersResponse struct { + Runners []*GetRunnersRunnersRunner `json:"Runners"` +} + +// GetRunners returns GetRunnersResponse.Runners, and is useful for accessing the field via an interface. +func (v *GetRunnersResponse) GetRunners() []*GetRunnersRunnersRunner { return v.Runners } + +// GetRunnersRunnersRunner includes the requested fields of the GraphQL type Runner. +// The GraphQL type's documentation follows. +// +// A runner available for use inside of a pipeline. +type GetRunnersRunnersRunner struct { + // The id of the runner. + Id string `json:"id"` + // The name of the runner. + Name string `json:"name"` +} + +// GetId returns GetRunnersRunnersRunner.Id, and is useful for accessing the field via an interface. +func (v *GetRunnersRunnersRunner) GetId() string { return v.Id } + +// GetName returns GetRunnersRunnersRunner.Name, and is useful for accessing the field via an interface. +func (v *GetRunnersRunnersRunner) GetName() string { return v.Name } + +// GetSecretsResponse is returned by GetSecrets on success. +type GetSecretsResponse struct { + Secrets []*GetSecretsSecretsSecret `json:"Secrets"` +} + +// GetSecrets returns GetSecretsResponse.Secrets, and is useful for accessing the field via an interface. +func (v *GetSecretsResponse) GetSecrets() []*GetSecretsSecretsSecret { return v.Secrets } + +// GetSecretsSecretsSecret includes the requested fields of the GraphQL type Secret. +// The GraphQL type's documentation follows. +// +// A secret available for use inside of a pipeline. +type GetSecretsSecretsSecret struct { + // The id of the secret. + Id string `json:"id"` + // The name of the secret. + Name string `json:"name"` +} + +// GetId returns GetSecretsSecretsSecret.Id, and is useful for accessing the field via an interface. +func (v *GetSecretsSecretsSecret) GetId() string { return v.Id } + +// GetName returns GetSecretsSecretsSecret.Name, and is useful for accessing the field via an interface. +func (v *GetSecretsSecretsSecret) GetName() string { return v.Name } + +// __CreateCloneCredentialInput is used internally by genqlient +type __CreateCloneCredentialInput struct { + CredentialType string `json:"credentialType"` + Username string `json:"username"` + Secret string `json:"secret"` + Name string `json:"name"` +} + +// GetCredentialType returns __CreateCloneCredentialInput.CredentialType, and is useful for accessing the field via an interface. +func (v *__CreateCloneCredentialInput) GetCredentialType() string { return v.CredentialType } + +// GetUsername returns __CreateCloneCredentialInput.Username, and is useful for accessing the field via an interface. +func (v *__CreateCloneCredentialInput) GetUsername() string { return v.Username } + +// GetSecret returns __CreateCloneCredentialInput.Secret, and is useful for accessing the field via an interface. +func (v *__CreateCloneCredentialInput) GetSecret() string { return v.Secret } + +// GetName returns __CreateCloneCredentialInput.Name, and is useful for accessing the field via an interface. +func (v *__CreateCloneCredentialInput) GetName() string { return v.Name } + +// __CreatePipelineInput is used internally by genqlient +type __CreatePipelineInput struct { + Name string `json:"name"` + Url string `json:"url"` + PollInterval *int `json:"pollInterval"` + CloneCredentialId *string `json:"cloneCredentialId"` +} + +// GetName returns __CreatePipelineInput.Name, and is useful for accessing the field via an interface. +func (v *__CreatePipelineInput) GetName() string { return v.Name } + +// GetUrl returns __CreatePipelineInput.Url, and is useful for accessing the field via an interface. +func (v *__CreatePipelineInput) GetUrl() string { return v.Url } + +// GetPollInterval returns __CreatePipelineInput.PollInterval, and is useful for accessing the field via an interface. +func (v *__CreatePipelineInput) GetPollInterval() *int { return v.PollInterval } + +// GetCloneCredentialId returns __CreatePipelineInput.CloneCredentialId, and is useful for accessing the field via an interface. +func (v *__CreatePipelineInput) GetCloneCredentialId() *string { return v.CloneCredentialId } + +// __CreateRunnerInput is used internally by genqlient +type __CreateRunnerInput struct { + Name string `json:"name"` +} + +// GetName returns __CreateRunnerInput.Name, and is useful for accessing the field via an interface. +func (v *__CreateRunnerInput) GetName() string { return v.Name } + +// __CreateSecretInput is used internally by genqlient +type __CreateSecretInput struct { + Name string `json:"name"` + Secret string `json:"secret"` +} + +// GetName returns __CreateSecretInput.Name, and is useful for accessing the field via an interface. +func (v *__CreateSecretInput) GetName() string { return v.Name } + +// GetSecret returns __CreateSecretInput.Secret, and is useful for accessing the field via an interface. +func (v *__CreateSecretInput) GetSecret() string { return v.Secret } + +// __CreateWebhookInput is used internally by genqlient +type __CreateWebhookInput struct { + WebhookType string `json:"webhookType"` + PipelineId string `json:"pipelineId"` +} + +// GetWebhookType returns __CreateWebhookInput.WebhookType, and is useful for accessing the field via an interface. +func (v *__CreateWebhookInput) GetWebhookType() string { return v.WebhookType } + +// GetPipelineId returns __CreateWebhookInput.PipelineId, and is useful for accessing the field via an interface. +func (v *__CreateWebhookInput) GetPipelineId() string { return v.PipelineId } + +func CreateCloneCredential( + ctx context.Context, + client graphql.Client, + credentialType string, + username string, + secret string, + name string, +) (*CreateCloneCredentialResponse, error) { + req := &graphql.Request{ + OpName: "CreateCloneCredential", + Query: ` +mutation CreateCloneCredential ($credentialType: String!, $username: String!, $secret: String!, $name: String!) { + createCloneCredential(type: $credentialType, username: $username, secret: $secret, name: $name) { + type + username + secret + name + } +} +`, + Variables: &__CreateCloneCredentialInput{ + CredentialType: credentialType, + Username: username, + Secret: secret, + Name: name, + }, + } + var err error + + var data CreateCloneCredentialResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func CreatePipeline( + ctx context.Context, + client graphql.Client, + name string, + url string, + pollInterval *int, + cloneCredentialId *string, +) (*CreatePipelineResponse, error) { + req := &graphql.Request{ + OpName: "CreatePipeline", + Query: ` +mutation CreatePipeline ($name: String!, $url: String!, $pollInterval: Int, $cloneCredentialId: String) { + createPipeline(name: $name, url: $url, pollInterval: $pollInterval, cloneCredentialId: $cloneCredentialId) { + id + name + url + pollInterval + cloneCredential { + id + name + type + } + } +} +`, + Variables: &__CreatePipelineInput{ + Name: name, + Url: url, + PollInterval: pollInterval, + CloneCredentialId: cloneCredentialId, + }, + } + var err error + + var data CreatePipelineResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func CreateRunner( + ctx context.Context, + client graphql.Client, + name string, +) (*CreateRunnerResponse, error) { + req := &graphql.Request{ + OpName: "CreateRunner", + Query: ` +mutation CreateRunner ($name: String!) { + createRunner(name: $name) { + id + name + token + } +} +`, + Variables: &__CreateRunnerInput{ + Name: name, + }, + } + var err error + + var data CreateRunnerResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func CreateSecret( + ctx context.Context, + client graphql.Client, + name string, + secret string, +) (*CreateSecretResponse, error) { + req := &graphql.Request{ + OpName: "CreateSecret", + Query: ` +mutation CreateSecret ($name: String!, $secret: String!) { + createSecret(name: $name, secret: $secret) { + id + name + secret + } +} +`, + Variables: &__CreateSecretInput{ + Name: name, + Secret: secret, + }, + } + var err error + + var data CreateSecretResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func CreateWebhook( + ctx context.Context, + client graphql.Client, + webhookType string, + pipelineId string, +) (*CreateWebhookResponse, error) { + req := &graphql.Request{ + OpName: "CreateWebhook", + Query: ` +mutation CreateWebhook ($webhookType: String!, $pipelineId: String!) { + createWebhook(type: $webhookType, pipelineId: $pipelineId) { + id + secret + serverType + } +} +`, + Variables: &__CreateWebhookInput{ + WebhookType: webhookType, + PipelineId: pipelineId, + }, + } + var err error + + var data CreateWebhookResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func GetCloneCredentials( + ctx context.Context, + client graphql.Client, +) (*GetCloneCredentialsResponse, error) { + req := &graphql.Request{ + OpName: "GetCloneCredentials", + Query: ` +query GetCloneCredentials { + CloneCredentials { + id + name + type + } +} +`, + } + var err error + + var data GetCloneCredentialsResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func GetPipelines( + ctx context.Context, + client graphql.Client, +) (*GetPipelinesResponse, error) { + req := &graphql.Request{ + OpName: "GetPipelines", + Query: ` +query GetPipelines { + Pipelines { + id + name + } +} +`, + } + var err error + + var data GetPipelinesResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func GetRunners( + ctx context.Context, + client graphql.Client, +) (*GetRunnersResponse, error) { + req := &graphql.Request{ + OpName: "GetRunners", + Query: ` +query GetRunners { + Runners { + id + name + } +} +`, + } + var err error + + var data GetRunnersResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + +func GetSecrets( + ctx context.Context, + client graphql.Client, +) (*GetSecretsResponse, error) { + req := &graphql.Request{ + OpName: "GetSecrets", + Query: ` +query GetSecrets { + Secrets { + id + name + } +} +`, + } + var err error + + var data GetSecretsResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} diff --git a/schema.graphql b/schema.graphql new file mode 100644 index 0000000..493b8a8 --- /dev/null +++ b/schema.graphql @@ -0,0 +1,162 @@ +schema { + query: Query + mutation: Mutation +} +"A credential for authenticating with the pipeline source host." +type CloneCredential { + "The id of the credential." + id: String! + "The name of the credential." + name: String! + "The secret for the credential." + secret: String! + "The credential type." + type: String! + "The username to user with the credential." + username: String! +} +"A webhook for triggering pipelines" +type Webhook { + "The id of the webhook." + id: String! + "The secret used to validate the webhook." + secret: String! + "The format of the webhook." + serverType: String! +} +"" +type Mutation { + "Allow a secret to be accessed by a pipeline." + addSecretToPipeline( + "" + secretId: String, + "" + pipelineId: String! + ): Pipeline + "Create a new CloneCredential" + createCloneCredential( + "" + type: String!, + "" + username: String!, + "" + secret: String!, + "" + name: String! + ): CloneCredential + "Create a new pipeline" + createPipeline( + "" + name: String!, + "" + url: String!, + "" + pollInterval: Int, + "" + cloneCredentialId: String + ): Pipeline + "Create a new runner" + createRunner( + "" + name: String! + ): Runner + "Create a new secret" + createSecret( + "" + name: String!, + "" + secret: String! + ): Secret + "Create a new webhook" + createWebhook( + "" + type: String!, + "" + pipelineId: String! + ): Webhook + "Remove a pipeline's access to a secret." + removeSecretFromPipeline( + "" + secretId: String, + "" + pipelineId: String! + ): Pipeline + "Set the CloneCredential used by a pipeline to clone the source repo" + setPipelineCloneCredential( + "" + cloneCredentialId: String, + "" + pipelineId: String! + ): Pipeline +} +"A runner available for use inside of a pipeline." +type Runner { + "The id of the runner." + id: String! + "The name of the runner." + name: String! + "The token." + token: String! +} +"A pipeline for running ci jobs" +type Pipeline { + "The configured credential for cloning the pipeline source." + cloneCredential: CloneCredential + "The id of the pipeline." + id: String! + "The name of the pipeline." + name: String! + "The polling interval for the pipeline." + pollInterval: Int! + "The list of runs for the pipeline." + runs: [Run!]! + "The list of secrets for the pipeline." + secrets: [Secret!]! + "The url of the pipeline." + url: String! + "The list of webhooks for the pipeline." + webhooks: [Webhook!]! +} +"A secret available for use inside of a pipeline." +type Secret { + "The id of the secret." + id: String! + "The name of the secret." + name: String! + "The secret." + secret: String! +} +"" +type Query { + "" + CloneCredential( + "The id of the requested credential." + id: String! + ): CloneCredential + "" + CloneCredentials: [CloneCredential]! + "" + Pipeline( + "The id of the requested pipeline." + id: String! + ): Pipeline + "" + Pipelines: [Pipeline]! + "" + Runners: [Runner]! + "" + Secrets: [Secret]! +} +"A pipeline run" +type Run { + "The id of the run." + id: String! + "The progress status of the run." + inProgress: Boolean + "The result of the run." + result: Float + "The stderr used to validate the run." + stderr: String + "The stdout used to validate the run." + stdout: String +} diff --git a/screens/dashboard.go b/screens/dashboard.go index dee0037..8a404e8 100644 --- a/screens/dashboard.go +++ b/screens/dashboard.go @@ -3,11 +3,15 @@ package screens import ( "fmt" "io" + "net/http" "strings" + "github.com/Khan/genqlient/graphql" "github.com/charmbracelet/bubbles/list" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + + "git.ohea.xyz/cursorius/tui/widget" ) type CursoriusServer struct { @@ -16,8 +20,11 @@ type CursoriusServer struct { Token string } -func (s CursoriusServer) Login() ScreenSwitchMsg { - dashboard := createDashboard(s) +func (s CursoriusServer) Login() tea.Msg { + dashboard, err := createDashboard(s) + if err != nil { + return err + } return ScreenSwitchMsg{ NewScreen: dashboard, } @@ -47,6 +54,7 @@ type Dashboard struct { activeTab int width int height int + client graphql.Client } func (m Dashboard) Init() tea.Cmd { @@ -147,14 +155,39 @@ func (d dashboardItemDelegate) Render(w io.Writer, m list.Model, index int, list fmt.Fprint(w, fn(str)) } -func createDashboard(s CursoriusServer) Dashboard { +func createDashboard(s CursoriusServer) (Dashboard, error) { + + client := graphql.NewClient(s.Url, http.DefaultClient) + tabs := []string{"Pipelines", "Secrets", "Clone Credentials", "Runners"} - content := []list.Item{dashboardItem("Pipelines"), dashboardItem("Secrets"), dashboardItem("Clone Credentials"), dashboardItem("Runners")} + //testTabs := []list.Item{dashboardItem("Pipelines"), dashboardItem("Secrets"), dashboardItem("Clone Credentials"), dashboardItem("Runners")} + + pipelineWidget, err := widget.CreatePipelineWidget(client) + if err != nil { + return Dashboard{}, fmt.Errorf("Could not create Pipelines tab: %w", err) + } + + secretWidget, err := widget.CreateSecretWidget(client) + if err != nil { + return Dashboard{}, fmt.Errorf("Could not create Secrets tab: %w", err) + } + + cloneCredentialWidget, err := widget.CreateCloneCredentialWidget(client) + if err != nil { + return Dashboard{}, fmt.Errorf("Could not create Clone Credentials tab: %w", err) + } + + runnerWidget, err := widget.CreateRunnerWidget(client) + if err != nil { + return Dashboard{}, fmt.Errorf("Could not create Runner tab: %w", err) + } tabContent := []list.Model{ - list.New(content, dashboardItemDelegate{}, 50, 50), - list.New(content, dashboardItemDelegate{}, 50, 50), - list.New(content, dashboardItemDelegate{}, 50, 50), + //list.New(testTabs, dashboardItemDelegate{}, 50, 50), + pipelineWidget, + secretWidget, + cloneCredentialWidget, + runnerWidget, } return Dashboard{ @@ -162,7 +195,8 @@ func createDashboard(s CursoriusServer) Dashboard { TabContent: tabContent, width: 50, height: 50, - } + client: client, + }, nil } func max(a, b int) int { diff --git a/screens/editserver.go b/screens/editserver.go index 134427f..5594530 100644 --- a/screens/editserver.go +++ b/screens/editserver.go @@ -142,6 +142,7 @@ func createEditServer(s []CursoriusServer, pos int) EditServer { l.KeyMap.GoToEnd.SetEnabled(false) l.KeyMap.CursorDown.SetKeys(append(l.KeyMap.CursorDown.Keys(), "tab")...) l.KeyMap.Filter.SetEnabled(false) + l.KeyMap.Quit.SetEnabled(false) e := EditServer{ entries: l, servers: s, diff --git a/screens/error.go b/screens/error.go new file mode 100644 index 0000000..ff595f3 --- /dev/null +++ b/screens/error.go @@ -0,0 +1,19 @@ +package screens + +import tea "github.com/charmbracelet/bubbletea" + +type ErrorScreen struct { + Err error +} + +func (m ErrorScreen) Init() tea.Cmd { + return nil +} + +func (m ErrorScreen) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + return m, nil +} + +func (m ErrorScreen) View() string { + return m.Err.Error() +} diff --git a/widget/cloneCredential.go b/widget/cloneCredential.go new file mode 100644 index 0000000..548ae04 --- /dev/null +++ b/widget/cloneCredential.go @@ -0,0 +1,83 @@ +package widget + +import ( + "context" + "fmt" + "io" + + "github.com/Khan/genqlient/graphql" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + + "git.ohea.xyz/cursorius/tui/queries" +) + +type cloneCredentialListItem struct { + name string + widgetType string + id string +} + +type cloneCredentialCreateListItem string + +func (i cloneCredentialListItem) FilterValue() string { return "" } +func (i cloneCredentialCreateListItem) FilterValue() string { return "" } + +type cloneCredentialListItemDelegate struct{} + +func (d cloneCredentialListItemDelegate) Height() int { return 1 } +func (d cloneCredentialListItemDelegate) Spacing() int { return 0 } +func (d cloneCredentialListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil } +func (d cloneCredentialListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + switch i := listItem.(type) { + case cloneCredentialListItem: + fn := itemStyle.Render + faintFn := faintItemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + faintFn = faintSelectedItemStyle.Render + } + + str := fn(i.name) + faintFn(" ("+i.id+")") + fmt.Fprint(w, str) + case cloneCredentialCreateListItem: + fn := itemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + } + + str := string(i) + fmt.Fprint(w, fn(str)) + } +} + +func CreateCloneCredentialWidget(client graphql.Client) (list.Model, error) { + content := []list.Item{} + + getCloneCredentialResp, err := queries.GetCloneCredentials(context.Background(), client) + if err != nil { + return list.Model{}, fmt.Errorf("Could not connect to server: %w", err) + } + + if getCloneCredentialResp.CloneCredentials == nil { + + for _, cloneCredential := range getCloneCredentialResp.CloneCredentials { + content = append(content, cloneCredentialListItem{ + name: cloneCredential.Name, + id: cloneCredential.Id, + }) + } + } + + content = append(content, cloneCredentialCreateListItem("> Create Clone Credential <")) + + model := list.New(content, cloneCredentialListItemDelegate{}, 50, 50) + model.SetShowStatusBar(false) + model.Title = "Clone Credentials" + + return model, nil +} diff --git a/widget/common.go b/widget/common.go new file mode 100644 index 0000000..e147f7e --- /dev/null +++ b/widget/common.go @@ -0,0 +1,17 @@ +package widget + +import ( + "github.com/charmbracelet/bubbles/list" + "github.com/charmbracelet/lipgloss" +) + +var ( + titleStyle = lipgloss.NewStyle().MarginLeft(2) + itemStyle = lipgloss.NewStyle().PaddingLeft(4) + faintItemStyle = lipgloss.NewStyle().Faint(true) + selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170")) + faintSelectedItemStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("170")).Faint(true) + paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4) + helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1) + quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4) +) diff --git a/widget/pipeline.go b/widget/pipeline.go new file mode 100644 index 0000000..4311e6c --- /dev/null +++ b/widget/pipeline.go @@ -0,0 +1,81 @@ +package widget + +import ( + "context" + "fmt" + "io" + + "github.com/Khan/genqlient/graphql" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + + "git.ohea.xyz/cursorius/tui/queries" +) + +type pipelineListItem struct { + name string + id string +} + +type pipelineCreateListItem string + +func (i pipelineListItem) FilterValue() string { return "" } +func (i pipelineCreateListItem) FilterValue() string { return "" } + +type pipelineListItemDelegate struct{} + +func (d pipelineListItemDelegate) Height() int { return 1 } +func (d pipelineListItemDelegate) Spacing() int { return 0 } +func (d pipelineListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil } +func (d pipelineListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + switch i := listItem.(type) { + case pipelineListItem: + fn := itemStyle.Render + faintFn := faintItemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + faintFn = faintSelectedItemStyle.Render + } + + str := fn(i.name) + faintFn(" ("+i.id+")") + fmt.Fprint(w, str) + case pipelineCreateListItem: + fn := itemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + } + + str := string(i) + fmt.Fprint(w, fn(str)) + } +} + +func CreatePipelineWidget(client graphql.Client) (list.Model, error) { + content := []list.Item{} + + getPipelineResp, err := queries.GetPipelines(context.Background(), client) + if err != nil { + return list.Model{}, fmt.Errorf("Could not connect to server: %w", err) + } + + if getPipelineResp.Pipelines != nil { + for _, pipeline := range getPipelineResp.Pipelines { + content = append(content, pipelineListItem{ + name: pipeline.Name, + id: pipeline.Id, + }) + } + } + + content = append(content, pipelineCreateListItem("> Create Pipeline <")) + + model := list.New(content, pipelineListItemDelegate{}, 50, 50) + model.SetShowStatusBar(false) + model.Title = "Pipelines" + + return model, nil +} diff --git a/widget/runner.go b/widget/runner.go new file mode 100644 index 0000000..ab915a8 --- /dev/null +++ b/widget/runner.go @@ -0,0 +1,79 @@ +package widget + +import ( + "context" + "fmt" + "io" + + "github.com/Khan/genqlient/graphql" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + + "git.ohea.xyz/cursorius/tui/queries" +) + +type runnerListItem struct { + name string + id string +} + +type runnerCreateListItem string + +func (i runnerListItem) FilterValue() string { return "" } +func (i runnerCreateListItem) FilterValue() string { return "" } + +type runnerListItemDelegate struct{} + +func (d runnerListItemDelegate) Height() int { return 1 } +func (d runnerListItemDelegate) Spacing() int { return 0 } +func (d runnerListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil } +func (d runnerListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + switch i := listItem.(type) { + case runnerListItem: + fn := itemStyle.Render + faintFn := faintItemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + faintFn = faintSelectedItemStyle.Render + } + + str := fn(i.name) + faintFn(" ("+i.id+")") + fmt.Fprint(w, str) + case runnerCreateListItem: + fn := itemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + } + + str := string(i) + fmt.Fprint(w, fn(str)) + } +} + +func CreateRunnerWidget(client graphql.Client) (list.Model, error) { + content := []list.Item{} + + getRunnerResp, err := queries.GetRunners(context.Background(), client) + if err != nil { + return list.Model{}, fmt.Errorf("Could not connect to server: %w", err) + } + + if getRunnerResp.Runners == nil { + + for _, cloneCredential := range getRunnerResp.Runners { + content = append(content, runnerCreateListItem(cloneCredential.Name)) + } + } + + content = append(content, runnerCreateListItem("> Create Runner <")) + + model := list.New(content, runnerListItemDelegate{}, 50, 50) + model.SetShowStatusBar(false) + model.Title = "Runners" + + return model, nil +} diff --git a/widget/secrets.go b/widget/secrets.go new file mode 100644 index 0000000..0ac0e18 --- /dev/null +++ b/widget/secrets.go @@ -0,0 +1,82 @@ +package widget + +import ( + "context" + "fmt" + "io" + + "github.com/Khan/genqlient/graphql" + "github.com/charmbracelet/bubbles/list" + tea "github.com/charmbracelet/bubbletea" + + "git.ohea.xyz/cursorius/tui/queries" +) + +type secretListItem struct { + name string + id string +} + +type secretCreateListItem string + +func (i secretListItem) FilterValue() string { return "" } +func (i secretCreateListItem) FilterValue() string { return "" } + +type secretListItemDelegate struct{} + +func (d secretListItemDelegate) Height() int { return 1 } +func (d secretListItemDelegate) Spacing() int { return 0 } +func (d secretListItemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil } +func (d secretListItemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { + switch i := listItem.(type) { + case secretListItem: + fn := itemStyle.Render + faintFn := faintItemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + faintFn = faintSelectedItemStyle.Render + } + + str := fn(i.name) + faintFn(" ("+i.id+")") + fmt.Fprint(w, str) + case secretCreateListItem: + fn := itemStyle.Render + if index == m.Index() { + fn = func(s string) string { + return selectedItemStyle.Render("> " + s) + } + } + + str := string(i) + fmt.Fprint(w, fn(str)) + } +} + +func CreateSecretWidget(client graphql.Client) (list.Model, error) { + content := []list.Item{} + + getSecretResp, err := queries.GetSecrets(context.Background(), client) + if err != nil { + return list.Model{}, fmt.Errorf("Could not connect to server: %w", err) + } + + if getSecretResp.Secrets == nil { + + for _, secret := range getSecretResp.Secrets { + content = append(content, secretListItem{ + name: secret.Name, + id: secret.Id, + }) + } + } + + content = append(content, secretCreateListItem("> Create Secret <")) + + model := list.New(content, secretListItemDelegate{}, 50, 50) + model.SetShowStatusBar(false) + model.Title = "Secrets" + + return model, nil +}