Skip to content
Snippets Groups Projects
Commit 466725d4 authored by Lucendio's avatar Lucendio
Browse files

Remove dependency installation & rework build example

* removed hack folder and with it all code to install deps
* reworked `make build` to show more explicitly what needs to be done when
  producing an artifact
* bumped node version dep to v14 (to make jest work again)
* adjusted readme
* suppress console output when running jest client tests
parent 2137dcf3
No related branches found
No related tags found
No related merge requests found
.local
# macos
.DS_Store
......@@ -4,27 +4,19 @@ SHELL = /usr/bin/env bash -eo pipefail
MKFILE_DIR = $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
LOCAL_DIR = $(abspath $(MKFILE_DIR)/.local)
LOCAL_DIR := $(abspath $(MKFILE_DIR)/.local)
DATA_DIR = $(LOCAL_DIR)/data
LOG_DIR = $(LOCAL_DIR)/logs
DATA_DIR := $(LOCAL_DIR)/data
LOG_DIR := $(LOCAL_DIR)/logs
TEMP_DIR := $(LOCAL_DIR)/temp
APP_NODE_MODULE_DIRS = $(foreach dir, client server, $(subst %,$(dir),$(MKFILE_DIR)/app/%/node_modules))
# NOTE: make sure to use binaries installed via ./hack/Makefile if exist
export PATH := $(LOCAL_DIR)/bin:$(PATH)
default: all
all: install build
default: install build
.PHONY: install
......@@ -40,21 +32,29 @@ $(LOCAL_DIR)/%/:
.PHONY: clean
clean:
for nodeModulesDir in $(APP_NODE_MODULE_DIRS); do \
rm -rf "$${nodeModulesDir}"; \
done
rm -rf \
$(APP_NODE_MODULE_DIRS) \
$(TEMP_DIR) \
$(LOCAL_DIR)/dist
.PHONY: build
build: CLIENT_BUILD_PATH ?= $(MKFILE_DIR)/app/server/src/public
build: SERVER_PUBLIC_URL ?= http://localhost:3000
build: SERVER_PUBLIC_URL ?= http://127.0.0.1:3001
build: APP_BUILD_PATH ?= $(TEMP_DIR)
build:
rm -rf $(CLIENT_BUILD_PATH)
rm -rf $(APP_BUILD_PATH)
cp -r $(MKFILE_DIR)/app/server/src $(APP_BUILD_PATH)
cp $(MKFILE_DIR)/app/server/package* $(APP_BUILD_PATH)/
cd $(APP_BUILD_PATH) \
&& \
npm install --prod --no-audit --no-fund \
&& rm -rf ./package*
cd $(MKFILE_DIR)/app/client \
&& \
PUBLIC_URL=$(SERVER_PUBLIC_URL) \
BUILD_PATH=$(CLIENT_BUILD_PATH) \
BUILD_PATH=$(APP_BUILD_PATH)/public \
node ./scripts/build.js
......@@ -81,27 +81,32 @@ dev-test-client:
.PHONY: dev-start-db
dev-start-db: | $(LOG_DIR)/ $(DATA_DIR)/
mkdir -p $(DATA_DIR)/db
mongod --config $(MKFILE_DIR)/hack/local.mongod.conf
dev-start-db: $(LOG_DIR)/ $(DATA_DIR)/ $(DATA_DIR)/db/
mongod --config $(MKFILE_DIR)/app/server/dev.mongod.conf
.PHONY: dev-start-app
dev-start-app: build
dev-start-app:
cd $(MKFILE_DIR)/app/client \
&& \
PUBLIC_URL=$(SERVER_PUBLIC_URL) \
BUILD_PATH=$(MKFILE_DIR)/app/server/src/public \
node ./scripts/build.js
cd $(MKFILE_DIR)/app/server \
&& npm run start:dev
.PHONY: run
run: BUILD_PATH = $(LOCAL_DIR)/dist
run: PUBLIC_URL = http://localhost
run: SERVER_PORT = 3001
run: SERVER_PORT = 3000
run: DB_HOST = localhost
run: DB_PORT = 27017
run: | $(DATA_DIR)/ $(LOG_DIR)/
mkdir -p $(DATA_DIR)/db
make build SERVER_PUBLIC_URL=$(PUBLIC_URL):$(SERVER_PORT)
run: $(DATA_DIR)/ $(LOG_DIR)/ $(DATA_DIR)/db/
make build \
APP_BUILD_PATH=$(BUILD_PATH) \
SERVER_PUBLIC_URL=$(PUBLIC_URL):$(SERVER_PORT)
(exec mongod \
--port $(DB_PORT) \
......@@ -113,31 +118,7 @@ run: | $(DATA_DIR)/ $(LOG_DIR)/
(PORT=$(SERVER_PORT) \
MONGODB_URL=mongodb://$(DB_HOST):$(DB_PORT)/todo-app \
JWT_SECRET=myjwtsecret \
exec node $(MKFILE_DIR)/app/server/src/index.js \
exec node $(BUILD_PATH)/index.js \
) & PIDS[2]=$$!; \
\
for PID in $${PIDS[*]}; do wait $${PID}; done;
.PHONY: deps
deps:
NODEJS_VERSION=12.21.0 \
NPM_VERSION=6.14.11 \
MONGODB_VERSION=4.2.12 \
make -C $(MKFILE_DIR)/hack \
install
@echo ''
@echo 'In order to use the installed dependencies, the $$PATH variable must be adjusted.'
@echo 'Run:'
@echo ''
@echo ' export PATH=$$(pwd)/.local/bin:$${PATH}'
@echo ''
.PHONY: nuke
nuke:
cd $(MKFILE_DIR)/hack \
&& make clean
make clean
......@@ -18,7 +18,7 @@ Additionally, it documents various invocations that may help you adapting this a
**_Please note, that the `Makefile` is only meant to showcase steps that are usually needed to be taken in order to
automate the deployment lifecycle of such an application and code base.
It is NOT recommended to invoke `make` targets from the CI/CD, but rather to utilize platform-specific interfaces
(e.g. `Jenkinsfile`, `.travis.yml`, etc.), which may then invoke commands shown in the `make` target or in the `scripts`
(e.g. `.gitlab-ci.yml`, `Jenkinsfile`, etc.), which may then invoke commands shown in the `make` target or in the `scripts`
section of one of the `package.json` files._**
......@@ -26,39 +26,16 @@ It is NOT recommended to invoke `make` targets from the CI/CD, but rather to uti
The following software must be installed and available in your `${PATH}`:
* `node` ([NodeJS](https://nodejs.org/en/download))
* `npm` ([npm](https://www.npmjs.com/get-npm))
* `mongod` ([MongoDB](https://docs.mongodb.com/manual/installation/))
* `node` ([NodeJS](https://nodejs.org/en/download)): latest v14
* `npm` ([npm](https://www.npmjs.com/get-npm)): latest v6
* `mongod` ([MongoDB](https://docs.mongodb.com/manual/installation/)): latest v4.2
*NOTE: [required versions](https://github.com/lucendio/lecture-devops-app/blob/master/hack/Makefile#L18-L20)*
#### Option 1
*NOTE: the application in this repository has not been tested with versions newer than that*
Choose for yourself how you want to install these dependencies. Perhaps you can use the package manager
available on your operating system, or maybe you prefer using container images.
#### Option 2
Install all executables via `Makefile` into this project structure.
a) from the root directory:
```sh
make deps
```
b) from the `./hack` folder:
```sh
$(cd ./hack && make install)
```
__Don't forget to add the new folder (`./.local/bin` ) to your `${PATH}` variable in your shell environment:__
```sh
export PATH=$(pwd)/.local/bin:${PATH}
```
### Commands
The following commands are available from the root directory:
......@@ -71,13 +48,15 @@ The following commands are available from the root directory:
#### `make build`
* builds the client code
* copies it over into the server
1. copies server source into some empty location
2. copies dependency manifest (`package*`) into the same location right next to the server source
3. installs server dependencies
4. builds client code (requires client dependencies to be installed already) and puts it next to the server source into
#### `make test`
*NOTE: requires a MongoDB service to already run (see `MONGODB_URL` in target on where it's assumed to be running)*
*NOTE: requires a MongoDB service already ro be running (see `MONGODB_URL` in target on where it's assumed to be running)*
* runs client & server tests in [CI mode](https://jestjs.io/docs/en/cli.html#--ci) (exits regardless of the test outcome; closed tty)
......@@ -101,8 +80,8 @@ The following commands are available from the root directory:
*NOTE (1): only demonstrates a use case during local development and are not meant to run in any other context (e.g. automation)*
*NOTE (2): it might be desired to first start a database service (e.g. `make dev-start-db`)*
* builds client (see `make build`)
* starts server in development mode and with development configuration
* builds client
* starts server in development mode with development configuration
#### `make run`
......@@ -119,14 +98,4 @@ The following commands are available from the root directory:
#### `make clean`
* removes all `node_modules` dependencies that have been installed locally via `npm`
#### `make deps`
* installs the software prerequisites as prebuild binaries locally in `.local/bin`
#### `make nuke`
* removes all `npm` dependencies (see `make clean`)
* throws away `.local` folder and thus all software prerequisites that were installed within it
* removes other temporarily created folder in `.local`
......@@ -2,13 +2,17 @@ import React from 'react';
import { render, waitForElement, fireEvent } from '@testing-library/react';
import App from './App';
// NOTE: suppress virtual console output
console.error = ()=>{};
test.skip('renders header title "ToDo App"', () => {
const { getByText } = render(<App />);
const linkElement = getByText(/ToDo App/i);
expect(linkElement).toBeInTheDocument();
});
test('renders a header title', () => {
test('renders a header container', () => {
const { container } = render(<App />);
const header = container.querySelector('.header-main')
expect(header).toHaveTextContent(/.+/);
......@@ -16,18 +20,18 @@ test('renders a header title', () => {
test('renders a login form', async () => {
const { getByText } = render(<App />);
await waitForElement(() => getByText(/Sign in/i))
await waitForElement(() => getByText(/Email/i))
await waitForElement(() => getByText(/Password/i))
await waitForElement(() => getByText(/Login/i))
await waitForElement(() => getByText(/Sign in/i));
await waitForElement(() => getByText(/Email/i));
await waitForElement(() => getByText(/Password/i));
await waitForElement(() => getByText(/Login/i));
});
test('renders registration form when register button clicked', async () => {
const { getByText } = render(<App />);
await waitForElement(() => getByText(/Signup/i))
fireEvent.click(getByText('Signup'))
await waitForElement(() => getByText(/Your name/i))
await waitForElement(() => getByText(/Your email/i))
await waitForElement(() => getByText(/Your password/i))
await waitForElement(() => getByText(/Create User/i))
await waitForElement(() => getByText(/Signup/i));
fireEvent.click(getByText('Signup'));
await waitForElement(() => getByText(/Your name/i));
await waitForElement(() => getByText(/Your email/i));
await waitForElement(() => getByText(/Your password/i));
await waitForElement(() => getByText(/Create User/i));
});
File moved
.DEFAULT_GOAL := default
SHELL = /usr/bin/env bash -eo pipefail
MKFILE_DIR = $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
PLATFORM := $(shell if echo $$OSTYPE | grep -q darwin; then echo darwin; else echo linux; fi)
LOCAL_DIR = $(abspath $(MKFILE_DIR)/../.local)
BIN_DIR = $(LOCAL_DIR)/bin
LIB_DIR = $(LOCAL_DIR)/lib
TEMP_DIR = $(LOCAL_DIR)/tmp
# next LTS: 14.13.0
NODEJS_VERSION ?= 12.21.0
NPM_VERSION ?= 6.14.11
MONGODB_VERSION ?= 4.2.12
REACT_APP_VERSION = 3.4.1
NODEJS_URL = https://nodejs.org/dist/v$(NODEJS_VERSION)/node-v$(NODEJS_VERSION)-$(PLATFORM)-x64.tar.gz
NODEJS_ARTIFACT = $(TEMP_DIR)/node-v$(NODEJS_VERSION)-$(PLATFORM)-x64.tar.gz
NODEJS_ARCHIVE = $(patsubst %.tar.gz,%,$(notdir $(NODEJS_ARTIFACT)))
NODEJS_BIN = $(BIN_DIR)/node
NPM_BIN = $(BIN_DIR)/npm
NODEJS_SHA256 ?= $(shell cat $(MKFILE_DIR)/versions/nodejs.256.sums | grep v$(NODEJS_VERSION)-$(PLATFORM)-x64 | awk '{ print $$ 1 }')
ifeq ($(PLATFORM), darwin)
MONGODB_URL = https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-$(MONGODB_VERSION).tgz
else ifeq ($(PLATFORM), linux)
# NOTE: hard-coded Debian version. Others can be found here: https://www.mongodb.com/download-center/community
MONGODB_URL = https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-debian10-$(MONGODB_VERSION).tgz
else
fail 'Unknown platform. No condition met'
endif
MONGODB_ARTIFACT = $(TEMP_DIR)/mongodb-$(PLATFORM)-$(MONGODB_VERSION).tar.gz
MONGODB_ARCHIVE = $(patsubst %.tar.gz,%,$(notdir $(MONGODB_ARTIFACT)))
MONGODB_BIN = $(BIN_DIR)/mongod
MONGODB_SHA256 ?= $(shell cat $(MKFILE_DIR)/versions/mongodb.256.sums | grep $(PLATFORM)-x86_64-$(MONGODB_VERSION) | awk '{ print $$ 1 }')
default: all
all: install
.PHONY: install
install: node npm mongod
$(LOCAL_DIR)/%/:
mkdir -p $(@)
.PHONY: clean
clean:
rm -rf \
$(LOCAL_DIR)
.PHONY: node
node: $(NODEJS_BIN)
$(NODEJS_BIN): | $(NODEJS_ARTIFACT) $(BIN_DIR)/
@ [ $$(openssl dgst -sha256 "$(NODEJS_ARTIFACT)" | awk '{ print $$ 2 }') == $(NODEJS_SHA256) ] || ( echo "Invalid SHA256." && rm $(NODEJS_ARTIFACT) && exit 1 )
tar \
--extract \
--verbose \
--strip-components 2 \
--directory "$(BIN_DIR)" \
--file "$(NODEJS_ARTIFACT)" \
$(NODEJS_ARCHIVE)/bin/node
chmod +x "$@"
$(NODEJS_ARTIFACT): | $(TEMP_DIR)/
curl \
--silent --show-error \
--location \
$(NODEJS_URL) \
> $(NODEJS_ARTIFACT)
.PHONY: npm
npm: $(NPM_BIN)
npm: export PATH := $(BIN_DIR):$(PATH)
$(NPM_BIN): | $(NODEJS_BIN)
mkdir -p $(LIB_DIR)
tar \
--extract \
--verbose \
--strip-components 2 \
--directory "$(LIB_DIR)" \
--file "$(NODEJS_ARTIFACT)" \
$(NODEJS_ARCHIVE)/lib/node_modules
chmod +x $(LIB_DIR)/node_modules/npm/bin/npm-cli.js
ln -s $(LIB_DIR)/node_modules/npm/bin/npm-cli.js $(NPM_BIN)
npm install -g npm@$(NPM_VERSION)
.PHONY: mongod
mongod: $(MONGODB_BIN)
$(MONGODB_BIN): | $(MONGODB_ARTIFACT) $(BIN_DIR)/
@ [ $$(openssl dgst -sha256 "$(MONGODB_ARTIFACT)" | awk '{ print $$ 2 }') == $(MONGODB_SHA256) ] || ( echo "Invalid SHA256." && rm $(MONGODB_ARTIFACT) && exit 1 )
mkdir -p $(TEMP_DIR)/$(MONGODB_ARCHIVE)
tar \
--extract \
--verbose \
--strip-components 2 \
--directory "$(TEMP_DIR)/$(MONGODB_ARCHIVE)" \
--file "$(MONGODB_ARTIFACT)"
mv $(TEMP_DIR)/$(MONGODB_ARCHIVE)/mongod "$@"
chmod +x "$@"
rm -rf $(TEMP_DIR)/$(MONGODB_ARCHIVE)
$(MONGODB_ARTIFACT): | $(TEMP_DIR)/
curl \
--silent --show-error \
--location \
$(MONGODB_URL) \
> $(MONGODB_ARTIFACT)
.PHONY: update-react-app-template
update-react-app-template: export PATH := $(BIN_DIR):$(PATH)
update-react-app-template:
rm -rf $(TEMP_DIR)/npm-project-scope
mkdir -p $(TEMP_DIR)/npm-project-scope
cd $(TEMP_DIR)/npm-project-scope \
&& npm install --save-dev react-scripts@$(REACT_APP_VERSION) \
&& npm init react-app $(TEMP_DIR)/npm-project-scope/cra
cp \
$(TEMP_DIR)/npm-project-scope/cra/src/* \
$(MKFILE_DIR)/../app/client/src/
cp \
$(TEMP_DIR)/npm-project-scope/cra/public/* \
$(MKFILE_DIR)/../app/client/public/
cp \
$(TEMP_DIR)/npm-project-scope/cra/package.json \
$(MKFILE_DIR)/../app/client/
rm -rf \
$(MKFILE_DIR)/../app/client/src/logo.svg
36e7355b133a15c12e2fb5e8fefef354a99ffa048906cd855d639064f0f795b6 mongodb-linux-x86_64-4.2.12.tgz
06adf7b23ad3a3d97ae688d9001221c6cb263392ef74f3e265129b9b77b0a2e2 mongodb-darwin-x86_64-4.2.12.tgz
ab121de3c472d76ec425480b0594e43109ee607bd57c3d5314bdb65fa816bf1c node-v12.21.0-linux-x64.tar.gz
4d0b5d07d41a16909fdeb41c3158c27bcdccf16231cccf76d5eb6835e2076e90 node-v12.21.0-darwin-x64.tar.gz
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment