diff --git a/.circleci/config.yml b/.circleci/config.yml index 721a4c701..2ec954564 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,12 @@ jobs: - attach_workspace: at: ~/coralproject/talk - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + keys: + # Find a cache corresponding to this specific package-lock.json + # checksum when this file is changed, this key will fail. + - v1-dependency-cache-{{ checksum "package-lock.json" }} + # Find the most recently generated cache used from any branch + - v1-dependency-cache- - run: name: Update NPM command: sudo npm update -g npm @@ -29,11 +34,11 @@ jobs: command: npm audit - run: name: Install dependencies - command: npm install + command: npm ci - save_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: v1-dependency-cache-{{ checksum "package-lock.json" }} paths: - - ./node_modules + - ~/.npm - persist_to_workspace: root: . paths: node_modules @@ -85,20 +90,33 @@ jobs: at: ~/coralproject/talk - restore_cache: keys: - - build-cache-{{ .Branch }}-{{ .Revision }} - - build-cache-{{ .Branch }}- - - build-cache- + - v1-build-cache-{{ .Branch }}-{{ .Revision }} + - v1-build-cache-{{ .Branch }}- + - v1-build-cache- - run: name: Build command: npm run build - save_cache: - key: build-cache-{{ .Branch }}-{{ .Revision }} + key: v1-build-cache-{{ .Branch }}-{{ .Revision }} paths: - ./dist - persist_to_workspace: root: . paths: dist + # release_docker will build and push the Docker image. + release_docker: + <<: *job_defaults + steps: + - checkout + - setup_remote_docker + - run: + name: Build + command: docker build -t coralproject/talk:next --build-arg REVISION_HASH=${CIRCLE_SHA1} . + - run: + name: Push + command: docker push coralproject/talk:next + workflows: version: 2 build-and-test: @@ -113,3 +131,11 @@ workflows: - build: requires: - npm_dependencies + - release_docker: + requires: + - lint + - unit_tests + - build + filters: + branches: + only: next diff --git a/.gitignore b/.gitignore index 318868371..5e57fcf6a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,4 @@ coverage *.DS_STORE *.css.d.ts -__generated__ - +__generated__ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8bae06482..d7ad7771c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:8-alpine -# Install installation dependancies. +# Install build dependancies. RUN apk --no-cache add git # Create app directory. @@ -36,6 +36,7 @@ ENV NODE_ENV production # Store the current git revision. ARG REVISION_HASH -ENV REVISION_HASH=${REVISION_HASH} +RUN mkdir dist/core/common/__generated__ && \ + echo "{\"revision\": \"${REVISION_HASH}\"}" > dist/core/common/__generated__/revision.json CMD ["npm", "run", "start"] diff --git a/package.json b/package.json index 22ec9c61d..fee38ffb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,18 @@ { "name": "@coralproject/talk", "version": "5.0.0", + "author": "The Coral Project", + "homepage": "https://coralproject.net/", + "repository": { + "type": "git", + "url": "git://github.com/coralproject/talk.git" + }, + "engines": { + "node": ">=8.9.0", + "npm": ">=6.4.1" + }, + "bugs": "https://github.com/coralproject/talk/issues", + "contributors": "https://github.com/coralproject/talk/graphs/contributors", "description": "A better commenting experience from Mozilla, The Washington Post, and The New York Times.", "scripts": { "build": "npm-run-all compile --parallel build:*", @@ -31,7 +43,6 @@ "tscheck:scripts": "tsc --project ./tsconfig.json --noEmit", "watch": "NODE_ENV=development ts-node ./scripts/watcher/bin/watcher.ts --config ./config/watcher.ts" }, - "author": "", "license": "Apache-2.0", "dependencies": { "akismet-api": "^4.2.0", diff --git a/src/core/common/version.ts b/src/core/common/version.ts new file mode 100644 index 000000000..66f5f47bc --- /dev/null +++ b/src/core/common/version.ts @@ -0,0 +1,16 @@ +import fs from "fs"; +import path from "path"; + +export let revision: string = ""; +export let version: string = ""; + +// Pull the version information from the package.json file. +const packagePath = path.join(__dirname, "..", "..", "..", "package.json"); +({ version } = JSON.parse(fs.readFileSync(packagePath, "utf8"))); + +// Try to get the revision from the revision file. This file is generated by the +// Docker build. +const revisionPath = path.join(__dirname, "__generated__", "revision.json"); +if (fs.existsSync(revisionPath)) { + ({ revision } = JSON.parse(fs.readFileSync(revisionPath, "utf8"))); +} diff --git a/src/core/server/app/handlers/admin/admin.ts b/src/core/server/app/handlers/admin/admin.ts deleted file mode 100644 index df36614fc..000000000 --- a/src/core/server/app/handlers/admin/admin.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { RequestHandler } from "express"; - -export const adminHandler: RequestHandler = (req, res) => { - res.render("admin"); -}; diff --git a/src/core/server/app/handlers/auth/local.ts b/src/core/server/app/handlers/api/tenant/auth/local.ts similarity index 100% rename from src/core/server/app/handlers/auth/local.ts rename to src/core/server/app/handlers/api/tenant/auth/local.ts diff --git a/src/core/server/app/handlers/install/tenant.ts b/src/core/server/app/handlers/api/tenant/install.ts similarity index 100% rename from src/core/server/app/handlers/install/tenant.ts rename to src/core/server/app/handlers/api/tenant/install.ts diff --git a/src/core/server/app/handlers/api/version.ts b/src/core/server/app/handlers/api/version.ts new file mode 100644 index 000000000..d22cdbfab --- /dev/null +++ b/src/core/server/app/handlers/api/version.ts @@ -0,0 +1,6 @@ +import { RequestHandler } from "express"; +import { revision, version } from "talk-common/version"; + +export const versionHandler: RequestHandler = (req, res, next) => { + res.json({ version, revision }); +}; diff --git a/src/core/server/app/router/api/auth.ts b/src/core/server/app/router/api/auth.ts index 82fece982..df7f7a05b 100644 --- a/src/core/server/app/router/api/auth.ts +++ b/src/core/server/app/router/api/auth.ts @@ -4,7 +4,7 @@ import { AppOptions } from "talk-server/app"; import { logoutHandler, signupHandler, -} from "talk-server/app/handlers/auth/local"; +} from "talk-server/app/handlers/api/tenant/auth/local"; import { wrapAuthn } from "talk-server/app/middleware/passport"; import { RouterOptions } from "talk-server/app/router/types"; diff --git a/src/core/server/app/router/api/index.ts b/src/core/server/app/router/api/index.ts index 59603cc1a..82d342f14 100644 --- a/src/core/server/app/router/api/index.ts +++ b/src/core/server/app/router/api/index.ts @@ -2,6 +2,7 @@ import express from "express"; import passport from "passport"; import { AppOptions } from "talk-server/app"; +import { versionHandler } from "talk-server/app/handlers/api/version"; import { apiErrorHandler } from "talk-server/app/middleware/error"; import { errorLogger } from "talk-server/app/middleware/logging"; @@ -26,6 +27,8 @@ export async function createAPIRouter(app: AppOptions, options: RouterOptions) { // Configure the management routes. router.use("/management", await createManagementRouter(app)); + router.get("/version", versionHandler); + // General API error handler. router.use(errorLogger); router.use(apiErrorHandler); diff --git a/src/core/server/app/router/api/tenant.ts b/src/core/server/app/router/api/tenant.ts index 8648bfc5d..7be01b0ca 100644 --- a/src/core/server/app/router/api/tenant.ts +++ b/src/core/server/app/router/api/tenant.ts @@ -1,7 +1,7 @@ import express from "express"; import { AppOptions } from "talk-server/app"; -import { tenantInstallHandler } from "talk-server/app/handlers/install/tenant"; +import { tenantInstallHandler } from "talk-server/app/handlers/api/tenant/install"; import tenantMiddleware from "talk-server/app/middleware/tenant"; import { RouterOptions } from "talk-server/app/router/types"; import tenantGraphMiddleware from "talk-server/graph/tenant/middleware";