From 09ef26106a5b092e77a3a1daa892e88c71eddf4d Mon Sep 17 00:00:00 2001 From: tangoyankee Date: Wed, 11 Sep 2024 15:38:13 -0400 Subject: [PATCH] Configure deployment workflow Support deployments from main Deploy to heroku and netlify from github actions Require code quality checks to pass before deploying Fix linting errors to pass quality checks closes #1244 Co-authored-by: horatio --- .github/workflows/production.yml | 123 ++++++++++++++++++ .github/workflows/qa.yml | 118 +++++++++++++++++ .github/workflows/staging.yml | 109 ++++++++++++++++ client/app/adapters/package.js | 2 +- .../packages/landuse-form/housing-plans.hbs | 4 +- .../components/packages/rwcds-form/edit.hbs | 2 +- client/app/optionsets/common.js | 2 +- client/config/environment.js | 1 + client/package.json | 2 +- client/tests/unit/models/milestone-test.js | 4 +- 10 files changed, 359 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/production.yml create mode 100644 .github/workflows/qa.yml create mode 100644 .github/workflows/staging.yml diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml new file mode 100644 index 00000000..ddd51d20 --- /dev/null +++ b/.github/workflows/production.yml @@ -0,0 +1,123 @@ +name: ๐ŸŒ  Deploy to production + +on: workflow_dispatch + +jobs: + test-client: + name: ๐Ÿงช Test client code + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: client + - uses: actions/setup-node@v1 + with: + node-version: 12.x + - name: install dependencies + run: yarn install --frozen-lockfile --non-interactive + working-directory: client + - name: build + env: + DISABLE_SOURCE_MAPS: true + BROCCOLI_ENV: production + run: yarn build + working-directory: client + - name: test + run: yarn test + working-directory: client + deploy-server: + name: ๐Ÿš€ Deploy server + needs: test-client + environment: + name: production + url: https://applicants-api.nycplanningdigital.com + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: server + - uses: akhileshns/heroku-deploy@v3.13.15 + name: Deploy server to Heroku + with: + heroku_email: ${{secrets.HEROKU_EMAIL}} + heroku_api_key: ${{secrets.HEROKU_API_KEY}} + heroku_app_name: ${{ vars.HEROKU_APP_NAME }} + team: ${{secrets.HEROKU_TEAM}} + appdir: server + env: + HD_ADO_PRINCIPAL: ${{ secrets.ADO_PRINCIPAL }} + HD_AUTHORITY_HOST_URL: ${{ secrets.AUTHORITY_HOST_URL }} + HD_CITYPAY_AGENCYID: ${{ secrets.CITYPAY_AGENCYID }} + HD_CITYPAY_CUSTOMER_LINK: ${{ secrets.CITYPAY_CUSTOMER_LINK }} + HD_CITYPAY_DOMAIN: ${{ secrets.CITYPAY_DOMAIN }} + HD_CITYPAY_PASSWORD: ${{ secrets.CITYPAY_PASSWORD }} + HD_CITYPAY_POSTBACK: ${{ secrets.CITYPAY_POSTBACK }} + HD_CITYPAY_RETURN_FROM_CART: ${{ secrets.CITYPAY_RETURN_FROM_CART }} + HD_CITYPAY_RETURN_FROM_CHECKOUT: ${{ secrets.CITYPAY_RETURN_FROM_CHECKOUT }} + HD_CITYPAY_USERNAME: ${{ secrets.CITYPAY_USERNAME }} + HD_CLIENT_ID: ${{ secrets.CLIENT_ID }} + HD_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + HD_CRM_HOST: ${{ secrets.CRM_HOST }} + HD_CRM_SERVICE_CONTACT_ID: ${{ secrets.CRM_SERVICE_CONTACT_ID }} + HD_CRM_URL_PATH: ${{ secrets.CRM_URL_PATH }} + HD_FIXIE_URL: ${{ secrets.FIXIE_URL }} + HD_MS_APPLICANT_PORTAL_PASSWORD: ${{ secrets.MS_APPLICANT_PORTAL_PASSWORD }} + HD_MS_APPLICANT_PORTAL_USERNAME: ${{ secrets.MS_APPLICANT_PORTAL_USERNAME }} + HD_NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }} + HD_NEW_RELIC_LOG: ${{ secrets.NEW_RELIC_LOG }} + HD_NODE_ENV: ${{ vars.NODE_ENV }} + HD_NYCID_DOMAIN: ${{ secrets.NYCID_DOMAIN }} + HD_NYCID_SERVICE_ACCOUNT_USERNAME: ${{ secrets.NYCID_SERVICE_ACCOUNT_USERNAME }} + HD_NYCID_TOKEN_SECRET: ${{ secrets.NYCID_TOKEN_SECRET }} + HD_PAPERTRAIL_API_TOKEN: ${{ secrets.PAPERTRAIL_API_TOKEN }} + HD_PAYMENT_BASE_URL: ${{ secrets.PAYMENT_BASE_URL }} + HD_PAYMENT_IP_RANGE: ${{ secrets.PAYMENT_IP_RANGE }} + HD_PAYMENT_STEP1_URL: ${{ secrets.PAYMENT_STEP1_URL }} + HD_RER_FILETYPE_UUID: ${{ secrets.RER_FILETYPE_UUID }} + HD_SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + HD_SHAREPOINT_CLIENT_ID: ${{ secrets.SHAREPOINT_CLIENT_ID }} + HD_SHAREPOINT_CLIENT_SECRET: ${{ secrets.SHAREPOINT_CLIENT_SECRET }} + HD_SHAREPOINT_CRM_SITE: ${{ secrets.SHAREPOINT_CRM_SITE }} + HD_SHAREPOINT_SITE_ID: ${{ secrets.SHAREPOINT_SITE_ID }} + HD_SHAREPOINT_TARGET_HOST: ${{ secrets.SHAREPOINT_TARGET_HOST }} + HD_TENANT_ID: ${{ secrets.TENANT_ID }} + HD_TOKEN_PATH: ${{ secrets.TOKEN_PATH }} + HD_ZAP_TOKEN_SECRET: ${{ secrets.ZAP_TOKEN_SECRET }} + deploy-client: + name: ๐Ÿ›ซ Deploy client + needs: [test-client, deploy-server] + environment: + name: production + url: https://applicants.planning.nyc.gov + runs-on: ubuntu-latest + env: + HOST: ${{ vars.ZAP_API_HOST }} + MAINTENANCE_START: ${{ vars.MAINTENANCE_START }} + MAINTENANCE_END: ${{ vars.MAINTENANCE_END }} + HD_NYCID_DOMAIN: ${{ secrets.NYCID_DOMAIN }} + NODE_ENV: ${{ vars.NODE_ENV }} + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: client + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 12.x + - name: Install application dependencies + working-directory: client + run: yarn install --immutable --immutable-cache --check-cache + - name: Build client + working-directory: client + run: yarn run build --environment=production + - name: Install netlify + # Use npm over yarn because yarn was not respecting the exact version of a dependency + run: npm i -g netlify-cli@11.8.3 + - name: Deploy client to Netlify + run: | + netlify deploy \ + --dir client/dist \ + --site ${{secrets.NETLIFY_SITE_ID}} \ + --auth ${{secrets.NETLIFY_AUTH_TOKEN}} \ + --message "${{ github.event.head_commit.message }}" + --prod \ No newline at end of file diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml new file mode 100644 index 00000000..3a8bd832 --- /dev/null +++ b/.github/workflows/qa.yml @@ -0,0 +1,118 @@ +name: ๐Ÿ•ต๏ธ Deploy to quality assurance + +on: workflow_dispatch + +jobs: + test-client: + name: ๐Ÿงช Test client code + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: client + - uses: actions/setup-node@v1 + with: + node-version: 12.x + - name: install dependencies + run: yarn install --frozen-lockfile --non-interactive + working-directory: client + - name: build + env: + DISABLE_SOURCE_MAPS: true + BROCCOLI_ENV: production + run: yarn build + working-directory: client + - name: test + run: yarn test + working-directory: client + deploy-server: + name: ๐Ÿš€ Deploy server + needs: test-client + environment: + name: qa + url: https://qa-applicants-api.nycplanningdigital.com + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: server + - uses: akhileshns/heroku-deploy@v3.13.15 + name: Deploy server to Heroku + with: + heroku_email: ${{secrets.HEROKU_EMAIL}} + heroku_api_key: ${{secrets.HEROKU_API_KEY}} + heroku_app_name: ${{ vars.HEROKU_APP_NAME }} + team: ${{secrets.HEROKU_TEAM}} + appdir: server + env: + HD_ADO_PRINCIPAL: ${{ secrets.ADO_PRINCIPAL }} + HD_AUTHORITY_HOST_URL: ${{ secrets.AUTHORITY_HOST_URL }} + HD_CITYPAY_AGENCYID: ${{ secrets.CITYPAY_AGENCYID }} + HD_CITYPAY_CUSTOMER_LINK: ${{ secrets.CITYPAY_CUSTOMER_LINK }} + HD_CITYPAY_DOMAIN: ${{ secrets.CITYPAY_DOMAIN }} + HD_CITYPAY_PASSWORD: ${{ secrets.CITYPAY_PASSWORD }} + HD_CITYPAY_POSTBACK: ${{ secrets.CITYPAY_POSTBACK }} + HD_CITYPAY_RETURN_FROM_CART: ${{ secrets.CITYPAY_RETURN_FROM_CART }} + HD_CITYPAY_RETURN_FROM_CHECKOUT: ${{ secrets.CITYPAY_RETURN_FROM_CHECKOUT }} + HD_CITYPAY_USERNAME: ${{ secrets.CITYPAY_USERNAME }} + HD_CLIENT_ID: ${{ secrets.CLIENT_ID }} + HD_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + HD_CRM_HOST: ${{ secrets.CRM_HOST }} + HD_CRM_SERVICE_CONTACT_ID: ${{ secrets.CRM_SERVICE_CONTACT_ID }} + HD_CRM_URL_PATH: ${{ secrets.CRM_URL_PATH }} + HD_FIXIE_URL: ${{ secrets.FIXIE_URL }} + HD_MS_APPLICANT_PORTAL_PASSWORD: ${{ secrets.MS_APPLICANT_PORTAL_PASSWORD }} + HD_MS_APPLICANT_PORTAL_USERNAME: ${{ secrets.MS_APPLICANT_PORTAL_USERNAME }} + HD_NODE_ENV: ${{ vars.NODE_ENV }} + HD_NYCID_SERVICE_ACCOUNT_USERNAME: ${{ secrets.NYCID_SERVICE_ACCOUNT_USERNAME }} + HD_NYCID_TOKEN_SECRET: ${{ secrets.NYCID_TOKEN_SECRET }} + HD_PAPERTRAIL_API_TOKEN: ${{ secrets.PAPERTRAIL_API_TOKEN }} + HD_PAYMENT_BASE_URL: ${{ secrets.PAYMENT_BASE_URL }} + HD_PAYMENT_IP_RANGE: ${{ secrets.PAYMENT_IP_RANGE }} + HD_PAYMENT_STEP1_URL: ${{ secrets.PAYMENT_STEP1_URL }} + HD_RER_FILETYPE_UUID: ${{ secrets.RER_FILETYPE_UUID }} + HD_SHAREPOINT_CLIENT_ID: ${{ secrets.SHAREPOINT_CLIENT_ID }} + HD_SHAREPOINT_CLIENT_SECRET: ${{ secrets.SHAREPOINT_CLIENT_SECRET }} + HD_SHAREPOINT_CRM_SITE: ${{ secrets.SHAREPOINT_CRM_SITE }} + HD_SHAREPOINT_SITE_ID: ${{ secrets.SHAREPOINT_SITE_ID }} + HD_SHAREPOINT_TARGET_HOST: ${{ secrets.SHAREPOINT_TARGET_HOST }} + HD_TENANT_ID: ${{ secrets.TENANT_ID }} + HD_TOKEN_PATH: ${{ secrets.TOKEN_PATH }} + HD_ZAP_TOKEN_SECRET: ${{ secrets.ZAP_TOKEN_SECRET }} + deploy-client: + name: ๐Ÿ›ซ Deploy client + needs: [test-client, deploy-server] + environment: + name: staging + runs-on: ubuntu-latest + env: + HOST: ${{ vars.ZAP_API_HOST }} + MAINTENANCE_START: ${{ vars.MAINTENANCE_START }} + MAINTENANCE_END: ${{ vars.MAINTENANCE_END }} + NODE_ENV: ${{ vars.NODE_ENV }} + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: client + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 12.x + - name: Install application dependencies + working-directory: client + run: yarn install --immutable --immutable-cache --check-cache + - name: Build client + working-directory: client + run: yarn run build --environment=production + - name: Install netlify + # Use npm over yarn because yarn was not respecting the exact version of a dependency + run: npm i -g netlify-cli@11.8.3 + - name: Deploy client to Netlify + run: | + netlify deploy \ + --dir client/dist \ + --alias ${{github.ref_name}}_${{github.sha}} \ + --site ${{secrets.NETLIFY_SITE_ID}} \ + --auth ${{secrets.NETLIFY_AUTH_TOKEN}} \ + --message "${{ github.event.head_commit.message }}" + diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 00000000..944643a3 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,109 @@ +name: ๐ŸŽญ Deploy to staging + +on: + push: + branches: + - main + +jobs: + test-client: + name: ๐Ÿงช Test client code + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: client + - uses: actions/setup-node@v1 + with: + node-version: 12.x + - name: install dependencies + run: yarn install --frozen-lockfile --non-interactive + working-directory: client + - name: build + env: + DISABLE_SOURCE_MAPS: true + BROCCOLI_ENV: production + run: yarn build + working-directory: client + - name: test + run: yarn test + working-directory: client + deploy-server: + name: ๐Ÿš€ Deploy server + needs: test-client + environment: + name: staging + url: https://staging-applicants-api.nycplanningdigital.com + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: 'main' + sparse-checkout: server + - uses: akhileshns/heroku-deploy@v3.13.15 + name: Deploy server to Heroku + with: + heroku_email: ${{ secrets.HEROKU_EMAIL }} + heroku_api_key: ${{ secrets.HEROKU_API_KEY }} + heroku_app_name: ${{ vars.HEROKU_APP_NAME }} + team: ${{ secrets.HEROKU_TEAM }} + appdir: server + env: + HD_ADO_PRINCIPAL: ${{ secrets.ADO_PRINCIPAL }} + HD_AUTHORITY_HOST_URL: ${{ secrets.AUTHORITY_HOST_URL }} + HD_CLIENT_ID: ${{ secrets.CLIENT_ID }} + HD_CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} + HD_CRM_HOST: ${{ secrets.CRM_HOST }} + HD_CRM_SERVICE_CONTACT_ID: ${{ secrets.CRM_SERVICE_CONTACT_ID }} + HD_CRM_URL_PATH: ${{ secrets.CRM_URL_PATH }} + HD_FIXIE_URL: ${{ secrets.FIXIE_URL }} + HD_NODE_ENV: ${{ vars.NODE_ENV }} + HD_NYCID_SERVICE_ACCOUNT_USERNAME: ${{ secrets.NYCID_SERVICE_ACCOUNT_USERNAME }} + HD_NYCID_TOKEN_SECRET: ${{ secrets.NYCID_TOKEN_SECRET }} + HD_PAPERTRAIL_API_TOKEN: ${{ secrets.PAPERTRAIL_API_TOKEN }} + HD_RER_FILETYPE_UUID: ${{ secrets.RER_FILETYPE_UUID }} + HD_SHAREPOINT_CLIENT_ID: ${{ secrets.SHAREPOINT_CLIENT_ID }} + HD_SHAREPOINT_CLIENT_SECRET: ${{ secrets.SHAREPOINT_CLIENT_SECRET }} + HD_SHAREPOINT_CRM_SITE: ${{ secrets.SHAREPOINT_CRM_SITE }} + HD_SHAREPOINT_TARGET_HOST: ${{ secrets.SHAREPOINT_TARGET_HOST }} + HD_TENANT_ID: ${{ secrets.TENANT_ID }} + HD_TOKEN_PATH: ${{ secrets.TOKEN_PATH }} + HD_ZAP_TOKEN_SECRET: ${{ secrets.ZAP_TOKEN_SECRET }} + deploy-client: + name: ๐Ÿ›ซ Deploy client + needs: [test-client, deploy-server] + environment: + name: staging + url: https://staging--applicant-portal.netlify.app + runs-on: ubuntu-latest + env: + HOST: ${{ vars.ZAP_API_HOST }} + MAINTENANCE_START: ${{ vars.MAINTENANCE_START }} + MAINTENANCE_END: ${{ vars.MAINTENANCE_END }} + NODE_ENV: ${{ vars.NODE_ENV }} + steps: + - uses: actions/checkout@v4 + with: + ref: 'main' + sparse-checkout: client + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 12.x + - name: Install application dependencies + working-directory: client + run: yarn install --immutable --immutable-cache --check-cache + - name: Build client + working-directory: client + run: yarn run build --environment=production + - name: Install netlify + # Use npm over yarn because yarn was not respecting the exact version of a dependency + run: npm i -g netlify-cli@11.8.3 + - name: Deploy client to Netlify + run: | + netlify deploy \ + --dir client/dist \ + --alias staging \ + --site ${{secrets.NETLIFY_SITE_ID}} \ + --auth ${{secrets.NETLIFY_AUTH_TOKEN}} \ + --message "${{ github.event.head_commit.message }}" diff --git a/client/app/adapters/package.js b/client/app/adapters/package.js index c2128392..1cadd77a 100644 --- a/client/app/adapters/package.js +++ b/client/app/adapters/package.js @@ -46,7 +46,7 @@ export default class PackageAdapter extends JSONAPIAdapter { const data = serializeIntoHash(store, type, snapshot); - let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); + const url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); return this.ajax(url, 'PATCH', { data }); } diff --git a/client/app/components/packages/landuse-form/housing-plans.hbs b/client/app/components/packages/landuse-form/housing-plans.hbs index 2aebb096..372bd96f 100644 --- a/client/app/components/packages/landuse-form/housing-plans.hbs +++ b/client/app/components/packages/landuse-form/housing-plans.hbs @@ -163,8 +163,8 @@ - + diff --git a/client/app/components/packages/rwcds-form/edit.hbs b/client/app/components/packages/rwcds-form/edit.hbs index c63fc9c6..47956ef3 100644 --- a/client/app/components/packages/rwcds-form/edit.hbs +++ b/client/app/components/packages/rwcds-form/edit.hbs @@ -1,4 +1,4 @@ -
+

