diff --git a/.github/workflows/build_and_release.yaml b/.github/workflows/build_and_release.yaml new file mode 100644 index 000000000..f74d55d9a --- /dev/null +++ b/.github/workflows/build_and_release.yaml @@ -0,0 +1,173 @@ +# This workflow will do a clean ins +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Admin Panel Client CI/CD Pipeline Next + +on: + push: + branches: + - '*' + +env: + project-directory: ./ + repository: 'Greenstand/treetracker-admin-client' + +jobs: + prepare: + name: checking and prepare settings for jobs + runs-on: ubuntu-latest + outputs: + CHANNEL: ${{ steps.resolver.outputs.CHANNEL }} + S3_BUCKET_SECRET_NAME: ${{ steps.resolver.outputs.S3_BUCKET_SECRET_NAME }} + CDN_ID_SECRET_NAME: ${{ steps.resolver.outputs.CDN_ID_SECRET_NAME }} + NO_NEED_TO_BUILD: ${{ steps.resolver.outputs.NO_NEED_TO_BUILD }} + + + steps + - uses: actions/setup-node@v1 + with: + node-version: '18.x' + - uses: actions/checkout@v2 + - run: | + echo "::debug:: begin preparing..."; + echo "::debug:: branch to rlease: $GITHUB_REF_NAME" + node <> $GITHUB_OUTPUT + const ref = process.env.GITHUB_REF_NAME + const s3BucketSecretNames = { + "master": "DEV_CDN_S3_BUCKET", + "freetown": "DEV_CDN_S3_BUCKET_FREETOWN", + "beta": "DEV_STAGING_CDN_S3_BUCKET", + "alpha": "DEV_ALPHA_CDN_S3_BUCKET", + } + const cdnIdSecretNames = { + "master": "DEV_CDN_DISTRIBUTION_ID", + "freetown": "DEV_CDN_DISTRIBUTION_ID_FREETOWN", + "beta": "DEV_STAGING_CDN_DISTRIBUTION_ID", + "alpha": "DEV_ALPHA_CDN_DISTRIBUTION_ID", + } + const releaseJson = require("./.releaserc.json"); + const branches = releaseJson.branches.map(e => e.name? e.name : e); + if(branches.indexOf(ref) === -1){ + console.log("NO_NEED_TO_BUILD=true"); + process.exit(0); + } + let channel = releaseJson.branches.reduce((a,c) => a || (c === ref && c) || (c.name === ref && c.channel), false); + let s3BucketSecretName; + let cdnIdSecretName; + s3BucketSecretName = s3BucketSecretNames[channel]; + if(!s3BucketSecretName){ + throw '::error:: can not find s3 bucket secret name by, channel:' + channel ; + } + cdnIdSecretName = cdnIdSecretNames[channel]; + if(!cdnIdSecretName){ + throw '::error:: can not find cdn id secret name by, channel:' + channel ; + } + console.log("CHANNEL=" + channel); + console.log("S3_BUCKET_SECRET_NAME=" + s3BucketSecretName); + console.log("CDN_ID_SECRET_NAME=" + cdnIdSecretName); + + EOF + id: resolver + env: + VERSION_TO_DEPLOY: ${{ github.event.inputs.version }} + ENV_TO_DEPLOY: ${{ github.event.inputs.env }} + - run: | + echo "channel: ${{ steps.resolver.outputs.CHANNEL}}" + echo "s3: ${{ steps.resolver.outputs.S3_BUCKET_SECRET_NAME}}" + echo "cdn: ${{ steps.resolver.outputs.CDN_ID_SECRET_NAME}}" + echo "need to deplay: ${{ steps.resolver.outputs.NO_NEED_TO_BUILD}}" + name: Print resolver + client: + name: Build Client Project + runs-on: ubuntu-latest + needs: prepare + if: | + !contains(github.event.head_commit.message, 'skip-ci') && !contains(needs.prepare.outputs.NO_NEED_TO_BUILD, 'true') + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 16.14.x + uses: actions/setup-node@v1 + with: + node-version: '16.14.x' + - name: npm clean install + if: ${{ !env.ACT }} + run: npm ci --legacy-peer-deps + working-directory: ${{ env.project-directory }} + - name: run ESLint + if: ${{ !env.ACT }} + run: npm run lint + working-directory: ${{ env.project-directory }} + - name: build client dev project + if: github.event_name == 'push' && github.repository == ${{ env.repository }} + #if: ${{ !env.ACT }} + run: npm run build:dev + working-directory: ${{ env.project-directory }} + - uses: actions/upload-artifact@v2 + if: github.event_name == 'push' && github.repository == ${{ env.repository }} + #if: ${{ !env.ACT }} + with: + name: client-bundle + path: build-dev + - name: build client project + if: ${{ !env.ACT }} + run: npm run build + working-directory: + ${{ env.project-directory }} + - name: run React tests + if: ${{ !env.ACT }} + run: npm test + working-directory: ${{ env.project-directory }} + release: + name: Release semantic version + needs: [client, prepare] + runs-on: ubuntu-latest + if: | + !contains(github.event.head_commit.message, 'skip-ci') && + github.event_name == 'push' && + github.repository == ${{ github.env.repository }} + steps: + - name: Check out repository code + uses: actions/checkout@v2 + with: + persist-credentials: false + - name: Set up Node.js + uses: actions/setup-node@v1 + with: + node-version: '18.x' + # install dependencies and run semantic-release + - run: npm i -g semantic-release @semantic-release/{git,exec,changelog} + - run: semantic-release + if: ${{ !env.ACT }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GH_TOKEN }} + deploy: + name: Deploy to dev CDN + runs-on: ubuntu-latest + needs: [release, prepare] + if: | + !contains(github.event.head_commit.message, 'skip-ci') && + github.event_name == 'push' && + github.repository == ${{ github.env.repository }} + steps: + - uses: actions/checkout@v2 + - name: Download bundled client resources + if: ${{ !env.ACT }} + uses: actions/download-artifact@v2 + with: + name: client-bundle + path: build-dev + - name: Configure AWS credentials from Test account + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_KEY_ID_DADIOR }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_DADIOR }} + aws-region: us-east-1 + - name: install-aws-cli + uses: unfor19/install-aws-cli-action@v1 + - name: Copy front end resources to s3 bucket + run: | + aws s3 sync build-dev s3://${{secrets[needs.prepare.outputs.S3_BUCKET_SECRET_NAME]}} --delete + - name: Invalidate cloudfront caches + run: | + aws cloudfront create-invalidation --distribution-id ${{ secrets[needs.prepare.outputs.CDN_ID_SECRET_NAME]}} --paths "/*" diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 000000000..63232ed8a --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,157 @@ +name: Deploy + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to deploy' + required: true + default: 'e.g. v1.20.1-freetown.1' + env: + type: choice + description: Environment to deploy to + options: + - dev + - test + - prod + default: 'dev' + +env: + project-directory: ./ + repository: 'Greenstand/treetracker-admin-client' + + +jobs: + prepare: + name: checking and prepare settings for jobs + runs-on: ubuntu-latest + outputs: + CHANNEL: ${{ steps.resolver.outputs.CHANNEL }} + S3_BUCKET_SECRET_NAME: ${{ steps.resolver.outputs.S3_BUCKET_SECRET_NAME }} + CDN_ID_SECRET_NAME: ${{ steps.resolver.outputs.CDN_ID_SECRET_NAME }} + steps: + - uses: actions/setup-node@v1 + with: + node-version: '18.x' + - uses: actions/checkout@v2 + with: + # have to checkout master, to read releaserc, which means we must update the rc file in master with the newest settings + ref: master + - run: | + echo "::debug:: begin preparing..."; + echo "::debug:: version to deploy: $VERSION_TO_DEPLOY"; + echo "::debug:: env to deploy: ${{ github.event.inputs.env }}"; + ls -a + node <> $GITHUB_OUTPUT + const s3BucketSecretNames = { + "master-dev": "DEV_CDN_S3_BUCKET", + "master-prod": "PROD_CDN_S3_BUCKET", + "freetown-dev": "DEV_CDN_S3_BUCKET_FREETOWN", + "freetown-prod": "PROD_CDN_S3_BUCKET_FREETOWN", + "beta-dev": "DEV_STAGING_CDN_S3_BUCKET", + "beta-prod": "STAGING_CDN_S3_BUCKET", + "alpha-dev": "DEV_ALPHA_CDN_S3_BUCKET", + "alpha-prod": "PROD_ALPHA_CDN_S3_BUCKET", + } + const cdnIdSecretNames = { + "master-dev": "DEV_CDN_DISTRIBUTION_ID", + "master-prod": "PROD_CDN_DISTRIBUTION_ID", + "freetown-dev": "DEV_CDN_DISTRIBUTION_ID_FREETOWN", + "freetown-prod": 'PROD_CDN_DISTRIBUTION_ID_FREETOWN"', + "beta-dev": "DEV_STAGING_CDN_DISTRIBUTION_ID", + "beta-prod": "STAGING_CDN_DISTRIBUTION_ID", + "alpha-dev": "DEV_ALPHA_CDN_DISTRIBUTION_ID", + "alpha-prod": "PROD_ALPHA_CDN_DISTRIBUTION_ID", + } + const releaseJson = require("./.releaserc.json"); + const version = process.env.VERSION_TO_DEPLOY + const env = process.env.ENV_TO_DEPLOY; + const m = version.match(/^v\d+\.\d+.\d+(-([\w-\/\.]+)\.\d+)?$/) + let channel; + let s3BucketSecretName; + let cdnIdSecretName; + if(!m){ + throw '::error:: wrong version:' + version; + }else{ + if(!m[1]){ + channel = "master"; + }else{ + const releaseName = m[2]; + channel = releaseJson.branches.reduce((a,c) => a || (c.prerelease === releaseName && c.channel) || (c.name === releaseName && c.channel), false); + } + } + s3BucketSecretName = s3BucketSecretNames[channel + '-' + env]; + if(!s3BucketSecretName){ + throw '::error:: can not find s3 bucket secret name by, channel:' + channel + ' env:' + env; + } + cdnIdSecretName = cdnIdSecretNames[channel + '-' + env]; + console.log("CHANNEL=" + channel); + console.log("S3_BUCKET_SECRET_NAME=" + s3BucketSecretName); + console.log("CDN_ID_SECRET_NAME=" + cdnIdSecretName); + + EOF + id: resolver + env: + VERSION_TO_DEPLOY: ${{ github.event.inputs.version }} + ENV_TO_DEPLOY: ${{ github.event.inputs.env }} + - run: | + echo "resolver: ${{ steps.resolver.outputs.CHANNEL}}" + echo "resolver: ${{ steps.resolver.outputs.S3_BUCKET_SECRET_NAME}}" + echo "resolver: ${{ steps.resolver.outputs.CDN_ID_SECRET_NAME}}" + name: Print resolver + + frontend: + name: Build Frontend Project + runs-on: ubuntu-latest + needs: prepare + if: | + !contains(github.event.head_commit.message, 'skip-ci') + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.version }} + - name: Use Node.js 16.14.x + uses: actions/setup-node@v1 + with: + node-version: '16.14.x' + - name: npm clean install + run: npm ci --legacy-peer-deps + working-directory: ${{ env.project-directory }} + # define the endpoints for PROD in github secrets + - name: build frontend project + run: npm run build:staging + working-directory: ${{ env.project-directory }} + - uses: actions/upload-artifact@v2 + with: + name: frontend-bundle + path: build + + deploy: + name: Deploy to CDN + runs-on: ubuntu-latest + needs: [frontend, prepare] + if: | + github.repository == ${{ github.env.repository }} + steps: + - name: Print vars + run: | + echo "channel: ${{ needs.prepare.outputs.CHANNEL }}" + echo "s3: ${{ needs.prepare.outputs.S3_BUCKET_SECRET_NAME }}" + echo "cdn: ${{ needs.prepare.outputs.CDN_ID_SECRET_NAME }}" + - name: Download bundled frontend resources + uses: actions/download-artifact@v2 + with: + name: frontend-bundle + path: build + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_KEY_ID_DADIOR }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_DADIOR }} + aws-region: us-east-1 + - name: Copy front end resources to s3 bucket + run: | + aws s3 sync build s3://${{secrets[needs.prepare.outputs.S3_BUCKET_SECRET_NAME]}} --delete + - name: Invalidate cloudfront caches + run: | + aws cloudfront create-invalidation --distribution-id ${{ secrets[needs.prepare.outputs.CDN_ID_SECRET_NAME]}} --paths "/*" diff --git a/.releaserc b/.releaserc deleted file mode 100644 index eb54850d5..000000000 --- a/.releaserc +++ /dev/null @@ -1,25 +0,0 @@ -{ - "branches": ["master"], - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/changelog", - "@semantic-release/npm", - ["@semantic-release/git", { - "assets": ["docs", "package.json", "CHANGELOG.md"], - "message": "chore(release): ${nextRelease.version} [skip ci]", - "successComment": false, - "failComment": false, - "failTitle": false, - "labels": false, - "releasedLabels": false - }], - ["@semantic-release/github", { - "successComment": false, - "failComment": false, - "failTitle": false, - "labels": false, - "releasedLabels": false - }] - ] -} \ No newline at end of file diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 000000000..283aef16b --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,46 @@ +{ + "branches": [ + "+([0-9])?(.{+([0-9]),x}).x", + "master", + "next", + "next-major", + { + "name": "freetown", + "prerelease": true, + "channel": "freetown" + } + ,{ + "name": "hotfix/v1.107", + "prerelease": "hotfix-v1-107", + "channel": "beta" + } + ], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + "@semantic-release/changelog", + "@semantic-release/npm", + [ + "@semantic-release/git", + { + "assets": ["docs", "package.json", "CHANGELOG.md"], + "message": "chore(release): ${nextRelease.version} [skip ci]", + "successComment": false, + "failComment": false, + "failTitle": false, + "labels": false, + "releasedLabels": false + } + ], + [ + "@semantic-release/github", + { + "successComment": false, + "failComment": false, + "failTitle": false, + "labels": false, + "releasedLabels": false + } + ] + ] +}