From e9ebb666feccae1754792d41e49df3b9f95ef0aa Mon Sep 17 00:00:00 2001 From: Filip Sushko Date: Thu, 7 Jul 2022 09:17:20 +0200 Subject: [PATCH] SC-9516: Configure NPM and Node version from deploy.*.yaml (#337) * SC-9516: implemented Node and NPM version configuration * SC-9516: clean code + added validation rule * SC-9516: clean code * Update 02-deploy.file.reference.v1.md SC-9516: updated doc * Update 02-deploy.file.reference.v1.md Co-authored-by: Andrii Tserkovnyi --- bin/sdk/images/common.sh | 3 + .../02-deploy.file.reference.v1.md | 20 ++++++ .../config/validation.yml | 12 ++++ .../src/Validator/Rule/RangeValueRule.php | 18 ++++- generator/index.php | 66 ++++++++++++++++++- generator/src/templates/deploy.bash.twig | 5 ++ images/common/application/Dockerfile.twig | 16 +++++ images/common/cli/Dockerfile | 7 -- 8 files changed, 136 insertions(+), 11 deletions(-) diff --git a/bin/sdk/images/common.sh b/bin/sdk/images/common.sh index ad051847e..21e7be74e 100644 --- a/bin/sdk/images/common.sh +++ b/bin/sdk/images/common.sh @@ -59,6 +59,9 @@ function Images::_buildApp() { --build-arg "KNOWN_HOSTS=${KNOWN_HOSTS}" \ --build-arg "SPRYKER_BUILD_HASH=${SPRYKER_BUILD_HASH:-"current"}" \ --build-arg "SPRYKER_BUILD_STAMP=${SPRYKER_BUILD_STAMP:-""}" \ + --build-arg "SPRYKER_NODE_IMAGE_VERSION=${SPRYKER_NODE_IMAGE_VERSION}" \ + --build-arg "SPRYKER_NODE_IMAGE_DISTRO=${SPRYKER_NODE_IMAGE_DISTRO}" \ + --build-arg "SPRYKER_NPM_VERSION=${SPRYKER_NPM_VERSION}" \ "${DEPLOYMENT_PATH}/context" 1>&2 docker build \ diff --git a/docs/07-deploy-file/02-deploy.file.reference.v1.md b/docs/07-deploy-file/02-deploy.file.reference.v1.md index 6183d01c9..aee2a7d3e 100644 --- a/docs/07-deploy-file/02-deploy.file.reference.v1.md +++ b/docs/07-deploy-file/02-deploy.file.reference.v1.md @@ -258,6 +258,25 @@ image: ``` *** +### image: node: + +Defines Node.js settings. + +* `image: node: version:` - defines a Node.js version. Supports only major versions that are greater than the default one. The default version is `12`. +* `image: node: npm` - defines an NPM version. Supports only major versions that are greater than the default one. The default version is `6`. +* `image: node: distro:` - defines a Linux distribution for the Node Docker image. Should be equal to your base PHP image. Possible values are `alpine` and `debian`. This variable is optional with the default value of `alpine`. + +```yaml +image: + ... + node: + version: 18 + distro: alpine + npm: 8 +``` +*** + + ### image: php: Defines PHP settings for Spryker applications. @@ -280,6 +299,7 @@ image: - tideways ``` *** + ### assets: Defines the setting of *Assets*. diff --git a/generator/deploy-file-generator/config/validation.yml b/generator/deploy-file-generator/config/validation.yml index 2937889e6..4c3f4ff2e 100644 --- a/generator/deploy-file-generator/config/validation.yml +++ b/generator/deploy-file-generator/config/validation.yml @@ -33,6 +33,18 @@ image.php: array-type: image.php.enabled-extensions: array-type: +image.node.version: + integer-type: + range-value: + - 12 +image.node.distro: + only-value: + - alpine + - debian +image.node.npm: + integer-type: + range-value: + - 6 # Assets assets.image: diff --git a/generator/deploy-file-generator/src/Validator/Rule/RangeValueRule.php b/generator/deploy-file-generator/src/Validator/Rule/RangeValueRule.php index f4e2ad29e..34939e0b5 100644 --- a/generator/deploy-file-generator/src/Validator/Rule/RangeValueRule.php +++ b/generator/deploy-file-generator/src/Validator/Rule/RangeValueRule.php @@ -45,7 +45,15 @@ public function isValid(string $validateField, array $data): bool return true; } - return !($data < $this->ruleConfig[0] || $data > $this->ruleConfig[1]); + if ($data < $this->ruleConfig[0]) { + return false; + } + + if (array_key_exists(1, $this->ruleConfig) && $data > $this->ruleConfig[1]) { + return false; + } + + return true; } foreach ($data as $range) { @@ -53,7 +61,11 @@ public function isValid(string $validateField, array $data): bool continue; } - if ($range > $this->ruleConfig[0] || $range < $this->ruleConfig[1]) { + if ($range < $this->ruleConfig[0]) { + return false; + } + + if (array_key_exists(1, $this->ruleConfig) && $range > $this->ruleConfig[1]) { return false; } } @@ -68,6 +80,6 @@ public function isValid(string $validateField, array $data): bool */ public function getValidationMessage(string $fieldName): string { - return sprintf(static::VALIDATION_MESSAGE_TEMPLATE, $fieldName, $this->ruleConfig[0] . '...' . $this->ruleConfig[1]); + return sprintf(static::VALIDATION_MESSAGE_TEMPLATE, $fieldName, $this->ruleConfig[0] . '...' . $this->ruleConfig[1] ?? ''); } } diff --git a/generator/index.php b/generator/index.php index 79b6ac3b5..ad33ce164 100644 --- a/generator/index.php +++ b/generator/index.php @@ -3,7 +3,6 @@ use DeployFileGenerator\DeployFileGeneratorFactory; use DeployFileGenerator\Transfer\DeployFileTransfer; use Spatie\Url\Url; -use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Yaml\Parser; use Twig\Environment; use Twig\Loader\ChainLoader; @@ -156,6 +155,19 @@ public function setIsActive(bool $isActive): void GLUE_BACKEND => 'GlueBackend', ]; +const DEBIAN_DISTRO_NAME = 'bullseye'; +const ALPINE_DISTRO_NAME = 'alpine'; + +const SPRYKER_NODE_IMAGE_DISTRO_ENV_NAME = 'SPRYKER_NODE_IMAGE_DISTRO'; +const SPRYKER_NODE_IMAGE_VERSION_ENV_NAME = 'SPRYKER_NODE_IMAGE_VERSION'; +const SPRYKER_NPM_VERSION_ENV_NAME = 'SPRYKER_NPM_VERSION'; + +const DEFAULT_NODE_VERSION = 12; +const DEFAULT_NODE_DISTRO = ALPINE_DISTRO_NAME; +const DEFAULT_NPM_VERSION = 6; + +$projectData['_node_npm_config'] = buildNodeJsNpmBuildConfig($projectData); + foreach ($projectData['groups'] ?? [] as $groupName => $groupData) { foreach ($groupData['applications'] ?? [] as $applicationName => $applicationData) { foreach ($applicationData['endpoints'] ?? [] as $endpoint => $endpointData) { @@ -1580,3 +1592,55 @@ function isArmArchitecture(): bool return in_array($currentArchitecture, $possibleValue); } + +/** + * @param array $projectData + * + * @return array + */ +function buildNodeJsNpmBuildConfig(array $projectData): array +{ + $imageName = $projectData['image']['tag']; + $nodejsConfig = $projectData['image']['node'] ?? []; + + return [ + SPRYKER_NODE_IMAGE_DISTRO_ENV_NAME => getNodeDistroName($nodejsConfig, $imageName), + SPRYKER_NODE_IMAGE_VERSION_ENV_NAME => array_key_exists('version', $nodejsConfig) + ? (int)$nodejsConfig['version'] + : DEFAULT_NODE_VERSION, + SPRYKER_NPM_VERSION_ENV_NAME => array_key_exists('npm', $nodejsConfig) + ? (int)$nodejsConfig['npm'] + : DEFAULT_NPM_VERSION, + ]; +} + +/** + * @param array $nodejsConfig + * @param string $imageName + * + * @return string + */ +function getNodeDistroName(array $nodejsConfig, string $imageName): string +{ + if (array_key_exists('distro', $nodejsConfig)) { + if ($nodejsConfig['distro'] == 'debian') { + return DEBIAN_DISTRO_NAME; + } + + if ($nodejsConfig['distro'] == 'alpine') { + return ALPINE_DISTRO_NAME; + } + } + + $imageData = explode('/', $imageName); + + if ($imageData[0] !== 'spryker') { + return DEFAULT_NODE_DISTRO; + } + + if (str_contains($imageData[1], 'debian')) { + return DEBIAN_DISTRO_NAME; + } + + return ALPINE_DISTRO_NAME; +} diff --git a/generator/src/templates/deploy.bash.twig b/generator/src/templates/deploy.bash.twig index 7cc5f75dc..1a5d1b168 100644 --- a/generator/src/templates/deploy.bash.twig +++ b/generator/src/templates/deploy.bash.twig @@ -137,6 +137,11 @@ readonly SPRYKER_REPOSITORY_HASH="${SPRYKER_BUILD_HASH:-"$(git rev-parse --verif {% include "service/" ~ engine ~ "/" ~ serviceName ~ ".bash.twig" ignore missing with _context %} {% endfor %} +# NodeJS variables +{% for envName, envValue in _node_npm_config %} +readonly {{ envName }}="{{ "${%s:-%s}" | format(envName, envValue) }}" +{% endfor %} + # Variables from environment SPRYKER_XDEBUG_ENABLE="$([ "${SPRYKER_XDEBUG_ENABLE}" == '1' ] && echo '1' || echo '')" SPRYKER_XDEBUG_ENABLE_FOR_CLI='' diff --git a/images/common/application/Dockerfile.twig b/images/common/application/Dockerfile.twig index 471eaf37c..3914dd7e8 100644 --- a/images/common/application/Dockerfile.twig +++ b/images/common/application/Dockerfile.twig @@ -1,5 +1,14 @@ # syntax = docker/dockerfile:experimental ARG SPRYKER_PLATFORM_IMAGE=spryker/php:7.3 +ARG SPRYKER_NODE_IMAGE_VERSION +ARG SPRYKER_NODE_IMAGE_DISTRO + +FROM node:${SPRYKER_NODE_IMAGE_VERSION}-${SPRYKER_NODE_IMAGE_DISTRO} AS node + +ARG SPRYKER_NPM_VERSION + +RUN npm install -g npm@${SPRYKER_NPM_VERSION} + FROM ${SPRYKER_PLATFORM_IMAGE} AS application-basic ENV SPRYKER_IN_DOCKER=1 @@ -51,3 +60,10 @@ COPY --chown=spryker:spryker jenkins/jenkins.docker.xml.twig /home/spryker/jenki # Build info COPY --chown=spryker:spryker php/build.php /home/spryker/build.php + +# NodeJS + NPM +COPY --from=node /usr/lib /usr/lib +COPY --from=node /usr/local/share /usr/local/share +COPY --from=node /usr/local/lib /usr/local/lib +COPY --from=node /usr/local/include /usr/local/include +COPY --from=node /usr/local/bin /usr/local/bin diff --git a/images/common/cli/Dockerfile b/images/common/cli/Dockerfile index 4ed6fa386..8f37f123a 100644 --- a/images/common/cli/Dockerfile +++ b/images/common/cli/Dockerfile @@ -15,8 +15,6 @@ ENV PATH=/data/vendor/bin:$PATH RUN --mount=type=cache,id=aptlib,sharing=locked,target=/var/lib/apt \ --mount=type=cache,id=aptcache,sharing=locked,target=/var/cache/apt \ bash -c 'if [ ! -z "$(which apt)" ]; then apt update -y && apt install -y \ - nodejs \ - npm \ inotify-tools \ netcat-openbsd \ git \ @@ -33,14 +31,9 @@ RUN --mount=type=cache,id=aptlib,sharing=locked,target=/var/lib/apt \ apt update -y && apt install -y \ yarn \ ; fi' -# Debian contains outdated NPM package -RUN --mount=type=cache,id=npm,sharing=locked,target=/root/.npm \ - bash -c 'if [ ! -z "$(which apt)" ]; then npm install npm@^6.0.0 -g; fi' RUN --mount=type=cache,id=apk,sharing=locked,target=/var/cache/apk mkdir -p /etc/apk && ln -vsf /var/cache/apk /etc/apk/cache && \ bash -c 'if [ ! -z "$(which apk)" ]; then apk update && apk add \ - nodejs \ - npm \ inotify-tools \ netcat-openbsd \ coreutils \