diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 2b1a2490..5f4a9860 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -26,8 +26,6 @@ Runs CodeQL against the PR code ### [on PR, Trunk] One App Unit and Lint Tests Runs One App's unit tests and linting tests against the PR code -This workflow creates two checks, one for node 14 and one for node 16. - ### [on PR] DangerJS Runs dangerJS against the PR code diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index 66ac98d0..8e001585 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16.x + node-version-file: .nvmrc - uses: preactjs/compressed-size-action@v2 env: NODE_ENV: development diff --git a/.github/workflows/on-pr-and-trunk_one-app-unit-and-lint-tests.yml b/.github/workflows/on-pr-and-trunk_one-app-unit-and-lint-tests.yml index 52b24167..dc9ac5e1 100644 --- a/.github/workflows/on-pr-and-trunk_one-app-unit-and-lint-tests.yml +++ b/.github/workflows/on-pr-and-trunk_one-app-unit-and-lint-tests.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x, "^18 < 18.16"] + node-version: [16.x, 18.x] steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/on-pr_dangerJS.yml b/.github/workflows/on-pr_dangerJS.yml index 39f7f9b8..3a043526 100644 --- a/.github/workflows/on-pr_dangerJS.yml +++ b/.github/workflows/on-pr_dangerJS.yml @@ -8,7 +8,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v3 with: - node-version: '16.x' + node-version-file: .nvmrc - uses: actions/cache@v3 with: path: ~/.npm diff --git a/.github/workflows/on-pr_one-app-integration-tests.yml b/.github/workflows/on-pr_one-app-integration-tests.yml index 47526b74..2e0f7a05 100644 --- a/.github/workflows/on-pr_one-app-integration-tests.yml +++ b/.github/workflows/on-pr_one-app-integration-tests.yml @@ -14,10 +14,10 @@ jobs: ${{ runner.os }}-node- - uses: actions/setup-node@v3 with: - node-version: 16.x + node-version-file: .nvmrc - name: npm install run: NODE_ENV=development npm ci - name: Build docker image - run: docker build -t one-app:at-test . --build-arg USER=root + run: docker build -t one-app:at-test . --build-arg USER=root --build-arg VERSION=$(cat .nvmrc) - name: Run Integration Tests run: ONE_DANGEROUSLY_SKIP_ONE_APP_IMAGE_BUILD=true npm run test:integration diff --git a/.github/workflows/release-step-1_manual_create-release-pr.yml b/.github/workflows/release-step-1_manual_create-release-pr.yml index bd292005..0acf3880 100644 --- a/.github/workflows/release-step-1_manual_create-release-pr.yml +++ b/.github/workflows/release-step-1_manual_create-release-pr.yml @@ -28,7 +28,7 @@ jobs: ${{ runner.os }}-node- - uses: actions/setup-node@v3 with: - node-version: 16.x + node-version-file: .nvmrc - name: One App release id: vars run: | diff --git a/.github/workflows/release-step-4_automatic_docker-prod-build-and-publish.yml b/.github/workflows/release-step-4_automatic_docker-prod-build-and-publish.yml index 6efd8bc9..9830d18e 100644 --- a/.github/workflows/release-step-4_automatic_docker-prod-build-and-publish.yml +++ b/.github/workflows/release-step-4_automatic_docker-prod-build-and-publish.yml @@ -73,7 +73,7 @@ jobs: - name: Docker login run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login --username ${{ secrets.DOCKER_USER }} --password-stdin - name: Build production docker image - run: docker build -t prod . + run: docker build -t prod . --build-arg VERSION=$(cat .nvmrc) - name: Tag Docker Images run: | # Always tag the exact version diff --git a/.github/workflows/release-step-5_automatic_docker-dev-build-and-publish.yml b/.github/workflows/release-step-5_automatic_docker-dev-build-and-publish.yml index 8d68d452..aed59b59 100644 --- a/.github/workflows/release-step-5_automatic_docker-dev-build-and-publish.yml +++ b/.github/workflows/release-step-5_automatic_docker-dev-build-and-publish.yml @@ -68,7 +68,7 @@ jobs: - name: Docker login run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login --username ${{ secrets.DOCKER_USER }} --password-stdin - name: Build development docker image - run: docker build -t dev . --target=development + run: docker build -t dev . --target=development --build-arg VERSION=$(cat .nvmrc) - name: Tag Docker Images run: | # Always tag the exact version diff --git a/.github/workflows/release-step-6-automatic_publish-one-app-statics-to-npm.yml b/.github/workflows/release-step-6-automatic_publish-one-app-statics-to-npm.yml index af464366..ba17d873 100644 --- a/.github/workflows/release-step-6-automatic_publish-one-app-statics-to-npm.yml +++ b/.github/workflows/release-step-6-automatic_publish-one-app-statics-to-npm.yml @@ -27,7 +27,7 @@ jobs: # Setup .npmrc file to publish to npm - uses: actions/setup-node@v3 with: - node-version: '16.x' + node-version-file: .nvmrc registry-url: 'https://registry.npmjs.org' - name: Docker login run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login --username ${{ secrets.DOCKER_USER }} --password-stdin diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..4a1f488b --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18.17.1 diff --git a/Dockerfile b/Dockerfile index dd6fed9f..8e93ac8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,9 @@ +ARG VERSION=lts # Use the pre-baked fat node image only in the builder # which includes build utils preinstalled (e.g. gcc, make, etc). # This will result in faster and reliable One App docker image # builds as we do not have to run apk installs for alpine. -FROM node:18.17.1 as builder +FROM node:$VERSION as builder WORKDIR /opt/build RUN npm install -g npm@9.6.7 --registry=https://registry.npmjs.org COPY --chown=node:node ./ /opt/build @@ -29,7 +30,7 @@ RUN NODE_ENV=production npm run build && \ # development image # docker build . --target=development -FROM node:18.17.1-alpine as development +FROM node:$VERSION-alpine as development ARG USER ENV USER ${USER:-node} ENV NODE_ENV=development @@ -47,7 +48,7 @@ COPY --from=builder --chown=node:node /opt/one-app/development ./ # production image # last so that it's the default image artifact -FROM node:18.17.1-alpine as production +FROM node:$VERSION-alpine as production ARG USER ENV USER ${USER:-node} ENV NODE_ENV=production diff --git a/__tests__/package.spec.js b/__tests__/package.spec.js index 1acad1ce..b1f0317d 100644 --- a/__tests__/package.spec.js +++ b/__tests__/package.spec.js @@ -13,16 +13,50 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ - -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs/promises'; +import path from 'node:path'; const PACKAGE_DIR_PATH = path.resolve(path.join(__dirname, '../')); describe('package.json', () => { - it('is formatted properly', () => { - const rawPkg = fs.readFileSync(path.join(PACKAGE_DIR_PATH, 'package.json'), 'utf8'); + it('is parseable', async () => { + expect.assertions(1); + const rawPkg = await fs.readFile(path.join(PACKAGE_DIR_PATH, 'package.json'), 'utf8'); + expect(() => JSON.parse(rawPkg)).not.toThrow(); + }); + it('is formatted like npm does', async () => { + expect.assertions(1); + const rawPkg = await fs.readFile(path.join(PACKAGE_DIR_PATH, 'package.json'), 'utf8'); const parsedPkg = JSON.parse(rawPkg); - expect(rawPkg).toEqual(`${JSON.stringify(parsedPkg, null, 2)}\n`); + const builtPkg = { ...parsedPkg }; + + [ + 'dependencies', + 'devDependencies', + 'optionalDependencies', + ].forEach((listName) => { + if (!Object.hasOwnProperty.call(parsedPkg, listName)) { + return; + } + builtPkg[listName] = Object + .entries(parsedPkg[listName]) + .sort(([packageNameA], [packageNameB]) => ( + // let the engine do the work of sorting the strings + [packageNameA, packageNameB].sort()[0] === packageNameA ? -1 : 1) + ) + // ECMAScript Objects do not have an order to their keys, but the V8 implementation does + .reduce( + (orderedList, [packageName, versionRange]) => { + // adding properties one at a time is less bad than rebuilding (via destructuring) a + // new object every iteration of the loop + /* eslint-disable-next-line no-param-reassign */ + orderedList[packageName] = versionRange; + return orderedList; + }, + {} + ); + }); + + expect(rawPkg).toEqual(`${JSON.stringify(builtPkg, null, 2)}\n`); }); }); diff --git a/docs/guides/Running-In-Production.md b/docs/guides/Running-In-Production.md index e2390f37..b731eb9b 100644 --- a/docs/guides/Running-In-Production.md +++ b/docs/guides/Running-In-Production.md @@ -140,7 +140,7 @@ You can build the One App [Docker](https://www.docker.com/) image and run it in ```bash git clone https://github.com/americanexpress/one-app.git cd one-app -docker build . +docker build . --build-arg VERSION=$(cat .nvmrc) ``` Or you can build from source which creates your server side assets at `./lib` and your client @@ -217,6 +217,6 @@ under the "Software" category click "Edit". Enter all the required environment v After the deployment is complete, you can navigate to your application by clicking on "Go to environment". If the application health displays an error, One App might be failing to start due to a missing environment variable or missing configuration. You can request the logs and the console should display the reason why One App is crashing. -More information on how to deploy Docker containers on AWS Elastic Beanstalk can be found on the official [AWS Documentation](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker.html). +More information on how to deploy Docker containers on AWS Elastic Beanstalk can be found on the official [AWS Documentation](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker.html). [☝️ Return To Top](#running-in-production)