diff --git a/.golangci.yaml b/.golangci.yaml index b3a7184f..acb0922a 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -49,3 +49,4 @@ linters-settings: - github.com/stretchr/testify/assert - github.com/google/uuid - github.com/caarlos0/env/v9 + - github.com/go-git/go-git/v5 diff --git a/cmd/gale/list/list.go b/cmd/gale/list/list.go index c604c118..33023c67 100644 --- a/cmd/gale/list/list.go +++ b/cmd/gale/list/list.go @@ -54,7 +54,12 @@ func NewCommand() *cobra.Command { // TODO: add more information about the workflow like the trigger, etc. // TODO: maybe we could add better formatting for the output - for _, workflow := range rc.Repo.Workflows { + workflows, err := rc.LoadWorkflows() + if err != nil { + return err + } + + for _, workflow := range workflows { fmt.Printf("Workflow: ") if workflow.Name != workflow.Path { fmt.Printf("%s (path: %s)\n", workflow.Name, workflow.Path) diff --git a/cmd/ghx/run/run.go b/cmd/ghx/run/run.go index e4f5ffee..a0b3f368 100644 --- a/cmd/ghx/run/run.go +++ b/cmd/ghx/run/run.go @@ -29,7 +29,12 @@ func NewCommand() *cobra.Command { } // Load workflow - wf, ok := ctx.Repo.Workflows[args[0]] + workflows, err := ctx.LoadWorkflows() + if err != nil { + return err + } + + wf, ok := workflows[args[0]] if !ok { return ghx.ErrWorkflowNotFound } diff --git a/go.mod b/go.mod index bd80f954..2f05e01d 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/adrg/xdg v0.4.0 github.com/caarlos0/env/v9 v9.0.0 github.com/cli/go-gh/v2 v2.1.0 + github.com/go-git/go-git/v5 v5.9.0 github.com/google/uuid v1.3.1 github.com/julienschmidt/httprouter v1.3.0 github.com/rhysd/actionlint v1.6.25 @@ -17,23 +18,41 @@ require ( ) require ( + dario.cat/mergo v1.0.0 // indirect github.com/99designs/gqlgen v0.17.36 // indirect github.com/Khan/genqlient v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect github.com/cli/safeexec v1.0.1 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.15.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron v1.2.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/vektah/gqlparser/v2 v2.5.8 // indirect - golang.org/x/net v0.12.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.10.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/tools v0.13.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 173a0816..fce23e47 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,28 @@ dagger.io/dagger v0.8.6 h1:+Tw43g6XWnFNOTxW6dCLID3NkaApNsTboEhR7H5P/bk= dagger.io/dagger v0.8.6/go.mod h1:DbJi6aSXaRLuio0lHlnpNxfuAL5uMJvRy4UIytmbtLo= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/99designs/gqlgen v0.17.36 h1:u/o/rv2SZ9s5280dyUOOrkpIIkr/7kITMXYD3rkJ9go= github.com/99designs/gqlgen v0.17.36/go.mod h1:6RdyY8puhCoWAQVr2qzF2OMVfudQzc8ACxzpzluoQm4= github.com/Khan/genqlient v0.6.0 h1:Bwb1170ekuNIVIwTJEqvO8y7RxBxXu639VJOkKSrwAk= github.com/Khan/genqlient v0.6.0/go.mod h1:rvChwWVTqXhiapdhLDV4bp9tz/Xvtewwkon4DpWWCRM= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= github.com/cli/go-gh/v2 v2.1.0 h1:JzYEJyv3VOoU+O9prmoAb3q4JvCwx8dGgLjJF992+18= @@ -18,13 +30,30 @@ github.com/cli/go-gh/v2 v2.1.0/go.mod h1:DwqlWB1TCBcKmDt/9/81EnlbGG7elLoevF4ypt5 github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/cli/shurcooL-graphql v0.0.3 h1:CtpPxyGDs136/+ZeyAfUKYmcQBjDlq5aqnrDCW5Ghh8= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= +github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY= +github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -33,14 +62,20 @@ github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSAS github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -52,6 +87,11 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rhysd/actionlint v1.6.25 h1:0Is99a51w1iocdxKUzNYiBNwjoSlO2Klqzll98joVj4= @@ -61,14 +101,19 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -76,24 +121,79 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e h1:BuzhfgfWQbX0dWzYzT1zsORLnHRv3bcRcsaUk0VmXA8= github.com/vektah/gqlparser/v2 v2.5.8 h1:pm6WOnGdzFOCfcQo9L3+xzW51mKrlwTEg4Wr7AH1JW4= github.com/vektah/gqlparser/v2 v2.5.8/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/go.work.sum b/go.work.sum index 1e8330ae..66ad0c5d 100644 --- a/go.work.sum +++ b/go.work.sum @@ -32,6 +32,7 @@ github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/bradleyjkemp/cupaloy/v2 v2.6.0 h1:knToPYa2xtfg42U3I6punFEjaGFKWQRXJwj0JTv4mTs= +github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/charmbracelet/glamour v0.5.1-0.20220727184942-e70ff2d969da h1:FGz53GWQRiKQ/5xUsoCCkewSQIC7u81Scaxx2nUy3nM= github.com/charmbracelet/glamour v0.5.1-0.20220727184942-e70ff2d969da/go.mod h1:HXz79SMFnF9arKxqeoHWxmo1BhplAH7wehlRhKQIL94= @@ -48,6 +49,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= @@ -62,8 +64,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -118,6 +118,7 @@ github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU= github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= @@ -141,6 +142,7 @@ github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2 github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mmcloughlin/avo v0.5.0 h1:nAco9/aI9Lg2kiuROBY6BhCI/z0t5jEvJfjWbL8qXLU= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= @@ -149,15 +151,17 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/sagikazarmark/crypt v0.10.0 h1:96E1qrToLBU6fGzo+PRRz7KGOc9FkYFiPnR3/zf8Smg= github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -175,7 +179,6 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRT github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU= github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os= @@ -197,8 +200,6 @@ go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= @@ -211,48 +212,31 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDA golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.2.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-20201119102817-f84b799fce68/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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -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.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.11.1/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= 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= diff --git a/internal/core/repository.go b/internal/core/repository.go index 9a4a73dd..c7155961 100644 --- a/internal/core/repository.go +++ b/internal/core/repository.go @@ -1,97 +1,46 @@ package core import ( - "context" "encoding/json" "fmt" - "dagger.io/dagger" - "github.com/cli/go-gh/v2" ) // Repository represents a GitHub repository type Repository struct { - ID string - Name string - NameWithOwner string - URL string - Owner RepositoryOwner - DefaultBranchRef RepositoryBranchRef - GitRef *RepositoryGitRef + ID string `json:"id" env:"GALE_REPO_ID" container_env:"true"` + Name string `json:"name" env:"GALE_REPO_NAME" container_env:"true"` + NameWithOwner string `json:"name_with_owner" env:"GALE_REPO_NAME_WITH_OWNER" container_env:"true"` + URL string `json:"url" env:"GALE_REPO_URL" container_env:"true"` + Owner RepositoryOwner `json:"owner"` + DefaultBranchRef RepositoryBranchRef `json:"default_branch_ref"` } // RepositoryOwner represents a GitHub repository owner type RepositoryOwner struct { - ID string - Login string + ID string `json:"id" env:"GALE_REPO_OWNER_ID" container_env:"true"` + Login string `json:"login" env:"GALE_REPO_OWNER_LOGIN" container_env:"true"` } // RepositoryBranchRef represents a GitHub repository branch ref type RepositoryBranchRef struct { - Name string -} - -// GetRepositoryOpts represents the options for refs used to get a repository. Only one of the -// options can be set. -// -// If none of the options are set, the default branch will be used. Default branch or remote repositories is configured -// in the GitHub repository settings. For local repositories, it's the branch that is currently checked out. -// -// If multiple options are set, the precedence is as follows: tag, branch. -type GetRepositoryOpts struct { - Branch string - Tag string -} - -// GetCurrentRepository returns current repository information. This is a wrapper around GetRepository with empty name. -func GetCurrentRepository(ctx context.Context, client *dagger.Client, opts ...GetRepositoryOpts) (*Repository, error) { - return GetRepository(ctx, client, "", opts...) + Name string `json:"name" env:"GALE_REPO_BRANCH_NAME" container_env:"true"` } // GetRepository returns repository information. If name is empty, the current repository will be used. -func GetRepository(ctx context.Context, client *dagger.Client, name string, opts ...GetRepositoryOpts) (*Repository, error) { +func GetRepository(name string) (Repository, error) { var repo Repository stdout, stderr, err := gh.Exec("repo", "view", name, "--json", "id,name,owner,nameWithOwner,url,defaultBranchRef") if err != nil { - return nil, fmt.Errorf("failed to get current repository: %w stderr: %s", err, stderr.String()) + return repo, fmt.Errorf("failed to get current repository: %w stderr: %s", err, stderr.String()) } err = json.Unmarshal(stdout.Bytes(), &repo) if err != nil { - return nil, fmt.Errorf("failed to unmarshal current repository: %s err: %w", stdout.String(), err) - } - - opt := GetRepositoryOpts{} - if len(opts) > 0 { - opt = opts[0] - } - - // load repo tree based on the options precedence - switch { - case opt.Tag != "": - repo.GitRef, err = GetRepositoryGitRef(ctx, client, repo.URL, RefTypeTag, opt.Tag) - if err != nil { - return nil, err - } - case opt.Branch != "": - repo.GitRef, err = GetRepositoryGitRef(ctx, client, repo.URL, RefTypeBranch, opt.Branch) - if err != nil { - return nil, err - } - case name != "": - repo.GitRef, err = GetRepositoryGitRef(ctx, client, repo.URL, RefTypeBranch, repo.DefaultBranchRef.Name) - if err != nil { - return nil, err - } - default: - // TODO: current directory could be a subdirectory of the repository. Should we handle this case? - repo.GitRef, err = GetRepositoryRefFromDir(ctx, client, client.Host().Directory(".")) - if err != nil { - return nil, err - } + return repo, fmt.Errorf("failed to unmarshal current repository: %s err: %w", stdout.String(), err) } - return &repo, nil + return repo, nil } diff --git a/internal/core/repository_gitref.go b/internal/core/repository_gitref.go index 4ca96eb3..6b4364e0 100644 --- a/internal/core/repository_gitref.go +++ b/internal/core/repository_gitref.go @@ -1,101 +1,105 @@ package core import ( - "context" + "errors" "fmt" - "strings" - "dagger.io/dagger" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" ) +// errRefFound is a sentinel error used to stop iteration early. +var errRefFound = errors.New("stop") + // RepositoryGitRef represents a Git ref (branch or tag) in a repository type RepositoryGitRef struct { - Ref string - RefName string - RefType RefType - SHA string - Dir *dagger.Directory + Ref string `json:"ref" env:"GALE_REPO_REF" container_env:"true"` + RefName string `json:"ref_name" env:"GALE_REPO_REF_NAME" container_env:"true"` + RefType RefType `json:"ref_type" env:"GALE_REPO_REF_TYPE" container_env:"true"` + SHA string `json:"sha" env:"GALE_REPO_SHA" container_env:"true"` + ShortSHA string `json:"short_sha" env:"GALE_REPO_SHORT_SHA" container_env:"true"` + IsRemote bool `json:"is_remote" env:"GALE_REPO_IS_REMOTE" container_env:"true"` } -// GetRepositoryGitRef returns a Git ref (branch or tag) in a repository. If name is empty, the current repository will be used. -func GetRepositoryGitRef(ctx context.Context, client *dagger.Client, url string, refType RefType, refName string) (*RepositoryGitRef, error) { - var ( - ref string - dir *dagger.Directory - ) +// GetRepositoryRefFromDir returns a Git ref (branch or tag) from given directory. If dir is empty or not git repository, it will return an error. +func GetRepositoryRefFromDir(path, tag, branch string) (RepositoryGitRef, error) { + var ref RepositoryGitRef - git := client.Git(url, dagger.GitOpts{KeepGitDir: true}) + repo, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{DetectDotGit: true, EnableDotGitCommonDir: true}) + if err != nil { + return ref, fmt.Errorf("failed to open repository: %w", err) + } - switch refType { - case RefTypeBranch: - dir = git.Branch(refName).Tree() - ref = fmt.Sprintf("refs/heads/%s", refName) - case RefTypeTag: - dir = git.Tag(refName).Tree() - ref = fmt.Sprintf("refs/tags/%s", refName) - default: - return nil, fmt.Errorf("invalid ref type: %s", refType) + // Get current reference (branch, tag, or commit) + head, err := repo.Head() + if err != nil { + return ref, fmt.Errorf("failed to get head reference: %w", err) } - sha, err := getRepoSHA(ctx, client, dir) + if head.Hash().IsZero() { + return ref, fmt.Errorf("failed to get head reference: %w", plumbing.ErrReferenceNotFound) + } + + iter, err := repo.References() if err != nil { - return nil, err + return ref, fmt.Errorf("failed to get references: %w", err) } - return &RepositoryGitRef{Ref: ref, RefName: refName, RefType: refType, SHA: sha, Dir: dir}, nil -} + var found *plumbing.Reference -// GetRepositoryRefFromDir returns a Git ref (branch or tag) from given directory. If dir is empty or not git repository, it will return an error. -func GetRepositoryRefFromDir(ctx context.Context, client *dagger.Client, dir *dagger.Directory) (*RepositoryGitRef, error) { - var ( - ref string - refType RefType - refName string - sha string - ) + // Iterate through all references to find the matching one + err = iter.ForEach(func(ref *plumbing.Reference) error { + if ref.Hash() == head.Hash() { + found = ref - out, err := client. - Container(). - From("alpine/git"). - WithMountedDirectory("/src", dir).WithWorkdir("/src"). - WithExec([]string{"rev-parse", "--symbolic-full-name", "HEAD"}). - Stdout(ctx) - if err != nil { - return nil, err + return errRefFound + } + + return nil + }) + + if err != nil && !errors.Is(err, errRefFound) { + return ref, err } - ref = strings.TrimSpace(out) + var ( + refType RefType + refFull string + refName string + isRemote bool + ) switch { - case strings.HasPrefix(ref, "refs/heads/"): + case found.Name().IsBranch(): refType = RefTypeBranch - refName = strings.TrimPrefix(ref, "refs/heads/") - case strings.HasPrefix(ref, "refs/tags/"): + refFull = found.Name().String() + refName = found.Name().Short() + isRemote = found.Name().IsRemote() + case found.Name().IsTag(): refType = RefTypeTag - refName = strings.TrimPrefix(ref, "refs/tags/") + refFull = found.Name().String() + refName = found.Name().Short() + isRemote = found.Name().IsRemote() + case found.Name() == "HEAD" && tag != "": // we're in detached head state and tag is provided, so we're using the tag + refType = RefTypeTag + refFull = fmt.Sprintf("refs/tags/%s", tag) + refName = tag + isRemote = true + case found.Name() == "HEAD" && branch != "": // we're in detached head state and branch is provided, so we're using the branch + refType = RefTypeBranch + refFull = fmt.Sprintf("refs/heads/%s", branch) + refName = branch + isRemote = true default: - return nil, fmt.Errorf("invalid ref type: %s", refType) - } - - sha, err = getRepoSHA(ctx, client, dir) - if err != nil { - return nil, err - } - - return &RepositoryGitRef{Ref: ref, RefName: refName, RefType: refType, SHA: sha, Dir: dir}, nil -} - -func getRepoSHA(ctx context.Context, client *dagger.Client, dir *dagger.Directory) (string, error) { - out, err := client. - Container(). - From("alpine/git"). - WithMountedDirectory("/src", dir).WithWorkdir("/src"). - WithExec([]string{"rev-parse", "HEAD"}). - Stdout(ctx) - - if err != nil { - return "", err + return ref, fmt.Errorf("unsupported ref: %s", found.Name().String()) } - return strings.TrimSpace(out), nil + return RepositoryGitRef{ + Ref: refFull, + RefName: refName, + RefType: refType, + SHA: found.Hash().String(), + ShortSHA: found.Hash().String()[:7], + IsRemote: isRemote, + }, nil } diff --git a/internal/core/repository_test.go b/internal/core/repository_test.go index 486b53c4..49324f94 100644 --- a/internal/core/repository_test.go +++ b/internal/core/repository_test.go @@ -21,7 +21,7 @@ func TestGetCurrentRepository(t *testing.T) { defer client.Close() // get current repository with current directory. This will load tests directory as repository. It's ok for testing. - repo, err := core.GetCurrentRepository(ctx, client) + repo, err := core.GetRepository("") if err != nil { t.Fatalf("Failed to get current repository: %s", err) } @@ -33,24 +33,6 @@ func TestGetCurrentRepository(t *testing.T) { if repo.NameWithOwner != "aweris/gale" { t.Fatalf("Expected repository name with owner to be aweris/gale but got %s", repo.NameWithOwner) } - - entries, err := repo.GitRef.Dir.Entries(ctx) - if err != nil { - t.Fatalf("Failed to get directory entries: %s", err) - } - - if len(entries) == 0 { - t.Fatalf("Expected directory entries to be more than 0 but got %d", len(entries)) - } - - data, err := repo.GitRef.Dir.File("testdata/content.txt").Contents(ctx) - if err != nil { - t.Fatalf("Failed to get file contents: %s", err) - } - - if data != "Hello World" { - t.Fatalf("Expected file contents to be Hello World but got %s", data) - } } func TestGetRepository(t *testing.T) { @@ -64,7 +46,7 @@ func TestGetRepository(t *testing.T) { defer client.Close() // get repository with default branch - repo, err := core.GetRepository(ctx, client, "aweris/gale") + repo, err := core.GetRepository("aweris/gale") if err != nil { t.Fatalf("Failed to get current repository: %s", err) } @@ -76,15 +58,6 @@ func TestGetRepository(t *testing.T) { if repo.NameWithOwner != "aweris/gale" { t.Fatalf("Expected repository name with owner to be aweris/gale but got %s", repo.NameWithOwner) } - - entries, err := repo.GitRef.Dir.Entries(ctx) - if err != nil { - t.Fatalf("Failed to get directory entries: %s", err) - } - - if len(entries) == 0 { - t.Fatalf("Expected directory entries to be more than 0 but got %d", len(entries)) - } } /* diff --git a/internal/gctx/gctx.go b/internal/gctx/gctx.go index 1b53a5ed..5bb9bc17 100644 --- a/internal/gctx/gctx.go +++ b/internal/gctx/gctx.go @@ -99,7 +99,7 @@ func (c *Context) WithContainerFunc() dagger.WithContainerFunc { container = container.With(c.Runner.WithContainerFunc()) // load repository to container - container = container.WithMountedDirectory(c.Github.Workspace, c.Repo.Repository.GitRef.Dir) + container = container.WithMountedDirectory(c.Github.Workspace, c.Repo.Source) container = container.WithWorkdir(c.Github.Workspace) return container diff --git a/internal/gctx/github.go b/internal/gctx/github.go index 2cb64d38..c37bb35b 100644 --- a/internal/gctx/github.go +++ b/internal/gctx/github.go @@ -162,7 +162,7 @@ func (c *Context) LoadGithubContext() error { } // SetRepo sets the repository information in the context. -func (c *GithubContext) setRepo(repo *core.Repository) *GithubContext { +func (c *GithubContext) setRepo(repo core.Repository, ref core.RepositoryGitRef) *GithubContext { c.Repository = repo.NameWithOwner c.RepositoryID = repo.ID c.RepositoryOwner = repo.Owner.Login @@ -170,8 +170,6 @@ func (c *GithubContext) setRepo(repo *core.Repository) *GithubContext { c.RepositoryURL = repo.URL c.Workspace = fmt.Sprintf("/home/runner/work/%s/%s", repo.Name, repo.Name) - ref := repo.GitRef - c.Ref = ref.Ref c.RefName = ref.RefName c.RefType = string(ref.RefType) diff --git a/internal/gctx/helpers.go b/internal/gctx/helpers.go index e9e2fee0..c550ae38 100644 --- a/internal/gctx/helpers.go +++ b/internal/gctx/helpers.go @@ -30,41 +30,51 @@ const trueStr = "true" // using the `env` tag value as their name. func WithContainerEnv[T any](client *dagger.Client, t *T) dagger.WithContainerFunc { return func(container *dagger.Container) *dagger.Container { - val := reflect.ValueOf(t).Elem() - typ := val.Type() - - for i := 0; i < typ.NumField(); i++ { - field := typ.Field(i) + return loadFieldsIntoContainer(client, container, t) + } +} - containerEnvTag := typ.Field(i).Tag.Get("container_env") - containerSecretTag := typ.Field(i).Tag.Get("container_secret") +func loadFieldsIntoContainer(client *dagger.Client, container *dagger.Container, t interface{}) *dagger.Container { + val := reflect.ValueOf(t).Elem() + typ := val.Type() - // skip if the field is not tagged with container_env or container_secret - if containerEnvTag == "" && containerSecretTag == "" { - continue - } + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) - if containerEnvTag == trueStr && containerSecretTag == trueStr { - return helpers.FailPipeline(container, fmt.Errorf("field %s is tagged with both container_env and container_secret", field.Name)) - } + containerEnvTag := typ.Field(i).Tag.Get("container_env") + containerSecretTag := typ.Field(i).Tag.Get("container_secret") - envTag := field.Tag.Get("env") - if envTag == "" { - return helpers.FailPipeline(container, fmt.Errorf("field %s is tagged with container_env or container_secret but not tagged with env", field.Name)) - } + // skip if the field is not tagged with container_env or container_secret + if containerEnvTag == "" && containerSecretTag == "" { + continue + } - // TODO: handle other types properly - envVal := val.Field(i).Interface() + if containerEnvTag == trueStr && containerSecretTag == trueStr { + return helpers.FailPipeline(container, fmt.Errorf("field %s is tagged with both container_env and container_secret", field.Name)) + } - if containerEnvTag == trueStr { - container = container.WithEnvVariable(envTag, fmt.Sprintf("%v", envVal)) - } + var ( + fieldVal = val.Field(i) + envTag = field.Tag.Get("env") + ) - if containerSecretTag == trueStr { - container = container.WithSecretVariable(envTag, client.SetSecret(envTag, fmt.Sprintf("%v", envVal))) - } + // if env tag is empty and the field is not a struct, fail the pipeline. We're using env tag as the name of the + // environment variable or secret. If it's empty, we can't load the field. + if envTag == "" && val.Field(i).Kind() != reflect.Struct { + return helpers.FailPipeline(container, fmt.Errorf("field %s is tagged with container_env or container_secret but not tagged with env", field.Name)) } - return container + switch { + case fieldVal.Kind() == reflect.Struct: + container = loadFieldsIntoContainer(client, container, fieldVal.Addr().Interface()) + case containerEnvTag == trueStr: + container = container.WithEnvVariable(envTag, fmt.Sprintf("%v", fieldVal.Interface())) + case containerSecretTag == trueStr: + container = container.WithSecretVariable(envTag, client.SetSecret(envTag, fmt.Sprintf("%v", fieldVal.Interface()))) + default: + return helpers.FailPipeline(container, fmt.Errorf("unsupported field type: %s", fieldVal.Kind())) + } } + + return container } diff --git a/internal/gctx/repo.go b/internal/gctx/repo.go index fdacadba..673c15ae 100644 --- a/internal/gctx/repo.go +++ b/internal/gctx/repo.go @@ -2,6 +2,7 @@ package gctx import ( "context" + "os" "path/filepath" "strings" @@ -21,54 +22,113 @@ type LoadRepoOpts struct { } type RepoContext struct { - Repository *core.Repository `json:"-"` - CacheVol *data.CacheVolume `json:"-"` - WorkflowsDir string `json:"workflows_dir" env:"GALE_WORKFLOWS_DIR" envDefault:".github/workflows" container_env:"true"` - Workflows map[string]core.Workflow `json:"-"` + CacheVol *data.CacheVolume `json:"-"` + Source *dagger.Directory `json:"-"` + Info core.Repository `json:"info" container_env:"true"` + Ref core.RepositoryGitRef `json:"ref" container_env:"true"` + WorkflowsDir string `json:"workflows_dir" env:"GALE_WORKFLOWS_DIR" envDefault:".github/workflows" container_env:"true"` } // LoadRepo initializes the context with the specified or current repository's default branch if no options are provided. func (c *Context) LoadRepo(repo string, opts ...LoadRepoOpts) error { + // load repo context from env rc, err := NewContextFromEnv[RepoContext]() if err != nil { return err } + // in container mode, we don't need to load the repository information from the host, we can use the one from the + // environment. + if !c.isContainer { + rc.Info, err = core.GetRepository(repo) + if err != nil { + return err + } + } + + // load repository source - it doesn't matter if we're in container mode or not, we need to load the repository + opt := LoadRepoOpts{} if len(opts) > 0 { opt = opts[0] } - r, err := core.GetRepository(c.Context, config.ClientNoLog(), repo, core.GetRepositoryOpts{Branch: opt.Branch, Tag: opt.Tag}) - if err != nil { - return err - } - - rc.Repository = r + // load repository source + rc.Source = getRepository(repo, rc.Info, opt) // cache volume only used non container mode. Instead of leaving it nil, we create a new one in container mode kas // well to avoid nil pointer errors. There is no harm in doing so since we're supporting Dagger in Dagger mode. - rc.CacheVol = data.NewCacheVolume(r) + rc.CacheVol = data.NewCacheVolume(rc.Info) - // if it's not in container mode, workflows dir should be set from the options + // load rest of the repository context since we have the repository information and the source. Same here, in + // container mode, we don't need to load the repository ref from the host, we can use the one from the environment. if !c.isContainer { + rc.Ref, err = getRepositoryRef(c.Context, repo, opt, rc.Source) + if err != nil { + return err + } + rc.WorkflowsDir = opt.WorkflowsDir + + c.Github.setRepo(rc.Info, rc.Ref) } - // load workflows - workflows, err := loadWorkflows(c.Context, r, rc.WorkflowsDir) - if err != nil { - return err + c.Repo = rc + + return nil +} + +// getRepository returns a dagger directory for the specified repository and options. If repo and options are empty, +// the current git repository will be used as it is. If repo or any of the options are provided, the repository will +// be cloned from the specified url and the specified tag or branch will be checked out. +func getRepository(repo string, info core.Repository, opt LoadRepoOpts) (source *dagger.Directory) { + // if repo and options are empty, use the current repository + if repo == "" && opt.Tag == "" && opt.Branch == "" { + return config.Client().Host().Directory(".") } - rc.Workflows = workflows + switch { + case opt.Tag != "": + source = config.Client().Git(info.URL, dagger.GitOpts{KeepGitDir: true}).Tag(opt.Tag).Tree() + case opt.Branch != "": + source = config.Client().Git(info.URL, dagger.GitOpts{KeepGitDir: true}).Branch(opt.Branch).Tree() + default: + source = config.Client().Git(info.URL, dagger.GitOpts{KeepGitDir: true}).Branch(info.DefaultBranchRef.Name).Tree() + } - c.Repo = rc + return source +} - // set repo to github context - c.Github.setRepo(r) +// getRepositoryRef gets the repository ref from the specified repository and options. +func getRepositoryRef(ctx context.Context, repo string, opt LoadRepoOpts, source *dagger.Directory) (ref core.RepositoryGitRef, err error) { + path := "." + + // if repo is not a local directory, we need to export it to a temp directory and use that as the path for the + // getting the ref from the git repository directly. + // + // for this conditional: + // - if repo is not empty, it means that the user has provided a remote repo + // - if repo is empty, but tag or branch is provided, it means that the user wants to use the current repository + // with the specified tag or branch + // + // So for both cases, we're using dagger git to clone the repository to a directory, no local directory is + // provided. + if repo != "" || opt.Tag != "" && opt.Branch != "" { + dir, err := os.MkdirTemp("/tmp", strings.ReplaceAll(repo, "/", "-")) + if err != nil { + return ref, err + } + defer os.RemoveAll(dir) - return nil + _, err = source.Export(ctx, dir) + if err != nil { + return ref, err + } + + path = dir + } + + return core.GetRepositoryRefFromDir(path, opt.Tag, opt.Branch) } // LoadCurrentRepo initializes the context with the repository information from the current working directory, @@ -85,10 +145,10 @@ func (c *RepoContext) WithContainerFunc() dagger.WithContainerFunc { } } -func loadWorkflows(ctx context.Context, repo *core.Repository, path string) (map[string]core.Workflow, error) { - dir := repo.GitRef.Dir.Directory(path) +func (c *Context) LoadWorkflows() (map[string]core.Workflow, error) { + dir := c.Repo.Source.Directory(c.Repo.WorkflowsDir) - entries, err := dir.Entries(ctx) + entries, err := dir.Entries(c.Context) if err != nil { return nil, err } @@ -100,7 +160,7 @@ func loadWorkflows(ctx context.Context, repo *core.Repository, path string) (map if strings.HasSuffix(entry, ".yaml") || strings.HasSuffix(entry, ".yml") { file := dir.File(entry) - workflow, err := loadWorkflow(ctx, filepath.Join(path, entry), file) + workflow, err := loadWorkflow(c.Context, filepath.Join(c.Repo.WorkflowsDir, entry), file) if err != nil { return nil, err } diff --git a/internal/mage/docker/docker.go b/internal/mage/docker/docker.go index cb818140..779fb458 100644 --- a/internal/mage/docker/docker.go +++ b/internal/mage/docker/docker.go @@ -8,6 +8,8 @@ import ( "strings" "dagger.io/dagger" + + "github.com/google/uuid" ) // Publish publishes the docker image for the given version. @@ -29,19 +31,20 @@ func Publish(ctx context.Context, version string) error { image = fmt.Sprintf("%s/aweris/gale:%s", registry, version) } + // build ldflags for commands var ldflags []string ldflags = append(ldflags, "-s", "-w") ldflags = append(ldflags, "-X github.com/aweris/gale/internal/version.gitVersion="+version) - // builds + // builds all components of the gale - gale := build(client, "./cmd/gale", "/src/out/gale") - ghx := build(client, "./cmd/ghx", "/src/out/ghx") - artifact := build(client, "./services/artifact", "/src/out/artifact-service") - artifactCache := build(client, "./services/artifactcache", "/src/out/artifactcache-service") + gale := build(client, "./cmd/gale", ldflags...) + ghx := build(client, "./cmd/ghx", ldflags...) + artifact := build(client, "./services/artifact") + artifactCache := build(client, "./services/artifactcache") - // container + // create a container that will be used to publish the image _, err = client.Container(). From("alpine:latest"). WithExec([]string{"apk", "add", "--no-cache", "git", "docker", "github-cli"}). @@ -55,8 +58,18 @@ func Publish(ctx context.Context, version string) error { return err } -func build(client *dagger.Client, path, out string) *dagger.File { - exec := []string{"go", "build", "-o", out, path} +// build builds the code for the given path and returns the output file. +func build(client *dagger.Client, path string, ldflags ...string) *dagger.File { + out := uuid.New().String() + + exec := []string{"go", "build", "-o", out} + + if len(ldflags) > 0 { + exec = append(exec, "-ldflags") + exec = append(exec, strings.Join(ldflags, " ")) + } + + exec = append(exec, path) return client.Container(). From("golang:"+strings.TrimPrefix(runtime.Version(), "go")). diff --git a/internal/mage/go.mod b/internal/mage/go.mod index 7d6d042a..208b6d81 100644 --- a/internal/mage/go.mod +++ b/internal/mage/go.mod @@ -3,9 +3,9 @@ module github.com/aweris/gale/internal/mage go 1.20 require ( - dagger.io/dagger v0.8.5 + dagger.io/dagger v0.8.6 + github.com/google/uuid v1.3.1 github.com/magefile/mage v1.15.0 - golang.org/x/mod v0.12.0 ) require ( diff --git a/internal/mage/go.sum b/internal/mage/go.sum index 759a25b8..c39cc21f 100644 --- a/internal/mage/go.sum +++ b/internal/mage/go.sum @@ -1,4 +1,4 @@ -dagger.io/dagger v0.8.5 h1:xzM08NwrKji0qSM7RXSIB4ndz1mUHVLgsX7vFeLPqIo= +dagger.io/dagger v0.8.6 h1:+Tw43g6XWnFNOTxW6dCLID3NkaApNsTboEhR7H5P/bk= github.com/99designs/gqlgen v0.17.36 h1:u/o/rv2SZ9s5280dyUOOrkpIIkr/7kITMXYD3rkJ9go= github.com/Khan/genqlient v0.6.0 h1:Bwb1170ekuNIVIwTJEqvO8y7RxBxXu639VJOkKSrwAk= github.com/Khan/genqlient v0.6.0/go.mod h1:rvChwWVTqXhiapdhLDV4bp9tz/Xvtewwkon4DpWWCRM= @@ -13,6 +13,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -29,7 +30,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/vektah/gqlparser/v2 v2.5.8 h1:pm6WOnGdzFOCfcQo9L3+xzW51mKrlwTEg4Wr7AH1JW4= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/data/cachevolume.go b/pkg/data/cachevolume.go index 913cd3fc..86c0c884 100644 --- a/pkg/data/cachevolume.go +++ b/pkg/data/cachevolume.go @@ -32,7 +32,7 @@ type CacheVolume struct { } // NewCacheVolume creates a new cache volume. -func NewCacheVolume(repo *core.Repository) *CacheVolume { +func NewCacheVolume(repo core.Repository) *CacheVolume { return &CacheVolume{ source: source(), volume: config.Client().CacheVolume(fmt.Sprintf("gale-data-%s-%s", repo.Owner.Login, repo.Name)),