diff --git a/.eslintrc.js b/.eslintrc.js index 16a033d..e2a53a6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1 @@ -module.exports = { - extends: [require.resolve('@backstage/cli/config/eslint.backend')], -}; +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/package.json b/package.json index ba407a0..6766d68 100644 --- a/package.json +++ b/package.json @@ -10,44 +10,41 @@ "main": "dist/index.cjs.js", "types": "dist/index.d.ts" }, + "backstage": { + "role": "backend-plugin" + }, "scripts": { - "start": "backstage-cli backend:dev", - "build": "backstage-cli backend:build", - "lint": "backstage-cli lint", - "test": "backstage-cli test", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean" + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" }, "dependencies": { - "@backstage/backend-common": "^0.10.0", - "@backstage/config": "^0.1.11", - "@types/express": "^4.17.6", - "axios": "^0.26.0", - "compression": "^1.7.4", - "cors": "^2.8.5", - "cross-fetch": "^3.0.6", - "dateformat": "^4.5.1", + "@backstage/backend-common": "^0.13.0", + "@backstage/config": "^1.0.0", + "@types/express": "*", "express": "^4.17.1", "express-promise-router": "^4.1.0", - "helmet": "^4.6.0", - "js-base64": "^3.6.1", - "node-fetch": "^2.6.1", - "redis": "^4.0.3", + "js-base64": "^3.7.2", + "moment": "^2.29.1", + "node-fetch": "^2.6.7", + "redis": "^4.0.4", "winston": "^3.2.1", "yn": "^4.0.0" }, "devDependencies": { - "@backstage/cli": "^0.10.1", - "@types/compression": "^1.7.0", - "@types/jest": "^27.0.3", + "@backstage/cli": "^0.16.0", + "@types/jest": "^27.4.1", "@types/node-fetch": "^2.6.1", "@types/supertest": "^2.0.8", - "msw": "^0.21.2", + "msw": "^0.35.0", "prettier": "^2.4.1", "supertest": "^6.1.6" }, "files": [ "dist" ] -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e69168e..e3e2a7e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/run.ts b/src/run.ts index a60e1cd..7d3ae89 100644 --- a/src/run.ts +++ b/src/run.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ import { getRootLogger } from "@backstage/backend-common"; import yn from "yn"; import { startStandaloneServer } from "./service/standaloneServer"; -const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7000; +const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007; const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); const logger = getRootLogger(); diff --git a/src/service/artifact.test.ts b/src/service/artifact.test.ts index fda2506..4202e46 100644 --- a/src/service/artifact.test.ts +++ b/src/service/artifact.test.ts @@ -1,8 +1,8 @@ +import { getVoidLogger } from "@backstage/backend-common"; +import { ConfigReader } from "@backstage/config"; +import express from "express"; import request from "supertest"; import { createRouter } from "./router"; -import express from "express"; -import { ConfigReader } from "@backstage/config"; -import { getVoidLogger } from "@backstage/backend-common"; describe("createRouter", () => { let app: express.Express; @@ -21,15 +21,6 @@ describe("createRouter", () => { app = express().use(router); }); - describe("GET /health", () => { - it("returns ok", async () => { - const response = await request(app).get("/health"); - - expect(response.statusCode).toEqual(200); - expect(response.body).toEqual({ status: "ok" }); - }); - }); - describe("GET /artifacts", () => { it("return repository info", async () => { const projectID = process.env.HARBOR_project; diff --git a/src/service/artifact.ts b/src/service/artifact.ts index c2df888..cbdbb66 100644 --- a/src/service/artifact.ts +++ b/src/service/artifact.ts @@ -1,7 +1,6 @@ import { Base64 } from "js-base64"; - -const fetch = require("node-fetch"); -const dateFormat = require("dateformat"); +import moment from "moment"; +import fetch from "node-fetch"; export async function getArtifacts( baseUrl: string, @@ -24,9 +23,7 @@ export async function getArtifacts( }, }).then((res: { json: () => any }) => res.json()); - const artifacts: any = []; - - await Promise.all( + return await Promise.all( response.map( async (element: { addition_links: { vulnerabilities: { href: string } }; @@ -82,11 +79,15 @@ export async function getArtifacts( } }); + const generatedTag = element.tags?.length + ? element.tags[0].name + : "undefined"; + const art: Artifact = { size: Math.round((element.size / 1028 / 1028) * 100) / 100, - tag: element.tags[0].name, - pullTime: dateFormat(element.pull_time, "yyyy-mm-dd HH:MM"), - pushTime: dateFormat(element.push_time, "yyyy-mm-dd HH:MM"), + tag: generatedTag, + pullTime: moment(element.pull_time).format("DD-MM-YYYY HH:MM"), + pushTime: moment(element.push_time).format("DD-MM-YYYY HH:MM"), projectID: projectId, repoUrl: `${baseUrl}/harbor/projects/${projectId}/repositories/${repository.replace( /\//g, @@ -101,23 +102,23 @@ export async function getArtifacts( low: low, none: none, }, + id: projectId + generatedTag + element.push_time, }; - artifacts.push(art); + return art; } ) ); - - return artifacts; } interface Artifact { tag: string; size: number; - pullTime: number; + pullTime: string; pushTime: string; projectID: number; repoUrl: string; vulnerabilities: Vulnerabilities; + id: string; } interface Vulnerabilities { diff --git a/src/service/router.test.ts b/src/service/router.test.ts new file mode 100644 index 0000000..c9642b8 --- /dev/null +++ b/src/service/router.test.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { getVoidLogger } from "@backstage/backend-common"; +import { ConfigReader } from "@backstage/config"; +import express from "express"; +import request from "supertest"; +import { createRouter } from "./router"; + +describe("createRouter", () => { + let app: express.Express; + + beforeAll(async () => { + const router = await createRouter({ + logger: getVoidLogger(), + config: new ConfigReader({ + harbor: { + baseUrl: process.env.APP_CONFIG_harbor_baseUrl, + username: process.env.APP_CONFIG_harbor_username, + password: process.env.APP_CONFIG_harbor_password, + }, + }), + }); + app = express().use(router); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe("GET /health", () => { + it("returns ok", async () => { + const response = await request(app).get("/health"); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ status: "ok" }); + }); + }); +}); diff --git a/src/service/router.ts b/src/service/router.ts index 4d9d4be..690547b 100644 --- a/src/service/router.ts +++ b/src/service/router.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,13 +31,13 @@ export interface RouterOptions { export async function createRouter( options: RouterOptions ): Promise { - const { logger } = options; + const { logger, config } = options; logger.info("Initializing harbor backend"); - const baseUrl = options.config.getString("harbor.baseUrl"); - const username = options.config.getString("harbor.username"); - const password = options.config.getString("harbor.password"); - const redisConfig = options.config.getOptionalConfig("redis"); + const baseUrl = config.getString("harbor.baseUrl"); + const username = config.getString("harbor.username"); + const password = config.getString("harbor.password"); + const redisConfig = config.getOptionalConfig("redis"); const router = Router(); router.use(express.json()); @@ -79,7 +79,6 @@ export async function createRouter( }); router.get("/health", (_, response) => { - logger.info("PONG!"); response.send({ status: "ok" }); }); router.use(errorHandler()); diff --git a/src/service/standaloneServer.ts b/src/service/standaloneServer.ts index ec7d0a4..0155df4 100644 --- a/src/service/standaloneServer.ts +++ b/src/service/standaloneServer.ts @@ -1,11 +1,11 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, diff --git a/src/service/teamArtifacts.ts b/src/service/teamArtifacts.ts index 14afc5b..d3764d3 100644 --- a/src/service/teamArtifacts.ts +++ b/src/service/teamArtifacts.ts @@ -1,6 +1,9 @@ +import { getRootLogger } from "@backstage/backend-common"; +import { Config } from "@backstage/config"; import fetch from "node-fetch"; import * as redis from "redis"; -import { Config } from "@backstage/config"; + +const logger = getRootLogger(); export async function getTeamArtifacts( body: string, @@ -43,6 +46,16 @@ async function teamArtifacts(RepoInformation: RepoInformation[]) { `http://localhost:7000/api/harbor/artifacts?project=${value.project}&repository=${value.repository}` ); const json = await response.json(); + if (json.length === 0) { + const errorMsg: HarborErrors = { + project: value.project, + repository: value.repository, + errorMsg: "Repository not found", + }; + errorMsgs.push(errorMsg); + logger.warn(JSON.stringify(errorMsg)); + return; + } if (json.hasOwnProperty("error")) { const errorMsg: HarborErrors = { @@ -51,7 +64,7 @@ async function teamArtifacts(RepoInformation: RepoInformation[]) { errorMsg: json.error.message, }; errorMsgs.push(errorMsg); - console.log(errorMsg); + logger.error(JSON.stringify(errorMsg)); return; } diff --git a/src/setupTests.ts b/src/setupTests.ts index ba33cf9..d323229 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020 Spotify AB + * Copyright 2020 The Backstage Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.