@@ -15,90 +15,51 @@
|
||||
"@backstage/app-defaults": "workspace:^",
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/core-compat-api": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/integration-react": "workspace:^",
|
||||
"@backstage/plugin-adr": "workspace:^",
|
||||
"@backstage/plugin-airbrake": "workspace:^",
|
||||
"@backstage/plugin-apache-airflow": "workspace:^",
|
||||
"@backstage/plugin-api-docs": "workspace:^",
|
||||
"@backstage/plugin-app-visualizer": "workspace:^",
|
||||
"@backstage/plugin-azure-devops": "workspace:^",
|
||||
"@backstage/plugin-azure-sites": "workspace:^",
|
||||
"@backstage/plugin-badges": "workspace:^",
|
||||
"@backstage/plugin-auth-react": "workspace:^",
|
||||
"@backstage/plugin-catalog": "workspace:^",
|
||||
"@backstage/plugin-catalog-common": "workspace:^",
|
||||
"@backstage/plugin-catalog-graph": "workspace:^",
|
||||
"@backstage/plugin-catalog-import": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "workspace:^",
|
||||
"@backstage/plugin-cloudbuild": "workspace:^",
|
||||
"@backstage/plugin-code-coverage": "workspace:^",
|
||||
"@backstage/plugin-cost-insights": "workspace:^",
|
||||
"@backstage/plugin-devtools": "workspace:^",
|
||||
"@backstage/plugin-dynatrace": "workspace:^",
|
||||
"@backstage/plugin-entity-feedback": "workspace:^",
|
||||
"@backstage/plugin-explore": "workspace:^",
|
||||
"@backstage/plugin-gcalendar": "workspace:^",
|
||||
"@backstage/plugin-gcp-projects": "workspace:^",
|
||||
"@backstage/plugin-github-actions": "workspace:^",
|
||||
"@backstage/plugin-gocd": "workspace:^",
|
||||
"@backstage/plugin-graphiql": "workspace:^",
|
||||
"@backstage/plugin-home": "workspace:^",
|
||||
"@backstage/plugin-jenkins": "workspace:^",
|
||||
"@backstage/plugin-kafka": "workspace:^",
|
||||
"@backstage/plugin-kubernetes": "workspace:^",
|
||||
"@backstage/plugin-lighthouse": "workspace:^",
|
||||
"@backstage/plugin-linguist": "workspace:^",
|
||||
"@backstage/plugin-linguist-common": "workspace:^",
|
||||
"@backstage/plugin-microsoft-calendar": "workspace:^",
|
||||
"@backstage/plugin-newrelic": "workspace:^",
|
||||
"@backstage/plugin-newrelic-dashboard": "workspace:^",
|
||||
"@backstage/plugin-octopus-deploy": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^",
|
||||
"@backstage/plugin-notifications": "workspace:^",
|
||||
"@backstage/plugin-org": "workspace:^",
|
||||
"@backstage/plugin-pagerduty": "workspace:^",
|
||||
"@backstage/plugin-permission-react": "workspace:^",
|
||||
"@backstage/plugin-playlist": "workspace:^",
|
||||
"@backstage/plugin-puppetdb": "workspace:^",
|
||||
"@backstage/plugin-rollbar": "workspace:^",
|
||||
"@backstage/plugin-scaffolder": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-react": "workspace:^",
|
||||
"@backstage/plugin-search": "workspace:^",
|
||||
"@backstage/plugin-search-common": "workspace:^",
|
||||
"@backstage/plugin-search-react": "workspace:^",
|
||||
"@backstage/plugin-sentry": "workspace:^",
|
||||
"@backstage/plugin-shortcuts": "workspace:^",
|
||||
"@backstage/plugin-stackstorm": "workspace:^",
|
||||
"@backstage/plugin-tech-insights": "workspace:^",
|
||||
"@backstage/plugin-tech-radar": "workspace:^",
|
||||
"@backstage/plugin-signals": "workspace:^",
|
||||
"@backstage/plugin-techdocs": "workspace:^",
|
||||
"@backstage/plugin-techdocs-module-addons-contrib": "workspace:^",
|
||||
"@backstage/plugin-techdocs-react": "workspace:^",
|
||||
"@backstage/plugin-todo": "workspace:^",
|
||||
"@backstage/plugin-user-settings": "workspace:^",
|
||||
"@backstage/theme": "workspace:^",
|
||||
"@circleci/backstage-plugin": "^0.1.1",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@octokit/rest": "^19.0.3",
|
||||
"@oriflame/backstage-plugin-score-card": "^0.8.0",
|
||||
"@roadiehq/backstage-plugin-buildkite": "^2.0.8",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^2.0.5",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^2.0.5",
|
||||
"app-next-example-plugin": "workspace:^",
|
||||
"@vitejs/plugin-react": "^4.0.4",
|
||||
"history": "^5.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-use": "^17.2.4",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"vite-plugin-node-polyfills": "^0.21.0",
|
||||
"zen-observable": "^0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -44,81 +44,35 @@
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/integration-react": "workspace:^",
|
||||
"@backstage/plugin-adr": "workspace:^",
|
||||
"@backstage/plugin-airbrake": "workspace:^",
|
||||
"@backstage/plugin-apache-airflow": "workspace:^",
|
||||
"@backstage/plugin-api-docs": "workspace:^",
|
||||
"@backstage/plugin-auth-react": "workspace:^",
|
||||
"@backstage/plugin-azure-devops": "workspace:^",
|
||||
"@backstage/plugin-azure-sites": "workspace:^",
|
||||
"@backstage/plugin-badges": "workspace:^",
|
||||
"@backstage/plugin-catalog": "workspace:^",
|
||||
"@backstage/plugin-catalog-common": "workspace:^",
|
||||
"@backstage/plugin-catalog-graph": "workspace:^",
|
||||
"@backstage/plugin-catalog-import": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "workspace:^",
|
||||
"@backstage/plugin-cloudbuild": "workspace:^",
|
||||
"@backstage/plugin-code-coverage": "workspace:^",
|
||||
"@backstage/plugin-cost-insights": "workspace:^",
|
||||
"@backstage/plugin-devtools": "workspace:^",
|
||||
"@backstage/plugin-dynatrace": "workspace:^",
|
||||
"@backstage/plugin-entity-feedback": "workspace:^",
|
||||
"@backstage/plugin-explore": "workspace:^",
|
||||
"@backstage/plugin-gcalendar": "workspace:^",
|
||||
"@backstage/plugin-gcp-projects": "workspace:^",
|
||||
"@backstage/plugin-github-actions": "workspace:^",
|
||||
"@backstage/plugin-github-pull-requests-board": "workspace:^",
|
||||
"@backstage/plugin-gocd": "workspace:^",
|
||||
"@backstage/plugin-graphiql": "workspace:^",
|
||||
"@backstage/plugin-home": "workspace:^",
|
||||
"@backstage/plugin-jenkins": "workspace:^",
|
||||
"@backstage/plugin-kafka": "workspace:^",
|
||||
"@backstage/plugin-kubernetes": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^",
|
||||
"@backstage/plugin-lighthouse": "workspace:^",
|
||||
"@backstage/plugin-linguist": "workspace:^",
|
||||
"@backstage/plugin-linguist-common": "workspace:^",
|
||||
"@backstage/plugin-microsoft-calendar": "workspace:^",
|
||||
"@backstage/plugin-newrelic": "workspace:^",
|
||||
"@backstage/plugin-newrelic-dashboard": "workspace:^",
|
||||
"@backstage/plugin-nomad": "workspace:^",
|
||||
"@backstage/plugin-notifications": "workspace:^",
|
||||
"@backstage/plugin-octopus-deploy": "workspace:^",
|
||||
"@backstage/plugin-org": "workspace:^",
|
||||
"@backstage/plugin-pagerduty": "workspace:^",
|
||||
"@backstage/plugin-permission-react": "workspace:^",
|
||||
"@backstage/plugin-playlist": "workspace:^",
|
||||
"@backstage/plugin-puppetdb": "workspace:^",
|
||||
"@backstage/plugin-rollbar": "workspace:^",
|
||||
"@backstage/plugin-scaffolder": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-react": "workspace:^",
|
||||
"@backstage/plugin-search": "workspace:^",
|
||||
"@backstage/plugin-search-common": "workspace:^",
|
||||
"@backstage/plugin-search-react": "workspace:^",
|
||||
"@backstage/plugin-sentry": "workspace:^",
|
||||
"@backstage/plugin-shortcuts": "workspace:^",
|
||||
"@backstage/plugin-signals": "workspace:^",
|
||||
"@backstage/plugin-stack-overflow": "workspace:^",
|
||||
"@backstage/plugin-stackstorm": "workspace:^",
|
||||
"@backstage/plugin-tech-insights": "workspace:^",
|
||||
"@backstage/plugin-tech-radar": "workspace:^",
|
||||
"@backstage/plugin-techdocs": "workspace:^",
|
||||
"@backstage/plugin-techdocs-module-addons-contrib": "workspace:^",
|
||||
"@backstage/plugin-techdocs-react": "workspace:^",
|
||||
"@backstage/plugin-todo": "workspace:^",
|
||||
"@backstage/plugin-user-settings": "workspace:^",
|
||||
"@backstage/theme": "workspace:^",
|
||||
"@circleci/backstage-plugin": "^0.1.1",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@octokit/rest": "^19.0.3",
|
||||
"@oriflame/backstage-plugin-score-card": "^0.8.0",
|
||||
"@roadiehq/backstage-plugin-buildkite": "^2.0.8",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^2.0.5",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^2.0.5",
|
||||
"@vitejs/plugin-react": "^4.0.4",
|
||||
"history": "^5.0.0",
|
||||
"react": "^18.0.2",
|
||||
|
||||
@@ -29,32 +29,23 @@
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/backend-tasks": "workspace:^",
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/plugin-adr-backend": "workspace:^",
|
||||
"@backstage/plugin-app-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-backend-module-github-provider": "workspace:^",
|
||||
"@backstage/plugin-auth-backend-module-guest-provider": "workspace:^",
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/plugin-azure-devops-backend": "workspace:^",
|
||||
"@backstage/plugin-badges-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-backstage-openapi": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-openapi": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^",
|
||||
"@backstage/plugin-devtools-backend": "workspace:^",
|
||||
"@backstage/plugin-entity-feedback-backend": "workspace:^",
|
||||
"@backstage/plugin-jenkins-backend": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-backend": "workspace:^",
|
||||
"@backstage/plugin-lighthouse-backend": "workspace:^",
|
||||
"@backstage/plugin-linguist-backend": "workspace:^",
|
||||
"@backstage/plugin-nomad-backend": "workspace:^",
|
||||
"@backstage/plugin-notifications-backend": "workspace:^",
|
||||
"@backstage/plugin-permission-backend": "workspace:^",
|
||||
"@backstage/plugin-permission-backend-module-allow-all-policy": "workspace:^",
|
||||
"@backstage/plugin-permission-common": "workspace:^",
|
||||
"@backstage/plugin-permission-node": "workspace:^",
|
||||
"@backstage/plugin-playlist-backend": "workspace:^",
|
||||
"@backstage/plugin-proxy-backend": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend-module-github": "workspace:^",
|
||||
@@ -64,9 +55,7 @@
|
||||
"@backstage/plugin-search-backend-module-techdocs": "workspace:^",
|
||||
"@backstage/plugin-search-backend-node": "workspace:^",
|
||||
"@backstage/plugin-signals-backend": "workspace:^",
|
||||
"@backstage/plugin-sonarqube-backend": "workspace:^",
|
||||
"@backstage/plugin-techdocs-backend": "workspace:^",
|
||||
"@backstage/plugin-todo-backend": "workspace:^"
|
||||
"@backstage/plugin-techdocs-backend": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^"
|
||||
|
||||
@@ -32,35 +32,21 @@
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/integration": "workspace:^",
|
||||
"@backstage/plugin-adr-backend": "workspace:^",
|
||||
"@backstage/plugin-app-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/plugin-azure-devops-backend": "workspace:^",
|
||||
"@backstage/plugin-azure-sites-common": "workspace:^",
|
||||
"@backstage/plugin-badges-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^",
|
||||
"@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^",
|
||||
"@backstage/plugin-catalog-node": "workspace:^",
|
||||
"@backstage/plugin-code-coverage-backend": "workspace:^",
|
||||
"@backstage/plugin-devtools-backend": "workspace:^",
|
||||
"@backstage/plugin-entity-feedback-backend": "workspace:^",
|
||||
"@backstage/plugin-events-backend": "workspace:^",
|
||||
"@backstage/plugin-events-node": "workspace:^",
|
||||
"@backstage/plugin-explore-backend": "workspace:^",
|
||||
"@backstage/plugin-jenkins-backend": "workspace:^",
|
||||
"@backstage/plugin-kafka-backend": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-backend": "workspace:^",
|
||||
"@backstage/plugin-lighthouse-backend": "workspace:^",
|
||||
"@backstage/plugin-linguist-backend": "workspace:^",
|
||||
"@backstage/plugin-nomad-backend": "workspace:^",
|
||||
"@backstage/plugin-permission-backend": "workspace:^",
|
||||
"@backstage/plugin-permission-common": "workspace:^",
|
||||
"@backstage/plugin-permission-node": "workspace:^",
|
||||
"@backstage/plugin-playlist-backend": "workspace:^",
|
||||
"@backstage/plugin-proxy-backend": "workspace:^",
|
||||
"@backstage/plugin-rollbar-backend": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^",
|
||||
"@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^",
|
||||
@@ -74,11 +60,7 @@
|
||||
"@backstage/plugin-search-backend-node": "workspace:^",
|
||||
"@backstage/plugin-signals-backend": "workspace:^",
|
||||
"@backstage/plugin-signals-node": "workspace:^",
|
||||
"@backstage/plugin-tech-insights-backend": "workspace:^",
|
||||
"@backstage/plugin-tech-insights-backend-module-jsonfc": "workspace:^",
|
||||
"@backstage/plugin-tech-insights-node": "workspace:^",
|
||||
"@backstage/plugin-techdocs-backend": "workspace:^",
|
||||
"@backstage/plugin-todo-backend": "workspace:^",
|
||||
"@gitbeaker/node": "^35.1.0",
|
||||
"@octokit/rest": "^19.0.3",
|
||||
"@opentelemetry/api": "^1.4.1",
|
||||
|
||||
@@ -37,13 +37,13 @@
|
||||
"@types/react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage-community/plugin-puppetdb": "^0.1.18",
|
||||
"@backstage-community/plugin-stackstorm": "^0.1.16",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/core-app-api": "workspace:^",
|
||||
"@backstage/frontend-app-api": "workspace:^",
|
||||
"@backstage/frontend-test-utils": "workspace:^",
|
||||
"@backstage/plugin-catalog": "workspace:^",
|
||||
"@backstage/plugin-puppetdb": "workspace:^",
|
||||
"@backstage/plugin-stackstorm": "workspace:^",
|
||||
"@oriflame/backstage-plugin-score-card": "^0.8.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^15.0.0"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
# Deprecated
|
||||
|
||||
This package has been moved to the [backstage-community/plugins](https://github.com/backstage/community-plugins) repository. Migrate to using `@backstage-community/plugin-linguist-backend` instead.
|
||||
@@ -1,123 +0,0 @@
|
||||
## API Report File for "@backstage/plugin-linguist-backend"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { AuthService } from '@backstage/backend-plugin-api';
|
||||
import { BackendFeature } from '@backstage/backend-plugin-api';
|
||||
import { CatalogProcessor } from '@backstage/plugin-catalog-node';
|
||||
import { CatalogProcessorCache } from '@backstage/plugin-catalog-node';
|
||||
import { Config } from '@backstage/config';
|
||||
import { DiscoveryService } from '@backstage/backend-plugin-api';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import express from 'express';
|
||||
import { HttpAuthService } from '@backstage/backend-plugin-api';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
import { LanguageType } from '@backstage/plugin-linguist-common';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
import { TaskScheduleDefinition } from '@backstage/backend-tasks';
|
||||
import { TokenManager } from '@backstage/backend-common';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
|
||||
// @public (undocumented)
|
||||
export function createRouter(
|
||||
pluginOptions: PluginOptions,
|
||||
routerOptions: RouterOptions,
|
||||
): Promise<express.Router>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function createRouterFromConfig(
|
||||
routerOptions: RouterOptions,
|
||||
): Promise<express.Router>;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface LinguistBackendApi {
|
||||
// (undocumented)
|
||||
getEntityLanguages(entityRef: string): Promise<Languages>;
|
||||
// (undocumented)
|
||||
processEntities(): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
const linguistPlugin: () => BackendFeature;
|
||||
export default linguistPlugin;
|
||||
|
||||
// @public
|
||||
export class LinguistTagsProcessor implements CatalogProcessor {
|
||||
constructor(options: LinguistTagsProcessorOptions);
|
||||
// (undocumented)
|
||||
static fromConfig(
|
||||
config: Config,
|
||||
options: LinguistTagsProcessorOptions,
|
||||
): LinguistTagsProcessor;
|
||||
// (undocumented)
|
||||
getProcessorName(): string;
|
||||
preProcessEntity(
|
||||
entity: Entity,
|
||||
_: any,
|
||||
__: any,
|
||||
___: any,
|
||||
cache: CatalogProcessorCache,
|
||||
): Promise<Entity>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface LinguistTagsProcessorOptions {
|
||||
bytesThreshold?: number;
|
||||
cacheTTL?: HumanDuration;
|
||||
// (undocumented)
|
||||
discovery: DiscoveryService;
|
||||
languageMap?: Record<string, string | undefined>;
|
||||
languageTypes?: LanguageType[];
|
||||
// (undocumented)
|
||||
logger: LoggerService;
|
||||
shouldProcessEntity?: ShouldProcessEntity;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface PluginOptions {
|
||||
// (undocumented)
|
||||
age?: HumanDuration;
|
||||
// (undocumented)
|
||||
batchSize?: number;
|
||||
// (undocumented)
|
||||
kind?: string[];
|
||||
// (undocumented)
|
||||
linguistJsOptions?: Record<string, unknown>;
|
||||
// (undocumented)
|
||||
schedule?: TaskScheduleDefinition;
|
||||
// (undocumented)
|
||||
useSourceLocation?: boolean;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RouterOptions {
|
||||
// (undocumented)
|
||||
auth?: AuthService;
|
||||
// (undocumented)
|
||||
config?: Config;
|
||||
// (undocumented)
|
||||
database: PluginDatabaseManager;
|
||||
// (undocumented)
|
||||
discovery: PluginEndpointDiscovery;
|
||||
// (undocumented)
|
||||
httpAuth?: HttpAuthService;
|
||||
// (undocumented)
|
||||
linguistBackendApi?: LinguistBackendApi;
|
||||
// (undocumented)
|
||||
logger: LoggerService;
|
||||
// (undocumented)
|
||||
reader: UrlReader;
|
||||
// (undocumented)
|
||||
scheduler?: PluginTaskScheduler;
|
||||
// (undocumented)
|
||||
tokenManager: TokenManager;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type ShouldProcessEntity = (entity: Entity) => boolean;
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-plugin-linguist-backend
|
||||
title: '@backstage/plugin-linguist-backend'
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-backend-plugin
|
||||
owner: awanlin
|
||||
Vendored
-72
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { TaskScheduleDefinition } from '@backstage/backend-tasks';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { Options as LinguistJsOptions } from 'linguist-js/dist/types';
|
||||
|
||||
export interface Config {
|
||||
/** Configuration options for the linguist plugin */
|
||||
linguist?: {
|
||||
schedule?: TaskScheduleDefinition;
|
||||
/**
|
||||
* @default 20
|
||||
*/
|
||||
batchSize?: number;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
useSourceLocation?: boolean;
|
||||
/**
|
||||
* Refresh generated language breakdown
|
||||
*/
|
||||
age?: HumanDuration;
|
||||
/**
|
||||
* @default ['API', 'Component', 'Template']
|
||||
*/
|
||||
kind?: string[];
|
||||
/**
|
||||
* [linguist-js](https://www.npmjs.com/package/linguist-js) options
|
||||
*/
|
||||
linguistJsOptions?: LinguistJsOptions;
|
||||
|
||||
/** Options for the tags processor */
|
||||
tagsProcessor?: {
|
||||
/**
|
||||
* Determines how many bytes of a language should be in a repo
|
||||
* for it to be added as an entity tag. Defaults to 0.
|
||||
*/
|
||||
bytesThreshold?: number;
|
||||
/**
|
||||
* The types of linguist languages that should be processed. Can be
|
||||
* any of "programming", "data", "markup", "prose". Defaults to ["programming"].
|
||||
*/
|
||||
languageTypes?: string[];
|
||||
/**
|
||||
* A custom mapping of linguist languages to how they should be rendered as entity tags.
|
||||
* If a language is mapped to '' it will not be included as a tag.
|
||||
*/
|
||||
languageMap?: {
|
||||
[language: string]: string | undefined;
|
||||
};
|
||||
/**
|
||||
* How long to cache entity languages for in memory. Used to avoid constant db hits during
|
||||
* processing. Defaults to 30 minutes.
|
||||
*/
|
||||
cacheTTL?: HumanDuration;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import('knex').Knex} knex
|
||||
*/
|
||||
exports.up = async function up(knex) {
|
||||
// Note for the reader: the knex increments types automatically make it a
|
||||
// primary column, whether you like it or not. That's why the id column is
|
||||
// not marked as primary as one might have expected; it's only used for
|
||||
// lookups by ID. Because, SQLite and MySQL don't return RETURNING on
|
||||
// inserts ... so we want a manually generated key for lookups (an uuid),
|
||||
// and also an index for ordering guarantees :)
|
||||
await knex.schema.createTable('entity_result', table => {
|
||||
table.comment('Table containing results from running Linguist');
|
||||
table
|
||||
.bigIncrements('index')
|
||||
.notNullable()
|
||||
.comment('An insert counter to ensure ordering');
|
||||
table.uuid('id').notNullable().comment('The ID of the Linguist result');
|
||||
table
|
||||
.string('entity_ref')
|
||||
.unique()
|
||||
.notNullable()
|
||||
.comment('The entity ref that this Linguist result applies to');
|
||||
table.text('languages').comment('The results json as a string');
|
||||
table
|
||||
.dateTime('created_at')
|
||||
.defaultTo(knex.fn.now())
|
||||
.notNullable()
|
||||
.comment('The timestamp when this entry was created');
|
||||
table
|
||||
.dateTime('processed_date')
|
||||
.defaultTo(knex.fn.now())
|
||||
.comment('The timestamp when this entity was processed');
|
||||
table.index('index', 'entity_result_index_idx');
|
||||
table.index('entity_ref', 'entity_result_entity_ref_idx');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('knex').Knex} knex
|
||||
*/
|
||||
exports.down = async function down(knex) {
|
||||
await knex.schema.alterTable('entity_result', table => {
|
||||
table.dropIndex([], 'entity_result_index_idx');
|
||||
table.dropIndex([], 'entity_result_entity_ref_idx');
|
||||
});
|
||||
await knex.schema.dropTable('entity_result');
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import('knex').Knex} knex
|
||||
*/
|
||||
exports.up = async function up(knex) {
|
||||
// Sqlite does not support this raw SQL
|
||||
if (!knex.client.config.client.includes('sqlite3')) {
|
||||
await knex.raw(
|
||||
'ALTER TABLE entity_result ALTER COLUMN processed_date DROP DEFAULT;',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {import('knex').Knex} knex
|
||||
*/
|
||||
exports.down = async function down(knex) {
|
||||
// Sqlite does not support this raw SQL
|
||||
if (!knex.client.config.client.includes('sqlite3')) {
|
||||
await knex.raw(
|
||||
'ALTER TABLE entity_result ALTER COLUMN processed_date SET DEFAULT now();',
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
{
|
||||
"name": "@backstage/plugin-linguist-backend",
|
||||
"version": "0.5.15",
|
||||
"backstage": {
|
||||
"role": "backend-plugin",
|
||||
"moved": "@backstage-community/plugin-linguist-backend"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/linguist-backend"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"config.d.ts",
|
||||
"migrations/**/*.{js,d.ts}"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"start": "backstage-cli package start",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/backend-tasks": "workspace:^",
|
||||
"@backstage/catalog-client": "workspace:^",
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/plugin-catalog-node": "workspace:^",
|
||||
"@backstage/plugin-linguist-common": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@types/express": "*",
|
||||
"express": "^4.18.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"fs-extra": "^11.0.0",
|
||||
"knex": "^3.0.0",
|
||||
"linguist-js": "^2.5.3",
|
||||
"luxon": "^3.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"uuid": "^9.0.0",
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-test-utils": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"js-yaml": "^4.1.0",
|
||||
"supertest": "^6.2.4"
|
||||
},
|
||||
"configSchema": "config.d.ts",
|
||||
"deprecated": "This package has been moved to the backstage/community-plugins repository. You should migrate to using @backstage-community/plugin-linguist-backend instead."
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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,
|
||||
ReadTreeResponse,
|
||||
UrlReader,
|
||||
} from '@backstage/backend-common';
|
||||
import { CatalogApi, GetEntitiesResponse } from '@backstage/catalog-client';
|
||||
import { Results } from 'linguist-js/dist/types';
|
||||
import { DateTime } from 'luxon';
|
||||
import { LinguistBackendStore } from '../db';
|
||||
import { kindOrDefault, LinguistBackendClient } from './LinguistBackendClient';
|
||||
import fs from 'fs-extra';
|
||||
import { LINGUIST_ANNOTATION } from '@backstage/plugin-linguist-common';
|
||||
import { mockServices } from '@backstage/backend-test-utils';
|
||||
|
||||
const linguistResultMock = Promise.resolve({
|
||||
files: {
|
||||
count: 4,
|
||||
bytes: 6010,
|
||||
results: {
|
||||
'/src/index.ts': 'TypeScript',
|
||||
'/src/cli.js': 'JavaScript',
|
||||
'/readme.md': 'Markdown',
|
||||
'/no-lang': null,
|
||||
},
|
||||
alternatives: {
|
||||
'~/alternatives.asc': ['AsciiDoc', 'Public Key'],
|
||||
},
|
||||
},
|
||||
languages: {
|
||||
count: 3,
|
||||
bytes: 6000,
|
||||
results: {
|
||||
JavaScript: { type: 'programming', bytes: 1000, color: '#f1e05a' },
|
||||
TypeScript: { type: 'programming', bytes: 2000, color: '#2b7489' },
|
||||
Markdown: { type: 'prose', bytes: 3000, color: '#083fa1' },
|
||||
},
|
||||
},
|
||||
unknown: {
|
||||
count: 1,
|
||||
bytes: 10,
|
||||
filenames: {
|
||||
'no-lang': 10,
|
||||
},
|
||||
extensions: {},
|
||||
},
|
||||
} as Results);
|
||||
|
||||
describe('kindOrDefault', () => {
|
||||
it('should return default kind when undefined', () => {
|
||||
expect(kindOrDefault()).toEqual(['API', 'Component', 'Template']);
|
||||
});
|
||||
it('should return the default kind when empty', () => {
|
||||
expect(kindOrDefault([])).toEqual(['API', 'Component', 'Template']);
|
||||
});
|
||||
it('should return provided kind when not empty', () => {
|
||||
expect(kindOrDefault(['API'])).toEqual(['API']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Linguist backend API', () => {
|
||||
const logger = getVoidLogger();
|
||||
|
||||
const store: jest.Mocked<LinguistBackendStore> = {
|
||||
insertEntityResults: jest.fn(),
|
||||
insertNewEntity: jest.fn(),
|
||||
getEntityResults: jest.fn(),
|
||||
getProcessedEntities: jest.fn(),
|
||||
getUnprocessedEntities: jest.fn(),
|
||||
getAllEntities: jest.fn(),
|
||||
deleteEntity: jest.fn(),
|
||||
};
|
||||
|
||||
const urlReader: jest.Mocked<UrlReader> = {
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
readUrl: jest.fn(),
|
||||
};
|
||||
|
||||
const catalogApi: jest.Mocked<CatalogApi> = {
|
||||
getEntities: jest.fn(),
|
||||
getEntityByRef: jest.fn(),
|
||||
} as any;
|
||||
|
||||
const api = new LinguistBackendClient(
|
||||
logger,
|
||||
store,
|
||||
urlReader,
|
||||
mockServices.auth(),
|
||||
catalogApi,
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should get languages for an entity', async () => {
|
||||
store.getEntityResults.mockResolvedValue({
|
||||
languageCount: 1,
|
||||
totalBytes: 2205,
|
||||
processedDate: '2023-02-15T20:10:21.378Z',
|
||||
breakdown: [
|
||||
{
|
||||
name: 'YAML',
|
||||
percentage: 100,
|
||||
bytes: 2205,
|
||||
type: 'data',
|
||||
color: '#cb171e',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const entityRef = 'template:default/create-react-app-template';
|
||||
const languages = await api.getEntityLanguages(entityRef);
|
||||
expect(languages).toEqual({
|
||||
languageCount: 1,
|
||||
totalBytes: 2205,
|
||||
processedDate: '2023-02-15T20:10:21.378Z',
|
||||
breakdown: [
|
||||
{
|
||||
name: 'YAML',
|
||||
percentage: 100,
|
||||
bytes: 2205,
|
||||
type: 'data',
|
||||
color: '#cb171e',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should insert new entities', async () => {
|
||||
const testEntityListResponse: GetEntitiesResponse = {
|
||||
items: [
|
||||
{
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
metadata: {
|
||||
name: 'service-one',
|
||||
},
|
||||
kind: 'Component',
|
||||
},
|
||||
{
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
metadata: {
|
||||
name: 'service-two',
|
||||
},
|
||||
kind: 'Component',
|
||||
},
|
||||
{
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
metadata: {
|
||||
name: 'service-three',
|
||||
},
|
||||
kind: 'Component',
|
||||
},
|
||||
],
|
||||
};
|
||||
catalogApi.getEntities.mockResolvedValue(testEntityListResponse);
|
||||
|
||||
await api.addNewEntities();
|
||||
expect(store.insertNewEntity).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should delete entities not in Catalog', async () => {
|
||||
store.getAllEntities.mockResolvedValue([
|
||||
'component:default/service-one',
|
||||
'component:default/stale-service-two',
|
||||
]);
|
||||
|
||||
catalogApi.getEntityByRef.mockResolvedValueOnce({
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
metadata: {
|
||||
name: 'service-one',
|
||||
},
|
||||
kind: 'Component',
|
||||
});
|
||||
|
||||
await api.cleanEntities();
|
||||
expect(store.deleteEntity).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should get default entity overview', async () => {
|
||||
store.getProcessedEntities.mockResolvedValue([
|
||||
{
|
||||
entityRef: 'component:default/service-one',
|
||||
processedDate: DateTime.now().toJSDate(),
|
||||
},
|
||||
{
|
||||
entityRef: 'component:default/stale-service-two',
|
||||
processedDate: DateTime.now().minus({ days: 45 }).toJSDate(),
|
||||
},
|
||||
]);
|
||||
|
||||
store.getUnprocessedEntities.mockResolvedValue([
|
||||
'component:default/service-three',
|
||||
'component:default/service-four',
|
||||
'component:default/service-five',
|
||||
]);
|
||||
|
||||
const overview = await api.getEntitiesOverview();
|
||||
expect(overview.entityCount).toEqual(5);
|
||||
expect(overview.processedCount).toEqual(2);
|
||||
expect(overview.staleCount).toEqual(0);
|
||||
expect(overview.pendingCount).toEqual(3);
|
||||
expect(overview.filteredEntities).toEqual([
|
||||
'component:default/service-three',
|
||||
'component:default/service-four',
|
||||
'component:default/service-five',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should get entity overview with stale items', async () => {
|
||||
const apiWithAge = new LinguistBackendClient(
|
||||
logger,
|
||||
store,
|
||||
urlReader,
|
||||
mockServices.auth(),
|
||||
catalogApi,
|
||||
{ days: 5 },
|
||||
);
|
||||
store.getProcessedEntities.mockResolvedValue([
|
||||
{
|
||||
entityRef: 'component:default/service-one',
|
||||
processedDate: DateTime.now().toJSDate(),
|
||||
},
|
||||
{
|
||||
entityRef: 'component:default/stale-service-two',
|
||||
processedDate: DateTime.now().minus({ days: 45 }).toJSDate(),
|
||||
},
|
||||
]);
|
||||
|
||||
store.getUnprocessedEntities.mockResolvedValue([
|
||||
'component:default/service-three',
|
||||
'component:default/service-four',
|
||||
'component:default/service-five',
|
||||
]);
|
||||
|
||||
const overview = await apiWithAge.getEntitiesOverview();
|
||||
expect(overview.entityCount).toEqual(5);
|
||||
expect(overview.processedCount).toEqual(2);
|
||||
expect(overview.staleCount).toEqual(1);
|
||||
expect(overview.pendingCount).toEqual(4);
|
||||
expect(overview.filteredEntities).toEqual([
|
||||
'component:default/service-three',
|
||||
'component:default/service-four',
|
||||
'component:default/service-five',
|
||||
'component:default/stale-service-two',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate and save languages for an entity', async () => {
|
||||
const spy = jest
|
||||
.spyOn(api, 'getLinguistResults')
|
||||
.mockImplementation(() => linguistResultMock);
|
||||
|
||||
urlReader.readTree.mockResolvedValueOnce({
|
||||
files: async () => [
|
||||
{
|
||||
content: async () => Buffer.from('-- XXX: code-data', 'utf8'),
|
||||
path: 'my-file.js',
|
||||
},
|
||||
],
|
||||
dir: async () => '/temp/my-code',
|
||||
} as ReadTreeResponse);
|
||||
|
||||
const fsSpy = jest.spyOn(fs, 'remove');
|
||||
|
||||
await api.generateEntityLanguages(
|
||||
'component:default/fake-service',
|
||||
'https://some.fake/service/',
|
||||
);
|
||||
expect(api.getLinguistResults).toHaveBeenCalled();
|
||||
expect(store.insertEntityResults).toHaveBeenCalled();
|
||||
expect(fs.remove).toHaveBeenCalled();
|
||||
spy.mockClear();
|
||||
fsSpy.mockClear();
|
||||
});
|
||||
|
||||
it('should generate languages for entities using default', async () => {
|
||||
store.getProcessedEntities.mockResolvedValue([
|
||||
{
|
||||
entityRef: 'component:default/service-one',
|
||||
processedDate: DateTime.now().toJSDate(),
|
||||
},
|
||||
{
|
||||
entityRef: 'component:default/stale-service-two',
|
||||
processedDate: DateTime.now().minus({ days: 45 }).toJSDate(),
|
||||
},
|
||||
]);
|
||||
|
||||
store.getUnprocessedEntities.mockResolvedValue([
|
||||
'component:default/service-three',
|
||||
'component:default/service-four',
|
||||
'component:default/service-five',
|
||||
]);
|
||||
|
||||
const entity = {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
metadata: {
|
||||
name: 'service-one',
|
||||
annotations: {
|
||||
[LINGUIST_ANNOTATION]: 'https://some.fake/service/',
|
||||
},
|
||||
},
|
||||
kind: 'Component',
|
||||
};
|
||||
|
||||
catalogApi.getEntityByRef.mockResolvedValue(entity);
|
||||
|
||||
const resultsSpy = jest
|
||||
.spyOn(api, 'getLinguistResults')
|
||||
.mockImplementation(() => linguistResultMock);
|
||||
|
||||
urlReader.readTree.mockResolvedValue({
|
||||
files: async () => [
|
||||
{
|
||||
content: async () => Buffer.from('-- XXX: code-data', 'utf8'),
|
||||
path: 'my-file.js',
|
||||
},
|
||||
],
|
||||
dir: async () => '/temp/my-code',
|
||||
} as ReadTreeResponse);
|
||||
|
||||
const fsSpy = jest.spyOn(fs, 'remove');
|
||||
|
||||
const generateEntityLanguages = jest.spyOn(api, 'generateEntityLanguages');
|
||||
await api.generateEntitiesLanguages();
|
||||
expect(generateEntityLanguages).toHaveBeenCalledTimes(3);
|
||||
|
||||
generateEntityLanguages.mockClear();
|
||||
resultsSpy.mockClear();
|
||||
fsSpy.mockClear();
|
||||
});
|
||||
|
||||
it('should generate languages for entities using defined batch size', async () => {
|
||||
const apiWithBatchSize = new LinguistBackendClient(
|
||||
logger,
|
||||
store,
|
||||
urlReader,
|
||||
mockServices.auth(),
|
||||
catalogApi,
|
||||
undefined,
|
||||
2,
|
||||
);
|
||||
|
||||
store.getProcessedEntities.mockResolvedValue([
|
||||
{
|
||||
entityRef: 'component:default/service-one',
|
||||
processedDate: DateTime.now().toJSDate(),
|
||||
},
|
||||
{
|
||||
entityRef: 'component:default/stale-service-two',
|
||||
processedDate: DateTime.now().minus({ days: 45 }).toJSDate(),
|
||||
},
|
||||
]);
|
||||
|
||||
store.getUnprocessedEntities.mockResolvedValue([
|
||||
'component:default/service-three',
|
||||
'component:default/service-four',
|
||||
'component:default/service-five',
|
||||
]);
|
||||
|
||||
const entity = {
|
||||
apiVersion: 'backstage.io/v1beta1',
|
||||
metadata: {
|
||||
name: 'service-one',
|
||||
annotations: {
|
||||
[LINGUIST_ANNOTATION]: 'https://some.fake/service/',
|
||||
},
|
||||
},
|
||||
kind: 'Component',
|
||||
};
|
||||
|
||||
catalogApi.getEntityByRef.mockResolvedValue(entity);
|
||||
|
||||
const resultsSpy = jest
|
||||
.spyOn(apiWithBatchSize, 'getLinguistResults')
|
||||
.mockImplementation(() => linguistResultMock);
|
||||
|
||||
urlReader.readTree.mockResolvedValue({
|
||||
files: async () => [
|
||||
{
|
||||
content: async () => Buffer.from('-- XXX: code-data', 'utf8'),
|
||||
path: 'my-file.js',
|
||||
},
|
||||
],
|
||||
dir: async () => '/temp/my-code',
|
||||
} as ReadTreeResponse);
|
||||
|
||||
const fsSpy = jest.spyOn(fs, 'remove');
|
||||
|
||||
const generateEntityLanguages = jest.spyOn(
|
||||
apiWithBatchSize,
|
||||
'generateEntityLanguages',
|
||||
);
|
||||
await apiWithBatchSize.generateEntitiesLanguages();
|
||||
expect(generateEntityLanguages).toHaveBeenCalledTimes(2);
|
||||
|
||||
generateEntityLanguages.mockClear();
|
||||
resultsSpy.mockClear();
|
||||
fsSpy.mockClear();
|
||||
});
|
||||
});
|
||||
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 {
|
||||
EntitiesOverview,
|
||||
EntityResults,
|
||||
Language,
|
||||
Languages,
|
||||
LINGUIST_ANNOTATION,
|
||||
} from '@backstage/plugin-linguist-common';
|
||||
import {
|
||||
CATALOG_FILTER_EXISTS,
|
||||
CatalogApi,
|
||||
GetEntitiesRequest,
|
||||
} from '@backstage/catalog-client';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
|
||||
import { DateTime } from 'luxon';
|
||||
import { LinguistBackendStore } from '../db';
|
||||
import fs from 'fs-extra';
|
||||
import linguist from 'linguist-js';
|
||||
import {
|
||||
ANNOTATION_SOURCE_LOCATION,
|
||||
stringifyEntityRef,
|
||||
} from '@backstage/catalog-model';
|
||||
import { assertError } from '@backstage/errors';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { Results } from 'linguist-js/dist/types';
|
||||
import { type AuthService, LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export interface LinguistBackendApi {
|
||||
getEntityLanguages(entityRef: string): Promise<Languages>;
|
||||
processEntities(): Promise<void>;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export class LinguistBackendClient implements LinguistBackendApi {
|
||||
private readonly logger: LoggerService;
|
||||
private readonly store: LinguistBackendStore;
|
||||
private readonly urlReader: UrlReader;
|
||||
private readonly auth: AuthService;
|
||||
|
||||
private readonly catalogApi: CatalogApi;
|
||||
private readonly age?: HumanDuration;
|
||||
private readonly batchSize?: number;
|
||||
private readonly useSourceLocation?: boolean;
|
||||
private readonly kind: string[];
|
||||
private readonly linguistJsOptions?: Record<string, unknown>;
|
||||
public constructor(
|
||||
logger: LoggerService,
|
||||
store: LinguistBackendStore,
|
||||
urlReader: UrlReader,
|
||||
auth: AuthService,
|
||||
catalogApi: CatalogApi,
|
||||
age?: HumanDuration,
|
||||
batchSize?: number,
|
||||
useSourceLocation?: boolean,
|
||||
kind?: string[],
|
||||
linguistJsOptions?: Record<string, unknown>,
|
||||
) {
|
||||
this.logger = logger;
|
||||
this.store = store;
|
||||
this.urlReader = urlReader;
|
||||
this.auth = auth;
|
||||
this.catalogApi = catalogApi;
|
||||
this.batchSize = batchSize;
|
||||
this.age = age;
|
||||
this.useSourceLocation = useSourceLocation;
|
||||
this.kind = kindOrDefault(kind);
|
||||
this.linguistJsOptions = linguistJsOptions;
|
||||
}
|
||||
|
||||
async getEntityLanguages(entityRef: string): Promise<Languages> {
|
||||
this.logger?.debug(`Getting languages for entity "${entityRef}"`);
|
||||
|
||||
return this.store.getEntityResults(entityRef);
|
||||
}
|
||||
|
||||
async processEntities(): Promise<void> {
|
||||
this.logger?.info('Updating list of entities');
|
||||
await this.addNewEntities();
|
||||
|
||||
this.logger?.info('Cleaning list of entities');
|
||||
await this.cleanEntities();
|
||||
|
||||
this.logger?.info('Processing applicable entities through Linguist');
|
||||
await this.generateEntitiesLanguages();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async addNewEntities(): Promise<void> {
|
||||
const annotationKey = this.useSourceLocation
|
||||
? ANNOTATION_SOURCE_LOCATION
|
||||
: LINGUIST_ANNOTATION;
|
||||
const request: GetEntitiesRequest = {
|
||||
filter: {
|
||||
kind: this.kind,
|
||||
[`metadata.annotations.${annotationKey}`]: CATALOG_FILTER_EXISTS,
|
||||
},
|
||||
fields: ['kind', 'metadata'],
|
||||
};
|
||||
|
||||
const { token } = await this.auth.getPluginRequestToken({
|
||||
onBehalfOf: await this.auth.getOwnServiceCredentials(),
|
||||
targetPluginId: 'catalog',
|
||||
});
|
||||
const response = await this.catalogApi.getEntities(request, { token });
|
||||
const entities = response.items;
|
||||
|
||||
entities.forEach(entity => {
|
||||
const entityRef = stringifyEntityRef(entity);
|
||||
this.store.insertNewEntity(entityRef);
|
||||
});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async cleanEntities(): Promise<void> {
|
||||
this.logger?.info('Cleaning entities in Linguist queue');
|
||||
const allEntities = await this.store.getAllEntities();
|
||||
|
||||
for (const entityRef of allEntities) {
|
||||
const { token } = await this.auth.getPluginRequestToken({
|
||||
onBehalfOf: await this.auth.getOwnServiceCredentials(),
|
||||
targetPluginId: 'catalog',
|
||||
});
|
||||
const result = await this.catalogApi.getEntityByRef(entityRef, { token });
|
||||
|
||||
if (!result) {
|
||||
this.logger?.info(
|
||||
`Entity ${entityRef} was not found in the Catalog, it will be deleted`,
|
||||
);
|
||||
await this.store.deleteEntity(entityRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async generateEntitiesLanguages(): Promise<void> {
|
||||
const entitiesOverview = await this.getEntitiesOverview();
|
||||
this.logger?.info(
|
||||
`Entities overview: Entity: ${entitiesOverview.entityCount}, Processed: ${entitiesOverview.processedCount}, Pending: ${entitiesOverview.pendingCount}, Stale ${entitiesOverview.staleCount}`,
|
||||
);
|
||||
|
||||
const entities = entitiesOverview.filteredEntities.slice(
|
||||
0,
|
||||
this.batchSize ?? 20,
|
||||
);
|
||||
|
||||
for (const entityRef of entities) {
|
||||
const { token } = await this.auth.getPluginRequestToken({
|
||||
onBehalfOf: await this.auth.getOwnServiceCredentials(),
|
||||
targetPluginId: 'catalog',
|
||||
});
|
||||
const entity = await this.catalogApi.getEntityByRef(entityRef, {
|
||||
token,
|
||||
});
|
||||
const annotationKey = this.useSourceLocation
|
||||
? ANNOTATION_SOURCE_LOCATION
|
||||
: LINGUIST_ANNOTATION;
|
||||
|
||||
let url = entity?.metadata.annotations?.[annotationKey] ?? '';
|
||||
if (url.startsWith('url:')) {
|
||||
url = url.slice(4);
|
||||
}
|
||||
|
||||
try {
|
||||
await this.generateEntityLanguages(entityRef, url);
|
||||
} catch (error) {
|
||||
assertError(error);
|
||||
this.logger.error(
|
||||
`Unable to process "${entityRef}" using "${url}", message: ${error.message}, stack: ${error.stack}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async getEntitiesOverview(): Promise<EntitiesOverview> {
|
||||
this.logger?.debug('Getting pending entities');
|
||||
|
||||
const processedEntities = await this.store.getProcessedEntities();
|
||||
const staleEntities = processedEntities
|
||||
.filter(pe => {
|
||||
if (this.age === undefined) return false;
|
||||
const staleDate = DateTime.now().minus(this.age as HumanDuration);
|
||||
return DateTime.fromJSDate(pe.processedDate) <= staleDate;
|
||||
})
|
||||
.map(pe => pe.entityRef);
|
||||
|
||||
const unprocessedEntities = await this.store.getUnprocessedEntities();
|
||||
const filteredEntities = unprocessedEntities.concat(staleEntities);
|
||||
|
||||
const entitiesOverview: EntitiesOverview = {
|
||||
entityCount: unprocessedEntities.length + processedEntities.length,
|
||||
processedCount: processedEntities.length,
|
||||
staleCount: staleEntities.length,
|
||||
pendingCount: filteredEntities.length,
|
||||
filteredEntities: filteredEntities,
|
||||
};
|
||||
|
||||
return entitiesOverview;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async generateEntityLanguages(
|
||||
entityRef: string,
|
||||
url: string,
|
||||
): Promise<string> {
|
||||
this.logger?.info(
|
||||
`Processing languages for entity ${entityRef} from ${url}`,
|
||||
);
|
||||
|
||||
const readTreeResponse = await this.urlReader.readTree(url);
|
||||
const dir = await readTreeResponse.dir();
|
||||
|
||||
const results = await this.getLinguistResults(dir);
|
||||
|
||||
try {
|
||||
const totalBytes = results.languages.bytes;
|
||||
const langResults = results.languages.results;
|
||||
|
||||
const breakdown: Language[] = [];
|
||||
for (const key in langResults) {
|
||||
if (Object.prototype.hasOwnProperty.call(langResults, key)) {
|
||||
const lang: Language = {
|
||||
name: key,
|
||||
percentage: +((langResults[key].bytes / totalBytes) * 100).toFixed(
|
||||
2,
|
||||
),
|
||||
bytes: langResults[key].bytes,
|
||||
type: langResults[key].type,
|
||||
color: langResults[key].color,
|
||||
};
|
||||
breakdown.push(lang);
|
||||
}
|
||||
}
|
||||
|
||||
const languages: Languages = {
|
||||
languageCount: results.languages.count,
|
||||
totalBytes: totalBytes,
|
||||
processedDate: new Date().toISOString(),
|
||||
breakdown: breakdown,
|
||||
};
|
||||
|
||||
const entityResults: EntityResults = {
|
||||
entityRef: entityRef,
|
||||
results: languages,
|
||||
};
|
||||
|
||||
return await this.store.insertEntityResults(entityResults);
|
||||
} finally {
|
||||
this.logger?.info(`Cleaning up files from ${dir}`);
|
||||
await fs.remove(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async getLinguistResults(dir: string): Promise<Results> {
|
||||
const results = await linguist(dir, { ...this.linguistJsOptions });
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
export function kindOrDefault(kind?: string[]): string[] {
|
||||
if (!kind || kind.length === 0) {
|
||||
return ['API', 'Component', 'Template'];
|
||||
}
|
||||
return kind;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export type { LinguistBackendApi } from './LinguistBackendClient';
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 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 { Knex as KnexType, Knex } from 'knex';
|
||||
import { TestDatabases } from '@backstage/backend-test-utils';
|
||||
import {
|
||||
LinguistBackendDatabase,
|
||||
LinguistBackendStore,
|
||||
} from './LinguistBackendDatabase';
|
||||
import { Languages, ProcessedEntity } from '@backstage/plugin-linguist-common';
|
||||
|
||||
function createDatabaseManager(
|
||||
client: KnexType,
|
||||
skipMigrations: boolean = false,
|
||||
) {
|
||||
return {
|
||||
getClient: async () => client,
|
||||
migrations: {
|
||||
skip: skipMigrations,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const rawDbEntityResultRows = [
|
||||
{
|
||||
id: '14b32439-848a-49b2-92a4-98753f932606',
|
||||
entity_ref: 'template:default/create-react-app-template',
|
||||
languages: undefined,
|
||||
processed_date: undefined,
|
||||
},
|
||||
{
|
||||
id: '8c85d3ec-ccea-4b29-9de9-ccdd7e5ba452',
|
||||
entity_ref: 'template:default/docs-template',
|
||||
languages: undefined,
|
||||
processed_date: undefined,
|
||||
},
|
||||
{
|
||||
id: 'b922c87b-37bc-4505-b4af-70a1438decda',
|
||||
entity_ref: 'template:default/pull-request',
|
||||
languages:
|
||||
'{"languageCount":1,"totalBytes":2205,"processedDate":"2023-02-15T20:10:21.378Z","breakdown":[{"name":"YAML","percentage":100,"bytes":2205,"type":"data","color":"#cb171e"}]}',
|
||||
processed_date: new Date('2023-02-15 20:10:21.378Z'),
|
||||
},
|
||||
{
|
||||
id: 'bd555e6d-a3d0-4b48-a930-194db8f80db7',
|
||||
entity_ref: 'template:default/react-ssr-template',
|
||||
languages:
|
||||
'{"languageCount":8,"totalBytes":8988,"processedDate":"2023-02-15T20:10:21.388Z","breakdown":[{"name":"INI","percentage":2.26,"bytes":203,"type":"data","color":"#d1dbe0"},{"name":"JavaScript","percentage":5.94,"bytes":534,"type":"programming","color":"#f1e05a"},{"name":"YAML","percentage":31.09,"bytes":2794,"type":"data","color":"#cb171e"},{"name":"Markdown","percentage":11.79,"bytes":1060,"type":"prose","color":"#083fa1"},{"name":"JSON","percentage":21.09,"bytes":1896,"type":"data","color":"#292929"},{"name":"CSS","percentage":0,"bytes":0,"type":"markup","color":"#563d7c"},{"name":"TSX","percentage":26.01,"bytes":2338,"type":"programming","color":"#3178c6"},{"name":"TypeScript","percentage":1.81,"bytes":163,"type":"programming","color":"#3178c6"}]}',
|
||||
processed_date: new Date('2023-02-15 20:10:21.388Z'),
|
||||
},
|
||||
{
|
||||
id: '4145c0cf-44e9-4e95-9d57-781af4685b28',
|
||||
entity_ref: 'template:default/springboot-template',
|
||||
languages:
|
||||
'{"languageCount":9,"totalBytes":80986,"processedDate":"2023-02-15T20:10:21.419Z","breakdown":[{"name":"Shell","percentage":0.16,"bytes":130,"type":"programming","color":"#89e051"},{"name":"INI","percentage":0.35,"bytes":286,"type":"data","color":"#d1dbe0"},{"name":"Dockerfile","percentage":0.3,"bytes":246,"type":"programming","color":"#384d54"},{"name":"YAML","percentage":3.92,"bytes":3171,"type":"data","color":"#cb171e"},{"name":"Markdown","percentage":1.31,"bytes":1059,"type":"prose","color":"#083fa1"},{"name":"XML","percentage":10.48,"bytes":8491,"type":"data","color":"#0060ac"},{"name":"Java","percentage":1.8,"bytes":1455,"type":"programming","color":"#b07219"},{"name":"Text","percentage":81.22,"bytes":65780,"type":"prose"},{"name":"Protocol Buffer","percentage":0.45,"bytes":368,"type":"data"}]}',
|
||||
processed_date: new Date('2023-02-15 20:10:21.419Z'),
|
||||
},
|
||||
];
|
||||
|
||||
describe('Linguist database', () => {
|
||||
const databases = TestDatabases.create();
|
||||
let store: LinguistBackendStore;
|
||||
let testDbClient: Knex<any, unknown[]>;
|
||||
beforeAll(async () => {
|
||||
testDbClient = await databases.init('SQLITE_3');
|
||||
const database = createDatabaseManager(testDbClient);
|
||||
|
||||
store = await LinguistBackendDatabase.create(await database.getClient());
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await testDbClient.batchInsert('entity_result', rawDbEntityResultRows);
|
||||
});
|
||||
afterEach(async () => {
|
||||
await testDbClient('entity_result').delete();
|
||||
});
|
||||
|
||||
it('should be able to return entity results', async () => {
|
||||
const validLanguagesResult: Languages = {
|
||||
languageCount: 1,
|
||||
totalBytes: 2205,
|
||||
processedDate: '2023-02-15T20:10:21.378Z',
|
||||
breakdown: [
|
||||
{
|
||||
name: 'YAML',
|
||||
percentage: 100,
|
||||
bytes: 2205,
|
||||
type: 'data',
|
||||
color: '#cb171e',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const entityResult = await store.getEntityResults(
|
||||
'template:default/pull-request',
|
||||
);
|
||||
expect(entityResult).toMatchObject(validLanguagesResult);
|
||||
});
|
||||
|
||||
it('should return empty entity results when not found', async () => {
|
||||
const validEmptyLanguagesResult: Languages = {
|
||||
languageCount: 0,
|
||||
totalBytes: 0,
|
||||
processedDate: 'undefined',
|
||||
breakdown: [],
|
||||
};
|
||||
|
||||
const entityResult = await store.getEntityResults(
|
||||
'template:default/create-react-app-template',
|
||||
);
|
||||
expect(entityResult).toMatchObject(validEmptyLanguagesResult);
|
||||
});
|
||||
|
||||
it('should be able to return unprocessed entities', async () => {
|
||||
const validUnprocessedEntities: string[] = [
|
||||
'template:default/create-react-app-template',
|
||||
'template:default/docs-template',
|
||||
];
|
||||
|
||||
const unprocessedEntities = await store.getUnprocessedEntities();
|
||||
|
||||
expect(unprocessedEntities).toMatchObject(validUnprocessedEntities);
|
||||
});
|
||||
|
||||
it('should return string[] when there is no unprocessed entities', async () => {
|
||||
await testDbClient('entity_result').delete();
|
||||
const unprocessedEntities = await store.getUnprocessedEntities();
|
||||
|
||||
expect(unprocessedEntities).toMatchObject([]);
|
||||
});
|
||||
|
||||
it('should be able to return processed entities', async () => {
|
||||
const validProcessedEntities: ProcessedEntity[] = [
|
||||
{
|
||||
entityRef: 'template:default/pull-request',
|
||||
processedDate: new Date('2023-02-15 20:10:21.378Z'),
|
||||
},
|
||||
{
|
||||
entityRef: 'template:default/react-ssr-template',
|
||||
processedDate: new Date('2023-02-15 20:10:21.388Z'),
|
||||
},
|
||||
{
|
||||
entityRef: 'template:default/springboot-template',
|
||||
processedDate: new Date('2023-02-15 20:10:21.419Z'),
|
||||
},
|
||||
];
|
||||
|
||||
const processedEntities = await store.getProcessedEntities();
|
||||
|
||||
expect(processedEntities).toMatchObject(validProcessedEntities);
|
||||
});
|
||||
|
||||
it('should return string[] when there is no processed entities', async () => {
|
||||
await testDbClient('entity_result').delete();
|
||||
const unprocessedEntities = await store.getProcessedEntities();
|
||||
|
||||
expect(unprocessedEntities).toMatchObject([]);
|
||||
});
|
||||
|
||||
it('should insert new entities and ignore duplicates', async () => {
|
||||
const before = testDbClient.from('entity_result').count();
|
||||
|
||||
await store.insertNewEntity('component:/default/new-entity-one');
|
||||
await store.insertNewEntity('component:/default/new-entity-two');
|
||||
await store.insertNewEntity('template:default/pull-request');
|
||||
|
||||
const after = testDbClient.from('entity_result').count();
|
||||
|
||||
expect(before).toEqual(after);
|
||||
});
|
||||
|
||||
it('should get all entities', async () => {
|
||||
const allEntities = await store.getAllEntities();
|
||||
|
||||
expect(allEntities.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should delete entity by its entityRef', async () => {
|
||||
const before = await testDbClient.from('entity_result').count();
|
||||
|
||||
await store.deleteEntity('template:default/create-react-app-template');
|
||||
|
||||
const after = await testDbClient.from('entity_result').count();
|
||||
|
||||
expect(before).toEqual([{ 'count(*)': 5 }]);
|
||||
expect(after).toEqual([{ 'count(*)': 4 }]);
|
||||
});
|
||||
});
|
||||
@@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { resolvePackagePath } from '@backstage/backend-common';
|
||||
import { Knex } from 'knex';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import {
|
||||
EntityResults,
|
||||
Languages,
|
||||
ProcessedEntity,
|
||||
} from '@backstage/plugin-linguist-common';
|
||||
|
||||
export type RawDbEntityResultRow = {
|
||||
id: string;
|
||||
entity_ref: string;
|
||||
languages?: string;
|
||||
processed_date?: Date;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface LinguistBackendStore {
|
||||
insertEntityResults(entityLanguages: EntityResults): Promise<string>;
|
||||
insertNewEntity(entityRef: string): Promise<void>;
|
||||
getEntityResults(entityRef: string): Promise<Languages>;
|
||||
getProcessedEntities(): Promise<ProcessedEntity[]>;
|
||||
getUnprocessedEntities(): Promise<string[]>;
|
||||
getAllEntities(): Promise<string[]>;
|
||||
deleteEntity(entityRef: string): Promise<void>;
|
||||
}
|
||||
|
||||
const migrationsDir = resolvePackagePath(
|
||||
'@backstage/plugin-linguist-backend',
|
||||
'migrations',
|
||||
);
|
||||
|
||||
/** @public */
|
||||
export class LinguistBackendDatabase implements LinguistBackendStore {
|
||||
static async create(knex: Knex): Promise<LinguistBackendStore> {
|
||||
await knex.migrate.latest({
|
||||
directory: migrationsDir,
|
||||
});
|
||||
return new LinguistBackendDatabase(knex);
|
||||
}
|
||||
|
||||
constructor(private readonly db: Knex) {}
|
||||
|
||||
async insertEntityResults(entityLanguages: EntityResults): Promise<string> {
|
||||
const entityLanguageId = uuid();
|
||||
const entityRef = entityLanguages.entityRef;
|
||||
|
||||
const [result] = await this.db<RawDbEntityResultRow>('entity_result')
|
||||
.insert({
|
||||
id: entityLanguageId,
|
||||
entity_ref: entityRef,
|
||||
languages: JSON.stringify(entityLanguages.results),
|
||||
processed_date: new Date(entityLanguages.results.processedDate),
|
||||
})
|
||||
.onConflict('entity_ref')
|
||||
.merge(['languages', 'processed_date'])
|
||||
.returning('id');
|
||||
|
||||
return result.id;
|
||||
}
|
||||
|
||||
async insertNewEntity(entityRef: string): Promise<void> {
|
||||
const entityLanguageId = uuid();
|
||||
|
||||
await this.db<RawDbEntityResultRow>('entity_result')
|
||||
.insert({
|
||||
id: entityLanguageId,
|
||||
entity_ref: entityRef,
|
||||
})
|
||||
.onConflict('entity_ref')
|
||||
.ignore(); // If the entity_ref is in the table already then we don't want to add it again
|
||||
}
|
||||
|
||||
async getEntityResults(entityRef: string): Promise<Languages> {
|
||||
const entityResults = await this.db<RawDbEntityResultRow>('entity_result')
|
||||
.whereNotNull('languages')
|
||||
.where({ entity_ref: entityRef })
|
||||
.first();
|
||||
|
||||
if (!entityResults || !entityResults.languages) {
|
||||
const emptyResults: Languages = {
|
||||
languageCount: 0,
|
||||
totalBytes: 0,
|
||||
processedDate: 'undefined',
|
||||
breakdown: [],
|
||||
};
|
||||
return emptyResults;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(entityResults.languages);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse languages for '${entityRef}', ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getProcessedEntities(): Promise<ProcessedEntity[]> {
|
||||
const rawEntities = await this.db<RawDbEntityResultRow>('entity_result')
|
||||
.whereNotNull('processed_date')
|
||||
.whereNotNull('languages');
|
||||
|
||||
if (!rawEntities) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const processedEntities = rawEntities.map(rawEntity => {
|
||||
// Note: processed_date should never be null, this is handled by the DB query above
|
||||
let processedDate = new Date();
|
||||
if (rawEntity.processed_date) {
|
||||
// SQLite will return a Timestamp whereas Postgres will return a proper Date
|
||||
// This tests to see if we are getting a timestamp and convert if needed
|
||||
processedDate = new Date(+rawEntity.processed_date.toString());
|
||||
if (isNaN(+rawEntity.processed_date.toString())) {
|
||||
processedDate = rawEntity.processed_date;
|
||||
}
|
||||
}
|
||||
|
||||
const processEntity = {
|
||||
entityRef: rawEntity.entity_ref,
|
||||
processedDate,
|
||||
};
|
||||
|
||||
return processEntity;
|
||||
});
|
||||
|
||||
return processedEntities;
|
||||
}
|
||||
|
||||
async getUnprocessedEntities(): Promise<string[]> {
|
||||
const rawEntities = await this.db<RawDbEntityResultRow>('entity_result')
|
||||
// TODO(ahhhndre) processed_date should always be null as well but it had a default to the current date
|
||||
// once the default has been removed and released, we can then come back an enable this check
|
||||
// .whereNull('processed_date')
|
||||
.whereNull('languages')
|
||||
.orderBy('created_at', 'asc');
|
||||
|
||||
if (!rawEntities) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const unprocessedEntities = rawEntities.map(rawEntity => {
|
||||
return rawEntity.entity_ref;
|
||||
});
|
||||
|
||||
return unprocessedEntities;
|
||||
}
|
||||
|
||||
async getAllEntities(): Promise<string[]> {
|
||||
const rawEntities = await this.db<RawDbEntityResultRow>('entity_result');
|
||||
|
||||
if (!rawEntities) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const allEntities = rawEntities.map(rawEntity => {
|
||||
return rawEntity.entity_ref;
|
||||
});
|
||||
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
async deleteEntity(entityRef: string): Promise<void> {
|
||||
await this.db<RawDbEntityResultRow>('entity_result')
|
||||
.where('entity_ref', entityRef)
|
||||
.delete();
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export { LinguistBackendDatabase } from './LinguistBackendDatabase';
|
||||
export type { LinguistBackendStore } from './LinguistBackendDatabase';
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Linguist backend plugin that contains the API for generating and retrieving language breakdown which is used by the Linguist frontend plugin.
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export * from './processor';
|
||||
export * from './service/router';
|
||||
export type { LinguistBackendApi } from './api';
|
||||
export { linguistPlugin as default } from './plugin';
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
import { createRouterFromConfig } from './service/router';
|
||||
|
||||
/**
|
||||
* Linguist backend plugin
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const linguistPlugin = createBackendPlugin({
|
||||
pluginId: 'linguist',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
auth: coreServices.auth,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
logger: coreServices.logger,
|
||||
config: coreServices.rootConfig,
|
||||
reader: coreServices.urlReader,
|
||||
database: coreServices.database,
|
||||
discovery: coreServices.discovery,
|
||||
scheduler: coreServices.scheduler,
|
||||
tokenManager: coreServices.tokenManager,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
},
|
||||
async init({
|
||||
auth,
|
||||
httpAuth,
|
||||
logger,
|
||||
config,
|
||||
reader,
|
||||
database,
|
||||
discovery,
|
||||
scheduler,
|
||||
tokenManager,
|
||||
httpRouter,
|
||||
}) {
|
||||
httpRouter.use(
|
||||
await createRouterFromConfig({
|
||||
auth,
|
||||
httpAuth,
|
||||
logger,
|
||||
config,
|
||||
reader,
|
||||
database,
|
||||
discovery,
|
||||
scheduler,
|
||||
tokenManager,
|
||||
}),
|
||||
);
|
||||
httpRouter.addAuthPolicy({
|
||||
path: '/health',
|
||||
allow: 'unauthenticated',
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,343 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 {
|
||||
LinguistTagsProcessor,
|
||||
LinguistTagsProcessorOptions,
|
||||
sanitizeTag,
|
||||
} from './LinguistTagsProcessor';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { CatalogProcessorCache } from '@backstage/plugin-catalog-node';
|
||||
import { Entity, makeValidator } from '@backstage/catalog-model';
|
||||
import { DiscoveryService } from '@backstage/backend-plugin-api';
|
||||
import fetch, { Response } from 'node-fetch';
|
||||
import * as path from 'path';
|
||||
import yaml from 'js-yaml';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const { isValidTag } = makeValidator();
|
||||
|
||||
jest.mock('node-fetch', () => jest.fn());
|
||||
const mockedFetch: jest.MockedFunction<typeof fetch> =
|
||||
fetch as jest.MockedFunction<typeof fetch>;
|
||||
|
||||
const discovery: DiscoveryService = {
|
||||
getBaseUrl: jest.fn().mockResolvedValue('http://example.com/api/linguist'),
|
||||
getExternalBaseUrl: jest.fn(),
|
||||
};
|
||||
|
||||
let state: Record<string, any> = {};
|
||||
const mockCacheGet = jest
|
||||
.fn()
|
||||
.mockImplementation(async (key: string) => state[key]);
|
||||
const mockCacheSet = jest.fn().mockImplementation((key: string, value: any) => {
|
||||
state[key] = value;
|
||||
});
|
||||
const cache: CatalogProcessorCache = {
|
||||
get: mockCacheGet,
|
||||
set: mockCacheSet,
|
||||
};
|
||||
|
||||
describe('sanitizeTag', () => {
|
||||
const linguistDataSet = yaml.load(
|
||||
fs.readFileSync(
|
||||
path.resolve(require.resolve('linguist-js'), '../../ext/languages.yml'),
|
||||
'utf-8',
|
||||
),
|
||||
) as Object;
|
||||
const languages = Object.keys(linguistDataSet);
|
||||
test('Should clean up all linguist languages', () => {
|
||||
const invalid = languages
|
||||
.map(sanitizeTag)
|
||||
.filter(lang => !isValidTag(lang));
|
||||
expect(invalid).toStrictEqual([]);
|
||||
// Keep a snapshot here so that as new languages are added to linguist,
|
||||
// we can spot check them to make sure the transformer for them makes sense.
|
||||
expect(languages.map(sanitizeTag)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('LinguistTagsProcessor', () => {
|
||||
afterEach(() => {
|
||||
mockedFetch.mockReset();
|
||||
mockCacheGet.mockClear();
|
||||
mockCacheSet.mockClear();
|
||||
state = {};
|
||||
});
|
||||
|
||||
test('Should construct fromConfig', () => {
|
||||
const config = new ConfigReader({
|
||||
linguist: {},
|
||||
});
|
||||
expect(() => {
|
||||
return LinguistTagsProcessor.fromConfig(config, {
|
||||
logger: getVoidLogger(),
|
||||
discovery,
|
||||
});
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
test('Should assign valid language tags', async () => {
|
||||
const processor = buildProcessor({});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual([
|
||||
'c++',
|
||||
'asp-dot-net',
|
||||
'java',
|
||||
'common-lisp',
|
||||
]);
|
||||
|
||||
entity.metadata.tags?.forEach(tag => {
|
||||
expect(isValidTag(tag)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test('Should not duplicate existing tags', async () => {
|
||||
const processor = buildProcessor({});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
entity.metadata.tags = ['existing', 'tags', 'java'];
|
||||
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual([
|
||||
'existing',
|
||||
'tags',
|
||||
'java',
|
||||
'c++',
|
||||
'asp-dot-net',
|
||||
'common-lisp',
|
||||
]);
|
||||
});
|
||||
|
||||
test('Should not process Resource entities by default', async () => {
|
||||
const processor = buildProcessor({});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
entity.kind = 'Resource';
|
||||
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(0);
|
||||
expect(entity.metadata.tags).toStrictEqual(undefined);
|
||||
});
|
||||
|
||||
test('Can process Resource entities by overriding shouldProcessEntity', async () => {
|
||||
const processor = buildProcessor({
|
||||
shouldProcessEntity: (entity: Entity) => {
|
||||
return entity.kind === 'Resource';
|
||||
},
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
entity.kind = 'Resource';
|
||||
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual([
|
||||
'c++',
|
||||
'asp-dot-net',
|
||||
'java',
|
||||
'common-lisp',
|
||||
]);
|
||||
});
|
||||
|
||||
test('Can omit languages using languageMap', async () => {
|
||||
const processor = buildProcessor({
|
||||
languageMap: {
|
||||
Java: '',
|
||||
'ASP.net': '',
|
||||
},
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual(['c++', 'common-lisp']);
|
||||
});
|
||||
|
||||
test('Can rewrite langs using languageMap', async () => {
|
||||
const processor = buildProcessor({
|
||||
languageMap: {
|
||||
Java: 'notjava',
|
||||
},
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual([
|
||||
'c++',
|
||||
'asp-dot-net',
|
||||
'notjava',
|
||||
'common-lisp',
|
||||
]);
|
||||
});
|
||||
|
||||
test('Can omit languages less than bytesThreshold', async () => {
|
||||
const processor = buildProcessor({
|
||||
bytesThreshold: 5000,
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual(['java', 'common-lisp']);
|
||||
});
|
||||
|
||||
test('Can include languages that arent programming', async () => {
|
||||
const processor = buildProcessor({
|
||||
languageTypes: ['data'],
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(entity.metadata.tags).toStrictEqual(['yaml', 'json']);
|
||||
});
|
||||
|
||||
test('Refetches from API when cache disabled', async () => {
|
||||
const processor = buildProcessor({
|
||||
cacheTTL: { minutes: 0 },
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(mockCacheGet).toHaveBeenCalledTimes(0);
|
||||
expect(mockCacheSet).toHaveBeenCalledTimes(0);
|
||||
mockedFetch.mockClear();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(mockCacheGet).toHaveBeenCalledTimes(0);
|
||||
expect(mockCacheSet).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('Caches across runs with cache enabled', async () => {
|
||||
const processor = buildProcessor({
|
||||
cacheTTL: { minutes: 5 },
|
||||
});
|
||||
|
||||
mockFetchImplementation();
|
||||
const entity = baseEntity();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(1);
|
||||
expect(mockCacheGet).toHaveBeenCalledTimes(1);
|
||||
expect(mockCacheSet).toHaveBeenCalledTimes(1);
|
||||
|
||||
mockedFetch.mockClear();
|
||||
mockCacheGet.mockClear();
|
||||
mockCacheSet.mockClear();
|
||||
await processor.preProcessEntity(entity, null, null, null, cache);
|
||||
expect(mockedFetch).toHaveBeenCalledTimes(0);
|
||||
expect(mockCacheGet).toHaveBeenCalledTimes(1);
|
||||
expect(mockCacheSet).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
function mockFetchImplementation(): void {
|
||||
mockedFetch.mockResolvedValue({
|
||||
json: jest.fn().mockResolvedValue({
|
||||
languageCount: 6,
|
||||
totalBytes: 43823,
|
||||
processedDate: '2023-06-20T21:37:48.337Z',
|
||||
breakdown: [
|
||||
{
|
||||
name: 'YAML',
|
||||
percentage: 2.23,
|
||||
bytes: 979,
|
||||
type: 'data',
|
||||
color: '#cb171e',
|
||||
},
|
||||
{
|
||||
name: 'JSON',
|
||||
percentage: 1.31,
|
||||
bytes: 574,
|
||||
type: 'data',
|
||||
color: '#292929',
|
||||
},
|
||||
{
|
||||
name: 'C++',
|
||||
percentage: 5.25,
|
||||
bytes: 2300,
|
||||
type: 'programming',
|
||||
color: '#f34b7d',
|
||||
},
|
||||
{
|
||||
name: 'ASP.net',
|
||||
percentage: 6.97,
|
||||
bytes: 3053,
|
||||
type: 'programming',
|
||||
color: '#178600',
|
||||
},
|
||||
{
|
||||
name: 'Java',
|
||||
percentage: 12.79,
|
||||
bytes: 5603,
|
||||
type: 'programming',
|
||||
color: '#b07219',
|
||||
},
|
||||
{
|
||||
name: 'Common Lisp',
|
||||
percentage: 71.46,
|
||||
bytes: 31314,
|
||||
type: 'programming',
|
||||
color: '#3fb68b',
|
||||
},
|
||||
],
|
||||
}),
|
||||
} as unknown as Response);
|
||||
}
|
||||
|
||||
function baseEntity(): Entity {
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'foo',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildProcessor(options: Partial<LinguistTagsProcessorOptions>) {
|
||||
const config = new ConfigReader({
|
||||
linguist: {
|
||||
tagsProcessor: {
|
||||
bytesThreshold: options.bytesThreshold,
|
||||
languageTypes: options.languageTypes,
|
||||
languageMap: options.languageMap,
|
||||
cacheTTL: options.cacheTTL,
|
||||
},
|
||||
},
|
||||
});
|
||||
return LinguistTagsProcessor.fromConfig(config, {
|
||||
logger: getVoidLogger(),
|
||||
discovery,
|
||||
shouldProcessEntity: options.shouldProcessEntity,
|
||||
});
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import {
|
||||
CatalogProcessor,
|
||||
CatalogProcessorCache,
|
||||
} from '@backstage/plugin-catalog-node';
|
||||
import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { Languages, LanguageType } from '@backstage/plugin-linguist-common';
|
||||
import fetch from 'node-fetch';
|
||||
import { durationToMilliseconds, HumanDuration } from '@backstage/types';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
/**
|
||||
* A function which given an entity, determines if it should be processed for linguist tags.
|
||||
* @public
|
||||
*/
|
||||
export type ShouldProcessEntity = (entity: Entity) => boolean;
|
||||
|
||||
interface CachedData {
|
||||
[key: string]: number | string[];
|
||||
languages: string[];
|
||||
cachedTime: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor options for building the LinguistTagsProcessor
|
||||
* @public
|
||||
*/
|
||||
export interface LinguistTagsProcessorOptions {
|
||||
logger: LoggerService;
|
||||
discovery: DiscoveryService;
|
||||
/**
|
||||
* Optional map that gives full control over which linguist languages should be included as tags and
|
||||
* how they should be represented. The keys should be exact matches to languages in the linguist
|
||||
* and the values should be how they render as backstage tags. Keep in mind that backstage has character
|
||||
* requirements for tags. If you map a key to a falsey value, it will not be emitted as a tag.
|
||||
*/
|
||||
languageMap?: Record<string, string | undefined>;
|
||||
/**
|
||||
* A function which determines which entities should be processed by the LinguistTagProcessor.
|
||||
*
|
||||
* The default is to process all entities of kind=Component
|
||||
*/
|
||||
shouldProcessEntity?: ShouldProcessEntity;
|
||||
/**
|
||||
* Determines how long to cache language breakdowns for entities in the processor. Considering
|
||||
* how often this processor runs, caching can help move some read traffic off of the linguist DB.
|
||||
*
|
||||
* If this caching is using up too much memory, you can disable it by setting cacheTTL to 0.
|
||||
*/
|
||||
cacheTTL?: HumanDuration;
|
||||
/**
|
||||
* How many bytes must exist of a language in a repo before we consider it for adding a tag to
|
||||
* the entity. This can be used if some repos have short utility scripts that may not be the primary
|
||||
* language for the repo.
|
||||
*/
|
||||
bytesThreshold?: number;
|
||||
/**
|
||||
* Which linguist file types to process tags for.
|
||||
*/
|
||||
languageTypes?: LanguageType[];
|
||||
}
|
||||
|
||||
/**
|
||||
* This processor will fetch the language breakdown from the linguist API and
|
||||
* add the languages to the entity as searchable tags.
|
||||
*
|
||||
* @public
|
||||
* */
|
||||
export class LinguistTagsProcessor implements CatalogProcessor {
|
||||
private logger: LoggerService;
|
||||
private discovery: DiscoveryService;
|
||||
private loggerMeta = { plugin: 'LinguistTagsProcessor' };
|
||||
private languageMap: Record<string, string | undefined> = {};
|
||||
private shouldProcessEntity: ShouldProcessEntity = (entity: Entity) => {
|
||||
return entity.kind === 'Component';
|
||||
};
|
||||
private cacheTTLMilliseconds: number;
|
||||
private bytesThreshold = 0;
|
||||
private languageTypes: LanguageType[] = ['programming'];
|
||||
|
||||
getProcessorName(): string {
|
||||
return 'LinguistTagsProcessor';
|
||||
}
|
||||
|
||||
constructor(options: LinguistTagsProcessorOptions) {
|
||||
this.logger = options.logger;
|
||||
this.discovery = options.discovery;
|
||||
if (options.shouldProcessEntity) {
|
||||
this.shouldProcessEntity = options.shouldProcessEntity;
|
||||
}
|
||||
this.cacheTTLMilliseconds = durationToMilliseconds(
|
||||
options.cacheTTL || { minutes: 30 },
|
||||
);
|
||||
if (options.bytesThreshold) {
|
||||
this.bytesThreshold = options.bytesThreshold;
|
||||
}
|
||||
if (options.languageTypes) {
|
||||
this.languageTypes = options.languageTypes;
|
||||
}
|
||||
if (options.languageMap) {
|
||||
this.languageMap = options.languageMap;
|
||||
}
|
||||
}
|
||||
|
||||
static fromConfig(
|
||||
config: Config,
|
||||
options: LinguistTagsProcessorOptions,
|
||||
): LinguistTagsProcessor {
|
||||
const c = config.getOptionalConfig('linguist.tagsProcessor');
|
||||
if (c) {
|
||||
options.bytesThreshold ??= c.getOptionalNumber('bytesThreshold');
|
||||
options.languageTypes ??= c.getOptionalStringArray(
|
||||
'languageTypes',
|
||||
) as LanguageType[];
|
||||
options.languageMap ??= c.getOptional('languageMap');
|
||||
options.cacheTTL ??= c.getOptional('cacheTTL');
|
||||
}
|
||||
|
||||
return new LinguistTagsProcessor(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an entity ref, fetches the language breakdown from the Linguist backend HTTP API.
|
||||
* @param entityRef - stringified entity ref
|
||||
* @returns The language breakdown
|
||||
*/
|
||||
private async getLanguagesFromLinguistAPI(
|
||||
entityRef: string,
|
||||
): Promise<string[]> {
|
||||
this.logger.debug(`Fetching languages from linguist API`, {
|
||||
...this.loggerMeta,
|
||||
entityRef,
|
||||
});
|
||||
|
||||
const baseUrl = await this.discovery.getBaseUrl('linguist');
|
||||
const linguistApi = new URL(`${baseUrl}/entity-languages`);
|
||||
linguistApi.searchParams.append('entityRef', entityRef);
|
||||
const linguistData = await fetch(linguistApi).then(
|
||||
res => res.json() as Promise<Languages>,
|
||||
);
|
||||
if (!linguistData || !linguistData.processedDate) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return linguistData.breakdown
|
||||
.filter(
|
||||
b =>
|
||||
this.languageTypes.includes(b.type) && b.bytes > this.bytesThreshold,
|
||||
)
|
||||
.map(b => b.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached wrapper around getLanguagesFromLinguistAPI
|
||||
* @param cache - The CatalogProcessorCache
|
||||
* @param entityRef - Stringified entity references
|
||||
*
|
||||
* @returns List of languages
|
||||
*/
|
||||
private async getCachedLanguages(
|
||||
cache: CatalogProcessorCache,
|
||||
entityRef: string,
|
||||
): Promise<string[]> {
|
||||
let cachedData = (await cache.get(entityRef)) as CachedData | undefined;
|
||||
if (!cachedData || this.isExpired(cachedData)) {
|
||||
const languages = await this.getLanguagesFromLinguistAPI(entityRef);
|
||||
cachedData = { languages, cachedTime: Date.now() };
|
||||
await cache.set(entityRef, cachedData);
|
||||
}
|
||||
this.logger.debug(`Fetched cached languages ${cachedData.languages}`, {
|
||||
...this.loggerMeta,
|
||||
entityRef,
|
||||
});
|
||||
return cachedData.languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if cached data is expired based on TTL
|
||||
*
|
||||
* @param cachedData - The cached data for this entity
|
||||
* @returns True if data is expired
|
||||
*/
|
||||
private isExpired(cachedData: CachedData): boolean {
|
||||
const elapsed = Date.now() - (cachedData.cachedTime || 0);
|
||||
return elapsed > this.cacheTTLMilliseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* This pre-processor will fetch linguist data for a Component and convert the language breakdown
|
||||
* into entity tags which will be appended to the entity.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
async preProcessEntity(
|
||||
entity: Entity,
|
||||
_: any,
|
||||
__: any,
|
||||
___: any,
|
||||
cache: CatalogProcessorCache,
|
||||
): Promise<Entity> {
|
||||
if (!this.shouldProcessEntity(entity)) {
|
||||
return entity;
|
||||
}
|
||||
const entityRef = stringifyEntityRef(entity);
|
||||
this.logger.debug(`Processing ${entityRef}`, {
|
||||
...this.loggerMeta,
|
||||
entityRef,
|
||||
});
|
||||
|
||||
const languages =
|
||||
this.cacheTTLMilliseconds > 0
|
||||
? await this.getCachedLanguages(cache, entityRef)
|
||||
: await this.getLanguagesFromLinguistAPI(entityRef);
|
||||
|
||||
const tags = (entity.metadata.tags ||= []);
|
||||
const originalTagCount = tags.length;
|
||||
|
||||
languages.forEach(lang => {
|
||||
const cleanedUpLangTag =
|
||||
lang in this.languageMap ? this.languageMap[lang] : sanitizeTag(lang);
|
||||
if (cleanedUpLangTag && !tags.includes(cleanedUpLangTag)) {
|
||||
tags.push(cleanedUpLangTag);
|
||||
}
|
||||
});
|
||||
|
||||
const addedCount = tags.length - originalTagCount;
|
||||
|
||||
this.logger.debug(`Added ${addedCount} language tags from linguist`, {
|
||||
...this.loggerMeta,
|
||||
entityRef,
|
||||
});
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts language tags from linguist to something acceptable by
|
||||
* the tag requirements for backstage
|
||||
*
|
||||
* @param tag - A language tag from linguist
|
||||
* @returns Cleaned up language tag
|
||||
* @internal
|
||||
*/
|
||||
export function sanitizeTag(tag: string): string {
|
||||
return tag
|
||||
.toLowerCase()
|
||||
.replace(/\.net/g, '-dot-net')
|
||||
.replace(/[^a-z0-9:+#-]+/g, '-')
|
||||
.replace(/-{2,}/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
}
|
||||
-707
@@ -1,707 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`sanitizeTag Should clean up all linguist languages 1`] = `
|
||||
[
|
||||
"1c-enterprise",
|
||||
"2-dimensional-array",
|
||||
"4d",
|
||||
"abap",
|
||||
"abap-cds",
|
||||
"abnf",
|
||||
"ags-script",
|
||||
"aidl",
|
||||
"al",
|
||||
"ampl",
|
||||
"antlr",
|
||||
"api-blueprint",
|
||||
"apl",
|
||||
"asl",
|
||||
"asn-1",
|
||||
"asp-dot-net",
|
||||
"ats",
|
||||
"actionscript",
|
||||
"ada",
|
||||
"adblock-filter-list",
|
||||
"adobe-font-metrics",
|
||||
"agda",
|
||||
"alloy",
|
||||
"alpine-abuild",
|
||||
"altium-designer",
|
||||
"angelscript",
|
||||
"ant-build-system",
|
||||
"antlers",
|
||||
"apacheconf",
|
||||
"apex",
|
||||
"apollo-guidance-computer",
|
||||
"applescript",
|
||||
"arc",
|
||||
"asciidoc",
|
||||
"aspectj",
|
||||
"assembly",
|
||||
"astro",
|
||||
"asymptote",
|
||||
"augeas",
|
||||
"autohotkey",
|
||||
"autoit",
|
||||
"avro-idl",
|
||||
"awk",
|
||||
"basic",
|
||||
"ballerina",
|
||||
"batchfile",
|
||||
"beef",
|
||||
"befunge",
|
||||
"berry",
|
||||
"bibtex",
|
||||
"bicep",
|
||||
"bikeshed",
|
||||
"bison",
|
||||
"bitbake",
|
||||
"blade",
|
||||
"blitzbasic",
|
||||
"blitzmax",
|
||||
"bluespec",
|
||||
"boo",
|
||||
"boogie",
|
||||
"brainfuck",
|
||||
"brighterscript",
|
||||
"brightscript",
|
||||
"browserslist",
|
||||
"c",
|
||||
"c#",
|
||||
"c++",
|
||||
"c-objdump",
|
||||
"c2hs-haskell",
|
||||
"cap-cds",
|
||||
"cil",
|
||||
"clips",
|
||||
"cmake",
|
||||
"cobol",
|
||||
"codeowners",
|
||||
"collada",
|
||||
"cson",
|
||||
"css",
|
||||
"csv",
|
||||
"cue",
|
||||
"cweb",
|
||||
"cabal-config",
|
||||
"cadence",
|
||||
"cairo",
|
||||
"cameligo",
|
||||
"cap-n-proto",
|
||||
"cartocss",
|
||||
"ceylon",
|
||||
"chapel",
|
||||
"charity",
|
||||
"checksums",
|
||||
"chuck",
|
||||
"circom",
|
||||
"cirru",
|
||||
"clarion",
|
||||
"clarity",
|
||||
"classic-asp",
|
||||
"clean",
|
||||
"click",
|
||||
"clojure",
|
||||
"closure-templates",
|
||||
"cloud-firestore-security-rules",
|
||||
"conll-u",
|
||||
"codeql",
|
||||
"coffeescript",
|
||||
"coldfusion",
|
||||
"coldfusion-cfc",
|
||||
"common-lisp",
|
||||
"common-workflow-language",
|
||||
"component-pascal",
|
||||
"cool",
|
||||
"coq",
|
||||
"cpp-objdump",
|
||||
"creole",
|
||||
"crystal",
|
||||
"csound",
|
||||
"csound-document",
|
||||
"csound-score",
|
||||
"cuda",
|
||||
"cue-sheet",
|
||||
"curry",
|
||||
"cycript",
|
||||
"cypher",
|
||||
"cython",
|
||||
"d",
|
||||
"d-objdump",
|
||||
"d2",
|
||||
"digital-command-language",
|
||||
"dm",
|
||||
"dns-zone",
|
||||
"dtrace",
|
||||
"dafny",
|
||||
"darcs-patch",
|
||||
"dart",
|
||||
"dataweave",
|
||||
"debian-package-control-file",
|
||||
"denizenscript",
|
||||
"dhall",
|
||||
"diff",
|
||||
"directx-3d-file",
|
||||
"dockerfile",
|
||||
"dogescript",
|
||||
"dotenv",
|
||||
"dylan",
|
||||
"e",
|
||||
"e-mail",
|
||||
"ebnf",
|
||||
"ecl",
|
||||
"eclipse",
|
||||
"ejs",
|
||||
"eq",
|
||||
"eagle",
|
||||
"earthly",
|
||||
"easybuild",
|
||||
"ecere-projects",
|
||||
"ecmarkup",
|
||||
"editorconfig",
|
||||
"edje-data-collection",
|
||||
"eiffel",
|
||||
"elixir",
|
||||
"elm",
|
||||
"elvish",
|
||||
"elvish-transcript",
|
||||
"emacs-lisp",
|
||||
"emberscript",
|
||||
"erlang",
|
||||
"euphoria",
|
||||
"f#",
|
||||
"f",
|
||||
"figlet-font",
|
||||
"flux",
|
||||
"factor",
|
||||
"fancy",
|
||||
"fantom",
|
||||
"faust",
|
||||
"fennel",
|
||||
"filebench-wml",
|
||||
"filterscript",
|
||||
"fluent",
|
||||
"formatted",
|
||||
"forth",
|
||||
"fortran",
|
||||
"fortran-free-form",
|
||||
"freebasic",
|
||||
"freemarker",
|
||||
"frege",
|
||||
"futhark",
|
||||
"g-code",
|
||||
"gaml",
|
||||
"gams",
|
||||
"gap",
|
||||
"gcc-machine-description",
|
||||
"gdb",
|
||||
"gdscript",
|
||||
"gedcom",
|
||||
"glsl",
|
||||
"gn",
|
||||
"gsc",
|
||||
"game-maker-language",
|
||||
"gemfile-lock",
|
||||
"gemini",
|
||||
"genero",
|
||||
"genero-forms",
|
||||
"genie",
|
||||
"genshi",
|
||||
"gentoo-ebuild",
|
||||
"gentoo-eclass",
|
||||
"gerber-image",
|
||||
"gettext-catalog",
|
||||
"gherkin",
|
||||
"git-attributes",
|
||||
"git-config",
|
||||
"git-revision-list",
|
||||
"gleam",
|
||||
"glyph",
|
||||
"glyph-bitmap-distribution-format",
|
||||
"gnuplot",
|
||||
"go",
|
||||
"go-checksums",
|
||||
"go-module",
|
||||
"go-workspace",
|
||||
"godot-resource",
|
||||
"golo",
|
||||
"gosu",
|
||||
"grace",
|
||||
"gradle",
|
||||
"grammatical-framework",
|
||||
"graph-modeling-language",
|
||||
"graphql",
|
||||
"graphviz-dot",
|
||||
"groovy",
|
||||
"groovy-server-pages",
|
||||
"haproxy",
|
||||
"hcl",
|
||||
"hlsl",
|
||||
"hocon",
|
||||
"html",
|
||||
"html+ecr",
|
||||
"html+eex",
|
||||
"html+erb",
|
||||
"html+php",
|
||||
"html+razor",
|
||||
"http",
|
||||
"hxml",
|
||||
"hack",
|
||||
"haml",
|
||||
"handlebars",
|
||||
"harbour",
|
||||
"haskell",
|
||||
"haxe",
|
||||
"hiveql",
|
||||
"holyc",
|
||||
"hosts-file",
|
||||
"hy",
|
||||
"hyphy",
|
||||
"idl",
|
||||
"igor-pro",
|
||||
"ini",
|
||||
"irc-log",
|
||||
"idris",
|
||||
"ignore-list",
|
||||
"imagej-macro",
|
||||
"imba",
|
||||
"inform-7",
|
||||
"ink",
|
||||
"inno-setup",
|
||||
"io",
|
||||
"ioke",
|
||||
"isabelle",
|
||||
"isabelle-root",
|
||||
"j",
|
||||
"jar-manifest",
|
||||
"jcl",
|
||||
"jflex",
|
||||
"json",
|
||||
"json-with-comments",
|
||||
"json5",
|
||||
"jsonld",
|
||||
"jsoniq",
|
||||
"janet",
|
||||
"jasmin",
|
||||
"java",
|
||||
"java-properties",
|
||||
"java-server-pages",
|
||||
"javascript",
|
||||
"javascript+erb",
|
||||
"jest-snapshot",
|
||||
"jetbrains-mps",
|
||||
"jinja",
|
||||
"jison",
|
||||
"jison-lex",
|
||||
"jolie",
|
||||
"jsonnet",
|
||||
"julia",
|
||||
"jupyter-notebook",
|
||||
"just",
|
||||
"krl",
|
||||
"kaitai-struct",
|
||||
"kakounescript",
|
||||
"kerboscript",
|
||||
"kicad-layout",
|
||||
"kicad-legacy-layout",
|
||||
"kicad-schematic",
|
||||
"kickstart",
|
||||
"kit",
|
||||
"kotlin",
|
||||
"kusto",
|
||||
"lfe",
|
||||
"llvm",
|
||||
"lolcode",
|
||||
"lsl",
|
||||
"ltspice-symbol",
|
||||
"labview",
|
||||
"lark",
|
||||
"lasso",
|
||||
"latte",
|
||||
"lean",
|
||||
"less",
|
||||
"lex",
|
||||
"ligolang",
|
||||
"lilypond",
|
||||
"limbo",
|
||||
"linker-script",
|
||||
"linux-kernel-module",
|
||||
"liquid",
|
||||
"literate-agda",
|
||||
"literate-coffeescript",
|
||||
"literate-haskell",
|
||||
"livescript",
|
||||
"logos",
|
||||
"logtalk",
|
||||
"lookml",
|
||||
"loomscript",
|
||||
"lua",
|
||||
"m",
|
||||
"m4",
|
||||
"m4sugar",
|
||||
"matlab",
|
||||
"maxscript",
|
||||
"mdx",
|
||||
"mlir",
|
||||
"mql4",
|
||||
"mql5",
|
||||
"mtml",
|
||||
"muf",
|
||||
"macaulay2",
|
||||
"makefile",
|
||||
"mako",
|
||||
"markdown",
|
||||
"marko",
|
||||
"mask",
|
||||
"mathematica",
|
||||
"maven-pom",
|
||||
"max",
|
||||
"mercury",
|
||||
"mermaid",
|
||||
"meson",
|
||||
"metal",
|
||||
"microsoft-developer-studio-project",
|
||||
"microsoft-visual-studio-solution",
|
||||
"minid",
|
||||
"miniyaml",
|
||||
"mint",
|
||||
"mirah",
|
||||
"modelica",
|
||||
"modula-2",
|
||||
"modula-3",
|
||||
"module-management-system",
|
||||
"monkey",
|
||||
"monkey-c",
|
||||
"moocode",
|
||||
"moonscript",
|
||||
"motoko",
|
||||
"motorola-68k-assembly",
|
||||
"move",
|
||||
"muse",
|
||||
"mustache",
|
||||
"myghty",
|
||||
"nasl",
|
||||
"ncl",
|
||||
"neon",
|
||||
"nl",
|
||||
"npm-config",
|
||||
"nsis",
|
||||
"nwscript",
|
||||
"nasal",
|
||||
"nearley",
|
||||
"nemerle",
|
||||
"netlinx",
|
||||
"netlinx+erb",
|
||||
"netlogo",
|
||||
"newlisp",
|
||||
"nextflow",
|
||||
"nginx",
|
||||
"nim",
|
||||
"ninja",
|
||||
"nit",
|
||||
"nix",
|
||||
"nu",
|
||||
"numpy",
|
||||
"nunjucks",
|
||||
"nushell",
|
||||
"oasv2-json",
|
||||
"oasv2-yaml",
|
||||
"oasv3-json",
|
||||
"oasv3-yaml",
|
||||
"ocaml",
|
||||
"objdump",
|
||||
"object-data-instance-notation",
|
||||
"objectscript",
|
||||
"objective-c",
|
||||
"objective-c++",
|
||||
"objective-j",
|
||||
"odin",
|
||||
"omgrofl",
|
||||
"opa",
|
||||
"opal",
|
||||
"open-policy-agent",
|
||||
"openapi-specification-v2",
|
||||
"openapi-specification-v3",
|
||||
"opencl",
|
||||
"openedge-abl",
|
||||
"openqasm",
|
||||
"openrc-runscript",
|
||||
"openscad",
|
||||
"openstep-property-list",
|
||||
"opentype-feature-file",
|
||||
"option-list",
|
||||
"org",
|
||||
"ox",
|
||||
"oxygene",
|
||||
"oz",
|
||||
"p4",
|
||||
"pddl",
|
||||
"peg-js",
|
||||
"php",
|
||||
"plsql",
|
||||
"plpgsql",
|
||||
"pov-ray-sdl",
|
||||
"pact",
|
||||
"pan",
|
||||
"papyrus",
|
||||
"parrot",
|
||||
"parrot-assembly",
|
||||
"parrot-internal-representation",
|
||||
"pascal",
|
||||
"pawn",
|
||||
"pep8",
|
||||
"perl",
|
||||
"pic",
|
||||
"pickle",
|
||||
"picolisp",
|
||||
"piglatin",
|
||||
"pike",
|
||||
"plantuml",
|
||||
"pod",
|
||||
"pod-6",
|
||||
"pogoscript",
|
||||
"polar",
|
||||
"pony",
|
||||
"portugol",
|
||||
"postcss",
|
||||
"postscript",
|
||||
"powerbuilder",
|
||||
"powershell",
|
||||
"prisma",
|
||||
"processing",
|
||||
"procfile",
|
||||
"proguard",
|
||||
"prolog",
|
||||
"promela",
|
||||
"propeller-spin",
|
||||
"protocol-buffer",
|
||||
"protocol-buffer-text-format",
|
||||
"public-key",
|
||||
"pug",
|
||||
"puppet",
|
||||
"pure-data",
|
||||
"purebasic",
|
||||
"purescript",
|
||||
"pyret",
|
||||
"python",
|
||||
"python-console",
|
||||
"python-traceback",
|
||||
"q#",
|
||||
"qml",
|
||||
"qmake",
|
||||
"qt-script",
|
||||
"quake",
|
||||
"r",
|
||||
"raml",
|
||||
"rbs",
|
||||
"rdoc",
|
||||
"realbasic",
|
||||
"rexx",
|
||||
"rmarkdown",
|
||||
"rpc",
|
||||
"rpgle",
|
||||
"rpm-spec",
|
||||
"runoff",
|
||||
"racket",
|
||||
"ragel",
|
||||
"raku",
|
||||
"rascal",
|
||||
"raw-token-data",
|
||||
"rescript",
|
||||
"readline-config",
|
||||
"reason",
|
||||
"reasonligo",
|
||||
"rebol",
|
||||
"record-jar",
|
||||
"red",
|
||||
"redcode",
|
||||
"redirect-rules",
|
||||
"regular-expression",
|
||||
"ren-py",
|
||||
"renderscript",
|
||||
"rich-text-format",
|
||||
"ring",
|
||||
"riot",
|
||||
"robotframework",
|
||||
"roff",
|
||||
"roff-manpage",
|
||||
"rouge",
|
||||
"routeros-script",
|
||||
"ruby",
|
||||
"rust",
|
||||
"sas",
|
||||
"scss",
|
||||
"selinux-policy",
|
||||
"smt",
|
||||
"sparql",
|
||||
"sqf",
|
||||
"sql",
|
||||
"sqlpl",
|
||||
"srecode-template",
|
||||
"ssh-config",
|
||||
"star",
|
||||
"stl",
|
||||
"ston",
|
||||
"svg",
|
||||
"swig",
|
||||
"sage",
|
||||
"saltstack",
|
||||
"sass",
|
||||
"scala",
|
||||
"scaml",
|
||||
"scenic",
|
||||
"scheme",
|
||||
"scilab",
|
||||
"self",
|
||||
"shaderlab",
|
||||
"shell",
|
||||
"shellcheck-config",
|
||||
"shellsession",
|
||||
"shen",
|
||||
"sieve",
|
||||
"simple-file-verification",
|
||||
"singularity",
|
||||
"slash",
|
||||
"slice",
|
||||
"slim",
|
||||
"smpl",
|
||||
"smali",
|
||||
"smalltalk",
|
||||
"smarty",
|
||||
"smithy",
|
||||
"snakemake",
|
||||
"solidity",
|
||||
"soong",
|
||||
"sourcepawn",
|
||||
"spline-font-database",
|
||||
"squirrel",
|
||||
"stan",
|
||||
"standard-ml",
|
||||
"starlark",
|
||||
"stata",
|
||||
"stringtemplate",
|
||||
"stylus",
|
||||
"subrip-text",
|
||||
"sugarss",
|
||||
"supercollider",
|
||||
"svelte",
|
||||
"sway",
|
||||
"swift",
|
||||
"systemverilog",
|
||||
"ti-program",
|
||||
"tl-verilog",
|
||||
"tla",
|
||||
"toml",
|
||||
"tsql",
|
||||
"tsv",
|
||||
"tsx",
|
||||
"txl",
|
||||
"talon",
|
||||
"tcl",
|
||||
"tcsh",
|
||||
"tex",
|
||||
"tea",
|
||||
"terra",
|
||||
"texinfo",
|
||||
"text",
|
||||
"textmate-properties",
|
||||
"textile",
|
||||
"thrift",
|
||||
"turing",
|
||||
"turtle",
|
||||
"twig",
|
||||
"type-language",
|
||||
"typescript",
|
||||
"unified-parallel-c",
|
||||
"unity3d-asset",
|
||||
"unix-assembly",
|
||||
"uno",
|
||||
"unrealscript",
|
||||
"urweb",
|
||||
"v",
|
||||
"vba",
|
||||
"vbscript",
|
||||
"vcl",
|
||||
"vhdl",
|
||||
"vala",
|
||||
"valve-data-format",
|
||||
"velocity-template-language",
|
||||
"verilog",
|
||||
"vim-help-file",
|
||||
"vim-script",
|
||||
"vim-snippet",
|
||||
"visual-basic-dot-net",
|
||||
"visual-basic-6-0",
|
||||
"volt",
|
||||
"vue",
|
||||
"vyper",
|
||||
"wdl",
|
||||
"wgsl",
|
||||
"wavefront-material",
|
||||
"wavefront-object",
|
||||
"web-ontology-language",
|
||||
"webassembly",
|
||||
"webassembly-interface-type",
|
||||
"webidl",
|
||||
"webvtt",
|
||||
"wget-config",
|
||||
"whiley",
|
||||
"wikitext",
|
||||
"win32-message-file",
|
||||
"windows-registry-entries",
|
||||
"witcher-script",
|
||||
"wollok",
|
||||
"world-of-warcraft-addon-data",
|
||||
"wren",
|
||||
"x-bitmap",
|
||||
"x-font-directory-index",
|
||||
"x-pixmap",
|
||||
"x10",
|
||||
"xc",
|
||||
"xcompose",
|
||||
"xml",
|
||||
"xml-property-list",
|
||||
"xpages",
|
||||
"xproc",
|
||||
"xquery",
|
||||
"xs",
|
||||
"xslt",
|
||||
"xojo",
|
||||
"xonsh",
|
||||
"xtend",
|
||||
"yaml",
|
||||
"yang",
|
||||
"yara",
|
||||
"yasnippet",
|
||||
"yacc",
|
||||
"yul",
|
||||
"zap",
|
||||
"zil",
|
||||
"zeek",
|
||||
"zenscript",
|
||||
"zephir",
|
||||
"zig",
|
||||
"zimpl",
|
||||
"curl-config",
|
||||
"desktop",
|
||||
"dircolors",
|
||||
"ec",
|
||||
"edn",
|
||||
"fish",
|
||||
"hoon",
|
||||
"jq",
|
||||
"kvlang",
|
||||
"mirc-script",
|
||||
"mcfunction",
|
||||
"mupad",
|
||||
"nanorc",
|
||||
"nesc",
|
||||
"ooc",
|
||||
"q",
|
||||
"restructuredtext",
|
||||
"robots-txt",
|
||||
"sed",
|
||||
"wisp",
|
||||
"xbase",
|
||||
]
|
||||
`;
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { 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) : 7007;
|
||||
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
|
||||
const logger = getRootLogger();
|
||||
|
||||
startStandaloneServer({ port, enableCors, logger }).catch(err => {
|
||||
logger.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
logger.info('CTRL+C pressed; exiting.');
|
||||
process.exit(0);
|
||||
});
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 {
|
||||
DatabaseManager,
|
||||
getVoidLogger,
|
||||
PluginDatabaseManager,
|
||||
PluginEndpointDiscovery,
|
||||
TokenManager,
|
||||
UrlReaders,
|
||||
} from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { createRouter, createRouterFromConfig } from './router';
|
||||
import { LinguistBackendApi } from '../api';
|
||||
import { TaskScheduleDefinition } from '@backstage/backend-tasks';
|
||||
|
||||
function createDatabase(): PluginDatabaseManager {
|
||||
return DatabaseManager.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
database: {
|
||||
client: 'better-sqlite3',
|
||||
connection: ':memory:',
|
||||
},
|
||||
},
|
||||
}),
|
||||
).forPlugin('code-coverage');
|
||||
}
|
||||
|
||||
const testDiscovery: jest.Mocked<PluginEndpointDiscovery> = {
|
||||
getBaseUrl: jest
|
||||
.fn()
|
||||
.mockResolvedValue('http://localhost:7007/api/code-coverage'),
|
||||
getExternalBaseUrl: jest.fn(),
|
||||
};
|
||||
|
||||
const mockedTokenManager: jest.Mocked<TokenManager> = {
|
||||
getToken: jest.fn(),
|
||||
authenticate: jest.fn(),
|
||||
};
|
||||
|
||||
const mockUrlReader = UrlReaders.default({
|
||||
logger: getVoidLogger(),
|
||||
config: new ConfigReader({}),
|
||||
});
|
||||
|
||||
const schedule: TaskScheduleDefinition = {
|
||||
frequency: { minutes: 2 },
|
||||
timeout: { minutes: 15 },
|
||||
initialDelay: { seconds: 15 },
|
||||
};
|
||||
|
||||
describe('createRouter', () => {
|
||||
let linguistBackendApi: jest.Mocked<LinguistBackendApi>;
|
||||
let app: express.Express;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('GET /health', () => {
|
||||
beforeAll(async () => {
|
||||
const router = await createRouter(
|
||||
{ schedule: schedule, age: { days: 30 }, useSourceLocation: false },
|
||||
{
|
||||
linguistBackendApi: linguistBackendApi,
|
||||
discovery: testDiscovery,
|
||||
database: createDatabase(),
|
||||
reader: mockUrlReader,
|
||||
logger: getVoidLogger(),
|
||||
tokenManager: mockedTokenManager,
|
||||
},
|
||||
);
|
||||
app = express().use(router);
|
||||
});
|
||||
it('returns ok', async () => {
|
||||
const response = await request(app).get('/health');
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual({ status: 'ok' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /health from config', () => {
|
||||
beforeAll(async () => {
|
||||
const config = new ConfigReader({
|
||||
linguist: {
|
||||
schedule: {
|
||||
frequency: { minutes: 2 },
|
||||
timeout: { minutes: 15 },
|
||||
initialDelay: { seconds: 15 },
|
||||
},
|
||||
age: { days: 30 },
|
||||
useSourceLocation: false,
|
||||
},
|
||||
});
|
||||
const router = await createRouterFromConfig({
|
||||
linguistBackendApi: linguistBackendApi,
|
||||
discovery: testDiscovery,
|
||||
database: createDatabase(),
|
||||
reader: mockUrlReader,
|
||||
logger: getVoidLogger(),
|
||||
config,
|
||||
tokenManager: mockedTokenManager,
|
||||
});
|
||||
app = express().use(router);
|
||||
});
|
||||
it('returns ok', async () => {
|
||||
const response = await request(app).get('/health');
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual({ status: 'ok' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 {
|
||||
createLegacyAuthAdapters,
|
||||
errorHandler,
|
||||
PluginDatabaseManager,
|
||||
PluginEndpointDiscovery,
|
||||
TokenManager,
|
||||
UrlReader,
|
||||
} from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { LinguistBackendApi } from '../api';
|
||||
import { LinguistBackendDatabase } from '../db';
|
||||
import {
|
||||
PluginTaskScheduler,
|
||||
readTaskScheduleDefinitionFromConfig,
|
||||
TaskScheduleDefinition,
|
||||
} from '@backstage/backend-tasks';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
import { LinguistBackendClient } from '../api/LinguistBackendClient';
|
||||
import { Config } from '@backstage/config';
|
||||
import {
|
||||
AuthService,
|
||||
HttpAuthService,
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export interface PluginOptions {
|
||||
schedule?: TaskScheduleDefinition;
|
||||
age?: HumanDuration;
|
||||
batchSize?: number;
|
||||
useSourceLocation?: boolean;
|
||||
linguistJsOptions?: Record<string, unknown>;
|
||||
kind?: string[];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface RouterOptions {
|
||||
linguistBackendApi?: LinguistBackendApi;
|
||||
logger: LoggerService;
|
||||
reader: UrlReader;
|
||||
tokenManager: TokenManager;
|
||||
database: PluginDatabaseManager;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
scheduler?: PluginTaskScheduler;
|
||||
config?: Config;
|
||||
auth?: AuthService;
|
||||
httpAuth?: HttpAuthService;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export async function createRouter(
|
||||
pluginOptions: PluginOptions,
|
||||
routerOptions: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const { logger, reader, database, discovery, scheduler, tokenManager, auth } =
|
||||
routerOptions;
|
||||
|
||||
const {
|
||||
schedule,
|
||||
age,
|
||||
batchSize,
|
||||
useSourceLocation,
|
||||
kind,
|
||||
linguistJsOptions,
|
||||
} = pluginOptions;
|
||||
|
||||
const linguistBackendStore = await LinguistBackendDatabase.create(
|
||||
await database.getClient(),
|
||||
);
|
||||
|
||||
const catalogClient = new CatalogClient({ discoveryApi: discovery });
|
||||
|
||||
const { auth: adaptedAuth } = createLegacyAuthAdapters({
|
||||
auth,
|
||||
tokenManager: tokenManager,
|
||||
discovery: discovery,
|
||||
});
|
||||
|
||||
const linguistBackendClient =
|
||||
routerOptions.linguistBackendApi ||
|
||||
new LinguistBackendClient(
|
||||
logger,
|
||||
linguistBackendStore,
|
||||
reader,
|
||||
adaptedAuth,
|
||||
catalogClient,
|
||||
age,
|
||||
batchSize,
|
||||
useSourceLocation,
|
||||
kind,
|
||||
linguistJsOptions,
|
||||
);
|
||||
|
||||
if (scheduler && schedule) {
|
||||
logger.info(
|
||||
`Scheduling processing of entities with: ${JSON.stringify(schedule)}`,
|
||||
);
|
||||
await scheduler.scheduleTask({
|
||||
id: 'linguist_process_entities',
|
||||
frequency: schedule.frequency,
|
||||
timeout: schedule.timeout,
|
||||
initialDelay: schedule.initialDelay,
|
||||
scope: schedule.scope,
|
||||
fn: async () => {
|
||||
await linguistBackendClient.processEntities();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
|
||||
router.get('/health', (_, response) => {
|
||||
response.send({ status: 'ok' });
|
||||
});
|
||||
|
||||
/**
|
||||
* /entity-languages?entity=component:default/my-component
|
||||
*/
|
||||
router.get('/entity-languages', async (req, res) => {
|
||||
const { entityRef: entityRef } = req.query;
|
||||
|
||||
if (!entityRef) {
|
||||
throw new Error('No entityRef was provided');
|
||||
}
|
||||
|
||||
const entityLanguages = await linguistBackendClient.getEntityLanguages(
|
||||
entityRef as string,
|
||||
);
|
||||
res.status(200).json(entityLanguages);
|
||||
});
|
||||
|
||||
router.use(errorHandler());
|
||||
return router;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export async function createRouterFromConfig(routerOptions: RouterOptions) {
|
||||
const { config } = routerOptions;
|
||||
const pluginOptions: PluginOptions = {};
|
||||
if (config) {
|
||||
if (config.has('linguist.schedule')) {
|
||||
pluginOptions.schedule = readTaskScheduleDefinitionFromConfig(
|
||||
config.getConfig('linguist.schedule'),
|
||||
);
|
||||
}
|
||||
pluginOptions.batchSize = config.getOptionalNumber('linguist.batchSize');
|
||||
pluginOptions.useSourceLocation =
|
||||
config.getOptionalBoolean('linguist.useSourceLocation') ?? false;
|
||||
pluginOptions.age = config.getOptionalConfig('linguist.age') as
|
||||
| HumanDuration
|
||||
| undefined;
|
||||
pluginOptions.kind = config.getOptionalStringArray('linguist.kind');
|
||||
pluginOptions.linguistJsOptions = config.getOptionalConfig(
|
||||
'linguist.linguistJsOptions',
|
||||
);
|
||||
}
|
||||
return createRouter(pluginOptions, routerOptions);
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 {
|
||||
createServiceBuilder,
|
||||
DatabaseManager,
|
||||
HostDiscovery,
|
||||
loadBackendConfig,
|
||||
ServerTokenManager,
|
||||
UrlReaders,
|
||||
} from '@backstage/backend-common';
|
||||
import { Server } from 'http';
|
||||
import { createRouter } from './router';
|
||||
import { TaskScheduleDefinition } from '@backstage/backend-tasks';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
export interface ServerOptions {
|
||||
port: number;
|
||||
enableCors: boolean;
|
||||
logger: LoggerService;
|
||||
}
|
||||
|
||||
export async function startStandaloneServer(
|
||||
options: ServerOptions,
|
||||
): Promise<Server> {
|
||||
const logger = options.logger.child({ service: 'linguist-backend' });
|
||||
const config = await loadBackendConfig({ logger, argv: process.argv });
|
||||
const manager = DatabaseManager.fromConfig(
|
||||
new ConfigReader({
|
||||
backend: {
|
||||
database: { client: 'better-sqlite3', connection: ':memory:' },
|
||||
},
|
||||
}),
|
||||
);
|
||||
const database = manager.forPlugin('linguist');
|
||||
|
||||
const schedule: TaskScheduleDefinition = {
|
||||
frequency: { minutes: 2 },
|
||||
timeout: { minutes: 15 },
|
||||
initialDelay: { seconds: 15 },
|
||||
};
|
||||
|
||||
logger.debug('Starting application server...');
|
||||
const router = await createRouter(
|
||||
{ schedule: schedule, age: { days: 30 }, useSourceLocation: false },
|
||||
{
|
||||
database,
|
||||
discovery: HostDiscovery.fromConfig(config),
|
||||
reader: UrlReaders.default({ logger, config }),
|
||||
logger,
|
||||
tokenManager: ServerTokenManager.noop(),
|
||||
},
|
||||
);
|
||||
|
||||
let service = createServiceBuilder(module)
|
||||
.setPort(options.port)
|
||||
.addRouter('/linguist', router);
|
||||
if (options.enableCors) {
|
||||
service = service.enableCors({ origin: 'http://localhost:3000' });
|
||||
}
|
||||
|
||||
return await service.start().catch(err => {
|
||||
logger.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.hot?.accept();
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export {};
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -1,38 +0,0 @@
|
||||
# @backstage/plugin-linguist-common
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
|
||||
## 0.1.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12a8c94eda8d: Add package repository and homepage metadata
|
||||
- d440f1dd0e72: Exported new LanguageType type alias
|
||||
|
||||
## 0.1.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d440f1dd0e72: Exported new LanguageType type alias
|
||||
|
||||
## 0.1.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12a8c94eda8d: Add package repository and homepage metadata
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 75cfee5688: Introduced the Linguist plugin, checkout the plugin's `README.md` for more details!
|
||||
@@ -1,3 +0,0 @@
|
||||
# Deprecated
|
||||
|
||||
This package has been moved to the [backstage-community/plugins](https://github.com/backstage/community-plugins) repository. Migrate to using `@backstage-community/plugin-linguist-common` instead.
|
||||
@@ -1,51 +0,0 @@
|
||||
## API Report File for "@backstage/plugin-linguist-common"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
// @public (undocumented)
|
||||
export type EntitiesOverview = {
|
||||
entityCount: number;
|
||||
processedCount: number;
|
||||
pendingCount: number;
|
||||
staleCount: number;
|
||||
filteredEntities: string[];
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type EntityResults = {
|
||||
entityRef: string;
|
||||
results: Languages;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type Language = {
|
||||
name: string;
|
||||
percentage: number;
|
||||
bytes: number;
|
||||
type: LanguageType;
|
||||
color?: `#${string}`;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type Languages = {
|
||||
languageCount: number;
|
||||
totalBytes: number;
|
||||
processedDate: string;
|
||||
breakdown: Language[];
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type LanguageType = 'programming' | 'data' | 'markup' | 'prose';
|
||||
|
||||
// @public (undocumented)
|
||||
export const LINGUIST_ANNOTATION = 'backstage.io/linguist';
|
||||
|
||||
// @public (undocumented)
|
||||
export type ProcessedEntity = {
|
||||
entityRef: string;
|
||||
processedDate: Date;
|
||||
};
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-plugin-linguist-common
|
||||
title: '@backstage/plugin-linguist-common'
|
||||
description: Common functionalities for the linguist plugin
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-common-library
|
||||
owner: awanlin
|
||||
@@ -1,2 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "@backstage/plugin-linguist-common",
|
||||
"version": "0.1.2",
|
||||
"description": "Common functionalities for the linguist plugin",
|
||||
"backstage": {
|
||||
"role": "common-library",
|
||||
"moved": "@backstage-community/plugin-linguist-common"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.cjs.js",
|
||||
"module": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/linguist-common"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^"
|
||||
},
|
||||
"deprecated": "This package has been moved to the backstage/community-plugins repository. You should migrate to using @backstage-community/plugin-linguist-common instead."
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
/** @public */
|
||||
export const LINGUIST_ANNOTATION = 'backstage.io/linguist';
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export * from './types';
|
||||
export * from './constants';
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
export {};
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
/** @public */
|
||||
export type EntityResults = {
|
||||
entityRef: string;
|
||||
results: Languages;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type Languages = {
|
||||
languageCount: number;
|
||||
totalBytes: number;
|
||||
processedDate: string;
|
||||
breakdown: Language[];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type LanguageType = 'programming' | 'data' | 'markup' | 'prose';
|
||||
|
||||
/** @public */
|
||||
export type Language = {
|
||||
name: string;
|
||||
percentage: number;
|
||||
bytes: number;
|
||||
type: LanguageType;
|
||||
color?: `#${string}`;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type ProcessedEntity = {
|
||||
entityRef: string;
|
||||
processedDate: Date;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type EntitiesOverview = {
|
||||
entityCount: number;
|
||||
processedCount: number;
|
||||
pendingCount: number;
|
||||
staleCount: number;
|
||||
filteredEntities: string[];
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -1,844 +0,0 @@
|
||||
# @backstage/plugin-linguist
|
||||
|
||||
## 0.1.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.11.3
|
||||
- @backstage/core-compat-api@0.2.4
|
||||
- @backstage/core-components@0.14.4
|
||||
- @backstage/core-plugin-api@1.9.2
|
||||
- @backstage/frontend-plugin-api@0.6.4
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.19-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/frontend-plugin-api@0.6.4-next.1
|
||||
- @backstage/core-compat-api@0.2.4-next.1
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/core-components@0.14.4-next.0
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/plugin-catalog-react@1.11.3-next.1
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.19-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.4-next.0
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/core-compat-api@0.2.4-next.0
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/frontend-plugin-api@0.6.4-next.0
|
||||
- @backstage/plugin-catalog-react@1.11.3-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e8f026a: Use ESM exports of react-use library
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.3
|
||||
- @backstage/plugin-catalog-react@1.11.2
|
||||
- @backstage/frontend-plugin-api@0.6.3
|
||||
- @backstage/core-compat-api@0.2.3
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e8f026a: Use ESM exports of react-use library
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.2
|
||||
- @backstage/plugin-catalog-react@1.11.1
|
||||
- @backstage/frontend-plugin-api@0.6.2
|
||||
- @backstage/core-compat-api@0.2.2
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4fb9600: Get component's title from translation file. See: https://backstage.io/docs/plugins/internationalization#for-an-application-developer-overwrite-plugin-messages
|
||||
- a0e3393: Updated to use `fetchApi` as per [ADR013](https://backstage.io/docs/architecture-decisions/adrs-adr013)
|
||||
- 786c9c4: Updated dependency `luxon` to `^3.0.0`.
|
||||
- 051fda1: Removed unused `dependencies` and `devDependencies` identified in Knip Report
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/plugin-catalog-react@1.11.0
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/core-compat-api@0.2.1
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/frontend-plugin-api@0.6.1
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.16-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 051fda1: Removed unused `dependencies` and `devDependencies` identified in Knip Report
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1-next.2
|
||||
- @backstage/plugin-catalog-react@1.11.0-next.2
|
||||
- @backstage/frontend-plugin-api@0.6.1-next.2
|
||||
- @backstage/core-compat-api@0.2.1-next.2
|
||||
- @backstage/catalog-model@1.4.5-next.0
|
||||
- @backstage/core-plugin-api@1.9.1-next.1
|
||||
- @backstage/errors@1.2.4-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.16-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1-next.1
|
||||
- @backstage/plugin-catalog-react@1.10.1-next.1
|
||||
- @backstage/core-plugin-api@1.9.1-next.1
|
||||
- @backstage/frontend-plugin-api@0.6.1-next.1
|
||||
- @backstage/catalog-model@1.4.5-next.0
|
||||
- @backstage/core-compat-api@0.2.1-next.1
|
||||
- @backstage/errors@1.2.4-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.16-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4fb9600: Get component's title from translation file. See: https://backstage.io/docs/plugins/internationalization#for-an-application-developer-overwrite-plugin-messages
|
||||
- a0e3393: Updated to use `fetchApi` as per [ADR013](https://backstage.io/docs/architecture-decisions/adrs-adr013)
|
||||
- 786c9c4: Updated dependency `luxon` to `^3.0.0`.
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.4-next.0
|
||||
- @backstage/core-components@0.14.1-next.0
|
||||
- @backstage/plugin-catalog-react@1.10.1-next.0
|
||||
- @backstage/catalog-model@1.4.5-next.0
|
||||
- @backstage/core-plugin-api@1.9.1-next.0
|
||||
- @backstage/frontend-plugin-api@0.6.1-next.0
|
||||
- @backstage/core-compat-api@0.2.1-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9aac2b0: Use `--cwd` as the first `yarn` argument
|
||||
- 8fe56a8: Widen `@types/react` dependency range to include version 18.
|
||||
- 995d280: Updated imports from named to default imports to help with the Material UI v4 to v5 migration
|
||||
- Updated dependencies
|
||||
- @backstage/frontend-plugin-api@0.6.0
|
||||
- @backstage/core-compat-api@0.2.0
|
||||
- @backstage/plugin-catalog-react@1.10.0
|
||||
- @backstage/core-components@0.14.0
|
||||
- @backstage/catalog-model@1.4.4
|
||||
- @backstage/core-plugin-api@1.9.0
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.15-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.0-next.2
|
||||
- @backstage/plugin-catalog-react@1.10.0-next.3
|
||||
- @backstage/catalog-model@1.4.4-next.0
|
||||
- @backstage/core-compat-api@0.2.0-next.3
|
||||
- @backstage/core-plugin-api@1.9.0-next.1
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/frontend-plugin-api@0.6.0-next.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.15-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9aac2b0: Use `--cwd` as the first `yarn` argument
|
||||
- 8fe56a8: Widen `@types/react` dependency range to include version 18.
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.0-next.1
|
||||
- @backstage/core-plugin-api@1.9.0-next.1
|
||||
- @backstage/frontend-plugin-api@0.6.0-next.2
|
||||
- @backstage/plugin-catalog-react@1.10.0-next.2
|
||||
- @backstage/core-compat-api@0.2.0-next.2
|
||||
- @backstage/catalog-model@1.4.4-next.0
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.15-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/frontend-plugin-api@0.6.0-next.1
|
||||
- @backstage/core-compat-api@0.2.0-next.1
|
||||
- @backstage/core-components@0.14.0-next.0
|
||||
- @backstage/catalog-model@1.4.4-next.0
|
||||
- @backstage/core-plugin-api@1.8.3-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.4-next.1
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.15-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 995d280: Updated imports from named to default imports to help with the Material UI v4 to v5 migration
|
||||
- Updated dependencies
|
||||
- @backstage/core-compat-api@0.1.2-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.4-next.0
|
||||
- @backstage/frontend-plugin-api@0.5.1-next.0
|
||||
- @backstage/core-components@0.13.10
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-plugin-api@1.8.2
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4016f21: Remove some unused dependencies
|
||||
- 4f42918: Added alpha support for the New Frontend System (Declarative Integration)
|
||||
- Updated dependencies
|
||||
- @backstage/core-compat-api@0.1.1
|
||||
- @backstage/frontend-plugin-api@0.5.0
|
||||
- @backstage/core-components@0.13.10
|
||||
- @backstage/core-plugin-api@1.8.2
|
||||
- @backstage/plugin-catalog-react@1.9.3
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.14-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4f42918: Added alpha support for the New Frontend System (Declarative Integration)
|
||||
- Updated dependencies
|
||||
- @backstage/core-compat-api@0.1.1-next.2
|
||||
- @backstage/frontend-plugin-api@0.4.1-next.2
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.2
|
||||
|
||||
## 0.1.14-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.2-next.0
|
||||
- @backstage/core-components@0.13.10-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.14-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4016f21: Remove some unused dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.10-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-plugin-api@1.8.1
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.1
|
||||
- @backstage/plugin-catalog-react@1.9.2
|
||||
- @backstage/core-components@0.13.9
|
||||
- @backstage/theme@0.5.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.13-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.9-next.3
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-plugin-api@1.8.1-next.1
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/theme@0.5.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.13-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.5.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.2
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-components@0.13.9-next.2
|
||||
- @backstage/core-plugin-api@1.8.1-next.1
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.13-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.9-next.1
|
||||
- @backstage/core-plugin-api@1.8.1-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/theme@0.5.0-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.13-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.1-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.0
|
||||
- @backstage/core-components@0.13.9-next.0
|
||||
- @backstage/theme@0.5.0-next.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c2b872153: Add official support for React 18.
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.9.0
|
||||
- @backstage/core-components@0.13.8
|
||||
- @backstage/core-plugin-api@1.8.0
|
||||
- @backstage/theme@0.4.4
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.11-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.8-next.2
|
||||
- @backstage/plugin-catalog-react@1.9.0-next.2
|
||||
|
||||
## 0.1.11-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.9.0-next.1
|
||||
- @backstage/core-components@0.13.8-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-plugin-api@1.8.0-next.0
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/theme@0.4.4-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.11-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c2b872153: Add official support for React 18.
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.7-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.0-next.0
|
||||
- @backstage/core-plugin-api@1.8.0-next.0
|
||||
- @backstage/theme@0.4.4-next.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`.
|
||||
- f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`.
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.5
|
||||
- @backstage/core-plugin-api@1.7.0
|
||||
- @backstage/core-components@0.13.6
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/theme@0.4.3
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.10-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.6-next.2
|
||||
- @backstage/core-plugin-api@1.7.0-next.1
|
||||
- @backstage/catalog-model@1.4.3-next.0
|
||||
- @backstage/plugin-catalog-react@1.8.5-next.2
|
||||
- @backstage/errors@1.2.3-next.0
|
||||
- @backstage/theme@0.4.3-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.10-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.6-next.1
|
||||
- @backstage/plugin-catalog-react@1.8.5-next.1
|
||||
- @backstage/core-plugin-api@1.7.0-next.0
|
||||
- @backstage/catalog-model@1.4.2
|
||||
- @backstage/errors@1.2.2
|
||||
- @backstage/theme@0.4.2
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.10-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.5-next.0
|
||||
- @backstage/core-plugin-api@1.7.0-next.0
|
||||
- @backstage/core-components@0.13.6-next.0
|
||||
- @backstage/catalog-model@1.4.2
|
||||
- @backstage/errors@1.2.2
|
||||
- @backstage/theme@0.4.2
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 482bb5c0bbf8: Moved `@types/react` to be a regular dependency
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- 8cec7664e146: Removed `@types/node` dependency
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.4
|
||||
- @backstage/core-components@0.13.5
|
||||
- @backstage/catalog-model@1.4.2
|
||||
- @backstage/core-plugin-api@1.6.0
|
||||
- @backstage/errors@1.2.2
|
||||
- @backstage/plugin-linguist-common@0.1.2
|
||||
- @backstage/theme@0.4.2
|
||||
|
||||
## 0.1.9-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/core-components@0.13.5-next.3
|
||||
- @backstage/core-plugin-api@1.6.0-next.3
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.3
|
||||
- @backstage/plugin-linguist-common@0.1.2-next.0
|
||||
- @backstage/theme@0.4.2-next.0
|
||||
|
||||
## 0.1.9-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8cec7664e146: Removed `@types/node` dependency
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.5-next.2
|
||||
- @backstage/core-plugin-api@1.6.0-next.2
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.2
|
||||
- @backstage/catalog-model@1.4.2-next.1
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-linguist-common@0.1.1
|
||||
|
||||
## 0.1.9-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.1
|
||||
- @backstage/core-components@0.13.5-next.1
|
||||
- @backstage/catalog-model@1.4.2-next.0
|
||||
- @backstage/core-plugin-api@1.6.0-next.1
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-linguist-common@0.1.1
|
||||
|
||||
## 0.1.8-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 482bb5c0bbf8: Moved `@types/react` to be a regular dependency
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.6.0-next.0
|
||||
- @backstage/core-components@0.13.5-next.0
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-catalog-react@1.8.3-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.1
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-linguist-common@0.1.1
|
||||
- @backstage/core-components@0.13.4
|
||||
- @backstage/plugin-catalog-react@1.8.1
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/theme@0.4.1
|
||||
|
||||
## 0.1.6-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-linguist-common@0.1.1-next.1
|
||||
- @backstage/plugin-catalog-react@1.8.1-next.1
|
||||
|
||||
## 0.1.6-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-linguist-common@0.1.1-next.0
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/core-components@0.13.4-next.0
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-catalog-react@1.8.1-next.0
|
||||
|
||||
## 0.1.6-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.4-next.0
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/plugin-catalog-react@1.8.1-next.0
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/plugin-catalog-react@1.8.0
|
||||
- @backstage/core-components@0.13.3
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.5-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.0-next.2
|
||||
- @backstage/theme@0.4.1-next.1
|
||||
- @backstage/core-plugin-api@1.5.3-next.1
|
||||
- @backstage/core-components@0.13.3-next.2
|
||||
- @backstage/catalog-model@1.4.1-next.0
|
||||
- @backstage/errors@1.2.1-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.5-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.4.1-next.0
|
||||
- @backstage/core-components@0.13.3-next.1
|
||||
- @backstage/core-plugin-api@1.5.3-next.0
|
||||
- @backstage/plugin-catalog-react@1.7.1-next.1
|
||||
|
||||
## 0.1.5-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.1-next.0
|
||||
- @backstage/core-components@0.13.3-next.0
|
||||
- @backstage/catalog-model@1.4.1-next.0
|
||||
- @backstage/core-plugin-api@1.5.2
|
||||
- @backstage/theme@0.4.0
|
||||
- @backstage/plugin-catalog-react@1.7.1-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.5.2
|
||||
- @backstage/core-components@0.13.2
|
||||
- @backstage/theme@0.4.0
|
||||
- @backstage/plugin-catalog-react@1.7.0
|
||||
- @backstage/catalog-model@1.4.0
|
||||
- @backstage/errors@1.2.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.4-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.2-next.3
|
||||
- @backstage/catalog-model@1.4.0-next.1
|
||||
- @backstage/core-plugin-api@1.5.2-next.0
|
||||
- @backstage/errors@1.2.0-next.0
|
||||
- @backstage/theme@0.4.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.7.0-next.3
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.4-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.4.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.7.0-next.2
|
||||
- @backstage/core-components@0.13.2-next.2
|
||||
- @backstage/core-plugin-api@1.5.2-next.0
|
||||
|
||||
## 0.1.4-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.0-next.0
|
||||
- @backstage/core-components@0.13.2-next.1
|
||||
- @backstage/plugin-catalog-react@1.7.0-next.1
|
||||
- @backstage/catalog-model@1.4.0-next.0
|
||||
- @backstage/core-plugin-api@1.5.2-next.0
|
||||
- @backstage/theme@0.4.0-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.4-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.7.0-next.0
|
||||
- @backstage/theme@0.4.0-next.0
|
||||
- @backstage/core-components@0.13.2-next.0
|
||||
- @backstage/core-plugin-api@1.5.1
|
||||
- @backstage/catalog-model@1.3.0
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.3.0
|
||||
- @backstage/plugin-catalog-react@1.6.0
|
||||
- @backstage/core-components@0.13.1
|
||||
- @backstage/catalog-model@1.3.0
|
||||
- @backstage/core-plugin-api@1.5.1
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.3-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.3.0-next.0
|
||||
- @backstage/core-components@0.13.1-next.1
|
||||
- @backstage/plugin-catalog-react@1.6.0-next.2
|
||||
- @backstage/core-plugin-api@1.5.1
|
||||
|
||||
## 0.1.3-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.1-next.0
|
||||
- @backstage/core-plugin-api@1.5.1
|
||||
- @backstage/plugin-catalog-react@1.6.0-next.1
|
||||
|
||||
## 0.1.3-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.6.0-next.0
|
||||
- @backstage/core-components@0.13.0
|
||||
- @backstage/core-plugin-api@1.5.1
|
||||
- @backstage/catalog-model@1.3.0
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/theme@0.2.19
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 29ba8267d69: Updated dependency `@material-ui/lab` to `4.0.0-alpha.61`.
|
||||
- e0c6e8b9c3c: Update peer dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.0
|
||||
- @backstage/plugin-catalog-react@1.5.0
|
||||
- @backstage/theme@0.2.19
|
||||
- @backstage/core-plugin-api@1.5.1
|
||||
- @backstage/catalog-model@1.3.0
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.2-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.5.0-next.3
|
||||
- @backstage/catalog-model@1.3.0-next.0
|
||||
- @backstage/core-components@0.13.0-next.3
|
||||
- @backstage/core-plugin-api@1.5.1-next.1
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/theme@0.2.19-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.6-next.2
|
||||
- @backstage/plugin-catalog-react@1.4.1-next.2
|
||||
- @backstage/core-plugin-api@1.5.1-next.1
|
||||
- @backstage/catalog-model@1.2.1
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/theme@0.2.19-next.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 29ba8267d69: Updated dependency `@material-ui/lab` to `4.0.0-alpha.61`.
|
||||
- e0c6e8b9c3c: Update peer dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.6-next.1
|
||||
- @backstage/core-plugin-api@1.5.1-next.0
|
||||
- @backstage/plugin-catalog-react@1.4.1-next.1
|
||||
- @backstage/theme@0.2.19-next.0
|
||||
- @backstage/catalog-model@1.2.1
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.6-next.0
|
||||
- @backstage/plugin-catalog-react@1.4.1-next.0
|
||||
- @backstage/core-plugin-api@1.5.0
|
||||
- @backstage/catalog-model@1.2.1
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/theme@0.2.18
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 52b0022dab7: Updated dependency `msw` to `^1.0.0`.
|
||||
- ab997ce243f: Updated `README.md` to removed images with refresh button as this feature was not implemented in the current version
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.5
|
||||
- @backstage/plugin-catalog-react@1.4.0
|
||||
- @backstage/errors@1.1.5
|
||||
- @backstage/core-plugin-api@1.5.0
|
||||
- @backstage/catalog-model@1.2.1
|
||||
- @backstage/theme@0.2.18
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.5-next.2
|
||||
- @backstage/plugin-catalog-react@1.4.0-next.2
|
||||
- @backstage/core-plugin-api@1.5.0-next.2
|
||||
|
||||
## 0.1.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 52b0022dab7: Updated dependency `msw` to `^1.0.0`.
|
||||
- ab997ce243f: Updated `README.md` to removed images with refresh button as this feature was not implemented in the current version
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.5-next.1
|
||||
- @backstage/errors@1.1.5-next.0
|
||||
- @backstage/core-plugin-api@1.4.1-next.1
|
||||
- @backstage/theme@0.2.18-next.0
|
||||
- @backstage/plugin-catalog-react@1.4.0-next.1
|
||||
- @backstage/catalog-model@1.2.1-next.1
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.4.0-next.0
|
||||
- @backstage/core-plugin-api@1.4.1-next.0
|
||||
- @backstage/catalog-model@1.2.1-next.0
|
||||
- @backstage/core-components@0.12.5-next.0
|
||||
- @backstage/errors@1.1.4
|
||||
- @backstage/theme@0.2.17
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 75cfee5688: Introduced the Linguist plugin, checkout the plugin's `README.md` for more details!
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.12.4
|
||||
- @backstage/catalog-model@1.2.0
|
||||
- @backstage/theme@0.2.17
|
||||
- @backstage/core-plugin-api@1.4.0
|
||||
- @backstage/plugin-catalog-react@1.3.0
|
||||
- @backstage/plugin-linguist-common@0.1.0
|
||||
- @backstage/errors@1.1.4
|
||||
@@ -1,3 +0,0 @@
|
||||
# Deprecated
|
||||
|
||||
This package has been moved to the [backstage-community/plugins](https://github.com/backstage/community-plugins) repository. Migrate to using `@backstage-community/plugin-linguist` instead.
|
||||
@@ -1,23 +0,0 @@
|
||||
## API Report File for "@backstage/plugin-linguist"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { BackstagePlugin } from '@backstage/frontend-plugin-api';
|
||||
import { TranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
|
||||
// @alpha (undocumented)
|
||||
const _default: BackstagePlugin<{}, {}>;
|
||||
export default _default;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export const linguistTranslationRef: TranslationRef<
|
||||
'linguist',
|
||||
{
|
||||
readonly 'entityCard.title': 'Languages';
|
||||
readonly 'entityCard.noData': 'There is currently no language data for this entity.';
|
||||
}
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -1,22 +0,0 @@
|
||||
## API Report File for "@backstage/plugin-linguist"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
|
||||
// @public (undocumented)
|
||||
export const EntityLinguistCard: () => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export const isLinguistAvailable: (entity: Entity) => boolean;
|
||||
|
||||
// @public (undocumented)
|
||||
export const linguistPlugin: BackstagePlugin<{}, {}>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-plugin-linguist
|
||||
title: '@backstage/plugin-linguist'
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-frontend-plugin
|
||||
owner: awanlin
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 React from 'react';
|
||||
import { createDevApp } from '@backstage/dev-utils';
|
||||
import { linguistPlugin, EntityLinguistCard } from '../src/plugin';
|
||||
|
||||
createDevApp()
|
||||
.registerPlugin(linguistPlugin)
|
||||
.addPage({
|
||||
element: <EntityLinguistCard />,
|
||||
title: 'Root Page',
|
||||
path: '/linguist',
|
||||
})
|
||||
.render();
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,2 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
{
|
||||
"name": "@backstage/plugin-linguist",
|
||||
"version": "0.1.19",
|
||||
"backstage": {
|
||||
"role": "frontend-plugin",
|
||||
"moved": "@backstage-community/plugin-linguist"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/linguist"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./alpha": "./src/alpha.ts",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"alpha": [
|
||||
"src/alpha.ts"
|
||||
],
|
||||
"package.json": [
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"start": "backstage-cli package start",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/core-compat-api": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/plugin-linguist-common": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/lab": "4.0.0-alpha.61",
|
||||
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"luxon": "^3.0.0",
|
||||
"react-use": "^17.2.4",
|
||||
"slugify": "^1.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/dev-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
||||
},
|
||||
"deprecated": "This package has been moved to the backstage/community-plugins repository. You should migrate to using @backstage-community/plugin-linguist instead."
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
export * from './alpha/index';
|
||||
export { default } from './alpha/index';
|
||||
export * from './translation';
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
export { default } from './plugin';
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 React from 'react';
|
||||
import {
|
||||
createApiExtension,
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
discoveryApiRef,
|
||||
fetchApiRef,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
import { LinguistClient, linguistApiRef } from '../api';
|
||||
import { compatWrapper } from '@backstage/core-compat-api';
|
||||
import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
|
||||
/** @alpha */
|
||||
export const entityLinguistCard = createEntityCardExtension({
|
||||
name: 'languages',
|
||||
loader: async () =>
|
||||
import('../components/LinguistCard').then(m =>
|
||||
compatWrapper(<m.LinguistCard />),
|
||||
),
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
export const linguistApi = createApiExtension({
|
||||
factory: createApiFactory({
|
||||
api: linguistApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
fetchApi: fetchApiRef,
|
||||
},
|
||||
factory: ({ discoveryApi, fetchApi }) =>
|
||||
new LinguistClient({ discoveryApi, fetchApi }),
|
||||
}),
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
export default createPlugin({
|
||||
id: 'linguist',
|
||||
extensions: [linguistApi, entityLinguistCard],
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { createApiRef } from '@backstage/core-plugin-api';
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
|
||||
export const linguistApiRef = createApiRef<LinguistApi>({
|
||||
id: 'plugin.linguist.service',
|
||||
});
|
||||
|
||||
export interface LinguistApi {
|
||||
getLanguages(entityRef: string): Promise<Languages>;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
import { LinguistApi } from './LinguistApi';
|
||||
|
||||
export class LinguistClient implements LinguistApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
private readonly fetchApi: FetchApi;
|
||||
|
||||
public constructor(options: {
|
||||
discoveryApi: DiscoveryApi;
|
||||
fetchApi: FetchApi;
|
||||
}) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
this.fetchApi = options.fetchApi;
|
||||
}
|
||||
|
||||
public async getLanguages(entityRef: string): Promise<Languages> {
|
||||
const queryString = new URLSearchParams();
|
||||
queryString.append('entityRef', entityRef);
|
||||
|
||||
const urlSegment = `entity-languages?${queryString}`;
|
||||
|
||||
const items = await this.get<Languages>(urlSegment);
|
||||
return items;
|
||||
}
|
||||
|
||||
private async get<T>(path: string): Promise<T> {
|
||||
const baseUrl = `${await this.discoveryApi.getBaseUrl('linguist')}/`;
|
||||
const url = new URL(path, baseUrl);
|
||||
|
||||
const response = await this.fetchApi.fetch(url.toString());
|
||||
|
||||
if (!response.ok) {
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
return response.json() as Promise<T>;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export * from './LinguistApi';
|
||||
export * from './LinguistClient';
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 Box from '@material-ui/core/Box';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import { makeStyles, useTheme } from '@material-ui/core/styles';
|
||||
import { InfoCard, Progress } from '@backstage/core-components';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import { DateTime } from 'luxon';
|
||||
import React from 'react';
|
||||
import slugify from 'slugify';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { useLanguages } from '../../hooks';
|
||||
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
import { linguistTranslationRef } from '../../translation';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
infoCard: {
|
||||
marginBottom: theme.spacing(3),
|
||||
},
|
||||
barContainer: {
|
||||
height: theme.spacing(2),
|
||||
marginBottom: theme.spacing(3),
|
||||
borderRadius: '4px',
|
||||
backgroundColor: 'transparent',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
bar: {
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
},
|
||||
languageDot: {
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
borderRadius: '50%',
|
||||
marginRight: theme.spacing(1),
|
||||
display: 'inline-block',
|
||||
},
|
||||
label: {
|
||||
color: 'inherit',
|
||||
},
|
||||
}));
|
||||
|
||||
export const LinguistCard = () => {
|
||||
const { t } = useTranslationRef(linguistTranslationRef);
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const { entity } = useEntity();
|
||||
const { items, loading, error } = useLanguages(entity);
|
||||
let barWidth = 0;
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
} else if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
}
|
||||
|
||||
if (items && items.languageCount === 0 && items.totalBytes === 0) {
|
||||
return (
|
||||
<InfoCard title={t('entityCard.title')} className={classes.infoCard}>
|
||||
<Grid container spacing={3}>
|
||||
<Box p={2}>
|
||||
<Typography>{t('entityCard.noData')}</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
</InfoCard>
|
||||
);
|
||||
}
|
||||
|
||||
const breakdown = items?.breakdown.sort((a, b) =>
|
||||
a.percentage < b.percentage ? 1 : -1,
|
||||
);
|
||||
const processedDate = items?.processedDate;
|
||||
|
||||
return breakdown && processedDate ? (
|
||||
<InfoCard title={t('entityCard.title')} className={classes.infoCard}>
|
||||
<Box className={classes.barContainer}>
|
||||
{breakdown.map((language, index: number) => {
|
||||
barWidth = barWidth + language.percentage;
|
||||
return (
|
||||
<Tooltip
|
||||
title={language.name}
|
||||
placement="bottom-end"
|
||||
key={slugify(language.name, { lower: true })}
|
||||
>
|
||||
<Box
|
||||
className={classes.bar}
|
||||
key={slugify(language.name, { lower: true })}
|
||||
style={{
|
||||
marginTop: index === 0 ? '0' : `-16px`,
|
||||
zIndex: Object.keys(breakdown).length - index,
|
||||
backgroundColor:
|
||||
language.color?.toString() ||
|
||||
theme.palette.background.default,
|
||||
width: `${barWidth}%`,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
<Tooltip
|
||||
title={`Generated ${DateTime.fromISO(processedDate).toRelative()}`}
|
||||
>
|
||||
<Box>
|
||||
{breakdown.map(languages => (
|
||||
<Chip
|
||||
classes={{
|
||||
label: classes.label,
|
||||
}}
|
||||
label={
|
||||
<Box>
|
||||
<Box
|
||||
component="span"
|
||||
className={classes.languageDot}
|
||||
style={{
|
||||
backgroundColor:
|
||||
languages?.color?.toString() ||
|
||||
theme.palette.background.default,
|
||||
}}
|
||||
/>
|
||||
{languages.name} - {languages.percentage}%
|
||||
</Box>
|
||||
}
|
||||
variant="outlined"
|
||||
key={slugify(languages.name, { lower: true })}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</InfoCard>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export { LinguistCard } from './LinguistCard';
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
export * from './useLanguages';
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { Entity, stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { linguistApiRef } from '../api';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import useAsync from 'react-use/esm/useAsync';
|
||||
|
||||
import { Languages } from '@backstage/plugin-linguist-common';
|
||||
|
||||
export function useLanguages(entity: Entity): {
|
||||
items?: Languages;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
} {
|
||||
const entityRef = stringifyEntityRef(entity);
|
||||
|
||||
const api = useApi(linguistApiRef);
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
return api.getLanguages(entityRef);
|
||||
}, [api, entityRef]);
|
||||
|
||||
return {
|
||||
items: value,
|
||||
loading,
|
||||
error,
|
||||
};
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
export {
|
||||
linguistPlugin,
|
||||
isLinguistAvailable,
|
||||
EntityLinguistCard,
|
||||
} from './plugin';
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { linguistPlugin } from './plugin';
|
||||
|
||||
describe('linguist', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(linguistPlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 {
|
||||
createApiFactory,
|
||||
createComponentExtension,
|
||||
createPlugin,
|
||||
discoveryApiRef,
|
||||
fetchApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { linguistApiRef, LinguistClient } from './api';
|
||||
import { LINGUIST_ANNOTATION } from '@backstage/plugin-linguist-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
/** @public */
|
||||
export const isLinguistAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[LINGUIST_ANNOTATION]);
|
||||
|
||||
/** @public */
|
||||
export const linguistPlugin = createPlugin({
|
||||
id: 'linguist',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: linguistApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
fetchApi: fetchApiRef,
|
||||
},
|
||||
factory: ({ discoveryApi, fetchApi }) =>
|
||||
new LinguistClient({ discoveryApi, fetchApi }),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export const EntityLinguistCard = linguistPlugin.provide(
|
||||
createComponentExtension({
|
||||
name: 'EntityLinguistCard',
|
||||
component: {
|
||||
lazy: () => import('./components/LinguistCard').then(m => m.LinguistCard),
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 '@testing-library/jest-dom';
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createTranslationRef } from '@backstage/core-plugin-api/alpha';
|
||||
|
||||
/** @alpha */
|
||||
export const linguistTranslationRef = createTranslationRef({
|
||||
id: 'linguist',
|
||||
messages: {
|
||||
entityCard: {
|
||||
title: 'Languages',
|
||||
noData: 'There is currently no language data for this entity.',
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -1,425 +0,0 @@
|
||||
# @backstage/plugin-nomad-backend
|
||||
|
||||
## 0.1.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d5a1fe1: Replaced winston logger with `LoggerService`
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.7
|
||||
- @backstage/backend-plugin-api@0.6.17
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
|
||||
## 0.1.19-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.7-next.1
|
||||
- @backstage/backend-plugin-api@0.6.17-next.1
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
|
||||
## 0.1.19-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.7-next.0
|
||||
- @backstage/backend-plugin-api@0.6.17-next.0
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
|
||||
## 0.1.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.6
|
||||
- @backstage/backend-plugin-api@0.6.16
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
|
||||
## 0.1.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.5
|
||||
- @backstage/backend-plugin-api@0.6.15
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
|
||||
## 0.1.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4467036: Allow unauthenticated access to health check endpoint.
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.4
|
||||
- @backstage/config@1.2.0
|
||||
- @backstage/errors@1.2.4
|
||||
- @backstage/backend-plugin-api@0.6.14
|
||||
|
||||
## 0.1.16-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.4-next.2
|
||||
- @backstage/backend-plugin-api@0.6.14-next.2
|
||||
- @backstage/config@1.2.0-next.1
|
||||
- @backstage/errors@1.2.4-next.0
|
||||
|
||||
## 0.1.16-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.2.0-next.1
|
||||
- @backstage/backend-common@0.21.4-next.1
|
||||
- @backstage/backend-plugin-api@0.6.14-next.1
|
||||
- @backstage/errors@1.2.4-next.0
|
||||
|
||||
## 0.1.15-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.3-next.0
|
||||
- @backstage/errors@1.2.4-next.0
|
||||
- @backstage/backend-plugin-api@0.6.13-next.0
|
||||
- @backstage/config@1.1.2-next.0
|
||||
|
||||
## 0.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9aac2b0: Use `--cwd` as the first `yarn` argument
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.0
|
||||
- @backstage/backend-plugin-api@0.6.10
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.12-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.0-next.3
|
||||
- @backstage/backend-plugin-api@0.6.10-next.3
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.12-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9aac2b0: Use `--cwd` as the first `yarn` argument
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.0-next.2
|
||||
- @backstage/backend-plugin-api@0.6.10-next.2
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.12-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.10-next.1
|
||||
- @backstage/backend-common@0.21.0-next.1
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.12-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.21.0-next.0
|
||||
- @backstage/backend-plugin-api@0.6.10-next.0
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4016f21: Remove some unused dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.1
|
||||
- @backstage/backend-plugin-api@0.6.9
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.11-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.9-next.2
|
||||
- @backstage/backend-common@0.20.1-next.2
|
||||
|
||||
## 0.1.11-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.1-next.1
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/backend-plugin-api@0.6.9-next.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.11-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4016f21: Remove some unused dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.1-next.0
|
||||
- @backstage/backend-plugin-api@0.6.9-next.0
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.0
|
||||
- @backstage/backend-plugin-api@0.6.8
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.10-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.0-next.3
|
||||
- @backstage/backend-plugin-api@0.6.8-next.3
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.10-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.0-next.2
|
||||
- @backstage/backend-plugin-api@0.6.8-next.2
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.10-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.0-next.1
|
||||
- @backstage/backend-plugin-api@0.6.8-next.1
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.10-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.20.0-next.0
|
||||
- @backstage/backend-plugin-api@0.6.8-next.0
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.9
|
||||
- @backstage/backend-plugin-api@0.6.7
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.9-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-plugin-api@0.6.7-next.2
|
||||
- @backstage/backend-common@0.19.9-next.2
|
||||
|
||||
## 0.1.9-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.9-next.1
|
||||
- @backstage/backend-plugin-api@0.6.7-next.1
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.9-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.9-next.0
|
||||
- @backstage/backend-plugin-api@0.6.7-next.0
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/errors@1.2.3
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6822918c50: Added support for the [new backend system](https://backstage.io/docs/backend-system/)
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.8
|
||||
- @backstage/errors@1.2.3
|
||||
- @backstage/backend-plugin-api@0.6.6
|
||||
- @backstage/config@1.1.1
|
||||
|
||||
## 0.1.8-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6822918c50: Added support for the [new backend system](https://backstage.io/docs/backend-system/)
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.8-next.2
|
||||
- @backstage/errors@1.2.3-next.0
|
||||
- @backstage/backend-plugin-api@0.6.6-next.2
|
||||
- @backstage/config@1.1.1-next.0
|
||||
|
||||
## 0.1.7-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.7-next.1
|
||||
- @backstage/config@1.1.0
|
||||
- @backstage/errors@1.2.2
|
||||
|
||||
## 0.1.7-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.7-next.0
|
||||
- @backstage/config@1.1.0
|
||||
- @backstage/errors@1.2.2
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.5
|
||||
- @backstage/config@1.1.0
|
||||
- @backstage/errors@1.2.2
|
||||
|
||||
## 0.1.5-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/errors@1.2.2-next.0
|
||||
- @backstage/backend-common@0.19.5-next.3
|
||||
|
||||
## 0.1.5-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.1
|
||||
- @backstage/backend-common@0.19.5-next.2
|
||||
- @backstage/errors@1.2.1
|
||||
|
||||
## 0.1.5-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/config@1.1.0-next.0
|
||||
- @backstage/backend-common@0.19.5-next.1
|
||||
- @backstage/errors@1.2.1
|
||||
|
||||
## 0.1.4-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.4-next.0
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/errors@1.2.1
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12a8c94eda8d: Add package repository and homepage metadata
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.2
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/errors@1.2.1
|
||||
|
||||
## 0.1.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.2-next.2
|
||||
|
||||
## 0.1.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12a8c94eda8d: Add package repository and homepage metadata
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.2-next.1
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/errors@1.2.1
|
||||
|
||||
## 0.1.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.2-next.0
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/errors@1.2.1
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.1
|
||||
- @backstage/backend-common@0.19.1
|
||||
- @backstage/config@1.0.8
|
||||
|
||||
## 0.1.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/errors@1.2.1-next.0
|
||||
- @backstage/backend-common@0.19.1-next.0
|
||||
- @backstage/config@1.0.8
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 05bf04ca6863: Initialize Nomad plugin with frontend and backend. List jobs/allocations
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/backend-common@0.19.0
|
||||
- @backstage/errors@1.2.0
|
||||
- @backstage/config@1.0.8
|
||||
@@ -1,3 +0,0 @@
|
||||
# Deprecated
|
||||
|
||||
This package has been moved to the [backstage-community/plugins](https://github.com/backstage/community-plugins) repository. Migrate to using `@backstage-community/plugin-nomad-backend` instead.
|
||||
@@ -1,27 +0,0 @@
|
||||
## API Report File for "@backstage/plugin-nomad-backend"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { BackendFeature } from '@backstage/backend-plugin-api';
|
||||
import { Config } from '@backstage/config';
|
||||
import express from 'express';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
// @public (undocumented)
|
||||
export function createRouter(options: RouterOptions): Promise<express.Router>;
|
||||
|
||||
// @public
|
||||
const nomadPlugin: () => BackendFeature;
|
||||
export default nomadPlugin;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RouterOptions {
|
||||
// (undocumented)
|
||||
config: Config;
|
||||
// (undocumented)
|
||||
logger: LoggerService;
|
||||
}
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-plugin-nomad-backend
|
||||
title: '@backstage/plugin-nomad-backend'
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-backend-plugin
|
||||
owner: maintainers
|
||||
@@ -1,2 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"name": "@backstage/plugin-nomad-backend",
|
||||
"version": "0.1.19",
|
||||
"backstage": {
|
||||
"role": "backend-plugin",
|
||||
"moved": "@backstage-community/plugin-nomad-backend"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.cjs.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/nomad-backend"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"start": "backstage-cli package start",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "workspace:^",
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@types/express": "*",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@types/supertest": "^2.0.8",
|
||||
"supertest": "^6.2.4"
|
||||
},
|
||||
"deprecated": "This package has been moved to the backstage/community-plugins repository. You should migrate to using @backstage-community/plugin-nomad-backend instead."
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
export * from './service/router';
|
||||
export { nomadPlugin as default } from './plugin';
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { nomadPlugin } from './plugin';
|
||||
|
||||
describe('nomad', () => {
|
||||
it('should export the nomad plugin', () => {
|
||||
expect(nomadPlugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { createRouter } from './service/router';
|
||||
|
||||
/**
|
||||
* Nomad backend plugin
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const nomadPlugin = createBackendPlugin({
|
||||
pluginId: 'nomad',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
logger: coreServices.logger,
|
||||
config: coreServices.rootConfig,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
},
|
||||
async init({ logger, config, httpRouter }) {
|
||||
httpRouter.use(
|
||||
await createRouter({
|
||||
/**
|
||||
* Logger for logging purposes
|
||||
*/
|
||||
logger,
|
||||
config,
|
||||
}),
|
||||
);
|
||||
httpRouter.addAuthPolicy({
|
||||
path: '/health',
|
||||
allow: 'unauthenticated',
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { getRootLogger } from '@backstage/backend-common';
|
||||
import yn from 'yn';
|
||||
import { startStandaloneServer } from './service/standaloneServer';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
|
||||
const config = new ConfigReader({});
|
||||
const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 7007;
|
||||
const enableCors = yn(process.env.PLUGIN_CORS, { default: false });
|
||||
const logger = getRootLogger();
|
||||
|
||||
startStandaloneServer({ config, port, enableCors, logger }).catch(err => {
|
||||
logger.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
logger.info('CTRL+C pressed; exiting.');
|
||||
process.exit(0);
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 express from 'express';
|
||||
import request from 'supertest';
|
||||
|
||||
import { createRouter } from './router';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
|
||||
describe('createRouter', () => {
|
||||
let app: express.Express;
|
||||
|
||||
beforeAll(async () => {
|
||||
const router = await createRouter({
|
||||
config: new ConfigReader({
|
||||
nomad: {
|
||||
addr: 'http://localhost.com',
|
||||
token: 'asdf',
|
||||
},
|
||||
}),
|
||||
logger: getVoidLogger(),
|
||||
});
|
||||
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' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 fetch from 'node-fetch';
|
||||
import { errorHandler, requestLoggingHandler } from '@backstage/backend-common';
|
||||
import { Config } from '@backstage/config';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import express from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export interface RouterOptions {
|
||||
logger: LoggerService;
|
||||
config: Config;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export async function createRouter(
|
||||
options: RouterOptions,
|
||||
): Promise<express.Router> {
|
||||
const { config, logger } = options;
|
||||
|
||||
// Get Nomad addr and token from config
|
||||
const addr = config.getString('nomad.addr');
|
||||
const token = config.getOptionalString('nomad.token');
|
||||
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
|
||||
router.get('/health', (_, resp) => {
|
||||
resp.json({ status: 'ok' });
|
||||
});
|
||||
|
||||
router.get('/v1/allocations', async (req, res) => {
|
||||
// Check namespace argument
|
||||
const namespace = (req.query.namespace as string) ?? '';
|
||||
if (!namespace || namespace === '') {
|
||||
throw new InputError(`Missing "namespace" query parameter`);
|
||||
}
|
||||
|
||||
// Check filter argument
|
||||
const filter = (req.query.filter as string) ?? '';
|
||||
logger.debug(`request headers: namespace=${namespace} filter=${filter}`);
|
||||
|
||||
// Issue the request
|
||||
const endpoint = `${addr}/v1/allocations?namespace=${encodeURIComponent(
|
||||
namespace,
|
||||
)}&filter=${encodeURIComponent(filter)}`;
|
||||
const allocationsResp = await fetch(endpoint, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Nomad-Token': token || '',
|
||||
},
|
||||
});
|
||||
|
||||
// Check response
|
||||
if (allocationsResp.status !== 200) {
|
||||
const body = await allocationsResp.text();
|
||||
logger.error(`failed to call /v1/allocations endpoint: ${body}`);
|
||||
res.status(allocationsResp.status).json({ message: body });
|
||||
return;
|
||||
}
|
||||
|
||||
// Deserialize and return
|
||||
const allocationsBody = await allocationsResp.json();
|
||||
logger.debug(`/v1/allocations response: ${allocationsBody}`);
|
||||
res.json(allocationsBody);
|
||||
});
|
||||
|
||||
router.get('/v1/job/:job_id/versions', async (req, resp) => {
|
||||
// Check namespace argument
|
||||
const namespace = (req.query.namespace as string) ?? '';
|
||||
if (!namespace || namespace === '') {
|
||||
throw new InputError(`Missing "namespace" query parameter`);
|
||||
}
|
||||
|
||||
// Get job ID
|
||||
const jobID = (req.params.job_id as string) ?? '';
|
||||
|
||||
// Issue the request
|
||||
const apiResp = await fetch(
|
||||
`${addr}/v1/job/${jobID}/versions?namespace=${encodeURIComponent(
|
||||
namespace,
|
||||
)}`,
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Nomad-Token': token || '',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Check response
|
||||
if (apiResp.status !== 200) {
|
||||
const body = await apiResp.text();
|
||||
logger.error(`failed to call /v1/job/:job_id/versions endpoint: ${body}`);
|
||||
resp.status(apiResp.status).json({ message: body });
|
||||
return;
|
||||
}
|
||||
|
||||
// Deserialize and return
|
||||
const versionsBody = await apiResp.json();
|
||||
logger.debug(`/v1/job/:job_id/versions response: ${versionsBody}`);
|
||||
resp.json(versionsBody);
|
||||
});
|
||||
|
||||
router.use(requestLoggingHandler());
|
||||
router.use(errorHandler());
|
||||
return router;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { createServiceBuilder } from '@backstage/backend-common';
|
||||
import { Server } from 'http';
|
||||
import { createRouter } from './router';
|
||||
import { Config } from '@backstage/config';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
export interface ServerOptions {
|
||||
config: Config;
|
||||
enableCors: boolean;
|
||||
logger: LoggerService;
|
||||
port: number;
|
||||
}
|
||||
|
||||
export async function startStandaloneServer(
|
||||
options: ServerOptions,
|
||||
): Promise<Server> {
|
||||
const logger = options.logger.child({ service: 'nomad' });
|
||||
logger.debug('Starting application server...');
|
||||
const router = await createRouter({
|
||||
logger,
|
||||
config: options.config,
|
||||
});
|
||||
|
||||
let service = createServiceBuilder(module)
|
||||
.setPort(options.port)
|
||||
.addRouter('/nomad', router);
|
||||
if (options.enableCors) {
|
||||
service = service.enableCors({ origin: 'http://localhost:3000' });
|
||||
}
|
||||
|
||||
return await service.start().catch(err => {
|
||||
logger.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.hot?.accept();
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
export {};
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -1,525 +0,0 @@
|
||||
# @backstage/plugin-nomad
|
||||
|
||||
## 0.1.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- abfbcfc: Updated dependency `@testing-library/react` to `^15.0.0`.
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.11.3
|
||||
- @backstage/core-components@0.14.4
|
||||
- @backstage/core-plugin-api@1.9.2
|
||||
- @backstage/catalog-model@1.4.5
|
||||
|
||||
## 0.1.15-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/core-components@0.14.4-next.0
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/plugin-catalog-react@1.11.3-next.1
|
||||
|
||||
## 0.1.15-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.4-next.0
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/plugin-catalog-react@1.11.3-next.0
|
||||
|
||||
## 0.1.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c116096: Added an optional ESLint rule - no-top-level-material-ui-4-imports -in nomad plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/nomad.
|
||||
- e8f026a: Use ESM exports of react-use library
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.3
|
||||
- @backstage/plugin-catalog-react@1.11.2
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/catalog-model@1.4.5
|
||||
|
||||
## 0.1.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c116096: Added an optional ESLint rule - no-top-level-material-ui-4-imports -in nomad plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/nomad.
|
||||
- e8f026a: Use ESM exports of react-use library
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.2
|
||||
- @backstage/plugin-catalog-react@1.11.1
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
- @backstage/catalog-model@1.4.5
|
||||
|
||||
## 0.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1
|
||||
- @backstage/plugin-catalog-react@1.11.0
|
||||
- @backstage/catalog-model@1.4.5
|
||||
- @backstage/core-plugin-api@1.9.1
|
||||
|
||||
## 0.1.12-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1-next.2
|
||||
- @backstage/plugin-catalog-react@1.11.0-next.2
|
||||
- @backstage/catalog-model@1.4.5-next.0
|
||||
- @backstage/core-plugin-api@1.9.1-next.1
|
||||
|
||||
## 0.1.12-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1-next.1
|
||||
- @backstage/plugin-catalog-react@1.10.1-next.1
|
||||
- @backstage/core-plugin-api@1.9.1-next.1
|
||||
- @backstage/catalog-model@1.4.5-next.0
|
||||
|
||||
## 0.1.12-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.1-next.0
|
||||
- @backstage/plugin-catalog-react@1.10.1-next.0
|
||||
- @backstage/catalog-model@1.4.5-next.0
|
||||
- @backstage/core-plugin-api@1.9.1-next.0
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9aac2b0: Use `--cwd` as the first `yarn` argument
|
||||
- 8fe56a8: Widen `@types/react` dependency range to include version 18.
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.10.0
|
||||
- @backstage/core-components@0.14.0
|
||||
- @backstage/catalog-model@1.4.4
|
||||
- @backstage/core-plugin-api@1.9.0
|
||||
|
||||
## 0.1.11-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.0-next.2
|
||||
- @backstage/plugin-catalog-react@1.10.0-next.3
|
||||
- @backstage/catalog-model@1.4.4-next.0
|
||||
- @backstage/core-plugin-api@1.9.0-next.1
|
||||
|
||||
## 0.1.11-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9aac2b0: Use `--cwd` as the first `yarn` argument
|
||||
- 8fe56a8: Widen `@types/react` dependency range to include version 18.
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.0-next.1
|
||||
- @backstage/core-plugin-api@1.9.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.10.0-next.2
|
||||
- @backstage/catalog-model@1.4.4-next.0
|
||||
|
||||
## 0.1.11-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.14.0-next.0
|
||||
- @backstage/catalog-model@1.4.4-next.0
|
||||
- @backstage/core-plugin-api@1.8.3-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.4-next.1
|
||||
|
||||
## 0.1.11-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.9.4-next.0
|
||||
- @backstage/core-components@0.13.10
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-plugin-api@1.8.2
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4016f21: Remove some unused dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.10
|
||||
- @backstage/core-plugin-api@1.8.2
|
||||
- @backstage/plugin-catalog-react@1.9.3
|
||||
- @backstage/catalog-model@1.4.3
|
||||
|
||||
## 0.1.10-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.2
|
||||
|
||||
## 0.1.10-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.2-next.0
|
||||
- @backstage/core-components@0.13.10-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
|
||||
## 0.1.10-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4016f21: Remove some unused dependencies
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.10-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.3-next.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/core-plugin-api@1.8.1
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.1
|
||||
- @backstage/plugin-catalog-react@1.9.2
|
||||
- @backstage/core-components@0.13.9
|
||||
- @backstage/theme@0.5.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
|
||||
## 0.1.9-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.9-next.3
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/core-plugin-api@1.8.1-next.1
|
||||
- @backstage/theme@0.5.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.3
|
||||
|
||||
## 0.1.9-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.5.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.2
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/core-components@0.13.9-next.2
|
||||
- @backstage/core-plugin-api@1.8.1-next.1
|
||||
|
||||
## 0.1.9-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.9-next.1
|
||||
- @backstage/core-plugin-api@1.8.1-next.1
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/theme@0.5.0-next.0
|
||||
|
||||
## 0.1.9-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.8.1-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.2-next.0
|
||||
- @backstage/core-components@0.13.9-next.0
|
||||
- @backstage/theme@0.5.0-next.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c2b872153: Add official support for React 18.
|
||||
- 4aa43f62aa: Updated dependency `cross-fetch` to `^4.0.0`.
|
||||
- fdb5e23602: Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.9.0
|
||||
- @backstage/core-components@0.13.8
|
||||
- @backstage/core-plugin-api@1.8.0
|
||||
- @backstage/theme@0.4.4
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
|
||||
## 0.1.7-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#20842](https://github.com/backstage/backstage/pull/20842) [`fdb5e23602`](https://github.com/backstage/backstage/commit/fdb5e2360299c5faa30f4d4236fc548b94d37446) Thanks [@benjdlambert](https://github.com/benjdlambert)! - Import `MissingAnnotationEmptyState` from `@backstage/plugin-catalog-react` to remove the cyclical dependency
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.8-next.2
|
||||
- @backstage/plugin-catalog-react@1.9.0-next.2
|
||||
|
||||
## 0.1.7-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.9.0-next.1
|
||||
- @backstage/core-components@0.13.8-next.1
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
- @backstage/core-plugin-api@1.8.0-next.0
|
||||
- @backstage/theme@0.4.4-next.0
|
||||
|
||||
## 0.1.7-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6c2b872153: Add official support for React 18.
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.7-next.0
|
||||
- @backstage/plugin-catalog-react@1.9.0-next.0
|
||||
- @backstage/core-plugin-api@1.8.0-next.0
|
||||
- @backstage/theme@0.4.4-next.0
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/config@1.1.1
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`.
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.5
|
||||
- @backstage/core-plugin-api@1.7.0
|
||||
- @backstage/core-components@0.13.6
|
||||
- @backstage/catalog-model@1.4.3
|
||||
- @backstage/theme@0.4.3
|
||||
- @backstage/config@1.1.1
|
||||
|
||||
## 0.1.6-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.6-next.2
|
||||
- @backstage/core-plugin-api@1.7.0-next.1
|
||||
- @backstage/catalog-model@1.4.3-next.0
|
||||
- @backstage/plugin-catalog-react@1.8.5-next.2
|
||||
- @backstage/theme@0.4.3-next.0
|
||||
- @backstage/config@1.1.1-next.0
|
||||
|
||||
## 0.1.6-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.6-next.1
|
||||
- @backstage/plugin-catalog-react@1.8.5-next.1
|
||||
- @backstage/core-plugin-api@1.7.0-next.0
|
||||
- @backstage/config@1.1.0
|
||||
- @backstage/catalog-model@1.4.2
|
||||
- @backstage/theme@0.4.2
|
||||
|
||||
## 0.1.6-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.5-next.0
|
||||
- @backstage/core-plugin-api@1.7.0-next.0
|
||||
- @backstage/core-components@0.13.6-next.0
|
||||
- @backstage/config@1.1.0
|
||||
- @backstage/catalog-model@1.4.2
|
||||
- @backstage/theme@0.4.2
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 482bb5c0bbf8: Moved `@types/react` to be a regular dependency
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- 8cec7664e146: Removed `@types/node` dependency
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.4
|
||||
- @backstage/core-components@0.13.5
|
||||
- @backstage/config@1.1.0
|
||||
- @backstage/catalog-model@1.4.2
|
||||
- @backstage/core-plugin-api@1.6.0
|
||||
- @backstage/theme@0.4.2
|
||||
|
||||
## 0.1.5-next.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 406b786a2a2c: Mark package as being free of side effects, allowing more optimized Webpack builds.
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.4.2-next.2
|
||||
- @backstage/config@1.1.0-next.2
|
||||
- @backstage/core-components@0.13.5-next.3
|
||||
- @backstage/core-plugin-api@1.6.0-next.3
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.3
|
||||
- @backstage/theme@0.4.2-next.0
|
||||
|
||||
## 0.1.5-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8cec7664e146: Removed `@types/node` dependency
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.5-next.2
|
||||
- @backstage/core-plugin-api@1.6.0-next.2
|
||||
- @backstage/config@1.1.0-next.1
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.2
|
||||
- @backstage/catalog-model@1.4.2-next.1
|
||||
- @backstage/theme@0.4.1
|
||||
|
||||
## 0.1.5-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.4-next.1
|
||||
- @backstage/core-components@0.13.5-next.1
|
||||
- @backstage/config@1.1.0-next.0
|
||||
- @backstage/catalog-model@1.4.2-next.0
|
||||
- @backstage/core-plugin-api@1.6.0-next.1
|
||||
- @backstage/theme@0.4.1
|
||||
|
||||
## 0.1.4-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 482bb5c0bbf8: Moved `@types/react` to be a regular dependency
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.6.0-next.0
|
||||
- @backstage/core-components@0.13.5-next.0
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-catalog-react@1.8.3-next.0
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12a8c94eda8d: Add package repository and homepage metadata
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.4
|
||||
- @backstage/plugin-catalog-react@1.8.1
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/theme@0.4.1
|
||||
|
||||
## 0.1.2-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.1-next.1
|
||||
|
||||
## 0.1.2-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 12a8c94eda8d: Add package repository and homepage metadata
|
||||
- Updated dependencies
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/core-components@0.13.4-next.0
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-catalog-react@1.8.1-next.0
|
||||
|
||||
## 0.1.2-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.4-next.0
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/plugin-catalog-react@1.8.1-next.0
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/theme@0.4.1
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 68531cc70e1f: Break some internal circular import chains
|
||||
- e6f50426333b: update some peer dependencies to silence yarn install
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.4.1
|
||||
- @backstage/plugin-catalog-react@1.8.0
|
||||
- @backstage/core-components@0.13.3
|
||||
- @backstage/core-plugin-api@1.5.3
|
||||
- @backstage/catalog-model@1.4.1
|
||||
- @backstage/config@1.0.8
|
||||
|
||||
## 0.1.1-next.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/plugin-catalog-react@1.8.0-next.2
|
||||
- @backstage/theme@0.4.1-next.1
|
||||
- @backstage/core-plugin-api@1.5.3-next.1
|
||||
- @backstage/core-components@0.13.3-next.2
|
||||
- @backstage/catalog-model@1.4.1-next.0
|
||||
- @backstage/config@1.0.8
|
||||
|
||||
## 0.1.1-next.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/theme@0.4.1-next.0
|
||||
- @backstage/core-components@0.13.3-next.1
|
||||
- @backstage/core-plugin-api@1.5.3-next.0
|
||||
- @backstage/plugin-catalog-react@1.7.1-next.1
|
||||
- @backstage/config@1.0.8
|
||||
|
||||
## 0.1.1-next.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 68531cc70e1f: Break some internal circular import chains
|
||||
- Updated dependencies
|
||||
- @backstage/core-components@0.13.3-next.0
|
||||
- @backstage/catalog-model@1.4.1-next.0
|
||||
- @backstage/config@1.0.8
|
||||
- @backstage/core-plugin-api@1.5.2
|
||||
- @backstage/theme@0.4.0
|
||||
- @backstage/plugin-catalog-react@1.7.1-next.0
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 05bf04ca6863: Initialize Nomad plugin with frontend and backend. List jobs/allocations
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @backstage/core-plugin-api@1.5.2
|
||||
- @backstage/core-components@0.13.2
|
||||
- @backstage/theme@0.4.0
|
||||
- @backstage/plugin-catalog-react@1.7.0
|
||||
- @backstage/catalog-model@1.4.0
|
||||
- @backstage/config@1.0.8
|
||||
@@ -1,3 +0,0 @@
|
||||
# Deprecated
|
||||
|
||||
This package has been moved to the [backstage-community/plugins](https://github.com/backstage/community-plugins) repository. Migrate to using `@backstage-community/plugin-nomad` instead.
|
||||
@@ -1,35 +0,0 @@
|
||||
## API Report File for "@backstage/plugin-nomad"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
/// <reference types="react" />
|
||||
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
// @public
|
||||
export const EntityNomadAllocationListTable: () => JSX_2.Element;
|
||||
|
||||
// @public
|
||||
export const EntityNomadJobVersionListCard: () => JSX_2.Element | null;
|
||||
|
||||
// @public (undocumented)
|
||||
export const isNomadAllocationsAvailable: (entity: Entity) => boolean;
|
||||
|
||||
// @public (undocumented)
|
||||
export const isNomadJobIDAvailable: (entity: Entity) => boolean;
|
||||
|
||||
// @public (undocumented)
|
||||
export const nomadPlugin: BackstagePlugin<
|
||||
{
|
||||
root: RouteRef<undefined>;
|
||||
entityContent: RouteRef<undefined>;
|
||||
},
|
||||
{}
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-plugin-nomad
|
||||
title: '@backstage/plugin-nomad'
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-frontend-plugin
|
||||
owner: maintainers
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { createDevApp } from '@backstage/dev-utils';
|
||||
import { nomadPlugin } from '../src/plugin';
|
||||
|
||||
createDevApp().registerPlugin(nomadPlugin).render();
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 117 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 52 KiB |
@@ -1,8 +0,0 @@
|
||||
# Knip report
|
||||
|
||||
## Unused devDependencies (1)
|
||||
|
||||
| Name | Location | Severity |
|
||||
| :--------------------- | :----------- | :------- |
|
||||
| @testing-library/react | package.json | error |
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
{
|
||||
"name": "@backstage/plugin-nomad",
|
||||
"version": "0.1.15",
|
||||
"backstage": {
|
||||
"role": "frontend-plugin",
|
||||
"moved": "@backstage-community/plugin-nomad"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/nomad"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"start": "backstage-cli package start",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"luxon": "^3.3.0",
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/dev-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^15.0.0",
|
||||
"cross-fetch": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
||||
},
|
||||
"configSchema": {
|
||||
"$schema": "https://backstage.io/schema/config-v1",
|
||||
"title": "@backstage/plugin-nomad",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nomad": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"addr": {
|
||||
"type": "string",
|
||||
"description": "The address of the Nomad API. See: https://developer.hashicorp.com/nomad/api-docs#addressing-and-ports",
|
||||
"visibility": "frontend"
|
||||
},
|
||||
"token": {
|
||||
"type": "string",
|
||||
"description": "The token to call the Nomad API with. See: https://developer.hashicorp.com/nomad/api-docs#authentication",
|
||||
"visibility": "secret"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"addr"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"deprecated": "This package has been moved to the backstage/community-plugins repository. You should migrate to using @backstage-community/plugin-nomad instead."
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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 React from 'react';
|
||||
import {
|
||||
useEntity,
|
||||
MissingAnnotationEmptyState,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import { EntityNomadAllocationListTable } from './components/EntityNomadAllocationListTable/EntityNomadAllocationListTable';
|
||||
import {
|
||||
NOMAD_GROUP_ANNOTATION,
|
||||
NOMAD_JOB_ID_ANNOTATION,
|
||||
isNomadAllocationsAvailable,
|
||||
} from './annotations';
|
||||
|
||||
export const EmbeddedRouter = () => {
|
||||
const { entity } = useEntity();
|
||||
|
||||
if (!isNomadAllocationsAvailable(entity)) {
|
||||
return (
|
||||
<MissingAnnotationEmptyState
|
||||
annotation={[NOMAD_JOB_ID_ANNOTATION, NOMAD_GROUP_ANNOTATION]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<EntityNomadAllocationListTable />} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 { Entity } from '@backstage/catalog-model';
|
||||
|
||||
/** @public */
|
||||
export const NOMAD_NAMESPACE_ANNOTATION = 'nomad.io/namespace';
|
||||
|
||||
/** @public */
|
||||
export const NOMAD_JOB_ID_ANNOTATION = 'nomad.io/job-id';
|
||||
|
||||
/** @public */
|
||||
export const NOMAD_GROUP_ANNOTATION = 'nomad.io/group';
|
||||
|
||||
/** @public */
|
||||
export const isNomadJobIDAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[NOMAD_JOB_ID_ANNOTATION]);
|
||||
|
||||
/** @public */
|
||||
export const isNomadAllocationsAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[NOMAD_JOB_ID_ANNOTATION]) ||
|
||||
Boolean(entity.metadata.annotations?.[NOMAD_GROUP_ANNOTATION]);
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* 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 {
|
||||
DiscoveryApi,
|
||||
FetchApi,
|
||||
createApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export const nomadApiRef = createApiRef<NomadApi>({
|
||||
id: 'plugin.nomad.service',
|
||||
});
|
||||
|
||||
/** @public */
|
||||
export type NomadApi = {
|
||||
/**
|
||||
* listAllocations is for listing all allocations matching some part of 'filter'.
|
||||
*
|
||||
* See: https://developer.hashicorp.com/nomad/api-docs/allocations#list-allocations
|
||||
*/
|
||||
listAllocations: (
|
||||
options: ListAllocationsRequest,
|
||||
) => Promise<ListAllocationsResponse>;
|
||||
|
||||
/**
|
||||
* listJobVersions is for listing all deployments matching some part of 'filter'.
|
||||
*
|
||||
* See: https://developer.hashicorp.com/nomad/api-docs/deployments#list-deployments
|
||||
*/
|
||||
listJobVersions: (
|
||||
options: ListJobVersionsRequest,
|
||||
) => Promise<ListJobVersionsResponse>;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export interface ListAllocationsRequest {
|
||||
namespace: string;
|
||||
filter: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface ListAllocationsResponse {
|
||||
allocations: Allocation[];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface Allocation {
|
||||
ClientStatus: string;
|
||||
CreateTime: number;
|
||||
DeploymentStatus: DeploymentStatus;
|
||||
ID: string;
|
||||
JobID: string;
|
||||
JobVersion: string;
|
||||
ModifyTime: number;
|
||||
Name: string;
|
||||
Namespace: string;
|
||||
NodeID: string;
|
||||
TaskGroup: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface DeploymentStatus {
|
||||
Healthy: boolean;
|
||||
Timestamp: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface ListJobVersionsRequest {
|
||||
namespace: string;
|
||||
jobID: string;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface ListJobVersionsResponse {
|
||||
versions: Version[];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface Version {
|
||||
ID: string;
|
||||
SubmitTime: number;
|
||||
Stable: boolean;
|
||||
Version: number;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export class FetchError extends Error {
|
||||
get name(): string {
|
||||
return this.constructor.name;
|
||||
}
|
||||
|
||||
static async forResponse(resp: Response): Promise<FetchError> {
|
||||
return new FetchError(
|
||||
`Request failed with status code ${
|
||||
resp.status
|
||||
}.\nReason: ${await resp.text()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export class NomadHttpApi implements NomadApi {
|
||||
static create(discoveryApi: DiscoveryApi, fetchApi: FetchApi) {
|
||||
return new NomadHttpApi(discoveryApi, fetchApi);
|
||||
}
|
||||
|
||||
constructor(private discoveryApi: DiscoveryApi, private fetchApi: FetchApi) {}
|
||||
|
||||
// TODO: pagination
|
||||
async listAllocations(
|
||||
options: ListAllocationsRequest,
|
||||
): Promise<ListAllocationsResponse> {
|
||||
const apiUrl = await this.discoveryApi.getBaseUrl('nomad');
|
||||
|
||||
const resp = await this.fetchApi.fetch(
|
||||
`${apiUrl}/v1/allocations?namespace=${encodeURIComponent(
|
||||
options.namespace,
|
||||
)}&filter=${encodeURIComponent(options.filter)}`,
|
||||
);
|
||||
if (!resp.ok) throw await FetchError.forResponse(resp);
|
||||
|
||||
return {
|
||||
allocations: await resp.json(),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: pagination
|
||||
async listJobVersions(
|
||||
options: ListJobVersionsRequest,
|
||||
): Promise<ListJobVersionsResponse> {
|
||||
const apiUrl = await this.discoveryApi.getBaseUrl('nomad');
|
||||
|
||||
const resp = await this.fetchApi.fetch(
|
||||
`${apiUrl}/v1/job/${
|
||||
options.jobID
|
||||
}/versions?namespace=${encodeURIComponent(options.namespace)}`,
|
||||
);
|
||||
if (!resp.ok) throw await FetchError.forResponse(resp);
|
||||
|
||||
const respJson = await resp.json();
|
||||
|
||||
return {
|
||||
versions: respJson.Versions,
|
||||
};
|
||||
}
|
||||
}
|
||||
-203
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* 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 { DateTime } from 'luxon';
|
||||
import {
|
||||
Link,
|
||||
ResponseErrorPanel,
|
||||
StatusError,
|
||||
StatusOK,
|
||||
StatusPending,
|
||||
StatusRunning,
|
||||
Table,
|
||||
TableColumn,
|
||||
} from '@backstage/core-components';
|
||||
import {
|
||||
useEntity,
|
||||
MissingAnnotationEmptyState,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import React, { useState } from 'react';
|
||||
import { Allocation, nomadApiRef } from '../../api';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
NOMAD_GROUP_ANNOTATION,
|
||||
NOMAD_JOB_ID_ANNOTATION,
|
||||
NOMAD_NAMESPACE_ANNOTATION,
|
||||
isNomadAllocationsAvailable,
|
||||
} from '../../annotations';
|
||||
import useAsync from 'react-use/esm/useAsync';
|
||||
|
||||
type rowType = Allocation & { nomadAddr: string };
|
||||
|
||||
const columns: TableColumn<rowType>[] = [
|
||||
{
|
||||
title: 'ID',
|
||||
field: 'ID',
|
||||
render: row => (
|
||||
<Link to={`${row.nomadAddr}/ui/allocations/${row.ID}`} underline="always">
|
||||
{row.ID.split('-')[0]}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Task Group',
|
||||
field: 'TaskGroup',
|
||||
render: row => (
|
||||
<Link
|
||||
to={`${row.nomadAddr}/ui/jobs/${row.JobID}/${row.TaskGroup}`}
|
||||
underline="always"
|
||||
>
|
||||
{row.TaskGroup}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Created',
|
||||
field: 'CreateTime',
|
||||
render: row =>
|
||||
DateTime.fromMillis(row.CreateTime / 1000000).toLocaleString(
|
||||
DateTime.DATETIME_MED_WITH_SECONDS,
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Status',
|
||||
field: 'ClientStatus',
|
||||
render: row =>
|
||||
({
|
||||
pending: <StatusPending>pending</StatusPending>,
|
||||
running: <StatusOK>running</StatusOK>,
|
||||
failed: <StatusError>failed</StatusError>,
|
||||
complete: <StatusRunning>complete</StatusRunning>,
|
||||
}[row.ClientStatus] || <text>{row.ClientStatus}</text>),
|
||||
},
|
||||
{
|
||||
title: 'Version',
|
||||
field: 'JobVersion',
|
||||
render: row => row.JobVersion,
|
||||
},
|
||||
{
|
||||
title: 'Client',
|
||||
field: 'NodeID',
|
||||
render: row => (
|
||||
<Link to={`${row.nomadAddr}/ui/clients/${row.NodeID}`} underline="always">
|
||||
{row.ID.split('-')[0]}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* EntityNomadAllocationListTable is roughly based off Nomad's Allocations tab's view.
|
||||
*/
|
||||
export const EntityNomadAllocationListTable = () => {
|
||||
// Wait on entity
|
||||
const { entity } = useEntity();
|
||||
|
||||
// Get ref to the backend API
|
||||
const [init, setInit] = useState(true);
|
||||
const configApi = useApi(configApiRef);
|
||||
const nomadApi = useApi(nomadApiRef);
|
||||
const nomadAddr = configApi.getString('nomad.addr');
|
||||
|
||||
// Store results of calling API
|
||||
const [allocations, setAllocations] = useState<rowType[]>([]);
|
||||
const [err, setErr] = useState<Error>();
|
||||
|
||||
// Check that attributes are available
|
||||
if (!isNomadAllocationsAvailable(entity)) {
|
||||
<MissingAnnotationEmptyState
|
||||
annotation={[NOMAD_JOB_ID_ANNOTATION, NOMAD_GROUP_ANNOTATION]}
|
||||
/>;
|
||||
}
|
||||
|
||||
// Get plugin attributes
|
||||
const namespace =
|
||||
entity.metadata.annotations?.[NOMAD_NAMESPACE_ANNOTATION] ?? 'default';
|
||||
const job = entity.metadata.annotations?.[NOMAD_JOB_ID_ANNOTATION] ?? '';
|
||||
const group = entity.metadata.annotations?.[NOMAD_GROUP_ANNOTATION] ?? '';
|
||||
|
||||
// Make filter from attributes
|
||||
const filter: string[] = [];
|
||||
if (job) {
|
||||
filter.push(`(JobID == "${job}")`);
|
||||
}
|
||||
if (group) {
|
||||
filter.push(`(TaskGroup matches "${group}")`);
|
||||
}
|
||||
|
||||
// Create a query to update allocations
|
||||
const query = async () => {
|
||||
try {
|
||||
// Make call to nomad-backend
|
||||
const resp = await nomadApi.listAllocations({
|
||||
namespace,
|
||||
filter: filter.join(' and '),
|
||||
});
|
||||
|
||||
// Sort results
|
||||
const results = resp.allocations
|
||||
.sort((a, b) => a.CreateTime - b.CreateTime)
|
||||
.sort(({ ClientStatus: a }, { ClientStatus: b }) => {
|
||||
if (a === 'running' || b !== 'running') {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
setAllocations(results.map(row => ({ ...row, id: row.ID, nomadAddr })));
|
||||
setErr(undefined);
|
||||
} catch (e) {
|
||||
setAllocations([]);
|
||||
setErr(e);
|
||||
}
|
||||
};
|
||||
|
||||
// Start querying for allocations every 5s
|
||||
useAsync(async () => {
|
||||
if (init) {
|
||||
setInit(false);
|
||||
query();
|
||||
}
|
||||
|
||||
const interval = setTimeout(() => {
|
||||
query();
|
||||
}, 5_000);
|
||||
|
||||
return () => clearTimeout(interval);
|
||||
}, [allocations, entity]);
|
||||
|
||||
// Store a ref to a potential error
|
||||
if (err) {
|
||||
return <ResponseErrorPanel error={err} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Table<rowType>
|
||||
title="Allocations"
|
||||
options={{
|
||||
search: true,
|
||||
padding: 'dense',
|
||||
sorting: true,
|
||||
draggable: false,
|
||||
paging: false,
|
||||
debounceInterval: 500,
|
||||
filterCellStyle: { padding: '0 16px 0 20px' },
|
||||
}}
|
||||
columns={columns}
|
||||
data={allocations}
|
||||
/>
|
||||
);
|
||||
};
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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 { DateTime } from 'luxon';
|
||||
import {
|
||||
InfoCard,
|
||||
ResponseErrorPanel,
|
||||
Table,
|
||||
TableColumn,
|
||||
} from '@backstage/core-components';
|
||||
import {
|
||||
useEntity,
|
||||
MissingAnnotationEmptyState,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Version, nomadApiRef } from '../../api';
|
||||
import { configApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
NOMAD_JOB_ID_ANNOTATION,
|
||||
NOMAD_NAMESPACE_ANNOTATION,
|
||||
isNomadJobIDAvailable,
|
||||
} from '../../annotations';
|
||||
import OpenInNewIcon from '@material-ui/icons/OpenInNew';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
|
||||
type rowType = Version & { nomadAddr: string };
|
||||
|
||||
const columns: TableColumn<rowType>[] = [
|
||||
{
|
||||
title: 'Version',
|
||||
field: 'Version',
|
||||
render: row => row.Version,
|
||||
},
|
||||
{
|
||||
title: 'Stable',
|
||||
field: 'Stable',
|
||||
render: row => <Chip label={`${row.Stable}`} />,
|
||||
},
|
||||
{
|
||||
title: 'Submitted',
|
||||
field: 'SubmitTime',
|
||||
render: row =>
|
||||
DateTime.fromMillis(row.SubmitTime / 1000000).toLocaleString(
|
||||
DateTime.DATETIME_MED_WITH_SECONDS,
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* EntityNomadJobVersionListCard is roughly based on the Nomad UI's versions tab.
|
||||
*/
|
||||
export const EntityNomadJobVersionListCard = () => {
|
||||
// Wait on entity
|
||||
const { entity } = useEntity();
|
||||
|
||||
// Get ref to the backend API
|
||||
const configApi = useApi(configApiRef);
|
||||
const nomadApi = useApi(nomadApiRef);
|
||||
const nomadAddr = configApi.getString('nomad.addr');
|
||||
|
||||
// Store results of calling API
|
||||
const [init, setInit] = useState(true);
|
||||
const [versions, setVersions] = useState<rowType[]>([]);
|
||||
const [err, setErr] = useState<Error>();
|
||||
|
||||
// Get plugin attributes
|
||||
const namespace =
|
||||
entity.metadata.annotations?.[NOMAD_NAMESPACE_ANNOTATION] ?? 'default';
|
||||
const jobID = entity.metadata.annotations?.[NOMAD_JOB_ID_ANNOTATION] ?? '';
|
||||
|
||||
// Start querying for allocations every 10s
|
||||
useEffect(() => {
|
||||
// Create a query to update allocations
|
||||
const query = async () => {
|
||||
try {
|
||||
// Make call to nomad-backend
|
||||
const resp = await nomadApi.listJobVersions({ namespace, jobID });
|
||||
|
||||
setVersions(
|
||||
resp.versions.map(row => ({ ...row, id: row.ID, nomadAddr })),
|
||||
);
|
||||
setErr(undefined);
|
||||
} catch (e) {
|
||||
setVersions([]);
|
||||
setErr(e);
|
||||
}
|
||||
};
|
||||
|
||||
if (init) {
|
||||
setInit(false);
|
||||
query();
|
||||
}
|
||||
|
||||
const interval = setTimeout(() => {
|
||||
query();
|
||||
}, 10_000);
|
||||
|
||||
return () => clearTimeout(interval);
|
||||
}, [init, jobID, namespace, nomadAddr, nomadApi]);
|
||||
|
||||
// Store a ref to a potential error
|
||||
if (err) {
|
||||
return <ResponseErrorPanel error={err} />;
|
||||
}
|
||||
|
||||
if (!entity) return null;
|
||||
|
||||
// Check that job ID is set
|
||||
if (!isNomadJobIDAvailable(entity)) {
|
||||
return (
|
||||
<InfoCard title="Job Versions">
|
||||
<MissingAnnotationEmptyState annotation={NOMAD_JOB_ID_ANNOTATION} />
|
||||
</InfoCard>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Table<rowType>
|
||||
title="Job versions"
|
||||
actions={[
|
||||
{
|
||||
icon: () => <OpenInNewIcon />,
|
||||
tooltip: 'Open in Nomad UI',
|
||||
isFreeAction: true,
|
||||
onClick: () => window.open(`${nomadAddr}/ui/jobs/${jobID}/versions`),
|
||||
},
|
||||
]}
|
||||
options={{
|
||||
search: false,
|
||||
padding: 'dense',
|
||||
sorting: true,
|
||||
draggable: false,
|
||||
paging: false,
|
||||
debounceInterval: 500,
|
||||
filterCellStyle: { padding: '0 16px 0 20px' },
|
||||
}}
|
||||
columns={columns}
|
||||
data={versions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
|
||||
export { EntityNomadJobVersionListCard } from './EntityNomadJobVersionListCard/EntityNomadJobVersionListCard';
|
||||
export { EntityNomadAllocationListTable } from './EntityNomadAllocationListTable/EntityNomadAllocationListTable';
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
*/
|
||||
export {
|
||||
nomadPlugin,
|
||||
EntityNomadJobVersionListCard,
|
||||
EntityNomadAllocationListTable,
|
||||
} from './plugin';
|
||||
export {
|
||||
isNomadAllocationsAvailable,
|
||||
isNomadJobIDAvailable,
|
||||
} from './annotations';
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 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 {
|
||||
nomadPlugin,
|
||||
entityContentRouteRef,
|
||||
EntityNomadContent,
|
||||
} from './plugin';
|
||||
|
||||
describe('nomad', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(nomadPlugin).toBeDefined();
|
||||
});
|
||||
|
||||
it('should export Nomad entity ref', () => {
|
||||
expect(entityContentRouteRef).toBeDefined();
|
||||
});
|
||||
|
||||
it('should export Nomad entity', () => {
|
||||
expect(EntityNomadContent).toBeDefined();
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user