diff --git a/.circleci/config.yml b/.circleci/config.yml index 650fd49..6554e1f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,24 +1,26 @@ -version: 2 +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/2.0/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: - release: + say-hello: + # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor docker: - - image: circleci/golang:1.16.6 - working_directory: /go/src/github.com/tenderly/tenderly-cli - environment: - GO111MODULE: "on" + - image: cimg/base:stable + # Add steps to the job + # See: https://circleci.com/docs/2.0/configuration-reference/#steps steps: - - checkout - - run: go get ./... - - run: GOOS=windows go get github.com/spf13/cobra - - run: GOOS=windows go get github.com/konsorten/go-windows-terminal-sequences - - run: curl -sL https://git.io/goreleaser | bash + - checkout + - run: + name: "Say hello" + command: "echo Hello, World!" + +# Invoke jobs via workflows +# See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: - version: 2 - release: + say-hello-workflow: jobs: - - release: - filters: - branches: - ignore: /.*/ - tags: - only: /v[0-9]+(\.[0-9]+)*(-.*)*/ + - say-hello diff --git a/.github/workflows/azure-webapps-node.yml b/.github/workflows/azure-webapps-node.yml new file mode 100644 index 0000000..a81f98a --- /dev/null +++ b/.github/workflows/azure-webapps-node.yml @@ -0,0 +1,74 @@ +# This workflow will build and push a node.js application to an Azure Web App when a commit is pushed to your default branch. +# +# This workflow assumes you have already created the target Azure App Service web app. +# For instructions see https://docs.microsoft.com/en-us/azure/app-service/quickstart-nodejs?tabs=linux&pivots=development-environment-cli +# +# To configure this workflow: +# +# 1. Download the Publish Profile for your Azure Web App. You can download this file from the Overview page of your Web App in the Azure Portal. +# For more information: https://docs.microsoft.com/en-us/azure/app-service/deploy-github-actions?tabs=applevel#generate-deployment-credentials +# +# 2. Create a secret in your repository named AZURE_WEBAPP_PUBLISH_PROFILE, paste the publish profile contents as the value of the secret. +# For instructions on obtaining the publish profile see: https://docs.microsoft.com/azure/app-service/deploy-github-actions#configure-the-github-secret +# +# 3. Change the value for the AZURE_WEBAPP_NAME. Optionally, change the AZURE_WEBAPP_PACKAGE_PATH and NODE_VERSION environment variables below. +# +# For more information on GitHub Actions for Azure: https://github.com/Azure/Actions +# For more information on the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# For more samples to get started with GitHub Action workflows to deploy to Azure: https://github.com/Azure/actions-workflow-samples + +on: + push: + branches: + - master + workflow_dispatch: + +env: + AZURE_WEBAPP_NAME: your-app-name # set this to your application's name + AZURE_WEBAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root + NODE_VERSION: '14.x' # set this to the node version to use + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + + - name: npm install, build, and test + run: | + npm install + npm run build --if-present + npm run test --if-present + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v2 + with: + name: node-app + path: . + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Development' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v2 + with: + name: node-app + + - name: 'Deploy to Azure WebApp' + id: deploy-to-webapp + uses: azure/webapps-deploy@v2 + with: + app-name: ${{ env.AZURE_WEBAPP_NAME }} + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} + package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} diff --git a/commands/actions/publish.go b/commands/actions/publish.go index d445f4f..33e8057 100644 --- a/commands/actions/publish.go +++ b/commands/actions/publish.go @@ -2,15 +2,16 @@ package actions import ( "fmt" - "github.com/pkg/errors" "os" "os/exec" "path/filepath" "time" "github.com/briandowns/spinner" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/tenderly/tenderly-cli/commands" "github.com/tenderly/tenderly-cli/commands/util" "github.com/tenderly/tenderly-cli/config" @@ -23,19 +24,21 @@ import ( var ( zipLimitBytes = 45 * 1024 * 1024 // 45 MB - srcZipped = "src/" - nodeModulesZipped = "nodejs/node_modules/" + srcPathInZip = "src/" + nodeModulesPathInZip = "nodejs/node_modules/" possibleFileExtensions = []string{"ts", "js"} ActionUrlPattern = "https://dashboard.tenderly.co/%s/action/%s" ) // Set and access from commands var ( - r *rest.Rest - projectSlug string - actions *actionsModel.ProjectActions - outDir string - sources map[string]string + r *rest.Rest + projectSlug string + actions *actionsModel.ProjectActions + outDir string + sources map[string]string + logicExist bool + dependenciesExist bool ) func init() { @@ -173,7 +176,14 @@ func deployFunc(cmd *cobra.Command, args []string) { publish(r, actions, sources, projectSlug, outDir, true) } -func publish(r *rest.Rest, actions *actionsModel.ProjectActions, sources map[string]string, projectSlug string, outDir string, deploy bool) { +func publish( + r *rest.Rest, + actions *actionsModel.ProjectActions, + sources map[string]string, + projectSlug string, + outDir string, + deploy bool, +) { if !deploy { logrus.Info("\nPublishing actions:") } else { @@ -184,17 +194,19 @@ func publish(r *rest.Rest, actions *actionsModel.ProjectActions, sources map[str "- %s", commands.Colorizer.Bold(commands.Colorizer.Green(actionName)))) } - sourcesDir := actions.Sources - dependenciesDir := filepath.Join(sourcesDir, typescript.NodeModulesDir) + logicZip, logicVersion := util.MustZipAndHashDir(outDir, srcPathInZip, zipLimitBytes) + if logicExist { + logicZip = nil + } - logicZip := util.MustZipDir(outDir, srcZipped, zipLimitBytes) + var ( + dependenciesZip []byte + dependenciesVersion string + ) - var dependenciesZip *[]byte - if util.ExistDir(dependenciesDir) { - dZip := util.MustZipDir(dependenciesDir, nodeModulesZipped, zipLimitBytes) - if len(dZip) > 0 { - dependenciesZip = &dZip - } + dependenciesDir := filepath.Join(actions.Sources, typescript.NodeModulesDir) + if !dependenciesExist { + dependenciesZip, dependenciesVersion = util.ZipAndHashDir(dependenciesDir, nodeModulesPathInZip, zipLimitBytes) } // TODO(marko): Send package-lock.json in publish request @@ -202,10 +214,10 @@ func publish(r *rest.Rest, actions *actionsModel.ProjectActions, sources map[str Actions: actions.ToRequest(sources), Deploy: deploy, Commitish: util.GetCommitish(), - LogicZip: logicZip, - LogicVersion: nil, - DependenciesZip: dependenciesZip, - DependenciesVersion: nil, + LogicZip: &logicZip, + LogicVersion: &logicVersion, + DependenciesZip: &dependenciesZip, + DependenciesVersion: &dependenciesVersion, } s := spinner.New(spinner.CharSets[33], 100*time.Millisecond) @@ -254,7 +266,9 @@ func mustBuildProject(sourcesDir string, tsconfig *typescript.TsConfig) { userError.NewUserError(err, commands.Colorizer.Sprintf( "Failed to run: %s.", - commands.Colorizer.Bold(commands.Colorizer.Red(fmt.Sprintf("npm --prefix %s run build", sourcesDir))), + commands.Colorizer.Bold( + commands.Colorizer.Red(fmt.Sprintf("npm --prefix %s run build", sourcesDir)), + ), ), ), ) @@ -262,7 +276,12 @@ func mustBuildProject(sourcesDir string, tsconfig *typescript.TsConfig) { } } -func mustValidateAndGetSources(r *rest.Rest, actions *actionsModel.ProjectActions, projectSlug string, sourcesDir string) map[string]string { +func mustValidateAndGetSources( + r *rest.Rest, + actions *actionsModel.ProjectActions, + projectSlug string, + sourcesDir string, +) map[string]string { logrus.Info("\nValidating actions...") validatedSources := make(map[string]string) @@ -272,7 +291,7 @@ func mustValidateAndGetSources(r *rest.Rest, actions *actionsModel.ProjectAction validatedSources[name] = source } - mustValidate(r, actions, validatedSources, projectSlug) + logicExist, dependenciesExist = mustValidate(r, actions, validatedSources, projectSlug) return validatedSources } @@ -317,12 +336,28 @@ func mustGetSource(sourcesDir string, locator string) string { return content } -func mustValidate(r *rest.Rest, actions *actionsModel.ProjectActions, sources map[string]string, projectSlug string) { - // TODO(marko): Send logic & dependencies version in validate request +// Validates sources and returns if source logic exist (LogicFound) and if dependencies logic exist (DependenciesFound) +func mustValidate( + r *rest.Rest, + actions *actionsModel.ProjectActions, + sources map[string]string, + projectSlug string, +) (bool, bool) { request := actions2.ValidateRequest{ - Actions: actions.ToRequest(sources), + Actions: actions.ToRequest(sources), + LogicVersion: nil, + DependenciesVersion: nil, } + _, logicVersion := util.MustZipAndHashDir(outDir, srcPathInZip, zipLimitBytes) + + request.LogicVersion = &logicVersion + + dependenciesDir := filepath.Join(actions.Sources, typescript.NodeModulesDir) + + _, dependenciesVersion := util.ZipAndHashDir(dependenciesDir, nodeModulesPathInZip, zipLimitBytes) + request.DependenciesVersion = &dependenciesVersion + response, err := r.Actions.Validate(request, projectSlug) if err != nil { userError.LogErrorf("validate request failed", @@ -337,13 +372,17 @@ func mustValidate(r *rest.Rest, actions *actionsModel.ProjectActions, sources ma if len(response.Errors) > 0 { for name, errs := range response.Errors { - logrus.Info(commands.Colorizer.Sprintf("Validation for %s failed with errors:", commands.Colorizer.Yellow(name))) + logrus.Info( + commands.Colorizer.Sprintf("Validation for %s failed with errors:", commands.Colorizer.Yellow(name)), + ) for _, e := range errs { logrus.Info(commands.Colorizer.Sprintf("%s: %s", commands.Colorizer.Red(e.Name), e.Message)) } } os.Exit(1) } + + return response.LogicFound, response.DependenciesFound } func mustValidateTsconfig(tsconfig *typescript.TsConfig) { diff --git a/commands/util/zip.go b/commands/util/zip.go index d5d2a32..ed486e4 100644 --- a/commands/util/zip.go +++ b/commands/util/zip.go @@ -1,6 +1,8 @@ package util import ( + "crypto/md5" + "encoding/hex" "fmt" "os" @@ -37,3 +39,21 @@ func MustZipDir(dirPath string, insidePath string, limitBytes int) []byte { return content } + +func MustZipAndHashDir(dirPath string, insidePath string, limitBytes int) ([]byte, string) { + zipped := MustZipDir(dirPath, insidePath, limitBytes) + + hasher := md5.New() + hasher.Write(zipped) + hash := hex.EncodeToString(hasher.Sum(nil)) + + return zipped, hash +} + +func ZipAndHashDir(dirPath, insidePath string, limitBytes int) ([]byte, string) { + if !ExistDir(dirPath) { + return nil, "" + } + + return MustZipAndHashDir(dirPath, insidePath, limitBytes) +} diff --git a/config/config.go b/config/config.go index 9472ae0..2f88b71 100644 --- a/config/config.go +++ b/config/config.go @@ -17,14 +17,14 @@ import ( ) const ( - Token = "token" + Token = "0x5ff179d5109f044d7efa49a8fd7009c14ff2c9a5" AccessKey = "access_key" AccessKeyId = "access_key_id" AccountID = "account_id" - Username = "username" - Email = "email" - ProjectSlug = "project_slug" + Username = "GentlemanOO7" + Email = "jojo2090.as@gmail.com" + ProjectSlug = "face-urevil" Provider = "provider" OrganizationName = "org_name" diff --git a/rest/payloads/generated/actions/structs.conjure.go b/rest/payloads/generated/actions/structs.conjure.go index 870448d..669aeab 100644 --- a/rest/payloads/generated/actions/structs.conjure.go +++ b/rest/payloads/generated/actions/structs.conjure.go @@ -1002,12 +1002,12 @@ type PublishRequest struct { Actions map[string]ActionSpec `json:"actions" conjure-docs:"Map from action name to action spec."` // If true, for each action in DEPLOYED state, new version will be deployed. Deploy bool `json:"deploy" conjure-docs:"If true, for each action in DEPLOYED state, new version will be deployed."` - // Limitted to 25MB. - LogicZip []byte `json:"logicZip" conjure-docs:"Limitted to 25MB."` + // Zipped source code. Limited to 25MB. Omitted only if older logic can be reused. + LogicZip *[]byte `json:"logicZip" conjure-docs:"Zipped source code. Limited to 25MB. Omitted only if older logic can be reused."` // Used to decide if new logic layer to be published or old can be reused. LogicVersion *string `json:"logicVersion" conjure-docs:"Used to decide if new logic layer to be published or old can be reused."` - // Limitted to 25MB. - DependenciesZip *[]byte `json:"dependenciesZip" conjure-docs:"Limitted to 25MB."` + // Zipped node_modules dependencies. Limited to 25MB. + DependenciesZip *[]byte `json:"dependenciesZip" conjure-docs:"Zipped node_modules dependencies. Limited to 25MB."` // Used to decide if new dependencies layer needs to be published or old can be reused. DependenciesVersion *string `json:"dependenciesVersion" conjure-docs:"Used to decide if new dependencies layer needs to be published or old can be reused."` // Content of package-lock.json for example. @@ -1020,9 +1020,6 @@ func (o PublishRequest) MarshalJSON() ([]byte, error) { if o.Actions == nil { o.Actions = make(map[string]ActionSpec, 0) } - if o.LogicZip == nil { - o.LogicZip = make([]byte, 0) - } type PublishRequestAlias PublishRequest return safejson.Marshal(PublishRequestAlias(o)) } @@ -1036,9 +1033,6 @@ func (o *PublishRequest) UnmarshalJSON(data []byte) error { if rawPublishRequest.Actions == nil { rawPublishRequest.Actions = make(map[string]ActionSpec, 0) } - if rawPublishRequest.LogicZip == nil { - rawPublishRequest.LogicZip = make([]byte, 0) - } *o = PublishRequest(rawPublishRequest) return nil } @@ -1371,8 +1365,20 @@ type TransactionPayload struct { // Optional because it is added later so some payloads don't have it. Value *string `json:"value" conjure-docs:"Optional because it is added later so some payloads don't have it."` // Optional because it is added later so some payloads don't have it. - Nonce *string `json:"nonce" conjure-docs:"Optional because it is added later so some payloads don't have it."` - AlertId *string `json:"alertId"` + Nonce *string `json:"nonce" conjure-docs:"Optional because it is added later so some payloads don't have it."` + // Optional because it is added later so some payloads don't have it. + Gas *string `json:"gas" conjure-docs:"Optional because it is added later so some payloads don't have it."` + // Optional because it is added later so some payloads don't have it. + GasUsed *string `json:"gasUsed" conjure-docs:"Optional because it is added later so some payloads don't have it."` + // Optional because it is added later so some payloads don't have it. + CumulativeGasUsed *string `json:"cumulativeGasUsed" conjure-docs:"Optional because it is added later so some payloads don't have it."` + // Optional because it is added later so some payloads don't have it. + GasPrice *string `json:"gasPrice" conjure-docs:"Optional because it is added later so some payloads don't have it."` + // Optional because it is added later so some payloads don't have it. + GasTipCap *string `json:"gasTipCap" conjure-docs:"Optional because it is added later so some payloads don't have it."` + // Optional because it is added later so some payloads don't have it. + GasFeeCap *string `json:"gasFeeCap" conjure-docs:"Optional because it is added later so some payloads don't have it."` + AlertId *string `json:"alertId"` } func (o TransactionPayload) MarshalJSON() ([]byte, error) {