diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md new file mode 100644 index 000000000..9d867cae8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue-template.md @@ -0,0 +1,13 @@ +--- +name: Issue template +about: 'Note, we don''t use GitHub to track issues with SST. Please start a new thread + on #help in https://discord.gg/sst' +title: '' +labels: '' +assignees: '' + +--- + +--- + +If you've already posted your issue on Discord, make sure to leave a link to it here. diff --git a/.github/workflows/binary.yml b/.github/workflows/binary.yml new file mode 100644 index 000000000..13027e16f --- /dev/null +++ b/.github/workflows/binary.yml @@ -0,0 +1,39 @@ +name: binary + +on: + push: + # run only against tags + tags: + - '*' + + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: write + packages: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - run: git fetch --force --tags + + - uses: actions/setup-go@v4 + with: + go-version: '>=1.21.0' + + - name: Go Mod + run: go mod download + + - uses: goreleaser/goreleaser-action@v4 + with: + distribution: goreleaser + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 000000000..d3efcd5d2 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,36 @@ +before: + hooks: + - go mod tidy +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + main: ./cmd/v10 + +archives: + - format: tar.gz + # this name template makes the OS and Arch compatible with the results of uname. + name_template: >- + v10- + {{- title .Os }}- + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + # use zip for windows archives + format_overrides: + - goos: windows + format: zip +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ incpatch .Version }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/cmd/v10/main.go b/cmd/v10/main.go index c882eb413..f3c8bca1c 100644 --- a/cmd/v10/main.go +++ b/cmd/v10/main.go @@ -6,7 +6,6 @@ import ( "os" "github.com/sst/v10/pkg/project" - "github.com/sst/v10/pkg/stack" cli "github.com/urfave/cli/v2" ) @@ -42,7 +41,7 @@ func main() { if err != nil { return err } - stack.Deploy(p) + p.Stack.Deploy() return nil }, }, @@ -55,7 +54,7 @@ func main() { if err != nil { return err } - stack.Remove(p) + p.Stack.Remove() return nil }, }, @@ -68,7 +67,7 @@ func main() { if err != nil { return err } - stack.Cancel(p) + p.Stack.Cancel() return nil }, }, @@ -109,11 +108,19 @@ func initProject() (*project.Project, error) { } slog.Info("using", "stage", p.Stage()) - _, err = p.GetAwsCredentials() + _, err = p.AWS.Config() if err != nil { return nil, err } + if _, err = p.Bootstrap.Bucket(); err != nil { + return nil, err + } + + if err := p.Stack.Login(); err != nil { + return nil, err + } + missingDeps := p.CheckDeps() if len(missingDeps) > 0 { p.InstallDeps(missingDeps) diff --git a/go.mod b/go.mod index c9252a92c..1912acfb1 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,33 @@ module github.com/sst/v10 go 1.21.3 require ( - github.com/aws/aws-sdk-go-v2 v1.22.2 + github.com/aws/aws-sdk-go-v2 v1.23.0 github.com/aws/aws-sdk-go-v2/config v1.25.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.42.2 + github.com/aws/aws-sdk-go-v2/service/ssm v1.42.2 github.com/evanw/esbuild v0.19.5 + github.com/google/uuid v1.4.0 github.com/urfave/cli/v2 v2.25.7 ) require ( + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.16.0 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.3 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 // indirect - github.com/aws/smithy-go v1.16.0 // indirect + github.com/aws/smithy-go v1.17.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/go.sum b/go.sum index 5b7ad0dcf..e4e6b295a 100644 --- a/go.sum +++ b/go.sum @@ -1,38 +1,66 @@ -github.com/aws/aws-sdk-go-v2 v1.22.2 h1:lV0U8fnhAnPz8YcdmZVV60+tr6CakHzqA6P8T46ExJI= -github.com/aws/aws-sdk-go-v2 v1.22.2/go.mod h1:Kd0OJtkW3Q0M0lUWGszapWjEvrXDzRW+D21JNsroB+c= +github.com/aws/aws-sdk-go-v2 v1.23.0 h1:PiHAzmiQQr6JULBUdvR8fKlA+UPKLT/8KbiqpFBWiAo= +github.com/aws/aws-sdk-go-v2 v1.23.0/go.mod h1:i1XDttT4rnf6vxc9AuskLc6s7XBee8rlLilKlc03uAA= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1 h1:ZY3108YtBNq96jNZTICHxN1gSBSbnvIdYwwqnvCV4Mc= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.1/go.mod h1:t8PYl/6LzdAqsU4/9tz28V/kU+asFePvpOMkdul0gEQ= github.com/aws/aws-sdk-go-v2/config v1.25.0 h1:WCwAqyrM/kqYi6pHjVpq/w2pLydeGKv8Af9vdtO3ciM= github.com/aws/aws-sdk-go-v2/config v1.25.0/go.mod h1:1QMnmhoWcR6957nC1MUUhhOLx9NOGFSVNG3Mag9vLU4= github.com/aws/aws-sdk-go-v2/credentials v1.16.0 h1:sSEHkXonpZBSPcyUBDRlZjxOi14qM/UK7/vfKhGwmTo= github.com/aws/aws-sdk-go-v2/credentials v1.16.0/go.mod h1:tXM8wmaeAhfC7nZoCxb0FzM/aRaB1m1WQ7x0qlBLq80= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 h1:G5KawTAkyHH6WyKQCdHiW4h3PmAXNJpOgwKg3H7sDRE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3/go.mod h1:hugKmSFnZB+HgNI1sYGT14BUPZkO6alC/e0AWu+0IAQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 h1:AaQsr5vvGR7rmeSWBtTCcw16tT9r51mWijuCQhzLnq8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2/go.mod h1:o1IiRn7CWocIFTXJjGKJDOwxv1ibL53NpcvcqGWyRBA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 h1:UZx8SXZ0YtzRiALzYAWcjb9Y9hZUR7MBKaBQ5ouOjPs= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2/go.mod h1:ipuRpcSaklmxR6C39G187TpBAO132gUfleTGccUPs8c= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3 h1:DUwbD79T8gyQ23qVXFUthjzVMTviSHi3y4z58KvghhM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3/go.mod h1:7sGSz1JCKHWWBHq98m6sMtWQikmYPpxjqOydDemiVoM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3 h1:AplLJCtIaUZDCbr6+gLYdsYNxne4iuaboJhVt9d+WXI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3/go.mod h1:ify42Rb7nKeDDPkFjKn7q1bPscVPu/+gmHH8d2c+anU= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.0 h1:usgqiJtamuGIBj+OvYmMq89+Z1hIKkMJToz1WpoeNUY= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.0/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 h1:h7j73yuAVVjic8pqswh+L/7r2IHP43QwRyOu6zcCDDE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2/go.mod h1:H07AHdK5LSy8F7EJUQhoxyiCNkePoHj2D8P2yGTWafo= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.3 h1:lMwCXiWJlrtZot0NJTjbC8G9zl+V3i68gBTBBvDeEXA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.3/go.mod h1:5yzAuE9i2RkVAttBl8yxZgQr5OCq4D5yDnG7j9x2L0U= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 h1:rpkF4n0CyFcrJUG/rNNohoTmhtWlFTRI4BsZOh9PvLs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1/go.mod h1:l9ymW25HOqymeU2m1gbUQ3rUIsTwKs8gYHXkqDQUhiI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.3 h1:xbwRyCy7kXrOj89iIKLB6NfE2WCpP9HoKyk8dMDvnIQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.3/go.mod h1:R+/S1O4TYpcktbVwddeOYg+uwUfLhADP2S/x4QwsCTM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3 h1:kJOolE8xBAD13xTCgOakByZkyP4D/owNmvEiioeUNAg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3/go.mod h1:Owv1I59vaghv1Ax8zz8ELY8DN7/Y0rGS+WWAmjgi950= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.3 h1:KV0z2RDc7euMtg8aUT1czv5p29zcLlXALNFsd3jkkEc= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.3/go.mod h1:KZgs2ny8HsxRIRbDwgvJcHHBZPOzQr/+NtGwnP+w2ec= +github.com/aws/aws-sdk-go-v2/service/s3 v1.42.2 h1:NnduxUd9+Fq9DcCDdJK8v6l9lR1xDX4usvog+JuQAno= +github.com/aws/aws-sdk-go-v2/service/s3 v1.42.2/go.mod h1:NXRKkiRF+erX2hnybnVU660cYT5/KChRD4iUgJ97cI8= +github.com/aws/aws-sdk-go-v2/service/ssm v1.42.2 h1:RcO+28sK4dBo/XFmF7QXCUxQh2D+DNQN2mvc+xfKyIo= +github.com/aws/aws-sdk-go-v2/service/ssm v1.42.2/go.mod h1:5tNnH3XNzW2Jo3TXQjKKH/Ivx7gRsz9nGcvGhq6YPRA= github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 h1:km+ZNjtLtpXYf42RdaDZnNHm9s7SYAuDGTafy6nd89A= github.com/aws/aws-sdk-go-v2/service/sso v1.17.1/go.mod h1:aHBr3pvBSD5MbzOvQtYutyPLLRPbl/y9x86XyJJnUXQ= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 h1:iRFNqZH4a67IqPvK8xxtyQYnyrlsvwmpHOe9r55ggBA= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1/go.mod h1:pTy5WM+6sNv2tB24JNKFtn6EvciQ5k40ZJ0pq/Iaxj0= github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 h1:txgVXIXWPXyqdiVn92BV6a/rgtpX31HYdsOYj0sVQQQ= github.com/aws/aws-sdk-go-v2/service/sts v1.25.1/go.mod h1:VAiJiNaoP1L89STFlEMgmHX1bKixY+FaP+TpRFrmyZ4= -github.com/aws/smithy-go v1.16.0 h1:gJZEH/Fqh+RsvlJ1Zt4tVAtV6bKkp3cC+R6FCZMNzik= -github.com/aws/smithy-go v1.16.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/aws/smithy-go v1.17.0 h1:wWJD7LX6PBV6etBUwO0zElG0nWN9rUhp0WdYeHSHAaI= +github.com/aws/smithy-go v1.17.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/evanw/esbuild v0.19.5 h1:9ildZqajUJzDAwNf9MyQsLh2RdDRKTq3kcyyzhE39us= github.com/evanw/esbuild v0.19.5/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/project/aws.go b/pkg/project/aws.go index 60e459abc..fed573b4c 100644 --- a/pkg/project/aws.go +++ b/pkg/project/aws.go @@ -3,30 +3,58 @@ package project import ( "context" "log/slog" + "sync" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" ) -func (p *Project) GetAwsCredentials() (*aws.Credentials, error) { - if p.credentials != nil && !p.credentials.Expired() { - return p.credentials, nil +type projectAws struct { + project *Project + cfg aws.Config + sync.Once +} + +func (p *projectAws) Credentials() (*aws.Credentials, error) { + cfg, err := p.Config() + if err != nil { + return nil, err } - slog.Info("using", "profile", p.Profile()) ctx := context.Background() - slog.Info("getting aws credentials") - cfg, err := config.LoadDefaultConfig( - ctx, - config.WithSharedConfigProfile(p.Profile()), - ) + creds, err := cfg.Credentials.Retrieve(ctx) if err != nil { return nil, err } - credentials, err := cfg.Credentials.Retrieve(ctx) + return &creds, nil +} + +func (p *projectAws) Config() (aws.Config, error) { + var err error + + p.Do(func() { + slog.Info("using", "profile", p.project.Profile()) + ctx := context.Background() + slog.Info("getting aws credentials") + cfg, e := config.LoadDefaultConfig( + ctx, + config.WithSharedConfigProfile(p.project.Profile()), + ) + if e != nil { + err = e + return + } + _, e = cfg.Credentials.Retrieve(ctx) + if e != nil { + err = e + return + } + slog.Info("credentials found") + p.cfg = cfg + }) + if err != nil { - return nil, err + return aws.Config{}, err } - p.credentials = &credentials - slog.Info("credentials found") - return &credentials, nil + + return p.cfg, nil } diff --git a/pkg/project/bootstrap.go b/pkg/project/bootstrap.go new file mode 100644 index 000000000..168903a01 --- /dev/null +++ b/pkg/project/bootstrap.go @@ -0,0 +1,90 @@ +package project + +import ( + "context" + "errors" + "fmt" + "log/slog" + "sync" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" + "github.com/google/uuid" + + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +type bootstrap struct { + project *Project + bucket string + sync.Once +} + +const SSM_NAME_BUCKET = "/sst/bootstrap" + +func (b *bootstrap) Bucket() (string, error) { + var createErr error + + b.Do(func() { + ctx := context.TODO() + cfg, err := b.project.AWS.Config() + if err != nil { + createErr = err + return + } + + ssmClient := ssm.NewFromConfig(cfg) + slog.Info("fetching bootstrap bucket") + result, err := ssmClient.GetParameter(ctx, &ssm.GetParameterInput{ + Name: aws.String(SSM_NAME_BUCKET), + WithDecryption: aws.Bool(false), + }) + + if result != nil && result.Parameter.Value != nil { + slog.Info("found existing bootstrap bucket") + b.bucket = *result.Parameter.Value + return + } + + if err != nil { + var pnf *types.ParameterNotFound + if errors.As(err, &pnf) { + bucketName := fmt.Sprintf("sst-bootstrap-%v", uuid.New().String()) + slog.Info("creating bootstrap bucket", "name", bucketName) + s3Client := s3.NewFromConfig(cfg) + + _, err := s3Client.CreateBucket(context.TODO(), &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + }) + if err != nil { + createErr = err + return + } + + _, err = ssmClient.PutParameter( + ctx, + &ssm.PutParameterInput{ + Name: aws.String(SSM_NAME_BUCKET), + Type: types.ParameterTypeString, + Value: aws.String(bucketName), + }, + ) + if err != nil { + createErr = err + return + } + + b.bucket = bucketName + return + } + createErr = err + return + } + + }) + if createErr != nil { + return "", createErr + } + return b.bucket, nil +} diff --git a/pkg/project/project.go b/pkg/project/project.go index 8444cc509..26fe1656a 100644 --- a/pkg/project/project.go +++ b/pkg/project/project.go @@ -6,18 +6,20 @@ import ( "os" "path/filepath" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/sst/v10/internal/fs" "github.com/sst/v10/pkg/js" ) type Project struct { - root string - config string - name string - profile string - stage string - credentials *aws.Credentials + root string + config string + name string + profile string + stage string + + AWS *projectAws + Bootstrap *bootstrap + Stack *stack } func New() (*Project, error) { @@ -37,6 +39,15 @@ func New() (*Project, error) { root: rootPath, config: cfgPath, } + proj.AWS = &projectAws{ + project: proj, + } + proj.Bootstrap = &bootstrap{ + project: proj, + } + proj.Stack = &stack{ + project: proj, + } tmp := proj.PathTemp() _, err = os.Stat(tmp) diff --git a/pkg/stack/stack.go b/pkg/project/stack.go similarity index 50% rename from pkg/stack/stack.go rename to pkg/project/stack.go index f72d2f786..6cb5be05a 100644 --- a/pkg/stack/stack.go +++ b/pkg/project/stack.go @@ -1,14 +1,79 @@ -package stack +package project import ( + "encoding/json" "fmt" + "log/slog" + "os" + "path/filepath" "strings" "github.com/sst/v10/pkg/js" - "github.com/sst/v10/pkg/project" ) -func runtime(project *project.Project) string { +type stack struct { + project *Project +} + +func (s *stack) Login() error { + slog.Info("logging in") + bucket, err := s.project.Bootstrap.Bucket() + if err != nil { + return err + } + home, err := os.UserHomeDir() + if err != nil { + return err + } + + credentialsPath := filepath.Join( + home, + ".pulumi", + "credentials.json", + ) + data, err := os.ReadFile(credentialsPath) + + if err != nil { + data = []byte("{}") + } + var parsed struct { + Current string `json:"current"` + Accounts map[string]interface{} + } + err = json.Unmarshal(data, &parsed) + if err != nil { + return err + } + full := fmt.Sprintf("s3://%v", bucket) + parsed.Current = full + if parsed.Accounts == nil { + parsed.Accounts = map[string]interface{}{} + } + parsed.Accounts[full] = map[string]interface{}{ + "lastValidatedAt": "2021-08-31T18:00:00.000Z", + } + + data, err = json.Marshal(parsed) + if err != nil { + return err + } + err = os.MkdirAll(filepath.Dir(credentialsPath), 0755) + if err != nil { + return err + } + err = os.WriteFile( + credentialsPath, + data, + 0644, + ) + if err != nil { + return err + } + slog.Info("logged into", "bucket", full) + return nil +} + +func (s *stack) runtime() string { return fmt.Sprintf(` import * as aws from "@pulumi/aws"; globalThis.aws = aws @@ -20,12 +85,12 @@ func runtime(project *project.Project) string { projectName: "%s", stackName: "%s", }) - `, project.PathConfig(), project.Name(), project.Stage(), + `, s.project.PathConfig(), s.project.Name(), s.project.Stage(), ) } -func env(project *project.Project) ([]string, error) { - credentials, err := project.GetAwsCredentials() +func (s *stack) env() ([]string, error) { + credentials, err := s.project.AWS.Credentials() if err != nil { return nil, err } @@ -37,19 +102,19 @@ func env(project *project.Project) ([]string, error) { }, nil } -func Deploy(project *project.Project) error { - env, err := env(project) +func (s *stack) Deploy() error { + env, err := s.env() if err != nil { return err } cmd, err := js.Eval(js.EvalOptions{ - Dir: project.PathTemp(), + Dir: s.project.PathTemp(), Code: fmt.Sprintf(` %v await stack.up({ onOutput: console.log, }) - `, runtime(project)), + `, s.runtime()), Env: env, }) if err != nil { @@ -74,19 +139,19 @@ func Deploy(project *project.Project) error { return nil } -func Remove(project *project.Project) error { - env, err := env(project) +func (s *stack) Cancel() error { + env, err := s.env() if err != nil { return err } cmd, err := js.Eval(js.EvalOptions{ - Dir: project.PathTemp(), + Dir: s.project.PathTemp(), Code: fmt.Sprintf(` %v - await stack.destroy({ + await stack.cancel({ onOutput: console.log, }) - `, runtime(project)), + `, s.runtime()), Env: env, }) if err != nil { @@ -111,19 +176,19 @@ func Remove(project *project.Project) error { return nil } -func Cancel(project *project.Project) error { - env, err := env(project) +func (s *stack) Remove() error { + env, err := s.env() if err != nil { return err } cmd, err := js.Eval(js.EvalOptions{ - Dir: project.PathTemp(), + Dir: s.project.PathTemp(), Code: fmt.Sprintf(` %v - await stack.cancel({ + await stack.destroy({ onOutput: console.log, }) - `, runtime(project)), + `, s.runtime()), Env: env, }) if err != nil { @@ -135,7 +200,12 @@ func Cancel(project *project.Project) error { } for cmd.Out.Scan() { - fmt.Println(cmd.Out.Text()) + line := strings.TrimSpace(cmd.Out.Text()) + if line == "" { + continue + } + + fmt.Println(line) } cmd.Wait()