Attention

diff --git a/client/app/optionsets/common.js b/client/app/optionsets/common.js index a47cdcfd..1318cba6 100644 --- a/client/app/optionsets/common.js +++ b/client/app/optionsets/common.js @@ -100,7 +100,7 @@ const COMMON_OPTIONSETS = { YES_NO_PICKLIST_CODE, YES_NO_DONT_KNOW, YES_NO_INTEGER, - YES_NO_UNSURE_LONGINT + YES_NO_UNSURE_LONGINT, }; export default COMMON_OPTIONSETS; diff --git a/client/config/environment.js b/client/config/environment.js index 757c2c1e..4a737ba4 100644 --- a/client/config/environment.js +++ b/client/config/environment.js @@ -31,6 +31,7 @@ module.exports = function(environment) { APP: { // Here you can pass flags/options to your application instance // when it is created + showSelfService: false, }, "labs-search": { diff --git a/client/package.json b/client/package.json index c2a0d05c..1d085bbf 100644 --- a/client/package.json +++ b/client/package.json @@ -11,7 +11,7 @@ "test": "tests" }, "scripts": { - "build": "ember build --environment=production", + "build": "ember build", "lint": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*", "lint:hbs": "ember-template-lint .", "lint:js": "eslint .", diff --git a/client/tests/unit/models/milestone-test.js b/client/tests/unit/models/milestone-test.js index 9b1dd27f..23cb698b 100644 --- a/client/tests/unit/models/milestone-test.js +++ b/client/tests/unit/models/milestone-test.js @@ -6,8 +6,8 @@ module('Unit | Model | milestone', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { - let store = this.owner.lookup('service:store'); - let model = store.createRecord('milestone', {}); + const store = this.owner.lookup('service:store'); + const model = store.createRecord('milestone', {}); assert.ok(model); }); });