diff --git a/.circleci/config.aws.yml b/.circleci/config.aws.yml deleted file mode 100644 index c414057..0000000 --- a/.circleci/config.aws.yml +++ /dev/null @@ -1,63 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: docker:17.12.0-ce-git - working_directory: ~/repo - steps: - - checkout - - setup_remote_docker - - run: - name: Execute Pipeline (Build Source -> Test -> Build Web Server) - # code is checked out in the pipeline, consider copying from CI to Pipeline - # consider caching node_modules or switching to npm ci option when it becomes stable - command: | - docker build -f integration.Dockerfile . -t lemon-mart:$CIRCLE_BRANCH - mkdir -p docker-cache - docker save -o docker-cache/built-image.tar lemon-mart:$CIRCLE_BRANCH - - save_cache: - key: built-image-{{ .BuildNum }} - paths: - - docker-cache - - store_artifacts: - path: docker-cache/built-image.tar - destination: built-image.tar - - publish: - docker: - - image: docker:17.12.0-ce-git - working_directory: /usr/src - steps: - - restore_cache: - keys: - - built-image-{{ .BuildNum }} - - built-image - - setup_remote_docker - - run: - name: Sign into AWS ecr - command: $(aws ecr get-login --no-include-email --region us-east-1) - - run: - name: Push it to ECR - command: | - docker load < docker-cache/built-image.tar - docker tag my_app:$CIRCLE_BRANCH $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/lemon-mart:$CIRCLE_BRANCH - docker push $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/lemon-mart:$CIRCLE_BRANCH - -workflows: - version: 2 - build-and-deploy: - jobs: - - build - - publish: - requires: - - build - filters: - branches: - only: sequential-branch-filter - -# Consider tagging images with $CIRCLE_BRANCH -# Deployment Integrations https://circleci.com/docs/2.0/deployment-integrations -# For Docker Hub deploy see https://circleci.com/docs/2.0/building-docker-images/ -# For AWS ECS deploy see https://circleci.com/blog/how-to-build-a-docker-image-on-circleci-2-0/ -# For Heroku see https://devcenter.heroku.com/articles/container-registry-and-runtime#pushing-an-image-s -# For cache optimization read https://medium.com/@gajus/making-docker-in-docker-builds-x2-faster-using-docker-cache-from-option-c01febd8ef84 diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 01a025e..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: circleci/node:lts-browsers - - working_directory: ~/repo - - steps: - - checkout - - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - - run: yes | npm install || true - - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - - run: npm run build - - run: npm test diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..96bf144 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: ci + +on: + pull_request: + branches: [main, master] + +permissions: + contents: write + pull-requests: write + +jobs: + build-test: + runs-on: ubuntu-latest + if: github.event.pull_request.user.login == 'duluca' + strategy: + fail-fast: false + matrix: + include: + - subdir: server + image: minimal-mean-server + node: '12' + container_port: 3000 + expected: "Server is up and running" + needs_mongo: 'true' + - subdir: web-app + image: minimal-mean-web-app + node: '12' + container_port: 80 + expected: "Minimal MEAN Web App" + needs_mongo: 'false' + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + + - name: npm install + working-directory: ${{ matrix.subdir }} + run: npm install --legacy-peer-deps --no-audit --no-fund + + - name: npm run build + working-directory: ${{ matrix.subdir }} + run: npm run build + + - name: Build image + working-directory: ${{ matrix.subdir }} + run: docker build -t local-test:${{ github.sha }} . + + - name: Start mongo sidecar + if: matrix.needs_mongo == 'true' + run: | + docker network create testnet + docker run -d --name testmongo --network testnet mongo:5 + sleep 3 + + - name: Smoke test - container starts and stays up + run: | + extra="" + if [ "${{ matrix.needs_mongo }}" = "true" ]; then + extra="--network testnet -e MONGO_URI=mongodb://testmongo:27017/test" + fi + docker run -d --name testc $extra -p 8080:${{ matrix.container_port }} local-test:${{ github.sha }} + sleep 5 + docker ps --filter "name=testc" --filter "status=running" --format '{{.Names}}' | grep -q testc \ + || (echo "container exited"; docker logs testc; exit 1) + + - name: Endpoint check + run: | + for i in 1 2 3 4 5 6 7 8 9 10; do + if curl -fsS http://localhost:8080/ -o /tmp/body; then break; fi + sleep 2 + done + grep -qi "${{ matrix.expected }}" /tmp/body \ + || (echo "expected content missing. Container logs:"; docker logs testc; echo "Response body:"; cat /tmp/body 2>/dev/null || echo "(no body)"; exit 1) + + - name: Cleanup + if: always() + run: | + docker rm -f testc 2>/dev/null || true + docker rm -f testmongo 2>/dev/null || true + docker network rm testnet 2>/dev/null || true + + auto-merge: + needs: build-test + runs-on: ubuntu-latest + if: github.event.pull_request.user.login == 'duluca' + steps: + - name: Auto-merge PR + env: + GH_TOKEN: ${{ secrets.AUTOMERGE_PAT }} + run: gh pr merge ${{ github.event.pull_request.number }} --squash --delete-branch --admin -R ${{ github.repository }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..3474444 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,51 @@ +name: publish + +on: + push: + branches: [main, master] + +permissions: + contents: read + +jobs: + publish: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - subdir: server + image: minimal-mean-server + node: '12' + - subdir: web-app + image: minimal-mean-web-app + node: '12' + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + + - name: npm install + working-directory: ${{ matrix.subdir }} + run: npm install --legacy-peer-deps --no-audit --no-fund + + - name: npm run build + working-directory: ${{ matrix.subdir }} + run: npm run build + + - uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Build and push + working-directory: ${{ matrix.subdir }} + run: | + docker build \ + -t expertlysimple/${{ matrix.image }}:latest \ + -t expertlysimple/${{ matrix.image }}:${{ github.sha }} \ + . + docker push expertlysimple/${{ matrix.image }}:latest + docker push expertlysimple/${{ matrix.image }}:${{ github.sha }} diff --git a/server/Dockerfile b/server/Dockerfile index c2dbef8..e4f6b23 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,6 +1,6 @@ FROM node:lts-alpine -RUN apk add --update --no-progress make python bash +RUN apk add --update --no-progress make python3 bash ENV NPM_CONFIG_LOGLEVEL error ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_amd64 /usr/local/bin/dumb-init @@ -13,8 +13,8 @@ USER node WORKDIR /usr/src/app -ADD package.json . -ADD package-lock.json . +ADD --chown=node:node package.json . +ADD --chown=node:node package-lock.json . RUN NODE_ENV=production RUN npm install --only=production @@ -23,7 +23,7 @@ ENV HOST "0.0.0.0" ENV PORT 3000 EXPOSE 3000 -ADD dist dist +ADD --chown=node:node dist dist ENTRYPOINT ["dumb-init", "--"] CMD ["node", "dist/index"] \ No newline at end of file