Need a more "DRY" solution for my CircleCI tests - node.js

Currently I have a working circleci yaml file but it runs a separate test script for each app. It's not "DRY" and I think a better solution would be to run the test script from the root and loop over each app...but I can't figure out how to do that. I've seen some examples but anytime I try to apply them, circle can't seem to find the clover files so I'm not sure what I'm doing wrong. I'd LOVE to run everything in parallel too but my first need is to just eliminate all the extra steps.
This is the current setup:
file system structure:
- apps
- **app1**
- coverage
- clover.xml
- coverage-final.json
- src
- test-files
package.json
- **app2**
- coverage
- clover.xml
- coverage-final.json
- src
- test-files
package.json
- **app3**
- coverage
- clover.xml
- coverage-final.json
- src
- test-files
package.json
- package.json
root/package.json scripts
{
"scripts": {
"lint": "lerna run lint --concurrency=2",
"build": "lerna run build --concurrency=1 --stream",
"bootstrap:ci": "lerna bootstrap --ci --concurrency=2"
"test": "CI=true lerna run test:coverage --concurrency=2 --stream -- --coverage",
"test:app1": "cd apps/enhanced-date-editor && npm run test:coverage",
"test:app2": "cd apps/input-fields-group && npm run test:coverage",
"test:app3": "cd apps/markdown-items-list && npm run test:coverage",
},
"devDependencies": {
"lerna": "^3.22.1"
}
}
app[1/2/3]/package.json scripts
{
"scripts": {
"build": "react-scripts build",
"test": "react-scripts test",
"test:coverage": "npm t -- --coverage",
"deploy": "s3 bucket script",
},
"jest": {
"collectCoverageFrom": [
"**/*.{js,jsx,tsx}",
"!**/node_modules/**",
"!**/vendor/**"
]
}
}
circleci/config.yml
version: 2.1
executors:
node:
docker:
- image: cimg/node:14.15.4
jobs:
prepare:
executor: node
steps:
- checkout
- run:
name: Install dependencies
command: |
npm i
npm run bootstrap:ci
- persist_to_workspace:
root: .
paths:
- .
lint:
executor: node
steps:
- attach_workspace:
at: .
- run:
name: lint
command: npm run lint
test-reporter:
executor: node
steps:
- run:
name: Setup Code Climate test-reporter
command: |
# download test reporter as a static binary
mkdir -p testing-workspace/test-results/coverage
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > testing-workspace/cc-test-reporter
chmod +x testing-workspace/cc-test-reporter
- persist_to_workspace:
root: testing-workspace
paths:
- cc-test-reporter
test-app1:
executor: node
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:app1
testing-workspace/cc-test-reporter format-coverage \
"apps/app1/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.app1.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.app1.json
test-app2:
executor: node
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:app2
testing-workspace/cc-test-reporter format-coverage \
"apps/app2/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.app2.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.app2.json
test-app3:
executor: node
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:app3
testing-workspace/cc-test-reporter format-coverage \
"apps/app3/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.app3.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.app3.json
ship-all-the-test-results:
executor: node
steps:
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: sum coverage
command: testing-workspace/cc-test-reporter sum-coverage -o testing-workspace/test-results/coverage/coverage.total.json testing-workspace/test-results/coverage/coverage.*.json;
- run:
name: ship results to code climate
command: testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
- store_artifacts:
path: testing-workspace/test-results
destination: test-results
- store_test_results:
path: testing-workspace/test-results
workflows:
build-test-deploy:
jobs:
- prepare
- lint:
requires:
- prepare
- test-reporter:
requires:
- lint
- test-app1:
requires:
- test-reporter
- test-app2:
requires:
- test-reporter
- test-app3:
requires:
- test-reporter
- ship-all-the-test-results:
requires:
- test-app1
- test-app2
- test-app3
Example of what I've tried
testing-workspace/cc-test-reporter before-build
npm run test
testing-workspace/cc-test-reporter format-coverage apps/**/coverage/clover.xml --input-type clover --output apps/**/coverage/coverage-final.json
testing-workspace/cc-test-reporter sum-coverage apps/**/coverage/coverage-final.json --output testing-workspace/test-results/coverage/codeclimate.total.json
testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
testing-workspace/cc-test-reporter after-build --exit-code $?
error was git head does not match
Another Example of what I have tried
#!/bin/bash -eo pipefail
# notify codeclimate that a build is coming
testing-workspace/cc-test-reporter before-build
# run tests
# will receive a list of test files and the CircleCI CLI will split them by timing data.
TESTFILES=$(circleci tests glob "apps/**.js" | circleci tests split)
npm run test ${TESTFILES}
# format test results
testing-workspace/cc-test-reporter format-coverage "**/**/clover.xml" --input-type clover --output "apps/**/coverage/coverage-final.json"
# combine test results
testing-workspace/cc-test-reporter sum-coverage -o testing-workspace/test-results/coverage/coverage.total.json "apps/**/coverage/coverage-final.json"
# upload test results to codeclimate
testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
# notify codeclimate that build is completed
testing-workspace/cc-test-reporter after-build --exit-code $?
error was ```could not find coverage file //clover.xml
could not find any files in search paths for clover. search paths were: //clover.xml, build/logs/clover.xml, clover.xml ``

There is no loop in CircleCI config syntax, but you can make the config more DRY by adding a parameter for the app to your test-app job.
version: 2.1
executors:
node:
docker:
- image: cimg/node:14.15.4
jobs:
prepare:
executor: node
steps:
- checkout
- run:
name: Install dependencies
command: |
npm i
npm run bootstrap:ci
- persist_to_workspace:
root: .
paths:
- .
lint:
executor: node
steps:
- attach_workspace:
at: .
- run:
name: lint
command: npm run lint
test-reporter:
executor: node
steps:
- run:
name: Setup Code Climate test-reporter
command: |
# download test reporter as a static binary
mkdir -p testing-workspace/test-results/coverage
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > testing-workspace/cc-test-reporter
chmod +x testing-workspace/cc-test-reporter
- persist_to_workspace:
root: testing-workspace
paths:
- cc-test-reporter
test-app:
executor: node
parameters:
app_name:
type: string
steps:
- attach_workspace:
at: .
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: Testing and formatting for codeclimate
command: |
testing-workspace/cc-test-reporter before-build
npm run test:<< parameters.app_name >>
testing-workspace/cc-test-reporter format-coverage \
"apps/<< parameters.app_name >>/coverage/clover.xml" \
--input-type clover \
--output testing-workspace/test-results/coverage/coverage.<< parameters.app_name >>.json
- persist_to_workspace:
root: testing-workspace
paths:
- test-results/coverage/coverage.<< parameters.app_name >>.json
ship-all-the-test-results:
executor: node
steps:
- attach_workspace:
at: ~/project/testing-workspace
- run:
name: sum coverage
command: testing-workspace/cc-test-reporter sum-coverage -o testing-workspace/test-results/coverage/coverage.total.json testing-workspace/test-results/coverage/coverage.*.json;
- run:
name: ship results to code climate
command: testing-workspace/cc-test-reporter upload-coverage --input testing-workspace/test-results/coverage/coverage.total.json
- store_artifacts:
path: testing-workspace/test-results
destination: test-results
- store_test_results:
path: testing-workspace/test-results
workflows:
build-test-deploy:
jobs:
- prepare
- lint:
requires:
- prepare
- test-reporter:
requires:
- lint
- test-app:
name: test-app1
app_name: app1
requires:
- test-reporter
- test-app:
name: test-app2
app_name: app2
requires:
- test-reporter
- test-app:
name: test-app3
app_name: app3
requires:
- test-reporter
- ship-all-the-test-results:
requires:
- test-app1
- test-app2
- test-app3

Related

/bin/sh: eval: line 128: node_modules/.bin/ng: not found

I have script for pipeline like this .
I have two stages one for dependencies and tests
On the tests i have error when the script below is launched
- node_modules/.bin/ng test --code-coverage --watch=false --browsers=GitlabHeadlessChrome
image: ubuntu:latest
variables:
OUTPUT_PATH: "$CI_PROJECT_DIR/artifacts"
stages:
- install
- test
cache:
key:
files:
- package-lock.json
paths:
- node_modules
policy: pull
install_dependencies:
stage: install
image: node:15.13.0-alpine3.10
script:
- npm install
cache:
key:
files:
- package-lock.json
paths:
- node_modules
test_verydashboard:
stage: test
needs: [ "install_dependencies" ]
image: node:12-alpine
before_script:
- apk add chromium
- export CHROME_BIN=/usr/bin/chromium-browser
script:
- node_modules/.bin/ng test --code-coverage --watch=false --browsers=GitlabHeadlessChrome
coverage: '/Statements\s+:\s\d+.\d+%/'
artifacts:
name: "tests-and-coverage"
reports:
coverage_report:
coverage_format: cobertura
path: $OUTPUT_PATH/coverage/cobertura-coverage.xml
cache:
key:
files:
- yarn.lock
paths:
- node_modules
policy: pull
and on the test stage i have this error

CircleCI config.yml for nodejs

version: 2
jobs:
test:
docker:
- image: circleci/node:12.16
steps:
- checkout
- run: echo "Running tests"
- run: npm install
- run: npm test
build:
docker:
- image: circleci/node:12.16
steps:
- checkout
- run: echo "build project"
- npm install
- npm run build
workflows:
version: 2
test_build:
jobs:
- test
- build:
requires:
- test
The above YAML is my config.yml for CircleCI, but I get this error
Config does not conform to schema: {:workflows {:test_and_build {:jobs [nil {:build (not (map? nil)), :requires (not (map? a-clojure.lang.LazySeq))}]}}}
Another observation is if I run the jobs in parallel, they run without any errors.
That is if I remove the requires: - test as shown below
workflows:
version: 2
test_build:
jobs:
- test
- build
build is a job, just like test, and should be indented the same way it is:
version: 2
jobs:
test:
docker:
- image: circleci/node:12.16
steps:
- checkout
- run: echo "Running tests"
- run: npm install
- run: npm test
build:
docker:
- image: circleci/node:12.16
steps:
- checkout
- run: echo "build project"
- npm install
- npm run build
workflows:
version: 2
test_build:
jobs:
- test
- build:
requires:
- test
I tried this one and it worked. The problem with the previous one seemed to be related to versioning. CircleCI cloud 2.1 and CircleCI server 2. Also, I decided to use the node orbs this time.
version: 2.1
orbs:
node: circleci/node#3.0.1
jobs:
build:
working_directory: ~/backend_api
executor: node/default
steps:
- checkout
- node/install-npm
- node/install-packages:
app-dir: ~/backend_api
cache-path: node_modules
override-ci-command: npm i
- persist_to_workspace:
root: .
paths:
- .
test:
docker:
- image: cimg/node:current
steps:
- attach_workspace:
at: .
- run:
name: Test
command: npm test
workflows:
version: 2
build_and_test:
jobs:
- build
- test:
requires:
- build

React App + Node Gitlab cicd pipeline for GAE (Build and Deploy)

How do you create 2 stages 1 to build the react app and then one to deploy the files to GAE?
My current YML looks like this:
image: 'google/cloud-sdk:slim'
build-stage:
stage: build
image: 'node:latest'
script:
- 'npm install'
- 'npm install --prefix ./client'
- 'npm run build --prefix ./client'
only:
- master
deployment-stage:
stage: deploy
script:
- 'gcloud auth activate-service-account --key-file $GOOGLE_SERVICE_ACCOUNT_FILE'
- 'gcloud app deploy app.yaml --project $GOOGLE_PROJECT_ID --set-env-vars **redacted**'
only:
- master
Google App Engine doesn't show any builds happening on the builds tab. I have made a service account with these permissions: Here
I have set my CICD variables in Gitlab also, here is the output from the jobs so far.
Build stage:
$ npm run build --prefix ./client
> client#0.1.0 build /builds/**redacted**/client
> react-scripts build
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
276.17 KB build/static/js/2.63b40945.chunk.js
59.19 KB build/static/css/2.2e872fcd.chunk.css
4.3 KB build/static/js/main.7cffe524.chunk.js
923 B build/static/css/main.433538f4.chunk.css
772 B build/static/js/runtime-main.ef76e641.js
The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.
The build folder is ready to be deployed.
You may serve it with a static server:
npm install -g serve
serve -s build
Find out more about deployment here:
bit.ly/CRA-deploy
Job succeeded
Deploy stage:
Fetching changes with git depth set to 50...
Initialized empty Git repository in /builds/**redacted**/.git/
Created fresh repository.
From https://gitlab.com/**redacted**
* [new ref] refs/pipelines/124363587 -> refs/pipelines/124363587
* [new branch] master -> origin/master
Checking out f2026f12 as master...
Skipping Git submodules setup
$ gcloud auth activate-service-account --key-file $GOOGLE_SERVICE_ACCOUNT_FILE
00:02
Activated service account credentials for: [**redacted**]
$ gcloud app deploy app.yaml --project $GOOGLE_PROJECT_ID --set-env-vars **redacted**
Job succeeded
I think the issue is that the build files are not being uploaded as they are in a separate container.
I tried to run it all in 1 scripts step but the google/cloud-sdk:slim doesn't contain npm to do the build or installs.
Thanks!
You need to use GitLab artifacts. That's how you can pass an output from Stage 1 to Stage 2.
E.g.
stages:
- build
- deploy
build_project:
stage: build
image: node:15
script:
- echo "Start building App"
- npm install
- cd client
- npm install
- CI=false npm run build
- echo "Build successfully!"
artifacts:
expire_in: 1 hour
paths:
- client/build
- node_modules
deploy_production:
stage: deploy
image: google/cloud-sdk:alpine
environment: Production
only:
- master
script:
- echo $SERVICE_ACCOUNT > /tmp/$CI_PIPELINE_ID.json
- gcloud auth activate-service-account --key-file /tmp/$CI_PIPELINE_ID.json
- gcloud --quiet --project $PROJECT_ID app deploy app.yaml
after_script:
- rm /tmp/$CI_PIPELINE_ID.json
deploy_staging:
stage: deploy
image: google/cloud-sdk:alpine
environment: Staging
only:
- staging
script:
- echo $SERVICE_ACCOUNT > /tmp/$CI_PIPELINE_ID.json
- gcloud auth activate-service-account --key-file /tmp/$CI_PIPELINE_ID.json
- gcloud --quiet --project $PROJECT_ID app deploy staging-app.yaml --verbosity=info
after_script:
- rm /tmp/$CI_PIPELINE_ID.json
Figured this out with some trial and error...
image: python:2.7
before_script:
- echo "deb http://packages.cloud.google.com/apt cloud-sdk-jessie main" | tee /etc/apt/sources.list.d/google-cloud-sdk.list
- curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
- apt-get update
- apt-get -qq -y install google-cloud-sdk
- apt-get -qq -y install npm
- npm install
- npm install --prefix ./client
- npm run build --prefix ./client
deploy:
stage: deploy
environment: Production
only:
- master
script:
- gcloud auth activate-service-account --key-file $GOOGLE_SERVICE_ACCOUNT_FILE
- gcloud app deploy app.yaml --project $GOOGLE_PROJECT_ID
Moved the set-env-vars to the app.yaml as they cannot be set as a flag in the gloud app deploy as per the docs: https://cloud.google.com/appengine/docs/standard/nodejs/config/appref#environment_variables

Gitlab-ci file has no effect on my project

I'm trying to auto-build/deploy my angular app to my remote server but I don't get why the gitlab-ci.yml is not working :
image: trion/ng-cli-karma
cache:
paths:
- node_modules/
before_script:
- apt-get update -qq && apt-get install -y -qq sshpass
deploy_stage:
stage: deploy
environment: Staging
only:
- master
script:
- rm ./package-lock.json
- npm install
- ./node_modules/#angular/cli/bin/ng test --progress false --single-run=true --watch=false
- ./node_modules/#angular/cli/bin/ng e2e --progress false --watch=false
- ./node_modules/#angular/cli/bin/ng build --progress false --prod
- cd dist/
- ls
- sshpass -V
- export SSHPASS=$USER_PASS
- sshpass -e scp -o stricthostkeychecking=no -r . myusername#myserver:/var/www/html
deploy_production:
stage: deploy
environment: Production
only:
- tags
script:
- rm ./package-lock.json
- npm install
- ./node_modules/#angular/cli/bin/ng test --progress false --single-run=true --watch=false
- ./node_modules/#angular/cli/bin/ng e2e --progress false --watch=false
- ./node_modules/#angular/cli/bin/ng build --progress false --prod
- cd dist/
- ls
- sshpass -V
- export SSHPASS=$USER_PASS
- sshpass -e scp -o stricthostkeychecking=no -r . myusername#myserver-prd:/var/www/html
On my Gitlab CE server, I don't see the effect of the file, there is no build job :
Am I missing a step here?
The gitlab-ci.yml file you mentioned in your question should be renamed to .gitlab-ci.yml.
GitLab CI/CD Pipeline Configuration Reference
.

Gitlab Pipelines Stages take hours or days to show result (passed, failed) - docker, node app

I'm using Gitlab continuous integration (.gitlab-ci.yml) and docker, docker-compose to build, test and deploy my node app, but build and test takes so much time to complete on gitlab pipeline (in my local docker app builds and tests are running smoothly), I think this is not normal behavior of gitlab ci and i think i'm missing something or i'm using a wrong configuration
please check the configuration (.gitlab-ci.yml) below and screen shot of pipelines at the bottom
.gitlab-ci.yml
# GitLab CI Docker Image
image: node:6.10.0
# Build - Build necessary JS files
# Test - Run tests
# Deploy - Deploy application to ElasticBeanstalk
stages:
- build
- test
- deploy
# Configuration
variables:
POSTGRES_DB: f_ci
POSTGRES_USER: f_user
POSTGRES_PASSWORD: sucof
services:
- postgres:latest
cache:
paths:
- node_modules/
# Job: Build
# Installs npm packages
# Passes node_modules/ onto next steps using artifacts
build:linux:
stage: build
script:
- npm install
artifacts:
paths:
- node_modules/
tags:
- f-api
# Job: Test
# Run tests against our application
# If this fails, we do not deploy
test:linux:
stage: test
variables:
NODE_ENV: continuous_integration
script:
- ./node_modules/.bin/sequelize db:migrate --env=continuous_integration
- ./node_modules/.bin/sequelize db:seed:all --env=continuous_integration
- npm test
tags:
- f-api
# Job: Deploy
# Staging environment
deploy:staging:aws:
stage: deploy
script:
- apt-get update -qq
- apt-get -qq install python3 python3-dev
- curl -O https://bootstrap.pypa.io/get-pip.py
- python3 get-pip.py
- pip install awsebcli --upgrade
- mkdir ~/.aws/
- touch ~/.aws/credentials
- printf "[default]\naws_access_key_id = %s\naws_secret_access_key = %s\n" "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" >> ~/.aws/credentials
- touch ~/.aws/config
- printf "[profile adm-eb-cli]\naws_access_key_id = %s\naws_secret_access_key = %s\n" "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" >> ~/.aws/config
- eb deploy f-api-stg
environment:
name: staging
url: http://f-api-stg.gxnvwbgfma.ap-southeast-1.elasticbeanstalk.com
tags:
- f-api
only:
- staging
# Job: Deploy
# Production environment
deploy:prod:aws:
stage: deploy
script:
- echo "Deploy to production server"
environment:
name: production
url: http://f-api.gxnvwbgfma.ap-southeast-1.elasticbeanstalk.com
when: manual
tags:
- f-api
only:
- master
Dockerfile
FROM node:6.10.0
MAINTAINER Theodore GARSON-CORBEAUX <tgcorbeaux#maltem.com>
# Create app directory
ENV HOME=/usr/src/app
RUN mkdir -p $HOME
WORKDIR $HOME
# Install api dependencies
ADD package.json /usr/src/app/package.json
RUN npm install
ADD . /usr/src/app
EXPOSE 3000
CMD ["npm","start"]
docker-compose.yml
version: "2.1"
services:
db_dev:
image: postgres:latest
ports:
- "49170:5432"
environment:
- POSTGRES_USER=f_user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=f_dev
healthcheck:
test: "exit 0"
db_test:
image: postgres:latest
ports:
- "49171:5432"
environment:
- POSTGRES_USER=f_user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=f_test
healthcheck:
test: "exit 0"
app:
build: .
environment:
- NODE_ENV=development
command: "npm start"
ports:
- "49160:3000"
depends_on:
db_dev:
condition: service_healthy
migrate:
build: .
environment:
- NODE_ENV
command: "./node_modules/.bin/sequelize db:migrate --env ${NODE_ENV}"
depends_on:
db_dev:
condition: service_healthy
db_test:
condition: service_healthy
healthcheck:
test: "exit 0"
populate_db:
build: .
environment:
- NODE_ENV
command: "./node_modules/.bin/sequelize db:seed:all --env ${NODE_ENV}"
depends_on:
migrate:
condition: service_healthy
healthcheck:
test: "exit 0"
depopulate_db:
build: .
environment:
- NODE_ENV
command: "./node_modules/.bin/sequelize db:seed:undo:all --env ${NODE_ENV}"
depends_on:
migrate:
condition: service_healthy
healthcheck:
test: "exit 0"
test:
build: .
environment:
- NODE_ENV=test
command: "npm test"
depends_on:
populate_db:
condition: service_healthy

Resources