diff --git a/.github/workflows/delete-environment.yml b/.github/workflows/delete-environment.yml new file mode 100644 index 0000000000..c3286d8698 --- /dev/null +++ b/.github/workflows/delete-environment.yml @@ -0,0 +1,40 @@ +name: Delete Environment + +on: + repository_dispatch: + types: [delete-environment] +jobs: + delete-environment: + runs-on: ubuntu-latest + steps: + - name: checks out repository to $GITHUB_WORKSPACE + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup Node Environment + uses: actions/setup-node@v1 + with: + node-version: '12.x' + + - name: Set up workspace experimental + run: | + yarn config set workspaces-experimental true + + - name: Install dependencies + run: | + yarn global add serverless@1.59.3 + yarn add isomorphic-fetch -W + + - name: Remove Serverless + run: | + yarn workspace ${{ github.event.client_payload.package_name }} remove:${{ github.event.client_payload.environment }} + +env: + AWS_REGION: ${{secrets.AWS_REGION}} + AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} + AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} + RELEASE_SLACK_WEB_HOOK_URL: ${{secrets.RELEASE_SLACK_WEB_HOOK_URL}} + CYPRESS_USERNAME: ${{secrets.CYPRESS_USERNAME}} + CYPRESS_PASSWORD: ${{secrets.CYPRESS_PASSWORD}} + NPM_TOKEN: ${{secrets.NPM_TOKEN}} diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index ccaf6afc9b..0689797c9e 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -7,9 +7,6 @@ on: env: NPM_TOKEN: ${{secrets.NPM_TOKEN}} - AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} - AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} - AWS_REGION: ${{secrets.AWS_REGION}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} SENTRY_AUTH_TOKEN: ${{secrets.SENTRY_AUTH_TOKEN}} RELEASE_SLACK_WEB_HOOK_URL: ${{secrets.RELEASE_SLACK_WEB_HOOK_URL}} @@ -56,6 +53,14 @@ jobs: - name: Install dependencies run: yarn install --frozen-lockfile + + - name: Configure AWS credentials to Production + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }} + aws-region: ${{secrets.AWS_REGION}} + - name: Upload Artifact run: | yarn upload-artifact diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 25808d0f2b..090483dc54 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,14 +26,44 @@ jobs: yarn global add serverless@1.59.3 yarn add isomorphic-fetch -W + - name: Configure AWS credentials to production + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }} + aws-region: ${{secrets.AWS_REGION}} + + - name: Fetch artifact from prod + run: | + yarn fetch-artifact ${{ github.event.client_payload.package_name }} ${{ github.event.client_payload.current_tag }} + + - name: Configure AWS credentials by environment + uses: aws-actions/configure-aws-credentials@v1 + if: ${{ github.event.client_payload.environment == 'development' }} + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{secrets.AWS_REGION}} + if: ${{ github.event.client_payload.environment == 'staging' }} + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{secrets.AWS_REGION}} + if: ${{ github.event.client_payload.environment == 'production' }} + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_PROD }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_PROD }} + aws-region: ${{secrets.AWS_REGION}} + + - name: Fetch config + run: | + yarn fetch-config --name ${{ github.event.client_payload.environment }} + - name: Release Production run: | - yarn release ${{ github.event.client_payload.environment }} ${{ github.event.client_payload.package_name }} ${{ github.event.client_payload.current_tag }} ${{ github.event.client_payload.previous_tag }} + yarn release ${{ github.event.client_payload.environment }} ${{ github.event.client_payload.package_name }} ${{ github.event.client_payload.current_tag }} env: - AWS_REGION: ${{secrets.AWS_REGION}} - AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} - AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} RELEASE_SLACK_WEB_HOOK_URL: ${{secrets.RELEASE_SLACK_WEB_HOOK_URL}} CYPRESS_USERNAME: ${{secrets.CYPRESS_USERNAME}} CYPRESS_PASSWORD: ${{secrets.CYPRESS_PASSWORD}} diff --git a/package.json b/package.json index 3af39f5474..834814a551 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "update-release-note": "node ./scripts/release/update-release-note.js", "upload-artifact": "node ./scripts/release/upload-artifact.js", "release": "node ./scripts/release/release.js", + "fetch-artifact": "node ./scripts/release/fetch-artifact.js", "test": "lerna run test:ci --parallel", "test-e2e:ci": "lerna run test-e2e:ci --stream", "update-doc": "node --unhandled-rejections=strict ./scripts/document-update/get-release-and-create-pr.js", @@ -75,8 +76,8 @@ "error-polyfill": "^0.1.2", "graphql": "^14.5.8", "hardtack": "^4.1.2", - "pell": "^1.0.6", "papaparse": "^5.1.1", + "pell": "^1.0.6", "react": "^16.12.0", "react-datepicker": "^2.9.6", "react-dom": "^16.12.0", @@ -110,8 +111,8 @@ "@types/enzyme": "^3.10.3", "@types/enzyme-adapter-react-16": "^1.0.5", "@types/jest": "^24.0.23", - "@types/papaparse": "^5.0.3", "@types/node": "10.17.13", + "@types/papaparse": "^5.0.3", "@types/query-string": "^6.3.0", "@types/react": "^16.9.0", "@types/react-copy-to-clipboard": "^4.3.0", @@ -184,7 +185,10 @@ "serialize-error": "^7.0.1", "serve": "^11.2.0", "serverless": "^1.70.1", + "serverless-deployment-bucket": "^1.1.2", "serverless-plugin-ifelse": "^1.0.5", + "serverless-s3-deploy": "^0.9.0", + "serverless-s3-remover": "^0.6.0", "serverless-single-page-app-plugin": "^1.0.2", "shelljs": "^0.8.4", "start-server-and-test": "^1.11.0", diff --git a/packages/admin-portal/package.json b/packages/admin-portal/package.json index 4cd7060585..af8f7dd8a3 100644 --- a/packages/admin-portal/package.json +++ b/packages/admin-portal/package.json @@ -14,6 +14,10 @@ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", "release:dev": "node ../../scripts/release/release-dev.js admin-portal reapit-admin-portal-dev", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "test-e2e:dev": "cypress open --project './src/tests'", "cypress:ci": "cypress run --project \"./src/tests\"", "test-e2e:ci": "start-server-and-test start:prod http://localhost:8080 cypress:ci", diff --git a/packages/admin-portal/serverless.yml b/packages/admin-portal/serverless.yml index 9cdf1bd073..0549619225 100644 --- a/packages/admin-portal/serverless.yml +++ b/packages/admin-portal/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: admin-portal +service: cloud-admin-portal plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-admin-portal-${self:provider.stage} - + s3WebAppBucket: cloud-admin-portal-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: @@ -108,4 +122,4 @@ resources: Outputs: WebAppCloudFrontDistributionOutput: Value: - 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] \ No newline at end of file + 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] diff --git a/packages/aml-checklist/package.json b/packages/aml-checklist/package.json index 787acbe7b8..cd2257f6ec 100644 --- a/packages/aml-checklist/package.json +++ b/packages/aml-checklist/package.json @@ -17,6 +17,10 @@ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", "release:dev": "node ../../scripts/release/release-dev.js aml-checklist reapit-aml-checklist-dev", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges", "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx,js src\"", "lint:fix": "eslint --cache --ext=ts,tsx,js src --fix", @@ -26,7 +30,6 @@ }, "dependencies": { "@reapit/elements": "^0.5.60", - "@reapit/connect-session": "1.0.0-alpha.1", "@reapit/utils": "^0.0.1", "react-to-print": "^2.4.0", "snyk": "^1.341.1" diff --git a/packages/aml-checklist/serverless.yml b/packages/aml-checklist/serverless.yml index 87f25b8bd6..4d4026d22d 100644 --- a/packages/aml-checklist/serverless.yml +++ b/packages/aml-checklist/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: aml-checklist +service: cloud-aml-checklist plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-aml-checklist-${self:provider.stage} - + s3WebAppBucket: cloud-aml-checklist-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: diff --git a/packages/cognito-custom-mail-lambda/package.json b/packages/cognito-custom-mail-lambda/package.json index c5fc028e7a..65f3680f41 100644 --- a/packages/cognito-custom-mail-lambda/package.json +++ b/packages/cognito-custom-mail-lambda/package.json @@ -11,8 +11,10 @@ "test:dev": "cross-env TZ=UTC jest --watch --verbose", "build:prod": "rimraf dist && tsc --p tsconfig.json && rimraf dist/mailer/templates/ejs && ncp ./src/mailer/templates/ejs ./dist/mailer/templates/ejs", "release:dev": "serverless deploy --stage dev", - "release:development": "serverless deploy --stage prod", + "release:development": "serverless deploy --stage dev", "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges", "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx,js src\"", "lint:fix": "eslint --cache --ext=ts,tsx,js src --fix", diff --git a/packages/connect-session/src/browser/index.ts b/packages/connect-session/src/browser/index.ts index b1a14e7c6a..f946686e47 100644 --- a/packages/connect-session/src/browser/index.ts +++ b/packages/connect-session/src/browser/index.ts @@ -41,7 +41,6 @@ export class ReapitConnectBrowserSession { }` this.fetching = false this.session = null - // this.connectInternalRedirect = null this.connectBindPublicMethods() } diff --git a/packages/deploy-slack-bot/src/index.ts b/packages/deploy-slack-bot/src/index.ts index 9141ad2cd7..7cca66bc1e 100644 --- a/packages/deploy-slack-bot/src/index.ts +++ b/packages/deploy-slack-bot/src/index.ts @@ -64,8 +64,9 @@ export type GenerateMessageParams = { const generateMessage = ({ packageName, environment, currentTag, previousTag }: GenerateMessageParams) => { return { 'release-note': `Generating release note for \`${packageName}\` tag \`${currentTag}\`. Roll back version is \`${previousTag}\``, - release: `Releasing ${environment} \`${packageName}\` environment \`${currentTag}\`. Roll back version is \`${previousTag}\``, + release: `Releasing \`${packageName}\` ${environment} \`${currentTag}\``, 'update-release-note': `Updating release note for \`${packageName}\` tag \`${currentTag}\`.`, + 'delete-environment': `Teardown serverless environment for \`${packageName}\``, } } @@ -88,13 +89,14 @@ app.post('/release', async (req: Request, res: Response) => { \`@Reapit Cloud Releases release-note \` <= The command will generate the release note\n \`@Reapit Cloud Releases release \` <= The command will do the release and environment is development by default\n \`@Reapit Cloud Releases update-release-note \` <= The command will do update the release note in github and document\n +\`@Reapit Cloud Releases delete-environment \` <= The command will do update the release note in github and document\n `) return res.send({ challenge: req.body.challenge, status: 200 }) } - const isValidEnvironment = environment === 'development' || environment === 'production' + const isValidEnvironment = environment === 'development' || environment === 'production' || environment === 'staging' if (!isValidEnvironment) { - await sendMessageToSlack('Environment should be production or development') + await sendMessageToSlack('Environment should be development, staging or production') return res.send({ challenge: req.body.challenge, status: 200 }) } diff --git a/packages/developer-portal/package.json b/packages/developer-portal/package.json index a38c3e2564..fa4951c00e 100644 --- a/packages/developer-portal/package.json +++ b/packages/developer-portal/package.json @@ -14,6 +14,10 @@ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", "release:dev": "node ../../scripts/release/release-dev.js developer-portal reapit-developer-portal-dev", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "test-e2e:dev": "cypress open --project './src/tests'", "cypress:ci": "cypress run --project \"./src/tests\"", "test-e2e:ci": "start-server-and-test start:prod http://localhost:8080 cypress:ci", diff --git a/packages/developer-portal/serverless.yml b/packages/developer-portal/serverless.yml index e431a7b02e..3b7b66e911 100644 --- a/packages/developer-portal/serverless.yml +++ b/packages/developer-portal/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: developer-portal +service: cloud-developer-portal plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-developer-portal-${self:provider.stage} - + s3WebAppBucket: cloud-developer-portal-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: diff --git a/packages/geo-diary-v2/package.json b/packages/geo-diary-v2/package.json index 03403c278e..33f98c47b6 100644 --- a/packages/geo-diary-v2/package.json +++ b/packages/geo-diary-v2/package.json @@ -14,15 +14,17 @@ "build:prod": "rimraf public/dist && webpack --config ../../scripts/webpack/webpack.pwa.prod.js", "fetch-config": "yarn config-manager --namespace cloud --entity geo-diary-v2 --name local --mode fetch", "release:dev": "node ../../scripts/release/release-dev.js geo-diary-v2 reapit-geo-diary-v2-dev", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "start:dev": "webpack-dev-server --hot --progress --color --mode development --config ../../scripts/webpack/webpack.config.dev.js", "start:prod": "serve public/dist -s -l 8080", "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx,js src\"", "lint:fix": "eslint --cache --ext=ts,tsx,js src --fix", "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", - "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges", - "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx src\"", - "lint:fix": "lerna run lint:fix --parallel --stream --since master --include-dependencies --" + "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges" }, "dependencies": { "@reapit/connect-session": "1.0.0-alpha.1", diff --git a/packages/geo-diary-v2/serverless.yml b/packages/geo-diary-v2/serverless.yml index 48fc98ca13..85f31b20b8 100644 --- a/packages/geo-diary-v2/serverless.yml +++ b/packages/geo-diary-v2/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: geo-diary-v2 +service: cloud-geo-diary plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-geo-diary-v2-${self:provider.stage} - + s3WebAppBucket: cloud-geo-diary-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -74,9 +88,9 @@ resources: # Aliases: # If: '"${opt:stage, 'dev'}" == "dev"' # Set: - # - dev.geo-diary-v2.reapit.cloud + # - dev.geo-diary.reapit.cloud # ElseSet: - # - geo-diary-v2.reapit.cloud + # - geo-diary.reapit.cloud DefaultRootObject: index.html CustomErrorResponses: - ErrorCode: 404 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: @@ -108,4 +122,4 @@ resources: Outputs: WebAppCloudFrontDistributionOutput: Value: - 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] \ No newline at end of file + 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] diff --git a/packages/graphql-server/package.json b/packages/graphql-server/package.json index 55a319fe3b..695d5d63cc 100644 --- a/packages/graphql-server/package.json +++ b/packages/graphql-server/package.json @@ -14,6 +14,8 @@ "release:dev": "yarn build:schema && serverless deploy --stage dev", "release:development": "yarn build:schema && serverless deploy --stage dev", "release:production": "yarn build:schema && serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "start:dev": "yarn build:schema && serverless offline --stage local --printOutput", "start:prod": "node ./dist/app.js", "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", @@ -24,9 +26,9 @@ "prepublish": "npm run snyk-protect" }, "dependencies": { + "@reapit/cognito-auth": "^2.1.7", "@reapit/elements": "^0.5.60", "@reapit/foundations-ts-definitions": "2020-03-04", - "@reapit/cognito-auth": "^2.1.7", "@reapit/utils": "^0.0.1", "apollo-server-lambda": "2.10.1", "axios": "^0.19.2", @@ -40,10 +42,10 @@ "lodash.merge": "^4.6.2", "merge-graphql-schemas": "^1.7.6", "query-string": "^6.13.0", + "snyk": "^1.341.1", "tslib": "2.0.0", "uuid": "^3.3.3", - "winston": "^3.2.1", - "snyk": "^1.341.1" + "winston": "^3.2.1" }, "devDependencies": { "@babel/core": "^7.8.4", diff --git a/packages/graphql-server/serverless.yml b/packages/graphql-server/serverless.yml index ffecf693f8..13e0e790a8 100644 --- a/packages/graphql-server/serverless.yml +++ b/packages/graphql-server/serverless.yml @@ -2,8 +2,15 @@ service: graphql-server plugins: - serverless-webpack - serverless-offline + - serverless-deployment-bucket + - serverless-s3-remover + custom: + s3DeployBucket: cloud-graphql-server env: ${file(./config.json)} + remover: + buckets: + - ${self:custom.s3DeployBucket} webpack: webpackConfig: 'webpack.config.js' includeModules: true @@ -17,10 +24,12 @@ provider: name: aws runtime: nodejs12.x stage: ${opt:stage, 'dev'} + endpointType: REGIONAL region: eu-west-2 deploymentBucket: - name: graphql-server.${self:provider.stage} + name: ${self:custom.s3DeployBucket} blockPublicAccess: false + environment: NODE_ENV: 'production' COGNITO_USERPOOL_ID: ${self:custom.env.COGNITO_USERPOOL_ID} diff --git a/packages/graphql-server/src/resolvers/departments/types.graphql b/packages/graphql-server/src/resolvers/departments/types.graphql index c7f16119b1..9c9f96f9df 100644 --- a/packages/graphql-server/src/resolvers/departments/types.graphql +++ b/packages/graphql-server/src/resolvers/departments/types.graphql @@ -30,4 +30,3 @@ type Query { GetDepartments(pageSize: Int, pageNumber: Int, id: [String!], name: String): PagedResultDepartmentModel_! GetDepartmentById(id: String!): DepartmentModel! } - diff --git a/packages/marketplace/package.json b/packages/marketplace/package.json index 01cecf71e1..af26da372c 100644 --- a/packages/marketplace/package.json +++ b/packages/marketplace/package.json @@ -14,6 +14,10 @@ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", "release:dev": "node ../../scripts/release/release-dev.js marketplace reapit-app-store", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "test-e2e:dev": "cypress open --project './src/tests'", "cypress:ci": "cypress run --project \"./src/tests\"", "test-e2e:ci": "start-server-and-test start:prod http://localhost:8080 cypress:ci", diff --git a/packages/marketplace/serverless.yml b/packages/marketplace/serverless.yml index 98b57a4c1e..18b96dd5c2 100644 --- a/packages/marketplace/serverless.yml +++ b/packages/marketplace/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: marketplace +service: cloud-marketplace plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-marketplace-${self:provider.stage} - + s3WebAppBucket: cloud-marketplace-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: diff --git a/packages/reapit-connect/package.json b/packages/reapit-connect/package.json index 563079a232..35c882fa19 100644 --- a/packages/reapit-connect/package.json +++ b/packages/reapit-connect/package.json @@ -17,6 +17,10 @@ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", "release:dev": "cross-env IS_RELEASE=false node ../../scripts/release/release-dev.js reapit-connect reapit-reapit-connect-dev", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "test:update-badges": "yarn test:ci && jest-coverage-badges --input src/tests/coverage/coverage-summary.json --output src/tests/badges", "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx,js src\"", "lint:fix": "eslint --cache --ext=ts,tsx,js src --fix", diff --git a/packages/reapit-connect/serverless.yml b/packages/reapit-connect/serverless.yml index 8a1e769ed0..d95cc28718 100644 --- a/packages/reapit-connect/serverless.yml +++ b/packages/reapit-connect/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: reapit-connect +service: cloud-reapit-connect plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-reapit-connect-${self:provider.stage} - + s3WebAppBucket: cloud-reapit-connect-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: @@ -108,4 +122,4 @@ resources: Outputs: WebAppCloudFrontDistributionOutput: Value: - 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] \ No newline at end of file + 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] diff --git a/packages/smb-onboarder/package.json b/packages/smb-onboarder/package.json index e533309bf9..f0d86f84c9 100644 --- a/packages/smb-onboarder/package.json +++ b/packages/smb-onboarder/package.json @@ -17,6 +17,10 @@ "test:ci": "cross-env TZ=UTC jest --ci --colors --coverage --silent --forceExit --detectOpenHandles --runInBand", "test:dev": "cross-env TZ=UTC jest --watch --verbose", "release:dev": "node ../../scripts/release/release-dev.js smb-onboarder reapit-smb-dev", + "release:development": "serverless deploy --stage dev", + "release:production": "serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "lint": "concurrently \"tsc --noEmit\" \"eslint --cache --ext=ts,tsx,js src\"", "lint:fix": "eslint --cache --ext=ts,tsx,js src --fix", "test-e2e:dev": "cypress open --project './src/tests'", diff --git a/packages/smb-onboarder/serverless.yml b/packages/smb-onboarder/serverless.yml index ffffe8fbf0..06001c8bc6 100644 --- a/packages/smb-onboarder/serverless.yml +++ b/packages/smb-onboarder/serverless.yml @@ -1,18 +1,32 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: smb-onboarder +service: cloud-smb-onboarder plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-smb-onboarder-${self:provider.stage} - + s3WebAppBucket: cloud-smb-onboarder-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws runtime: nodejs10.x stage: ${opt:stage, 'dev'} region: eu-west-2 + deploymentBucket: + name: ${self:custom.s3CloudFormBucket} resources: Resources: @@ -20,7 +34,7 @@ resources: WebAppS3Bucket: Type: AWS::S3::Bucket Properties: - BucketName: ${self:custom.s3Bucket} + BucketName: ${self:custom.s3WebAppBucket} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html @@ -61,7 +75,7 @@ resources: ".s3.amazonaws.com" ] ] - Id: S3-${self:custom.s3Bucket} + Id: S3-${self:custom.s3WebAppBucket} CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 @@ -74,9 +88,9 @@ resources: # Aliases: # If: '"${opt:stage, 'dev'}" == "dev"' # Set: - # - dev.smb-app.reapit.cloud + # - dev.smb-onboarder.reapit.cloud # ElseSet: - # - smb-app.reapit.cloud + # - smb-onboarder.reapit.cloud DefaultRootObject: index.html CustomErrorResponses: - ErrorCode: 404 @@ -93,7 +107,7 @@ resources: - GET - HEAD - OPTIONS - TargetOriginId: S3-${self:custom.s3Bucket} + TargetOriginId: S3-${self:custom.s3WebAppBucket} ForwardedValues: QueryString: 'false' Cookies: @@ -108,4 +122,4 @@ resources: Outputs: WebAppCloudFrontDistributionOutput: Value: - 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] \ No newline at end of file + 'Fn::GetAtt': [ WebAppCloudFrontDistribution, DomainName ] diff --git a/packages/web-components-config-server/package.json b/packages/web-components-config-server/package.json index ffd20e66f1..61cb135c0f 100644 --- a/packages/web-components-config-server/package.json +++ b/packages/web-components-config-server/package.json @@ -17,6 +17,8 @@ "release:dev": "yarn build:credentials && serverless deploy --stage dev", "release:development": "yarn build:credentials && serverless deploy --stage dev", "release:production": "yarn build:credentials && serverless deploy --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "fetch-config": "yarn config-manager --namespace cloud --entity web-components-config-server --name local --mode fetch", "snyk-protect": "snyk protect", "prepublish": "npm run snyk-protect", diff --git a/packages/web-components/package.json b/packages/web-components/package.json index 000cf67047..2d21d417eb 100644 --- a/packages/web-components/package.json +++ b/packages/web-components/package.json @@ -76,6 +76,8 @@ "release:dev": "node ./scripts/release-serverless.js --stage dev && node ../../scripts/release/release-dev.js web-components reapit-web-components", "release:development": "node ./scripts/release-serverless.js --stage dev", "release:production": "node ./scripts/release-serverless.js --stage prod", + "remove:development": "serverless remove --stage dev", + "remove:production": "serverless remove --stage dev", "snyk-protect": "snyk protect", "prepublish": "npm run snyk-protect" }, diff --git a/scripts/release/fetch-artifact.js b/scripts/release/fetch-artifact.js new file mode 100644 index 0000000000..ac3b1a4e9a --- /dev/null +++ b/scripts/release/fetch-artifact.js @@ -0,0 +1,26 @@ +const { WEB_APPS, sendMessageToSlack } = require('./utils') +const execSync = require('child_process').execSync + +const fetchCachedTarFile = async () => { + const [, , ...args] = process.argv + const packageName = args[0] + const currentTag = args[1] + + if (WEB_APPS.includes(packageName)) { + try { + const fileName = `${currentTag}.tar.gz` + await sendMessageToSlack( + `Pulling the artifact \`${currentTag}\` from S3 bucket \`cloud-deployments-releases-cache-prod\``, + ) + const copyArtifactResult = execSync( + `aws s3 cp s3://cloud-deployments-releases-cache-prod/${fileName} ./packages/${packageName}/public`, + ).toString() + console.info(copyArtifactResult) + } catch (err) { + console.error('fetchArtifact', err) + throw new Error(err) + } + } +} + +fetchCachedTarFile() diff --git a/scripts/release/release-dev.js b/scripts/release/release-dev.js index a3a72f491b..c9dde93dd7 100644 --- a/scripts/release/release-dev.js +++ b/scripts/release/release-dev.js @@ -26,7 +26,7 @@ const releaseDev = () => { console.info(copyWithCache) // cp index.html and sw.js with no-cache control const copyWithNoCache = execSync( - `aws s3 cp ${distPath} s3://${bucketName} --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --recursive --exclude "*" --include "sw.js" --include "index.html" --include "config.json"`, + `aws s3 cp ${distPath} s3://${bucketName} --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --recursive --exclude "*" --include "sw.js" --include "index.html" --include "config.json" --cache-control "no-store"`, ).toString() console.info(copyWithNoCache) } catch (err) { diff --git a/scripts/release/release.js b/scripts/release/release.js index ea90d94304..955e9a222c 100644 --- a/scripts/release/release.js +++ b/scripts/release/release.js @@ -1,5 +1,6 @@ const { releaseWebApp, + releaseNewWebApp, sendMessageToSlack, releaseNpm, releaseServerless, @@ -14,7 +15,7 @@ const release = async () => { const env = args[0] const packageName = args[1] const currentTag = args[2] - const previousTag = args[3] + // Get Bucket name const bucketName = BUCKET_NAMES && BUCKET_NAMES[env] && BUCKET_NAMES[env][packageName] const isValidParams = !!packageName && !!currentTag if (!isValidParams) { @@ -28,30 +29,57 @@ const release = async () => { if (SERVERLESS_APPS.includes(packageName)) { try { - const isValidParamsServerless = isValidParams && !!previousTag && !!env + const isValidParamsServerless = isValidParams && !!env if (!isValidParamsServerless) { console.error('release params is not valid for packageName or currentTag or previousTag') process.exit(1) } releaseServerless({ tagName: currentTag, packageName, env }) } catch (err) { - await sendMessageToSlack(`Rolling back for serverless \`${packageName}\` with version \`${previousTag}\``) - releaseServerless({ tagName: previousTag, packageName, env }) + await sendMessageToSlack(`Deploy \`${packageName}\` version \`${currentTag}\` failed`) throw new Error(err) } } - if (WEB_APPS.includes(packageName)) { + if (WEB_APPS.includes(packageName) && env === 'production') { try { - const isValidWebApp = isValidParams && !!previousTag && !!env && !!bucketName + const isValidWebApp = isValidParams && !!env + if (!isValidWebApp) { + console.error('release params is not valid for packageName or currentTag or previousTag') + process.exit(1) + } + releaseNewWebApp({ tagName: currentTag, packageName, env }) + } catch (err) { + await sendMessageToSlack(`Deploy \`${packageName}\` version \`${currentTag}\` failed`) + throw new Error(err) + } + } + + if (WEB_APPS.includes(packageName) && env === 'staging') { + try { + const isValidWebApp = isValidParams && !!env && !!bucketName + if (!isValidWebApp) { + console.error('release params is not valid for packageName or currentTag or previousTag') + process.exit(1) + } + releaseWebApp({ tagName: currentTag, bucketName, packageName, env }) + } catch (err) { + await sendMessageToSlack(`Deploy \`${packageName}\` version \`${currentTag}\` failed`) + throw new Error(err) + } + } + + if (WEB_APPS.includes(packageName) && env === 'development') { + try { + const isValidWebApp = isValidParams && !!env && !!bucketName if (!isValidWebApp) { console.error('release params is not valid for packageName or currentTag or previousTag') process.exit(1) } releaseWebApp({ tagName: currentTag, bucketName, packageName, env }) + releaseNewWebApp({ tagName: currentTag, packageName, env }) } catch (err) { - await sendMessageToSlack(`Rolling back for web-app \`${packageName}\` with version \`${previousTag}\``) - releaseWebApp({ tagName: previousTag, bucketName, packageName, env }) + await sendMessageToSlack(`Deploy \`${packageName}\` version \`${currentTag}\` failed`) throw new Error(err) } } diff --git a/scripts/release/upload-artifact.js b/scripts/release/upload-artifact.js index 124cb413b6..561dff73a9 100644 --- a/scripts/release/upload-artifact.js +++ b/scripts/release/upload-artifact.js @@ -10,7 +10,7 @@ const uploadArtifact = async () => { workspaceName = '@reapit/elements' } try { - const fetchConfigResult = execSync(`yarn workspace ${workspaceName} fetch-config development`).toString() + const fetchConfigResult = execSync(`yarn workspace ${workspaceName} fetch-config --name production`).toString() console.info(fetchConfigResult) const lintResult = execSync(`yarn workspace ${workspaceName} lint`).toString() console.info(lintResult) @@ -23,7 +23,7 @@ const uploadArtifact = async () => { ).toString() console.info(resultTarFile) const copyS3Result = execSync( - `aws s3 cp ${fileName} s3://cloud-release-artifact --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers`, + `aws s3 cp ${fileName} s3://cloud-deployments-releases-cache-prod --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers`, ).toString() console.info(copyS3Result) await sendMessageToSlack(`Finish build \`${packageName}\` with file \`${fileName}\``) diff --git a/scripts/release/utils.js b/scripts/release/utils.js index 63abfa6b77..4a90e36b76 100644 --- a/scripts/release/utils.js +++ b/scripts/release/utils.js @@ -1,12 +1,8 @@ require('isomorphic-fetch') const spawn = require('child_process').spawnSync const execSync = require('child_process').execSync -const AWS = require('aws-sdk') -const fs = require('fs') const path = require('path') -const RELEASE_ARTIFACT_FOLDER_NAME = 'dist' - const removeUnuseChar = value => { if (!value) { return '' @@ -68,29 +64,49 @@ const sendMessageToSlack = async message => { } } -const fetchConfig = ({ packageName, env }) => { - const isValidParams = !!packageName && !!env - if (!isValidParams) { - console.error('fetchConfig params is not valid for packageName or env') - process.exit(1) +const extractTarFile = async ({ tagName, packageName }) => { + try { + const fileName = `${tagName}.tar.gz` + const tarDistResult = execSync( + `tar -C ./packages/${packageName}/public -xzvf ./packages/${packageName}/public/${fileName}`, + ).toString() + console.info(tarDistResult) + } catch (err) { + console.error('releaseWebApp', err) + throw new Error(err) } - const ssm = new AWS.SSM() - return new Promise((resolve, reject) => { - ssm.getParameter({ Name: `${packageName}-${env}`, WithDecryption: false }, (err, data) => { - if (err) { - console.error('Something went wrong when fetch the config.json') - console.error(err, err.stack) - reject(err) - } - const config = (data && data.Parameter && data.Parameter.Value) || {} - resolve(config) - }) - }) } -const syncFromLocalDistToS3Bucket = ({ bucketName }) => { +const copyConfig = ({ packageName }) => { + const destinationFolder = `${process.cwd()}/packages/${packageName}/public/dist` + const configFilePath = `${process.cwd()}/packages/${packageName}/config.json` + const copyConfigResult = execSync(`cp ${configFilePath} ${destinationFolder}`).toString() + console.info(copyConfigResult) +} + +const runReleaseCommand = async ({ packageName, tagName, env }) => { + await sendMessageToSlack(`Deploying for web app \`${packageName}\` with version \`${tagName}\``) + const realeaseResult = execSync(`yarn workspace ${packageName} release:${env}`).toString() + console.info(realeaseResult) + await sendMessageToSlack(`Finish the deployment for web app \`${packageName}\` with version \`${tagName}\``) +} + +const runTestCyPress = async ({ packageName, tagName, env }) => { + await sendMessageToSlack(`Testing cypress for web app \`${packageName}\` with version \`${tagName}\``) + const cypressTest = execSync( + `yarn workspace cloud-alert cypress:ci --env ENVIRONMENT=${env},PACKAGE_NAME=${packageName}`, + ).toString() + console.log(cypressTest) + await sendMessageToSlack(`Finish testing cypress for web app \`${packageName}\` with version \`${tagName}\``) +} + +/** + * @deprecated + * This function will be remove after finish migration to new cloud + */ +const syncFromLocalDistToS3Bucket = ({ bucketName, packageName }) => { try { - const distPath = path.resolve(process.cwd(), RELEASE_ARTIFACT_FOLDER_NAME) + const distPath = `${process.cwd()}/packages/${packageName}/public/dist` // cp all assert with cache-control 365 days exclude sw.js and index.html const copyWithCache = execSync( `aws s3 cp ${distPath} s3://${bucketName} --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --recursive --exclude "index.html" --exclude "sw.js" --exclude "config.json" --cache-control "no-store"`, @@ -108,71 +124,59 @@ const syncFromLocalDistToS3Bucket = ({ bucketName }) => { } } +/** + * @deprecated + * This function will be remove after finish migration to new cloud + */ const releaseWebApp = async ({ tagName, bucketName, packageName, env }) => { + // This is temporary fix for deployment to new prod and old prod env + if (env === 'staging') { + env = 'production' + } try { - const fileName = `${tagName}.tar.gz` - await sendMessageToSlack(`Pulling the artifact \`${tagName}\` from S3 bucket \`cloud-release-artifact\``) - const copyArtifactResult = execSync(`aws s3 cp s3://cloud-release-artifact/${fileName} .`).toString() - console.info(copyArtifactResult) - await sendMessageToSlack(`Extracting the artifact \`${tagName}\` from \`${fileName}\``) - const tarDistResult = execSync(`tar -xzvf ${fileName}`).toString() - console.info(tarDistResult) - await sendMessageToSlack(`Fetching the config \`${packageName}-${env}\``) - const config = await fetchConfig({ packageName, env }) - fs.writeFileSync(`${process.cwd()}/${RELEASE_ARTIFACT_FOLDER_NAME}/config.json`, config) + await extractTarFile({ tagName, packageName }) + await copyConfig({ packageName }) await sendMessageToSlack(`Deploying for web app \`${packageName}\` with version \`${tagName}\``) - syncFromLocalDistToS3Bucket({ bucketName }) + await syncFromLocalDistToS3Bucket({ bucketName, packageName }) await sendMessageToSlack(`Finish the deployment for web app \`${packageName}\` with version \`${tagName}\``) - await sendMessageToSlack(`Testing cypress for web app \`${packageName}\` with version \`${tagName}\``) - const cypressTest = execSync( - `yarn workspace cloud-alert cypress:ci --env ENVIRONMENT=${env},PACKAGE_NAME=${packageName}`, - ).toString() - console.log(cypressTest) - await sendMessageToSlack(`Finish testing cypress for web app \`${packageName}\` with version \`${tagName}\``) + await runTestCyPress({ packageName, tagName, env }) } catch (err) { console.error('releaseWebApp', err) throw new Error(err) } } +const releaseNewWebApp = async ({ tagName, packageName, env }) => { + try { + await extractTarFile({ tagName, packageName }) + await copyConfig({ packageName }) + await runReleaseCommand({ packageName, tagName, env }) + await runTestCyPress({ packageName, tagName, env }) + } catch (err) { + console.error('releaseNewWebApp', err) + throw new Error(err) + } +} + const releaseServerless = async ({ tagName, packageName, env }) => { + // This is temporary fix for deployment to new prod and old prod env + if (env === 'staging') { + env = 'production' + } try { await sendMessageToSlack(`Checking out for \`${packageName}\` with version \`${tagName}\``) const checkoutResult = execSync(`git checkout ${tagName}`).toString() console.info(checkoutResult) - await sendMessageToSlack(`Deploying for serverless \`${packageName}\` with version \`${tagName}\``) const isReleaseWebComponentPackage = WEB_COMPONENTS_SERVERLESS_APPS.includes(packageName) if (isReleaseWebComponentPackage) { - await sendMessageToSlack(`Fetching the config \`${packageName}-${env}\``) - const fetchConfigResult = execSync(`yarn workspace @reapit/web-components fetch-config ${env}`).toString() - console.info(fetchConfigResult) - const realeaseResult = execSync( - `yarn workspace @reapit/web-components release:${env} --name ${packageName}`, - ).toString() - console.info(realeaseResult) - await sendMessageToSlack(`Finish the deploy for serverless \`${packageName}\` with version \`${tagName}\``) - await sendMessageToSlack(`Testing cypress for serverless \`${packageName}\` with version \`${tagName}\``) - const cypressTest = execSync( - `yarn workspace cloud-alert cypress:ci --env ENVIRONMENT=${env},PACKAGE_NAME=${packageName}`, - ).toString() - console.log(cypressTest) - await sendMessageToSlack(`Finish testing cypress for serverless \`${packageName}\` with version \`${tagName}\``) + await copyConfig({ packageName: 'web-components' }) + await runReleaseCommand({ packageName: '@reapit/web-components', tagName, env }) + await runTestCyPress({ packageName, tagName, env }) return } - - await sendMessageToSlack(`Fetching the config \`${packageName}-${env}\``) - const fetchConfigResult = execSync(`yarn workspace ${packageName} fetch-config ${env}`).toString() - console.info(fetchConfigResult) - - const realeaseResult = execSync(`yarn workspace ${packageName} release:${env}`).toString() - console.info(realeaseResult) - await sendMessageToSlack(`Finish the deploy for serverless \`${packageName}\` with version \`${tagName}\``) - await sendMessageToSlack(`Testing cypress for serverless \`${packageName}\` with version \`${tagName}\``) - const cypressTest = execSync( - `yarn workspace cloud-alert cypress:ci --env ENVIRONMENT=${env},PACKAGE_NAME=${packageName}`, - ).toString() - console.log(cypressTest) - await sendMessageToSlack(`Finish testing cypress for serverless \`${packageName}\` with version \`${tagName}\``) + await copyConfig({ packageName }) + await runReleaseCommand({ packageName, tagName, env }) + await runTestCyPress({ packageName, tagName, env }) return } catch (err) { console.error('releaseServerless', err) @@ -265,7 +269,7 @@ const getCommitLog = ({ currentTag, previousTag, packageName }) => { } const BUCKET_NAMES = { - production: { + staging: { 'admin-portal': 'reapit-admin-portal-prod', 'developer-portal': 'reapit-developer-portal-prod', 'aml-checklist': 'reapit-aml-checklist-prod', @@ -326,6 +330,28 @@ const SERVERLESS_APPS = [ ...WEB_COMPONENTS_SERVERLESS_APPS, ] +const NEW_PROD_SERVERLESS_APPS = [ + 'cognito-custom-mail-lambda', + 'deploy-slack-bot', + 'graphql-server', + 'web-components-config-server', + ...WEB_COMPONENTS_SERVERLESS_APPS, + 'admin-portal', + 'developer-portal', + 'aml-checklist', + 'demo-site', + 'elements', + 'geo-diary', + 'geo-diary-v2', + 'lifetime-legal', + 'marketplace', + 'site-builder', + 'smb-onboarder', + 'web-components', + 'elements-next', + 'reapit-connect', +] + const NPM_APPS = [ 'cognito-auth', 'config-manager', @@ -342,7 +368,6 @@ module.exports = { removeUnuseChar, getVersionTag, syncFromLocalDistToS3Bucket, - fetchConfig, releaseWebApp, releaseServerless, releaseNpm, @@ -353,6 +378,8 @@ module.exports = { WEB_APPS, SERVERLESS_APPS, NPM_APPS, + NEW_PROD_SERVERLESS_APPS, formatReleaseNote, getCommitLog, + releaseNewWebApp, } diff --git a/scripts/serverless-template-generator/webapp.ejs b/scripts/serverless-template-generator/webapp.ejs index dc9a85e135..e32b510177 100644 --- a/scripts/serverless-template-generator/webapp.ejs +++ b/scripts/serverless-template-generator/webapp.ejs @@ -1,12 +1,25 @@ # https://www.npmjs.com/package/serverless-single-page-app-plugin -service: <%= appName %> +service: cloud-<%= appName %> plugins: - serverless-single-page-app-plugin - serverless-plugin-ifelse + - serverless-s3-remover + - serverless-s3-deploy custom: - s3Bucket: reapit-<%= appName %>-${self:provider.stage} + s3Bucket: cloud-<%= appName %>-web-app-${opt:stage, 'dev'} + s3CloudFormBucket: cloud-deployment-cloudform-templates-${opt:stage, 'dev'} + remover: + buckets: + - ${self:custom.s3WebAppBucket} + assets: + auto: true + targets: + - bucket: ${self:custom.s3WebAppBucket} + files: + - source: ./public/dist/ + globs: '**/*' provider: name: aws diff --git a/yarn.lock b/yarn.lock index ab7f91c1bb..b9bcbc641b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9181,7 +9181,7 @@ async-retry@^1.2.1: dependencies: retry "0.12.0" -async@0.9.x: +async@0.9.x, async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= @@ -9203,6 +9203,11 @@ async@^3.1.0, async@^3.2.0: resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== +async@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" + integrity sha1-+PwEyjoTeErenhZBr5hXjPvWR6k= + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -11695,7 +11700,7 @@ colornames@^1.1.1: resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= -colors@1.0.3: +colors@1.0.3, colors@1.0.x: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= @@ -12840,6 +12845,11 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +cycle@1.0.x: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" + integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= + cyclist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" @@ -13194,6 +13204,11 @@ deep-equal@^1.0.1, deep-equal@^1.1.0, deep-equal@^1.1.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deep-equal@~0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-0.2.2.tgz#84b745896f34c684e98f2ce0e42abaf43bba017d" + integrity sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0= + deep-extend@0.6.0, deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -15644,6 +15659,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= +eyes@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -17412,6 +17432,14 @@ github-username@^3.0.0: dependencies: gh-got "^5.0.0" +glob-all@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.2.1.tgz#082ca81afd2247cbd3ed2149bb2630f4dc877d95" + integrity sha512-x877rVkzB3ipid577QOp+eQCR6M5ZyiwrtaYgrX/z3EThaSPFtLDwBXFHc3sH1cG0R0vFYI5SRYeWMMSEyXkUw== + dependencies: + glob "^7.1.2" + yargs "^15.3.1" + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -18727,6 +18755,11 @@ hyphenate-style-name@^1.0.0: resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48" integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ== +i@0.3.x: + version "0.3.6" + resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" + integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= + iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.11, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -19994,7 +20027,7 @@ isomorphic-ws@^4.0.1: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -isstream@~0.1.2: +isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= @@ -23928,7 +23961,7 @@ mime-types@2.1.18: dependencies: mime-db "~1.33.0" -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.27" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== @@ -24188,7 +24221,7 @@ mkdirp@0.5.1: dependencies: minimist "0.0.8" -mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.x, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -24474,6 +24507,11 @@ nconf@^0.10.0: secure-keys "^1.0.0" yargs "^3.19.0" +ncp@1.0.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" + integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY= + ncp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" @@ -26388,6 +26426,16 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" +pkginfo@0.3.x: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" + integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= + +pkginfo@0.x.x: + version "0.4.1" + resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" + integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= + please-upgrade-node@^3.1.1, please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -27113,6 +27161,18 @@ promise.prototype.finally@^3.1.0: dependencies: asap "~2.0.3" +prompt@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prompt/-/prompt-1.0.0.tgz#8e57123c396ab988897fb327fd3aedc3e735e4fe" + integrity sha1-jlcSPDlquYiJf7Mn/Trtw+c15P4= + dependencies: + colors "^1.1.2" + pkginfo "0.x.x" + read "1.0.x" + revalidator "0.1.x" + utile "0.3.x" + winston "2.1.x" + prompts@^2.0.1, prompts@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" @@ -28466,7 +28526,7 @@ read-pkg@^5.0.0, read-pkg@^5.1.1, read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -read@1, read@^1.0.7, read@~1.0.1: +read@1, read@1.0.x, read@^1.0.7, read@~1.0.1: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= @@ -29405,6 +29465,11 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +revalidator@0.1.x: + version "0.1.8" + resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" + integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= + rgb-regex@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" @@ -29422,7 +29487,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: +rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -30144,6 +30209,13 @@ serve@^11.2.0: serve-handler "6.1.3" update-check "1.5.2" +serverless-deployment-bucket@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/serverless-deployment-bucket/-/serverless-deployment-bucket-1.1.2.tgz#26270412a6467db63604726363a39695d160c66f" + integrity sha512-jMjl6nCi67/LnV4a2ZYWm6K8DhV7oHoy41WOB35VCM5dvZF8zIe6KG2mDQNJdlgmAt2Eu2N1cA18uFpt9jAqdw== + dependencies: + chalk "^2.4.2" + serverless-http@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/serverless-http/-/serverless-http-2.5.0.tgz#3fb3edbf1d1ab5cff966ef9fe14500506f05ef89" @@ -30209,6 +30281,23 @@ serverless-plugin-ifelse@^1.0.5: resolved "https://registry.yarnpkg.com/serverless-plugin-ifelse/-/serverless-plugin-ifelse-1.0.5.tgz#38d43bfd4fe01bc47105d6aec6ca8614f8355f8d" integrity sha512-NsL+DASRYNmExAPIqrR4G3QDPFmiLl//22r/tJ16iJVJpAhCgVR1g9sG3qhYUvS3xRgeRV+rqnNfCu8GU3RQyQ== +serverless-s3-deploy@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/serverless-s3-deploy/-/serverless-s3-deploy-0.9.0.tgz#9d5c717a5a8aa97c193d2a843c925a5c1e19cb16" + integrity sha512-SlpWTTxikPq+22wxmdWFBeh+8vN+Qr2JwMZIlDPHpdUuIukX9OOozUtah8sFUZY/EovZ22TYwBPJUAer6ZJyHA== + dependencies: + bluebird "^3.5.1" + glob-all "^3.1.0" + mime-types "^2.1.18" + +serverless-s3-remover@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/serverless-s3-remover/-/serverless-s3-remover-0.6.0.tgz#634c65d5085bb30de53c384ba41df57e92e193ac" + integrity sha512-gwyqBLqcvru4csJ1IxrwJTgCrFIRkBl81EoqwsIRwV5+O+CUPTPlu3pR/4+aqTNbcaA/xykvfYCU9E9jt8hI0A== + dependencies: + chalk "^2.1.0" + prompt "^1.0.0" + serverless-single-page-app-plugin@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/serverless-single-page-app-plugin/-/serverless-single-page-app-plugin-1.0.2.tgz#6f714ab7506d44b2cbd4f3c68d1a6c2030b7b7b8" @@ -34085,6 +34174,18 @@ utila@^0.4.0, utila@~0.4: resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= +utile@0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/utile/-/utile-0.3.0.tgz#1352c340eb820e4d8ddba039a4fbfaa32ed4ef3a" + integrity sha1-E1LDQOuCDk2N26A5pPv6oy7U7zo= + dependencies: + async "~0.9.0" + deep-equal "~0.2.1" + i "0.3.x" + mkdirp "0.x.x" + ncp "1.0.x" + rimraf "2.x.x" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -34846,6 +34947,19 @@ winston-transport@^4.4.0: readable-stream "^2.3.7" triple-beam "^1.2.0" +winston@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.1.1.tgz#3c9349d196207fd1bdff9d4bc43ef72510e3a12e" + integrity sha1-PJNJ0ZYgf9G9/51LxD73JRDjoS4= + dependencies: + async "~1.0.0" + colors "1.0.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + pkginfo "0.3.x" + stack-trace "0.0.x" + winston@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07"