From 3442b8f0527678ada73b61cbb2c8c28ba854fa61 Mon Sep 17 00:00:00 2001 From: ssube Date: Tue, 11 Aug 2020 18:11:29 -0500 Subject: [PATCH] feat: initial project structure from template --- .eslintignore | 1 + .gitignore | 14 ++ .gitlab-ci.yml | 81 +++++++ .npmignore | 35 +++ Makefile | 194 +++++++++++++++ README.md | 0 config/api-extractor.json | 43 ++++ config/eslint.json | 365 +++++++++++++++++++++++++++++ config/gitlab/ci-rules.yml | 7 + config/gitlab/ci-tools.yml | 69 ++++++ config/mocha.json | 4 + config/rollup-external.json | 10 + config/rollup-globals.json | 1 + config/rollup-named.json | 76 ++++++ config/rollup-stub.json | 3 + config/rollup.js | 170 ++++++++++++++ config/tsconfig.json | 48 ++++ docs/dev.md | 0 docs/workflow.md | 0 run.mk | 1 + scripts/ci-project-path.sh | 7 + scripts/docker-build.sh | 27 +++ scripts/github-status.sh | 19 ++ scripts/mocha-module.js | 5 + scripts/mocha-preload.js | 10 + tsconfig.json | 3 + vendor/jsonpath-plus/index.d.ts | 8 + vendor/rollup-resources/index.d.ts | 9 + 28 files changed, 1210 insertions(+) create mode 100644 .eslintignore create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .npmignore create mode 100755 Makefile create mode 100644 README.md create mode 100644 config/api-extractor.json create mode 100644 config/eslint.json create mode 100644 config/gitlab/ci-rules.yml create mode 100644 config/gitlab/ci-tools.yml create mode 100755 config/mocha.json create mode 100644 config/rollup-external.json create mode 100644 config/rollup-globals.json create mode 100644 config/rollup-named.json create mode 100644 config/rollup-stub.json create mode 100644 config/rollup.js create mode 100755 config/tsconfig.json create mode 100644 docs/dev.md create mode 100644 docs/workflow.md create mode 100644 run.mk create mode 100755 scripts/ci-project-path.sh create mode 100755 scripts/docker-build.sh create mode 100755 scripts/github-status.sh create mode 100755 scripts/mocha-module.js create mode 100644 scripts/mocha-preload.js create mode 100755 tsconfig.json create mode 100644 vendor/jsonpath-plus/index.d.ts create mode 100644 vendor/rollup-resources/index.d.ts diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a860310 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +node_modules/** diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f377c3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.awcache/ +.licenses/ +.nyc_output/ +node_modules/ +out/ +temp/ + +# types +*.bak +*.swp +*.tmp + +package-lock.json +yarn-error.log diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..78202d9 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,81 @@ +include: + - local: /config/gitlab/ci-tools.yml + - local: /config/gitlab/ci-rules.yml + +stages: + - status-pre + - build + - image + - publish + - status-post + +# build jobs +build-node: + stage: build + extends: + - .build-node + + script: + - make ci + + artifacts: + when: always + expire_in: 1 day + paths: + - out/ + + cache: + key: "${CI_COMMIT_REF_SLUG}" + policy: pull-push + paths: + - node_modules/ + - out/api + - out/cache + - out/tmp + +# deploy jobs +deploy-test: + stage: publish + extends: + - .build-aws + except: + - master + script: + - make deploy + variables: + DEPLOY_BUCKET: "game-mtmb-test" + +deploy-prod: + stage: publish + extends: + - .build-aws + only: + - master + script: + - make deploy + variables: + DEPLOY_BUCKET: "game-mtmb-test" + +# commit status +github-pending: + stage: status-pre + extends: + - .build-curl + script: + - ./scripts/github-status.sh pending + +github-failure: + stage: status-post + extends: + - .build-curl + when: on_failure + script: + - ./scripts/github-status.sh failure + +github-success: + stage: status-post + extends: + - .build-curl + when: on_success + script: + - ./scripts/github-status.sh success diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..9535f29 --- /dev/null +++ b/.npmignore @@ -0,0 +1,35 @@ +.awcache/ +.github/ +.nyc_output/ + +config/ +deploy/ +node_modules/ +out/cache/ +out/coverage/ +out/coverage-* +out/docs/ +out/typings/ +out/*.db +out/*.html +out/*.json +out/test-* +out/tmp/ +scripts/ +src/ +temp/ +test/ +vendor/ + +.codeclimate.yml +.dockerignore +.gitlab-ci.yml +.gitmodules +.mdlrc + +Dockerfile +licensed.yml +Makefile +renovate.json +tsconfig.json +yarn-* diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..6714b99 --- /dev/null +++ b/Makefile @@ -0,0 +1,194 @@ +# Git +export GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) +export GIT_COMMIT ?= $(shell git rev-parse HEAD) +export GIT_OPTIONS ?= +export GIT_REMOTES ?= $(shell git remote -v | awk '{ print $1; }' | sort | uniq) +export GIT_TAG ?= $(shell git tag -l --points-at HEAD | head -1) + +# Paths +# resolve the makefile's path and directory, from https://stackoverflow.com/a/18137056 +export MAKE_PATH ?= $(abspath $(lastword $(MAKEFILE_LIST))) +export ROOT_PATH ?= $(dir $(MAKE_PATH)) +export CONFIG_PATH ?= $(ROOT_PATH)/config +export DOCS_PATH ?= $(ROOT_PATH)/docs +export SCRIPT_PATH ?= $(ROOT_PATH)/scripts +export SOURCE_PATH ?= $(ROOT_PATH)/src +export TARGET_PATH ?= $(ROOT_PATH)/out +export TARGET_LOG ?= $(TARGET_PATH)/make.log +export TARGET_MAIN ?= $(TARGET_PATH)/index.js +export TEST_PATH ?= $(ROOT_PATH)/test +export VENDOR_PATH ?= $(ROOT_PATH)/vendor + +# CI +export CI_COMMIT_REF_SLUG ?= $(GIT_BRANCH) +export CI_COMMIT_SHA ?= $(GIT_COMMIT) +export CI_COMMIT_TAG ?= $(GIT_TAG) +export CI_ENVIRONMENT_SLUG ?= local +export CI_JOB_ID ?= 0 +export CI_PROJECT_PATH ?= $(shell ROOT_PATH=$(ROOT_PATH) ${SCRIPT_PATH}/ci-project-path.sh) +export CI_RUNNER_DESCRIPTION ?= $(shell hostname) +export CI_RUNNER_ID ?= $(shell hostname) +export CI_RUNNER_VERSION ?= 0.0.0 + +# Debug +export DEBUG_BIND ?= 127.0.0.1 +export DEBUG_PORT ?= 9229 + +# Versions +export NODE_VERSION := $(shell node -v || echo "none") +export RUNNER_VERSION := $(CI_RUNNER_VERSION) + +# Node options +NODE_BIN := $(ROOT_PATH)/node_modules/.bin +NODE_CMD ?= $(shell env node) +NODE_DEBUG ?= --inspect-brk=$(DEBUG_BIND):$(DEBUG_PORT) --nolazy +NODE_INFO := $(shell node -v) +export NODE_OPTIONS ?= --max-old-space-size=4000 + +# Tool options +COVER_OPTS ?= --reporter=lcov --reporter=text-summary --reporter=html --report-dir="$(TARGET_PATH)/coverage" --exclude-after-remap +MOCHA_OPTS ?= --check-leaks --colors --sort --ui bdd # --experimental-modules +RELEASE_OPTS ?= --commit-all + +.PHONY: all clean clean-deps clean-target configure help todo +.PHONY: build build-bundle build-docs build-image test test-check test-cover test-watch +.PHONY: yarn-install yarn-upgrade git-push git-stats license-check release release-dry upload-climate upload-codecov + +all: build test ## builds, bundles, and tests the application + @echo Success! + +clean: ## clean up everything added by the default target +clean: clean-deps clean-target + +clean-deps: ## clean up the node_modules directory + rm -rf node_modules + +clean-target: ## clean up the target directory + rm -rf $(TARGET_PATH) + +configure: ## create the target directory and other files not in git + mkdir -p $(TARGET_PATH) + +node_modules: yarn-install + +# from https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html +help: ## print this help + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort \ + | sed 's/^.*\/\(.*\)/\1/' \ + | awk 'BEGIN {FS = ":[^:]*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +todo: + @echo "Remaining tasks:" + @echo "" + @grep -i "todo" -r docs/ src/ test/ || true + @echo "" + @echo "Pending tests:" + @echo "" + @grep "[[:space:]]xit" -r test/ || true + @echo "Casts to any:" + @echo "" + @grep "as any" -r src/ test/ || true + @echo "" + +# Build targets +build: ## builds, bundles, and tests the application +build: build-page build-bundle build-docs + +build-bundle: node_modules + $(NODE_BIN)/rollup --config $(CONFIG_PATH)/rollup.js + +build-docs: ## generate html docs + $(NODE_BIN)/api-extractor run --config $(CONFIG_PATH)/api-extractor.json --local -v + $(NODE_BIN)/api-documenter markdown -i $(TARGET_PATH)/api -o $(DOCS_PATH)/api + +build-image: ## build a docker image + $(SCRIPT_PATH)/docker-build.sh --push + +build-page: configure + cp -v $(SOURCE_PATH)/index.html $(TARGET_PATH)/index.html + +deploy: + aws s3 sync \ + --exclude 'README.md' \ + --exclude '*.tmx' \ + --exclude '*.tsx' \ + $(ROOT_PATH)/resources s3://$(DEPLOY_BUCKET) + aws s3 sync \ + --exclude '*' \ + --include '*.js' \ + --include 'index.html' \ + --exclude 'cache' \ + --exclude 'coverage' \ + --exclude 'test.*' \ + --exclude 'entry-*' \ + $(TARGET_PATH) s3://$(DEPLOY_BUCKET) + +test: ## run mocha unit tests +test: test-cover + +test-check: ## run mocha unit tests with coverage reports + $(NODE_BIN)/nyc $(COVER_OPTS) \ + $(NODE_BIN)/mocha $(MOCHA_OPTS) \ + --require esm \ + $(SCRIPT_PATH)/mocha-module.js + +test-cover: ## run mocha unit tests with coverage reports +test-cover: test-check + sed -i $(TARGET_PATH)/coverage/lcov.info \ + -e '/external ".*"$$/,/end_of_record/d' \ + -e '/ sync$$/,/end_of_record/d' \ + -e '/test sync/,/end_of_record/d' \ + -e '/node_modules/,/end_of_record/d' \ + -e '/bootstrap$$/,/end_of_record/d' \ + -e '/universalModuleDefinition/,/end_of_record/d' + sed -n '/^SF/,$$p' -i $(TARGET_PATH)/coverage/lcov.info + sed '1s;^;TN:\n;' -i $(TARGET_PATH)/coverage/lcov.info + +yarn-install: ## install dependencies from package and lock file + NODE_ENV='' yarn + +yarn-global: ## install bundle as a global tool + yarn global add file:$(ROOT_PATH) + +yarn-update: ## check yarn for outdated packages + yarn upgrade-interactive --latest + +# release targets +git-push: ## push to both gitlab and github (this assumes you have both remotes set up) + git push $(GIT_OPTIONS) github $(GIT_BRANCH) + git push $(GIT_OPTIONS) gitlab $(GIT_BRANCH) + +# from https://gist.github.com/amitchhajer/4461043#gistcomment-2349917 +git-stats: ## print git contributor line counts (approx, for fun) + git ls-files | while read f; do git blame -w -M -C -C --line-porcelain "$$f" |\ + grep -I '^author '; done | sort -f | uniq -ic | sort -n + +license-check: ## check license status + licensed cache + licensed status + +release: ## create a release + $(NODE_BIN)/standard-version --sign $(RELEASE_OPTS) + GIT_OPTIONS=--tags $(MAKE) git-push + +release-dry: ## test creating a release + $(NODE_BIN)/standard-version --sign $(RELEASE_OPTS) --dry-run + +upload-climate: + cc-test-reporter format-coverage -t lcov -o $(TARGET_PATH)/coverage/codeclimate.json -p $(ROOT_PATH) $(TARGET_PATH)/coverage/lcov.info + cc-test-reporter upload-coverage --debug -i $(TARGET_PATH)/coverage/codeclimate.json -r "$(shell echo "${CODECLIMATE_SECRET}" | base64 -d)" + +upload-codecov: + codecov --disable=gcov --file=$(TARGET_PATH)/coverage/lcov.info --token=$(shell echo "${CODECOV_SECRET}" | base64 -d) + +upload-sonar: node_modules + sonar-scanner \ + -Dsonar.projectKey=${CI_PROJECT_NAMESPACE}_${CI_PROJECT_NAME} \ + -Dsonar.projectVersion=${CI_COMMIT_REF_SLUG} \ + -Dsonar.organization=${CI_PROJECT_NAMESPACE}-github \ + -Dsonar.sources=src/,test/ \ + -Dsonar.host.url=https://sonarcloud.io \ + -Dsonar.login=${SONAR_SECRET} \ + -Dsonar.typescript.lcov.reportPaths=out/coverage/lcov.info + +include $(shell find $(ROOT_PATH) -name '*.mk' | grep -v node_modules) diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/config/api-extractor.json b/config/api-extractor.json new file mode 100644 index 0000000..2bbeed9 --- /dev/null +++ b/config/api-extractor.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "projectFolder": "..", + "mainEntryPointFilePath": "/out/src/index.d.ts", + "apiReport": { + "enabled": true, + "reportFolder": "/out/", + "reportTempFolder": "/out/tmp/" + }, + "docModel": { + "enabled": true, + "apiJsonFilePath": "/out/api/.api.json" + }, + + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/out/index.d.ts", + "betaTrimmedFilePath": "/out/index-beta.d.ts", + "publicTrimmedFilePath": "/out/index-public.d.ts" + }, + + "tsdocMetadata": { + }, + + "messages": { + "compilerMessageReporting": { + "default": { + "logLevel": "warning" + } + }, + + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + } + }, + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + } + } + } +} diff --git a/config/eslint.json b/config/eslint.json new file mode 100644 index 0000000..df54f5d --- /dev/null +++ b/config/eslint.json @@ -0,0 +1,365 @@ +{ + "env": { + "es6": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "eslint-plugin-chai", + "eslint-plugin-chai-expect", + "eslint-plugin-chai-expect-keywords", + "eslint-plugin-import", + "eslint-plugin-mocha", + "eslint-plugin-no-null", + "eslint-plugin-sonarjs", + "@typescript-eslint", + "@typescript-eslint/tslint" + ], + "rules": { + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/array-type": [ + "error", + { + "default": "generic" + } + ], + "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/ban-types": [ + "error", + { + "types": { + "null": "Use 'undefined' instead of 'null'" + } + } + ], + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "explicit", + "overrides": { + "constructors": "no-public" + } + } + ], + "@typescript-eslint/indent": [ + "error", + 2, + { + "ObjectExpression": "first", + "FunctionDeclaration": { + "parameters": "first" + }, + "FunctionExpression": { + "parameters": "first" + }, + "SwitchCase": 1 + } + ], + "@typescript-eslint/member-delimiter-style": [ + "error", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + } + ], + "@typescript-eslint/member-ordering": [ + "error", + { + "default": [ + "public-static-method", + "public-static-field", + "public-instance-field", + "protected-instance-field", + "public-constructor", + "public-instance-method", + "protected-instance-method" + ] + } + ], + "@typescript-eslint/no-empty-function": "error", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-for-in-array": "error", + "@typescript-eslint/no-inferrable-types": "error", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-non-null-assertion": "error", + "no-param-reassign": "error", + "@typescript-eslint/no-parameter-properties": "error", + "@typescript-eslint/no-this-alias": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "error", + "@typescript-eslint/no-use-before-declare": "off", + "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/prefer-for-of": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/quotes": [ + "error", + "single", + { + "avoidEscape": true + } + ], + "@typescript-eslint/restrict-plus-operands": "error", + "@typescript-eslint/semi": [ + "error", + "always" + ], + "space-in-parens": [ + "error", + "never" + ], + "@typescript-eslint/strict-boolean-expressions": "error", + "@typescript-eslint/triple-slash-reference": "error", + "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/unbound-method": "error", + "@typescript-eslint/unified-signatures": "error", + "arrow-body-style": "error", + "arrow-parens": [ + "error", + "always" + ], + "camelcase": "error", + "complexity": [ + "error", + { + "max": 12 + } + ], + "constructor-super": "error", + "curly": "error", + "default-case": "error", + "dot-notation": "error", + "eol-last": "error", + "eqeqeq": [ + "error", + "always" + ], + "guard-for-in": "error", + "id-blacklist": [ + "error", + "any", + "String", + "Boolean", + "Undefined" + ], + "id-match": "error", + "import/no-default-export": "error", + "import/no-deprecated": "error", + "import/no-extraneous-dependencies": "off", + "import/no-internal-modules": "off", + "import/order": [ + "error", + { + "groups": [ + [ + "builtin", + "external" + ], + [ + "index", + "parent", + "sibling", + "unknown" + ] + ] + } + ], + "max-classes-per-file": [ + "off", + 1 + ], + "max-len": [ + "error", + { + "code": 180 + } + ], + "max-lines": [ + "error", + 500 + ], + "new-parens": "error", + "no-bitwise": "off", + "no-caller": "error", + "no-cond-assign": "error", + "no-console": "error", + "no-debugger": "error", + "no-duplicate-case": "error", + "no-duplicate-imports": "error", + "no-empty": "error", + "no-eval": "error", + "no-extra-bind": "error", + "no-fallthrough": "off", + "no-invalid-this": "error", + "no-irregular-whitespace": "error", + "no-magic-numbers": [ + "error", + { + "ignore": [ + 0, + 1, + 10 + ] + } + ], + "no-multiple-empty-lines": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-null/no-null": "error", + "no-plusplus": [ + "error", + { + "allowForLoopAfterthoughts": true + } + ], + "no-redeclare": "error", + "no-restricted-syntax": [ + "error", + "ForInStatement" + ], + "no-return-await": "error", + "no-sequences": "error", + "no-shadow": [ + "error", + { + "hoist": "all" + } + ], + "no-sparse-arrays": "error", + "no-template-curly-in-string": "error", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-underscore-dangle": "error", + "no-unsafe-finally": "error", + "no-unused-expressions": "error", + "no-unused-labels": "error", + "no-useless-constructor": "error", + "no-var": "error", + "no-void": "error", + "max-params": [ + "error", + 4 + ], + "object-shorthand": "error", + "one-var": [ + "error", + "never" + ], + "prefer-const": "error", + "prefer-object-spread": "error", + "@typescript-eslint/prefer-readonly": "error", + "quote-props": [ + "error", + "consistent-as-needed" + ], + "radix": "error", + "space-before-function-paren": [ + "error", + { + "anonymous": "never", + "asyncArrow": "always", + "named": "never" + } + ], + "spaced-comment": "error", + "use-isnan": "error", + "valid-typeof": "off", + "sonarjs/max-switch-cases": "error", + "sonarjs/cognitive-complexity": "error", + "sonarjs/no-all-duplicated-branches": "error", + "sonarjs/no-collapsible-if": "error", + "sonarjs/no-collection-size-mischeck": "error", + "sonarjs/no-duplicate-string": "error", + "sonarjs/no-duplicated-branches": "error", + "sonarjs/no-element-overwrite": "error", + "sonarjs/no-identical-conditions": "error", + "sonarjs/no-identical-expressions": "error", + "sonarjs/no-identical-functions": "error", + "sonarjs/no-inverted-boolean-check": "error", + "sonarjs/no-redundant-boolean": "error", + "sonarjs/no-redundant-jump": "error", + "sonarjs/no-same-line-conditional": "error", + "sonarjs/no-useless-catch": "error", + "sonarjs/prefer-immediate-return": "error", + "@typescript-eslint/tslint/config": [ + "error", + { + "rules": { + "ban": [ + true, + { + "message": "use lodash isString", + "name": [ + "util", + "isString" + ] + }, + { + "message": "use lodash isNil", + "name": [ + "util", + "isNullOrUndefined" + ] + } + ], + "import-spacing": true, + "jsdoc-format": [ + true, + "check-multiline-start" + ], + "no-dynamic-delete": true, + "no-inferred-empty-object-type": true, + "no-reference-import": true, + "object-literal-sort-keys": true, + "one-line": [ + true, + "check-catch", + "check-else", + "check-finally", + "check-open-brace", + "check-whitespace" + ], + "prefer-switch": true, + "strict-type-predicates": true, + "trailing-comma": [ + true, + { + "esSpecCompliant": true, + "multiline": { + "arrays": "always", + "functions": "never", + "object": "always" + }, + "singleline": "never" + } + ], + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-type-operator", + "check-rest-spread" + ] + } + } + ] + } +} \ No newline at end of file diff --git a/config/gitlab/ci-rules.yml b/config/gitlab/ci-rules.yml new file mode 100644 index 0000000..a2fb9aa --- /dev/null +++ b/config/gitlab/ci-rules.yml @@ -0,0 +1,7 @@ +.deploy-branches: + except: + - tags + +.deploy-tags: + only: + - tags \ No newline at end of file diff --git a/config/gitlab/ci-tools.yml b/config/gitlab/ci-tools.yml new file mode 100644 index 0000000..22efe62 --- /dev/null +++ b/config/gitlab/ci-tools.yml @@ -0,0 +1,69 @@ +.build-base: + image: apextoaster/base:1.2 + tags: + - platform:k8s + - runner:shared + +.build-aws: + extends: + - .build-base + +.build-curl: + extends: + - .build-base + +.build-climate: + image: apextoaster/code-climate:0.6 + tags: + - platform:k8s + - runner:shared + allow_failure: false + variables: + CI_BRANCH: "${CI_COMMIT_REF_NAME}" + GIT_BRANCH: "${CI_COMMIT_REF_NAME}" + GIT_COMMIT_SHA: "${CI_COMMIT_SHA}" + +.build-codecov: + image: apextoaster/codecov:3.1 + tags: + - platform:k8s + - runner:shared + allow_failure: false + +.build-docker: + image: apextoaster/docker:18.09 + services: + - apextoaster/docker-dind:18.09 + tags: + - platform:k8s + - runner:shared + allow_failure: false + + before_script: + - mkdir ${HOME}/.docker + - echo "${DOCKER_SECRET}" | base64 -d > ${HOME}/.docker/config.json + script: + - ${CI_PROJECT_DIR}/scripts/docker-build.sh --push + after_script: + - rm -rfv ${HOME}/.docker + + variables: + DOCKER_DRIVER: overlay2 + DOCKER_HOST: tcp://localhost:2375 + +.build-node: + image: apextoaster/node:12.16 + tags: + - platform:k8s + - runner:shared + allow_failure: false + + before_script: + - echo "${NPM_SECRET}" | base64 -d > ${HOME}/.npmrc + +.build-sonar: + image: apextoaster/sonar-scanner:3.3 + tags: + - platform:k8s + - runner:shared + allow_failure: false \ No newline at end of file diff --git a/config/mocha.json b/config/mocha.json new file mode 100755 index 0000000..c7a4537 --- /dev/null +++ b/config/mocha.json @@ -0,0 +1,4 @@ +{ + "reporter": ["json"], + "ui": ["bdd"] +} diff --git a/config/rollup-external.json b/config/rollup-external.json new file mode 100644 index 0000000..ecba504 --- /dev/null +++ b/config/rollup-external.json @@ -0,0 +1,10 @@ +{ + "names": [ + "async_hooks", + "chai", + "dtrace-provider", + "sinon", + "source-map", + "source-map-support" + ] +} diff --git a/config/rollup-globals.json b/config/rollup-globals.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/config/rollup-globals.json @@ -0,0 +1 @@ +{} diff --git a/config/rollup-named.json b/config/rollup-named.json new file mode 100644 index 0000000..5181017 --- /dev/null +++ b/config/rollup-named.json @@ -0,0 +1,76 @@ +{ + "node_modules/chai/index.js": [ + "expect", + "use" + ], + "node_modules/deep-diff/index.js": [ + "applyDiff", + "diff" + ], + "node_modules/lodash/lodash.js": [ + "cloneDeep", + "defaultTo", + "flatten", + "intersection", + "isBoolean", + "isFunction", + "isMap", + "isNil", + "isObject", + "isString", + "kebabCase", + "merge", + "remove" + ], + "node_modules/minimatch/minimatch.js": [ + "Minimatch" + ], + "node_modules/noicejs/out/main-bundle.js": [ + "BaseError", + "ConsoleLogger", + "NullLogger", + "logWithLevel" + ], + "node_modules/js-yaml/index.js": [ + "DEFAULT_SAFE_SCHEMA", + "SAFE_SCHEMA", + "safeDump", + "safeLoad", + "safeLoadAll", + "Schema", + "Type" + ], + "node_modules/yargs/index.js": [ + "showCompletionScript", + "usage" + ], + "node_modules/phaser/src/phaser.js": [ + "AUTO", + "WEBGL", + "Cameras", + "Game", + "Input", + "Math", + "Renderer", + "Scene" + ], + "node_modules/react/index.js": [ + "useState", + "useRef", + "useMemo", + "useEffect", + "useCallback", + "useDebugValue", + "memo", + "forwardRef", + "Component", + "PureComponent", + "createElement" + ], + "node_modules/react-dom/index.js": [ + "unstable_batchedUpdates" + ], + "node_modules/seedrandom/index.js": [ + "alea" + ] +} \ No newline at end of file diff --git a/config/rollup-stub.json b/config/rollup-stub.json new file mode 100644 index 0000000..782e0e2 --- /dev/null +++ b/config/rollup-stub.json @@ -0,0 +1,3 @@ +{ + "names": [] +} diff --git a/config/rollup.js b/config/rollup.js new file mode 100644 index 0000000..23cc6f0 --- /dev/null +++ b/config/rollup.js @@ -0,0 +1,170 @@ +import { join, sep } from 'path'; +import commonjs from 'rollup-plugin-commonjs'; +import { eslint } from 'rollup-plugin-eslint'; +import json from 'rollup-plugin-json'; +import multiEntry from 'rollup-plugin-multi-entry'; +import polyfills from 'rollup-plugin-node-polyfills'; +import resolve from 'rollup-plugin-node-resolve'; +import replace from 'rollup-plugin-replace'; +import serve from 'rollup-plugin-serve'; +import { terser } from 'rollup-plugin-terser'; +import typescript from 'rollup-plugin-typescript2'; +import visualizer from 'rollup-plugin-visualizer'; +import yaml from 'rollup-plugin-yaml'; + +const flag_debug = process.env['DEBUG'] === 'TRUE'; +const flag_serve = process.env['SERVE'] === 'TRUE'; + +const metadata = require('../package.json'); + +const external = require('./rollup-external.json').names; +const namedExports = require('./rollup-named.json'); + +const rootPath = process.env['ROOT_PATH']; +const targetPath = process.env['TARGET_PATH']; + +const testModules = [ + 'chai', + 'chai-as-promised', + 'sinon', + 'sinon-chai', +]; + +const bundle = { + external, + input: { + include: [ + join(rootPath, 'src', 'index.ts'), + join(rootPath, 'test', 'harness.ts'), + join(rootPath, 'test', '**', 'Test*.ts'), + ], + }, + manualChunks(id) { + if (id.includes(`${sep}test${sep}`)) { + console.log(id, 'belongs to test chunk'); + return 'test'; + } + + if (id.match(/commonjs-external/i) || id.match(/commonjsHelpers/)) { + return 'vendor'; + } + + if (id.match(/node-resolve:/)) { + return 'vendor'; + } + + if (testModules.some(mod => id.includes(`${sep}${mod}${sep}`))) { + console.log(id, 'belongs to test chunk'); + return 'test'; + } + + if (id.includes(`${sep}node_modules${sep}`)) { + return 'vendor'; + } + + if (id.includes(`${sep}src${sep}index`)) { + return 'index'; + } + + if (id.includes(`${sep}src${sep}`) || id.includes(`${sep}rules${sep}`)) { + return 'main'; + } + + if (id.includes(process.env['HOME'])) { + return 'linked'; + } + + if (id.length === 30 && id.match(/^[a-f0-9]+$/)) { + return 'vendor'; + } + + if (flag_debug) { + console.log('file does not belong to any chunk:', id); + } + + return 'nochunk'; + }, + output: { + dir: targetPath, + chunkFileNames: '[name].js', + entryFileNames: 'entry-[name].js', + exports: 'named', + format: 'module', + minifyInternalExports: false, + sourcemap: true, + }, + plugins: [ + multiEntry(), + json(), + yaml(), + replace({ + delimiters: ['{{ ', ' }}'], + values: { + BUILD_JOB: process.env['CI_JOB_ID'], + BUILD_RUNNER: process.env['CI_RUNNER_DESCRIPTION'], + GIT_BRANCH: process.env['CI_COMMIT_REF_SLUG'], + GIT_COMMIT: process.env['CI_COMMIT_SHA'], + NODE_VERSION: process.env['NODE_VERSION'], + PACKAGE_NAME: metadata.name, + PACKAGE_VERSION: metadata.version, + }, + }), + resolve({ + browser: true, + preferBuiltins: true, + }), + commonjs({ + namedExports, + }), + polyfills({ + buffer: false, + }), + eslint({ + configFile: join('.', 'config', 'eslint.json'), + exclude: [ + join('node_modules', '**'), + join('src', 'resource'), + join('src', '**', '*.json'), + join('src', '**', '*.yml'), + ], + include: [ + join('src', '**', '*.ts'), + join('test', '**', '*.ts'), + ], + throwOnError: true, + useEslintrc: false, + }), + typescript({ + cacheRoot: join(targetPath, 'cache', 'rts2'), + rollupCommonJSResolveHack: true, + }), + visualizer({ + filename: join(rootPath, 'out', 'bundle-graph.html'), + sourcemap: true, + }), + /* + terser({ + keep_classnames: true, + }), + */ + ], +}; + +if (flag_serve) { + bundle.plugins.push(serve({ + host: '0.0.0.0', + open: true, + verbose: true, + contentBase: [ + join(rootPath, 'out'), + join(rootPath, 'resources'), + ], + mimeTypes: { + 'application/javascript': ['mjs'], + }, + })); +} + +export default [ + bundle, +]; diff --git a/config/tsconfig.json b/config/tsconfig.json new file mode 100755 index 0000000..e20e88b --- /dev/null +++ b/config/tsconfig.json @@ -0,0 +1,48 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "allowJs": false, + "allowSyntheticDefaultImports": true, + "declaration": true, + "declarationMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "jsx": "react", + "lib": [ + "dom", + "es2017", + "esnext.asynciterable" + ], + "module": "es6", + "moduleResolution": "node", + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "outDir": "../out", + "sourceMap": true, + "strict": true, + "strictNullChecks": true, + "target": "es2017", + "types": [ + "chai-as-promised", + "jsonpath-plus", + "mocha", + "node", + "rollup-resources", + "sinon-chai" + ], + "typeRoots": [ + "../node_modules/@types", + "../node_modules", + "../vendor" + ] + }, + "exclude": [ + "../node_modules" + ], + "include": [ + "../src/**/*", + "../test/**/*" + ] +} diff --git a/docs/dev.md b/docs/dev.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/workflow.md b/docs/workflow.md new file mode 100644 index 0000000..e69de29 diff --git a/run.mk b/run.mk new file mode 100644 index 0000000..a7e394f --- /dev/null +++ b/run.mk @@ -0,0 +1 @@ +ci: build test diff --git a/scripts/ci-project-path.sh b/scripts/ci-project-path.sh new file mode 100755 index 0000000..f941420 --- /dev/null +++ b/scripts/ci-project-path.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +PROJECT="${ROOT_PATH}" +PARENT="$(dirname "${PROJECT}")" +PROJECT_PATH="$(basename "${PARENT}")/$(basename "${PROJECT}")" + +echo "${PROJECT_PATH}" \ No newline at end of file diff --git a/scripts/docker-build.sh b/scripts/docker-build.sh new file mode 100755 index 0000000..bce104d --- /dev/null +++ b/scripts/docker-build.sh @@ -0,0 +1,27 @@ +#! /bin/bash + +IMAGE_PUSH="${1:---skip}" +IMAGE_DEFAULT="${2:---skip}" + +IMAGE_NAME="${CI_PROJECT_PATH}" +IMAGE_TAG="$(echo "${CI_COMMIT_TAG:-${CI_COMMIT_REF_SLUG}}" | sed -r 's/[^-_a-zA-Z0-9\\.]/-/g')" + +IMAGE_SHORT="${IMAGE_NAME}:${IMAGE_TAG}" +IMAGE_FULL="${IMAGE_NAME}:${IMAGE_TAG}-${IMAGE_ARCH}" + +echo "Building image: ${IMAGE_FULL}" + +docker build -f "Dockerfile.${IMAGE_ARCH}" -t "${IMAGE_FULL}" . + +if [[ "${IMAGE_PUSH}" == "--push" ]]; +then + echo "Pushing image: ${IMAGE_FULL}" + docker push "${IMAGE_FULL}" +fi + +if [[ "${IMAGE_DEFAULT}" == "--default" ]]; +then + echo "Pushing image (default architecture): ${IMAGE_SHORT}" + docker tag "${IMAGE_FULL}" "${IMAGE_SHORT}" + docker push "${IMAGE_SHORT}" +fi diff --git a/scripts/github-status.sh b/scripts/github-status.sh new file mode 100755 index 0000000..a0db255 --- /dev/null +++ b/scripts/github-status.sh @@ -0,0 +1,19 @@ +#! /bin/sh + +STATUS="${1}" +CI_COMMIT_SHA="${CI_COMMIT_SHA:-$(git rev-parse HEAD)}" + +STATUS_BODY="$(cat <