From 76d08989f024fba08a0d5e9aa217c172ef64ac8f Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Thu, 11 Jul 2019 07:32:07 -0400 Subject: [PATCH 1/6] provisioning: escape literal '$' with '$$' to avoid interpolation (#18045) fixes #17986 --- docs/sources/administration/provisioning.md | 2 ++ pkg/services/provisioning/values/values.go | 9 ++++++- .../provisioning/values/values_test.go | 25 +++++++++++++++++-- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index 1299b757752..15080b1ebab 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -45,6 +45,8 @@ datasources: password: $PASSWORD ``` +If you have a literal `$` in your value and want to avoid interpolation, `$$` can be used. +
## Configuration Management Tools diff --git a/pkg/services/provisioning/values/values.go b/pkg/services/provisioning/values/values.go index 63da76a9338..de86085671e 100644 --- a/pkg/services/provisioning/values/values.go +++ b/pkg/services/provisioning/values/values.go @@ -14,6 +14,7 @@ import ( "os" "reflect" "strconv" + "strings" "github.com/grafana/grafana/pkg/util/errutil" ) @@ -185,8 +186,14 @@ func transformMap(i map[interface{}]interface{}) interface{} { // interpolateValue returns final value after interpolation. At the moment only env var interpolation is done // here but in the future something like interpolation from file could be also done here. +// For a literal '$', '$$' can be used to avoid interpolation. func interpolateValue(val string) string { - return os.ExpandEnv(val) + parts := strings.Split(val, "$$") + interpolated := make([]string, len(parts)) + for i, v := range parts { + interpolated[i] = os.ExpandEnv(v) + } + return strings.Join(interpolated, "$") } type interpolated struct { diff --git a/pkg/services/provisioning/values/values_test.go b/pkg/services/provisioning/values/values_test.go index 284069be395..064dee86d6a 100644 --- a/pkg/services/provisioning/values/values_test.go +++ b/pkg/services/provisioning/values/values_test.go @@ -1,16 +1,18 @@ package values import ( - . "github.com/smartystreets/goconvey/convey" - "gopkg.in/yaml.v2" "os" "testing" + + . "github.com/smartystreets/goconvey/convey" + "gopkg.in/yaml.v2" ) func TestValues(t *testing.T) { Convey("Values", t, func() { os.Setenv("INT", "1") os.Setenv("STRING", "test") + os.Setenv("EMPTYSTRING", "") os.Setenv("BOOL", "true") Convey("IntValue", func() { @@ -61,6 +63,24 @@ func TestValues(t *testing.T) { So(d.Val.Value(), ShouldEqual, "") So(d.Val.Raw, ShouldEqual, "") }) + + Convey("empty var should have empty value", func() { + unmarshalingTest(`val: $EMPTYSTRING`, d) + So(d.Val.Value(), ShouldEqual, "") + So(d.Val.Raw, ShouldEqual, "$EMPTYSTRING") + }) + + Convey("$$ should be a literal $", func() { + unmarshalingTest(`val: $$`, d) + So(d.Val.Value(), ShouldEqual, "$") + So(d.Val.Raw, ShouldEqual, "$$") + }) + + Convey("$$ should be a literal $ and not expanded within a string", func() { + unmarshalingTest(`val: mY,Passwo$$rd`, d) + So(d.Val.Value(), ShouldEqual, "mY,Passwo$rd") + So(d.Val.Raw, ShouldEqual, "mY,Passwo$$rd") + }) }) Convey("BoolValue", func() { @@ -199,6 +219,7 @@ func TestValues(t *testing.T) { Reset(func() { os.Unsetenv("INT") os.Unsetenv("STRING") + os.Unsetenv("EMPTYSTRING") os.Unsetenv("BOOL") }) }) From 6aa58182c7886af1a5c5808449b39e5b12d371d3 Mon Sep 17 00:00:00 2001 From: Sofia Papagiannaki Date: Thu, 11 Jul 2019 16:13:23 +0300 Subject: [PATCH 2/6] Add missing pull requests to Changelog (#18061) --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f3a94e6628..4ca83dfa24a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,10 @@ * **AzureMonitor**: change clashing built-in Grafana variables/macro names for Azure Logs. [#17140](https://github.com/grafana/grafana/pull/17140), [@shavonn](https://github.com/shavonn) * **CloudWatch**: Made region visible for AWS Cloudwatch Expressions. [#17243](https://github.com/grafana/grafana/pull/17243), [@utkarshcmu](https://github.com/utkarshcmu) * **Cloudwatch**: Add AWS DocDB metrics. [#17241](https://github.com/grafana/grafana/pull/17241), [@utkarshcmu](https://github.com/utkarshcmu) +* **Dashboard**: Use timezone dashboard setting when exporting to CSV. [#18002](https://github.com/grafana/grafana/pull/18002), [@dehrax](https://github.com/dehrax) * **Data links**. [#17267](https://github.com/grafana/grafana/pull/17267), [@torkelo](https://github.com/torkelo) * **Docker**: Switch base image to ubuntu:latest from debian:stretch to avoid security issues.. [#17066](https://github.com/grafana/grafana/pull/17066), [@bergquist](https://github.com/bergquist) +* **Elasticsearch**: Support for visualizing logs in Explore . [#17605](https://github.com/grafana/grafana/pull/17605), [@marefr](https://github.com/marefr) * **Explore**: Adds Live option for supported datasources. [#17062](https://github.com/grafana/grafana/pull/17062), [@hugohaggmark](https://github.com/hugohaggmark) * **Explore**: Adds orgId to URL for sharing purposes. [#17895](https://github.com/grafana/grafana/pull/17895), [@kaydelaney](https://github.com/kaydelaney) * **Explore**: Adds support for new loki 'start' and 'end' params for labels endpoint. [#17512](https://github.com/grafana/grafana/pull/17512), [@kaydelaney](https://github.com/kaydelaney) @@ -27,12 +29,16 @@ * **Explore**: Support for new LogQL filtering syntax. [#16674](https://github.com/grafana/grafana/pull/16674), [@davkal](https://github.com/davkal) * **Explore**: Use new TimePicker from Grafana/UI. [#17793](https://github.com/grafana/grafana/pull/17793), [@hugohaggmark](https://github.com/hugohaggmark) * **Explore**: handle newlines in LogRow Highlighter. [#17425](https://github.com/grafana/grafana/pull/17425), [@rrfeng](https://github.com/rrfeng) +* **Graph**: Added new fill gradient option. [#17528](https://github.com/grafana/grafana/pull/17528), [@torkelo](https://github.com/torkelo) * **GraphPanel**: Don't sort series when legend table & sort column is not visible . [#17095](https://github.com/grafana/grafana/pull/17095), [@shavonn](https://github.com/shavonn) +* **InfluxDB**: Support for visualizing logs in Explore. [#17450](https://github.com/grafana/grafana/pull/17450), [@hugohaggmark](https://github.com/hugohaggmark) +* **Logging**: Login and Logout actions (#17760). [#17883](https://github.com/grafana/grafana/pull/17883), [@ATTron](https://github.com/ATTron) * **Logging**: Move log package to pkg/infra. [#17023](https://github.com/grafana/grafana/pull/17023), [@zhulongcheng](https://github.com/zhulongcheng) * **Metrics**: Expose stats about roles as metrics. [#17469](https://github.com/grafana/grafana/pull/17469), [@bergquist](https://github.com/bergquist) * **MySQL/Postgres/MSSQL**: Add parsing for day, weeks and year intervals in macros. [#13086](https://github.com/grafana/grafana/pull/13086), [@bernardd](https://github.com/bernardd) * **MySQL**: Add support for periodically reloading client certs. [#14892](https://github.com/grafana/grafana/pull/14892), [@tpetr](https://github.com/tpetr) * **Plugins**: replace dataFormats list with skipDataQuery flag in plugin.json. [#16984](https://github.com/grafana/grafana/pull/16984), [@ryantxu](https://github.com/ryantxu) +* **Prometheus**: Take timezone into account for step alignment. [#17477](https://github.com/grafana/grafana/pull/17477), [@fxmiii](https://github.com/fxmiii) * **Prometheus**: Use overridden panel range for $__range instead of dashboard range. [#17352](https://github.com/grafana/grafana/pull/17352), [@patrick246](https://github.com/patrick246) * **Prometheus**: added time range filter to series labels query. [#16851](https://github.com/grafana/grafana/pull/16851), [@FUSAKLA](https://github.com/FUSAKLA) * **Provisioning**: Support folder that doesn't exist yet in dashboard provisioning. [#17407](https://github.com/grafana/grafana/pull/17407), [@Nexucis](https://github.com/Nexucis) @@ -43,9 +49,10 @@ * **Templating**: Support selecting all filtered values of a multi-value variable. [#16873](https://github.com/grafana/grafana/pull/16873), [@r66ad](https://github.com/r66ad) * **Tracing**: allow propagation with Zipkin headers. [#17009](https://github.com/grafana/grafana/pull/17009), [@jrockway](https://github.com/jrockway) * **Users**: Disable users removed from LDAP. [#16820](https://github.com/grafana/grafana/pull/16820), [@alexanderzobnin](https://github.com/alexanderzobnin) - + ### Bug Fixes * **AddPanel**: Fix issue when removing moved add panel widget . [#17659](https://github.com/grafana/grafana/pull/17659), [@dehrax](https://github.com/dehrax) +* **CLI**: Fix encrypt-datasource-passwords fails with sql error. [#18014](https://github.com/grafana/grafana/pull/18014), [@marefr](https://github.com/marefr) * **Elasticsearch**: Fix default max concurrent shard requests. [#17770](https://github.com/grafana/grafana/pull/17770), [@marefr](https://github.com/marefr) * **Explore**: Fix browsing back to dashboard panel. [#17061](https://github.com/grafana/grafana/pull/17061), [@jschill](https://github.com/jschill) * **Explore**: Fix filter by series level in logs graph. [#17798](https://github.com/grafana/grafana/pull/17798), [@marefr](https://github.com/marefr) From e1cec1069cfe700ee4578bb18f908ab47a96c71e Mon Sep 17 00:00:00 2001 From: Tobias Skarhed Date: Thu, 11 Jul 2019 17:05:45 +0200 Subject: [PATCH 3/6] noImplicitAny: 1670 errors (#18035) * Sub 2000 errors * Down to 1670 errors * Minor fixes --- .../app/features/templating/template_srv.ts | 44 ++++++------ public/app/features/templating/variable.ts | 12 ++-- .../app/features/templating/variable_srv.ts | 31 ++++---- public/app/features/users/UsersActionBar.tsx | 2 +- public/app/features/users/UsersListPage.tsx | 8 +-- public/app/features/users/state/selectors.ts | 10 +-- .../datasource/cloudwatch/config_ctrl.ts | 12 ++-- .../datasource/cloudwatch/datasource.ts | 70 ++++++++++--------- .../datasource/cloudwatch/query_ctrl.ts | 3 +- .../cloudwatch/query_parameter_ctrl.ts | 22 +++--- .../cloudwatch/specs/datasource.test.ts | 34 ++++----- .../datasource/elasticsearch/bucket_agg.ts | 5 +- .../datasource/elasticsearch/config_ctrl.ts | 4 +- .../datasource/elasticsearch/datasource.ts | 62 ++++++++-------- .../elasticsearch/elastic_response.ts | 37 +++++----- .../datasource/elasticsearch/index_pattern.ts | 6 +- .../datasource/elasticsearch/metric_agg.ts | 3 +- .../elasticsearch/pipeline_variables.ts | 6 +- .../datasource/elasticsearch/query_builder.ts | 33 ++++----- .../datasource/elasticsearch/query_ctrl.ts | 8 +-- .../datasource/elasticsearch/query_def.ts | 30 ++++---- .../elasticsearch/specs/datasource.test.ts | 14 ++-- .../specs/elastic_response.test.ts | 28 ++++---- .../elasticsearch/specs/query_builder.test.ts | 3 +- .../__mocks__/query_ctrl.ts | 4 +- .../annotations_query_ctrl.ts | 10 +-- .../app_insights_datasource.test.ts | 23 +++--- .../app_insights/app_insights_datasource.ts | 28 ++++---- .../azure_log_analytics/__mocks__/schema.ts | 2 +- .../azure_monitor/supported_namespaces.ts | 2 +- .../editor/KustoQueryField.tsx | 4 +- .../graphite/specs/graphite_query.test.ts | 1 + .../datasource/loki/language_provider.test.ts | 8 +-- scripts/ci-frontend-metrics.sh | 2 +- 34 files changed, 300 insertions(+), 271 deletions(-) diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index 9e5a662e3e3..a37be2c4998 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -4,7 +4,7 @@ import { variableRegex } from 'app/features/templating/variable'; import { ScopedVars } from '@grafana/ui'; import { TimeRange } from '@grafana/data'; -function luceneEscape(value) { +function luceneEscape(value: string) { return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, '\\$1'); } @@ -12,8 +12,8 @@ export class TemplateSrv { variables: any[]; private regex = variableRegex; - private index = {}; - private grafanaVariables = {}; + private index: any = {}; + private grafanaVariables: any = {}; private builtIns: any = {}; private timeRange: TimeRange = null; @@ -23,7 +23,7 @@ export class TemplateSrv { this.variables = []; } - init(variables, timeRange?: TimeRange) { + init(variables: any, timeRange?: TimeRange) { this.variables = variables; this.timeRange = timeRange; this.updateIndex(); @@ -34,7 +34,7 @@ export class TemplateSrv { } updateIndex() { - const existsOrEmpty = value => value || value === ''; + const existsOrEmpty = (value: any) => value || value === ''; this.index = this.variables.reduce((acc, currentValue) => { if (currentValue.current && (currentValue.current.isNone || existsOrEmpty(currentValue.current.value))) { @@ -64,12 +64,12 @@ export class TemplateSrv { this.updateIndex(); } - variableInitialized(variable) { + variableInitialized(variable: any) { this.index[variable.name] = variable; } - getAdhocFilters(datasourceName) { - let filters = []; + getAdhocFilters(datasourceName: string) { + let filters: any = []; if (this.variables) { for (let i = 0; i < this.variables.length; i++) { @@ -92,7 +92,7 @@ export class TemplateSrv { return filters; } - luceneFormat(value) { + luceneFormat(value: any) { if (typeof value === 'string') { return luceneEscape(value); } @@ -108,7 +108,7 @@ export class TemplateSrv { // encode string according to RFC 3986; in contrast to encodeURIComponent() // also the sub-delims "!", "'", "(", ")" and "*" are encoded; // unicode handling uses UTF-8 as in ECMA-262. - encodeURIComponentStrict(str) { + encodeURIComponentStrict(str: string) { return encodeURIComponent(str).replace(/[!'()*]/g, c => { return ( '%' + @@ -120,7 +120,7 @@ export class TemplateSrv { }); } - formatValue(value, format, variable) { + formatValue(value: any, format: any, variable: any) { // for some scopedVars there is no variable variable = variable || {}; @@ -180,11 +180,11 @@ export class TemplateSrv { } } - setGrafanaVariable(name, value) { + setGrafanaVariable(name: string, value: any) { this.grafanaVariables[name] = value; } - getVariableName(expression) { + getVariableName(expression: string) { this.regex.lastIndex = 0; const match = this.regex.exec(expression); if (!match) { @@ -194,12 +194,12 @@ export class TemplateSrv { return variableName; } - variableExists(expression) { + variableExists(expression: string) { const name = this.getVariableName(expression); return name && this.index[name] !== void 0; } - highlightVariablesAsHtml(str) { + highlightVariablesAsHtml(str: string) { if (!str || !_.isString(str)) { return str; } @@ -214,7 +214,7 @@ export class TemplateSrv { }); } - getAllValue(variable) { + getAllValue(variable: any) { if (variable.allValue) { return variable.allValue; } @@ -225,7 +225,7 @@ export class TemplateSrv { return values; } - replace(target: string, scopedVars?: ScopedVars, format?: string | Function) { + replace(target: string, scopedVars?: ScopedVars, format?: string | Function): any { if (!target) { return target; } @@ -266,11 +266,11 @@ export class TemplateSrv { }); } - isAllValue(value) { + isAllValue(value: any) { return value === '$__all' || (Array.isArray(value) && value[0] === '$__all'); } - replaceWithText(target, scopedVars) { + replaceWithText(target: string, scopedVars: ScopedVars) { if (!target) { return target; } @@ -278,7 +278,7 @@ export class TemplateSrv { let variable; this.regex.lastIndex = 0; - return target.replace(this.regex, (match, var1, var2, fmt2, var3) => { + return target.replace(this.regex, (match: any, var1: any, var2: any, fmt2: any, var3: any) => { if (scopedVars) { const option = scopedVars[var1 || var2 || var3]; if (option) { @@ -297,7 +297,7 @@ export class TemplateSrv { }); } - fillVariableValuesForUrl(params, scopedVars?) { + fillVariableValuesForUrl(params: any, scopedVars?: ScopedVars) { _.each(this.variables, variable => { if (scopedVars && scopedVars[variable.name] !== void 0) { if (scopedVars[variable.name].skipUrlSync) { @@ -313,7 +313,7 @@ export class TemplateSrv { }); } - distributeVariable(value, variable) { + distributeVariable(value: any, variable: any) { value = _.map(value, (val: any, index: number) => { if (index !== 0) { return variable + '=' + val; diff --git a/public/app/features/templating/variable.ts b/public/app/features/templating/variable.ts index 930d2c49228..8a0cb0ea70b 100644 --- a/public/app/features/templating/variable.ts +++ b/public/app/features/templating/variable.ts @@ -16,12 +16,12 @@ export const variableRegexExec = (variableString: string) => { }; export interface Variable { - setValue(option); - updateOptions(); - dependsOn(variable); - setValueFromUrl(urlValue); - getValueForUrl(); - getSaveModel(); + setValue(option: any): any; + updateOptions(): any; + dependsOn(variable: any): any; + setValueFromUrl(urlValue: any): any; + getValueForUrl(): any; + getSaveModel(): any; } export let variableTypes = {}; diff --git a/public/app/features/templating/variable_srv.ts b/public/app/features/templating/variable_srv.ts index 7c6e8657969..9ee8773e761 100644 --- a/public/app/features/templating/variable_srv.ts +++ b/public/app/features/templating/variable_srv.ts @@ -1,5 +1,5 @@ // Libaries -import angular from 'angular'; +import angular, { IQService, ILocationService, auto, IPromise } from 'angular'; import _ from 'lodash'; // Utils & Services @@ -19,9 +19,9 @@ export class VariableSrv { /** @ngInject */ constructor( - private $q, - private $location, - private $injector, + private $q: IQService, + private $location: ILocationService, + private $injector: auto.IInjectorService, private templateSrv: TemplateSrv, private timeSrv: TimeSrv ) {} @@ -71,7 +71,7 @@ export class VariableSrv { }); } - processVariable(variable, queryParams) { + processVariable(variable: any, queryParams: any) { const dependencies = []; for (const otherVariable of this.variables) { @@ -100,7 +100,8 @@ export class VariableSrv { }); } - createVariableFromModel(model) { + createVariableFromModel(model: any) { + // @ts-ignore const ctor = variableTypes[model.type].ctor; if (!ctor) { throw { @@ -112,24 +113,24 @@ export class VariableSrv { return variable; } - addVariable(variable) { + addVariable(variable: any) { this.variables.push(variable); this.templateSrv.updateIndex(); this.dashboard.updateSubmenuVisibility(); } - removeVariable(variable) { + removeVariable(variable: any) { const index = _.indexOf(this.variables, variable); this.variables.splice(index, 1); this.templateSrv.updateIndex(); this.dashboard.updateSubmenuVisibility(); } - updateOptions(variable) { + updateOptions(variable: any) { return variable.updateOptions(); } - variableUpdated(variable, emitChangeEvents?) { + variableUpdated(variable: any, emitChangeEvents?: any) { // if there is a variable lock ignore cascading update because we are in a boot up scenario if (variable.initLock) { return this.$q.when(); @@ -152,7 +153,7 @@ export class VariableSrv { }); } - selectOptionsForCurrentValue(variable) { + selectOptionsForCurrentValue(variable: any) { let i, y, value, option; const selected: any = []; @@ -176,7 +177,7 @@ export class VariableSrv { return selected; } - validateVariableSelectionState(variable) { + validateVariableSelectionState(variable: any) { if (!variable.current) { variable.current = {}; } @@ -221,7 +222,7 @@ export class VariableSrv { * @param variable Instance of Variable * @param urlValue Value of the query parameter */ - setOptionFromUrl(variable: any, urlValue: string | string[]): Promise { + setOptionFromUrl(variable: any, urlValue: string | string[]): IPromise { let promise = this.$q.when(); if (variable.refresh) { @@ -268,7 +269,7 @@ export class VariableSrv { }); } - setOptionAsCurrent(variable, option) { + setOptionAsCurrent(variable: any, option: any) { variable.current = _.cloneDeep(option); if (_.isArray(variable.current.text) && variable.current.text.length > 0) { @@ -298,7 +299,7 @@ export class VariableSrv { this.$location.search(params); } - setAdhocFilter(options) { + setAdhocFilter(options: any) { let variable: any = _.find(this.variables, { type: 'adhoc', datasource: options.datasource, diff --git a/public/app/features/users/UsersActionBar.tsx b/public/app/features/users/UsersActionBar.tsx index 00c579978f9..c7f8c29cd4d 100644 --- a/public/app/features/users/UsersActionBar.tsx +++ b/public/app/features/users/UsersActionBar.tsx @@ -78,7 +78,7 @@ export class UsersActionBar extends PureComponent { } } -function mapStateToProps(state) { +function mapStateToProps(state: any) { return { searchQuery: getUsersSearchQuery(state.users), pendingInvitesCount: getInviteesCount(state.users), diff --git a/public/app/features/users/UsersListPage.tsx b/public/app/features/users/UsersListPage.tsx index c161c47f9e1..cd40bd3c8bb 100644 --- a/public/app/features/users/UsersListPage.tsx +++ b/public/app/features/users/UsersListPage.tsx @@ -34,7 +34,7 @@ export interface State { export class UsersListPage extends PureComponent { externalUserMngInfoHtml: string; - constructor(props) { + constructor(props: Props) { super(props); if (this.props.externalUserMngInfo) { @@ -59,13 +59,13 @@ export class UsersListPage extends PureComponent { return await this.props.loadInvitees(); } - onRoleChange = (role, user) => { + onRoleChange = (role: string, user: OrgUser) => { const updatedUser = { ...user, role: role }; this.props.updateUser(updatedUser); }; - onRemoveUser = user => { + onRemoveUser = (user: OrgUser) => { appEvents.emit('confirm-modal', { title: 'Delete', text: 'Are you sure you want to delete user ' + user.login + '?', @@ -119,7 +119,7 @@ export class UsersListPage extends PureComponent { } } -function mapStateToProps(state) { +function mapStateToProps(state: any) { return { navModel: getNavModel(state.navIndex, 'users'), users: getUsers(state.users), diff --git a/public/app/features/users/state/selectors.ts b/public/app/features/users/state/selectors.ts index 8bf052f61bd..d13c16f0958 100644 --- a/public/app/features/users/state/selectors.ts +++ b/public/app/features/users/state/selectors.ts @@ -1,4 +1,6 @@ -export const getUsers = state => { +import { UsersState } from 'app/types'; + +export const getUsers = (state: UsersState) => { const regex = new RegExp(state.searchQuery, 'i'); return state.users.filter(user => { @@ -6,7 +8,7 @@ export const getUsers = state => { }); }; -export const getInvitees = state => { +export const getInvitees = (state: UsersState) => { const regex = new RegExp(state.searchQuery, 'i'); return state.invitees.filter(invitee => { @@ -14,5 +16,5 @@ export const getInvitees = state => { }); }; -export const getInviteesCount = state => state.invitees.length; -export const getUsersSearchQuery = state => state.searchQuery; +export const getInviteesCount = (state: UsersState) => state.invitees.length; +export const getUsersSearchQuery = (state: UsersState) => state.searchQuery; diff --git a/public/app/plugins/datasource/cloudwatch/config_ctrl.ts b/public/app/plugins/datasource/cloudwatch/config_ctrl.ts index 6fe48cb1715..b25f46395ff 100644 --- a/public/app/plugins/datasource/cloudwatch/config_ctrl.ts +++ b/public/app/plugins/datasource/cloudwatch/config_ctrl.ts @@ -1,4 +1,6 @@ import _ from 'lodash'; +import DatasourceSrv from 'app/features/plugins/datasource_srv'; +import CloudWatchDatasource from './datasource'; export class CloudWatchConfigCtrl { static templateUrl = 'partials/config.html'; current: any; @@ -8,7 +10,7 @@ export class CloudWatchConfigCtrl { secretKeyExist = false; /** @ngInject */ - constructor($scope, datasourceSrv) { + constructor($scope: any, datasourceSrv: DatasourceSrv) { this.current.jsonData.timeField = this.current.jsonData.timeField || '@timestamp'; this.current.jsonData.authType = this.current.jsonData.authType || 'credentials'; @@ -32,7 +34,7 @@ export class CloudWatchConfigCtrl { { name: 'ARN', value: 'arn' }, ]; - indexPatternTypes = [ + indexPatternTypes: any = [ { name: 'No pattern', value: undefined }, { name: 'Hourly', value: 'Hourly', example: '[logstash-]YYYY.MM.DD.HH' }, { name: 'Daily', value: 'Daily', example: '[logstash-]YYYY.MM.DD' }, @@ -71,14 +73,14 @@ export class CloudWatchConfigCtrl { getRegions() { this.datasourceSrv .loadDatasource(this.current.name) - .then(ds => { + .then((ds: CloudWatchDatasource) => { return ds.getRegions(); }) .then( - regions => { + (regions: any) => { this.regions = _.map(regions, 'value'); }, - err => { + (err: any) => { console.error('failed to get latest regions'); } ); diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index de090d9e34c..dae94fbf309 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -1,9 +1,9 @@ -import angular from 'angular'; +import angular, { IQService } from 'angular'; import _ from 'lodash'; import { dateMath } from '@grafana/data'; import kbn from 'app/core/utils/kbn'; import { CloudWatchQuery } from './types'; -import { DataSourceApi, DataQueryRequest, DataSourceInstanceSettings } from '@grafana/ui'; +import { DataSourceApi, DataQueryRequest, DataSourceInstanceSettings, ScopedVars } from '@grafana/ui'; import { BackendSrv } from 'app/core/services/backend_srv'; import { TemplateSrv } from 'app/features/templating/template_srv'; import { TimeSrv } from 'app/features/dashboard/services/TimeSrv'; @@ -18,7 +18,7 @@ export default class CloudWatchDatasource extends DataSourceApi /** @ngInject */ constructor( private instanceSettings: DataSourceInstanceSettings, - private $q, + private $q: IQService, private backendSrv: BackendSrv, private templateSrv: TemplateSrv, private timeSrv: TimeSrv @@ -96,7 +96,7 @@ export default class CloudWatchDatasource extends DataSourceApi return this.performTimeSeriesQuery(request); } - getPeriod(target, options, now?) { + getPeriod(target: any, options: any, now?: number) { const start = this.convertToCloudWatchTime(options.range.from, false); const end = this.convertToCloudWatchTime(options.range.to, true); now = Math.round((now || Date.now()) / 1000); @@ -142,8 +142,8 @@ export default class CloudWatchDatasource extends DataSourceApi return period; } - performTimeSeriesQuery(request) { - return this.awsRequest('/api/tsdb/query', request).then(res => { + performTimeSeriesQuery(request: any) { + return this.awsRequest('/api/tsdb/query', request).then((res: any) => { const data = []; if (res.results) { @@ -165,7 +165,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - transformSuggestDataFromTable(suggestData) { + transformSuggestDataFromTable(suggestData: any) { return _.map(suggestData.results['metricFindQuery'].tables[0].rows, v => { return { text: v[0], @@ -174,7 +174,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - doMetricQueryRequest(subtype, parameters) { + doMetricQueryRequest(subtype: any, parameters: any) { const range = this.timeSrv.timeRange(); return this.awsRequest('/api/tsdb/query', { from: range.from.valueOf().toString(), @@ -192,7 +192,7 @@ export default class CloudWatchDatasource extends DataSourceApi parameters ), ], - }).then(r => { + }).then((r: any) => { return this.transformSuggestDataFromTable(r); }); } @@ -205,21 +205,27 @@ export default class CloudWatchDatasource extends DataSourceApi return this.doMetricQueryRequest('namespaces', null); } - getMetrics(namespace, region) { + getMetrics(namespace: string, region: string) { return this.doMetricQueryRequest('metrics', { region: this.templateSrv.replace(this.getActualRegion(region)), namespace: this.templateSrv.replace(namespace), }); } - getDimensionKeys(namespace, region) { + getDimensionKeys(namespace: string, region: string) { return this.doMetricQueryRequest('dimension_keys', { region: this.templateSrv.replace(this.getActualRegion(region)), namespace: this.templateSrv.replace(namespace), }); } - getDimensionValues(region, namespace, metricName, dimensionKey, filterDimensions) { + getDimensionValues( + region: string, + namespace: string, + metricName: string, + dimensionKey: string, + filterDimensions: {} + ) { return this.doMetricQueryRequest('dimension_values', { region: this.templateSrv.replace(this.getActualRegion(region)), namespace: this.templateSrv.replace(namespace), @@ -229,14 +235,14 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - getEbsVolumeIds(region, instanceId) { + getEbsVolumeIds(region: string, instanceId: string) { return this.doMetricQueryRequest('ebs_volume_ids', { region: this.templateSrv.replace(this.getActualRegion(region)), instanceId: this.templateSrv.replace(instanceId), }); } - getEc2InstanceAttribute(region, attributeName, filters) { + getEc2InstanceAttribute(region: string, attributeName: string, filters: any) { return this.doMetricQueryRequest('ec2_instance_attribute', { region: this.templateSrv.replace(this.getActualRegion(region)), attributeName: this.templateSrv.replace(attributeName), @@ -244,7 +250,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - getResourceARNs(region, resourceType, tags) { + getResourceARNs(region: string, resourceType: string, tags: any) { return this.doMetricQueryRequest('resource_arns', { region: this.templateSrv.replace(this.getActualRegion(region)), resourceType: this.templateSrv.replace(resourceType), @@ -252,7 +258,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - metricFindQuery(query) { + metricFindQuery(query: string) { let region; let namespace; let metricName; @@ -324,7 +330,7 @@ export default class CloudWatchDatasource extends DataSourceApi return this.$q.when([]); } - annotationQuery(options) { + annotationQuery(options: any) { const annotation = options.annotation; const statistics = _.map(annotation.statistics, s => { return this.templateSrv.replace(s); @@ -359,7 +365,7 @@ export default class CloudWatchDatasource extends DataSourceApi parameters ), ], - }).then(r => { + }).then((r: any) => { return _.map(r.results['annotationQuery'].tables[0].rows, v => { return { annotation: annotation, @@ -372,7 +378,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - targetContainsTemplate(target) { + targetContainsTemplate(target: any) { return ( this.templateSrv.variableExists(target.region) || this.templateSrv.variableExists(target.namespace) || @@ -395,14 +401,14 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - awsRequest(url, data) { + awsRequest(url: string, data: any) { const options = { method: 'POST', - url: url, - data: data, + url, + data, }; - return this.backendSrv.datasourceRequest(options).then(result => { + return this.backendSrv.datasourceRequest(options).then((result: any) => { return result.data; }); } @@ -411,14 +417,14 @@ export default class CloudWatchDatasource extends DataSourceApi return this.defaultRegion; } - getActualRegion(region) { + getActualRegion(region: string) { if (region === 'default' || _.isEmpty(region)) { return this.getDefaultRegion(); } return region; } - getExpandedVariables(target, dimensionKey, variable, templateSrv) { + getExpandedVariables(target: any, dimensionKey: any, variable: any, templateSrv: TemplateSrv) { /* if the all checkbox is marked we should add all values to the targets */ const allSelected: any = _.find(variable.options, { selected: true, text: 'All' }); const selectedVariables = _.filter(variable.options, v => { @@ -430,7 +436,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); const currentVariables = !_.isArray(variable.current.value) ? [variable.current] - : variable.current.value.map(v => { + : variable.current.value.map((v: any) => { return { text: v, value: v, @@ -440,9 +446,9 @@ export default class CloudWatchDatasource extends DataSourceApi selectedVariables.some((s: any) => { return s.value === currentVariables[0].value; }) || currentVariables[0].value === '$__all'; - return (useSelectedVariables ? selectedVariables : currentVariables).map(v => { + return (useSelectedVariables ? selectedVariables : currentVariables).map((v: any) => { const t = angular.copy(target); - const scopedVar = {}; + const scopedVar: any = {}; scopedVar[variable.name] = v; t.refId = target.refId + '_' + v.value; t.dimensions[dimensionKey] = templateSrv.replace(t.dimensions[dimensionKey], scopedVar); @@ -455,7 +461,7 @@ export default class CloudWatchDatasource extends DataSourceApi }); } - expandTemplateVariable(targets, scopedVars, templateSrv) { + expandTemplateVariable(targets: any, scopedVars: ScopedVars, templateSrv: TemplateSrv) { // Datasource and template srv logic uber-complected. This should be cleaned up. return _.chain(targets) .map(target => { @@ -480,15 +486,15 @@ export default class CloudWatchDatasource extends DataSourceApi .value(); } - convertToCloudWatchTime(date, roundUp) { + convertToCloudWatchTime(date: any, roundUp: any) { if (_.isString(date)) { date = dateMath.parse(date, roundUp); } return Math.round(date.valueOf() / 1000); } - convertDimensionFormat(dimensions, scopedVars) { - const convertedDimensions = {}; + convertDimensionFormat(dimensions: any, scopedVars: ScopedVars) { + const convertedDimensions: any = {}; _.each(dimensions, (value, key) => { convertedDimensions[this.templateSrv.replace(key, scopedVars)] = this.templateSrv.replace(value, scopedVars); }); diff --git a/public/app/plugins/datasource/cloudwatch/query_ctrl.ts b/public/app/plugins/datasource/cloudwatch/query_ctrl.ts index 55b7786e302..d1fe69e626e 100644 --- a/public/app/plugins/datasource/cloudwatch/query_ctrl.ts +++ b/public/app/plugins/datasource/cloudwatch/query_ctrl.ts @@ -1,5 +1,6 @@ import './query_parameter_ctrl'; import { QueryCtrl } from 'app/plugins/sdk'; +import { auto } from 'angular'; export class CloudWatchQueryCtrl extends QueryCtrl { static templateUrl = 'partials/query.editor.html'; @@ -7,7 +8,7 @@ export class CloudWatchQueryCtrl extends QueryCtrl { aliasSyntax: string; /** @ngInject */ - constructor($scope, $injector) { + constructor($scope: any, $injector: auto.IInjectorService) { super($scope, $injector); this.aliasSyntax = '{{metric}} {{stat}} {{namespace}} {{region}} {{}}'; } diff --git a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts index 45cbd79db12..5991305cf44 100644 --- a/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts +++ b/public/app/plugins/datasource/cloudwatch/query_parameter_ctrl.ts @@ -1,10 +1,12 @@ -import angular from 'angular'; +import angular, { IQService } from 'angular'; import coreModule from 'app/core/core_module'; import _ from 'lodash'; +import { TemplateSrv } from 'app/features/templating/template_srv'; +import DatasourceSrv from 'app/features/plugins/datasource_srv'; export class CloudWatchQueryParameterCtrl { /** @ngInject */ - constructor($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) { + constructor($scope: any, templateSrv: TemplateSrv, uiSegmentSrv: any, datasourceSrv: DatasourceSrv, $q: IQService) { $scope.init = () => { const target = $scope.target; target.namespace = target.namespace || ''; @@ -69,7 +71,7 @@ export class CloudWatchQueryParameterCtrl { ); }; - $scope.statSegmentChanged = (segment, index) => { + $scope.statSegmentChanged = (segment: any, index: number) => { if (segment.value === $scope.removeStatSegment.value) { $scope.statSegments.splice(index, 1); } else { @@ -91,7 +93,7 @@ export class CloudWatchQueryParameterCtrl { $scope.onChange(); }; - $scope.ensurePlusButton = segments => { + $scope.ensurePlusButton = (segments: any) => { const count = segments.length; const lastSegment = segments[Math.max(count - 1, 0)]; @@ -100,7 +102,7 @@ export class CloudWatchQueryParameterCtrl { } }; - $scope.getDimSegments = (segment, $index) => { + $scope.getDimSegments = (segment: any, $index: number) => { if (segment.type === 'operator') { return $q.when([]); } @@ -130,7 +132,7 @@ export class CloudWatchQueryParameterCtrl { }); }; - $scope.dimSegmentChanged = (segment, index) => { + $scope.dimSegmentChanged = (segment: any, index: number) => { $scope.dimSegments[index] = segment; if (segment.value === $scope.removeDimSegment.value) { @@ -148,7 +150,7 @@ export class CloudWatchQueryParameterCtrl { }; $scope.syncDimSegmentsWithModel = () => { - const dims = {}; + const dims: any = {}; const length = $scope.dimSegments.length; for (let i = 0; i < length - 2; i += 3) { @@ -165,7 +167,7 @@ export class CloudWatchQueryParameterCtrl { $scope.getRegions = () => { return $scope.datasource .metricFindQuery('regions()') - .then(results => { + .then((results: any) => { results.unshift({ text: 'default' }); return results; }) @@ -197,8 +199,8 @@ export class CloudWatchQueryParameterCtrl { $scope.onChange(); }; - $scope.transformToSegments = addTemplateVars => { - return results => { + $scope.transformToSegments = (addTemplateVars: any) => { + return (results: any) => { const segments = _.map(results, segment => { return uiSegmentSrv.newSegment({ value: segment.text, diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts index 2883335f617..3dcc817c51c 100644 --- a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts @@ -32,7 +32,7 @@ describe('CloudWatchDatasource', () => { } as any; beforeEach(() => { - ctx.ds = new CloudWatchDatasource(instanceSettings, {}, backendSrv, templateSrv, timeSrv); + ctx.ds = new CloudWatchDatasource(instanceSettings, {} as any, backendSrv, templateSrv, timeSrv); }); describe('When performing CloudWatch query', () => { @@ -56,7 +56,7 @@ describe('CloudWatchDatasource', () => { ], }; - const response = { + const response: any = { timings: [null], results: { A: { @@ -156,7 +156,7 @@ describe('CloudWatchDatasource', () => { }); it('should return series list', done => { - ctx.ds.query(query).then(result => { + ctx.ds.query(query).then((result: any) => { expect(result.data[0].target).toBe(response.results.A.series[0].name); expect(result.data[0].datapoints[0][0]).toBe(response.results.A.series[0].points[0][0]); done(); @@ -204,7 +204,7 @@ describe('CloudWatchDatasource', () => { ], }; - ctx.ds.query(query).then(result => { + ctx.ds.query(query).then((result: any) => { expect(requestParams.queries[0].region).toBe(instanceSettings.jsonData.defaultRegion); done(); }); @@ -231,7 +231,7 @@ describe('CloudWatchDatasource', () => { ], }; - const response = { + const response: any = { timings: [null], results: { A: { @@ -259,7 +259,7 @@ describe('CloudWatchDatasource', () => { }); it('should return series list', done => { - ctx.ds.query(query).then(result => { + ctx.ds.query(query).then((result: any) => { expect(result.data[0].target).toBe(response.results.A.series[0].name); expect(result.data[0].datapoints[0][0]).toBe(response.results.A.series[0].points[0][0]); done(); @@ -411,7 +411,7 @@ describe('CloudWatchDatasource', () => { }); it('should generate the correct query for multilple template variables with expression', done => { - const query = { + const query: any = { range: { from: 'now-1h', to: 'now' }, rangeRaw: { from: 1483228800, to: 1483232400 }, targets: [ @@ -466,17 +466,17 @@ describe('CloudWatchDatasource', () => { }); }); - function describeMetricFindQuery(query, func) { + function describeMetricFindQuery(query: any, func: any) { describe('metricFindQuery ' + query, () => { const scenario: any = {}; - scenario.setup = setupCallback => { + scenario.setup = (setupCallback: any) => { beforeEach(() => { setupCallback(); ctx.backendSrv.datasourceRequest = jest.fn(args => { scenario.request = args.data; return Promise.resolve({ data: scenario.requestResponse }); }); - ctx.ds.metricFindQuery(query).then(args => { + ctx.ds.metricFindQuery(query).then((args: any) => { scenario.result = args; }); }); @@ -486,7 +486,7 @@ describe('CloudWatchDatasource', () => { }); } - describeMetricFindQuery('regions()', scenario => { + describeMetricFindQuery('regions()', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { @@ -504,7 +504,7 @@ describe('CloudWatchDatasource', () => { }); }); - describeMetricFindQuery('namespaces()', scenario => { + describeMetricFindQuery('namespaces()', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { @@ -522,7 +522,7 @@ describe('CloudWatchDatasource', () => { }); }); - describeMetricFindQuery('metrics(AWS/EC2)', scenario => { + describeMetricFindQuery('metrics(AWS/EC2)', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { @@ -540,7 +540,7 @@ describe('CloudWatchDatasource', () => { }); }); - describeMetricFindQuery('dimension_keys(AWS/EC2)', scenario => { + describeMetricFindQuery('dimension_keys(AWS/EC2)', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { @@ -558,7 +558,7 @@ describe('CloudWatchDatasource', () => { }); }); - describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', scenario => { + describeMetricFindQuery('dimension_values(us-east-1,AWS/EC2,CPUUtilization,InstanceId)', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { @@ -576,7 +576,7 @@ describe('CloudWatchDatasource', () => { }); }); - describeMetricFindQuery('dimension_values(default,AWS/EC2,CPUUtilization,InstanceId)', scenario => { + describeMetricFindQuery('dimension_values(default,AWS/EC2,CPUUtilization,InstanceId)', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { @@ -594,7 +594,7 @@ describe('CloudWatchDatasource', () => { }); }); - describeMetricFindQuery('resource_arns(default,ec2:instance,{"environment":["production"]})', scenario => { + describeMetricFindQuery('resource_arns(default,ec2:instance,{"environment":["production"]})', (scenario: any) => { scenario.setup(() => { scenario.requestResponse = { results: { diff --git a/public/app/plugins/datasource/elasticsearch/bucket_agg.ts b/public/app/plugins/datasource/elasticsearch/bucket_agg.ts index 8701b2bf335..83f10c0da38 100644 --- a/public/app/plugins/datasource/elasticsearch/bucket_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/bucket_agg.ts @@ -1,10 +1,11 @@ import coreModule from 'app/core/core_module'; import _ from 'lodash'; import * as queryDef from './query_def'; +import { IQService } from 'angular'; export class ElasticBucketAggCtrl { /** @ngInject */ - constructor($scope, uiSegmentSrv, $q, $rootScope) { + constructor($scope: any, uiSegmentSrv: any, $q: IQService, $rootScope: any) { const bucketAggs = $scope.target.bucketAggs; $scope.orderByOptions = []; @@ -158,7 +159,7 @@ export class ElasticBucketAggCtrl { $scope.agg.settings.filters.push({ query: '*' }); }; - $scope.removeFiltersQuery = filter => { + $scope.removeFiltersQuery = (filter: any) => { $scope.agg.settings.filters = _.without($scope.agg.settings.filters, filter); }; diff --git a/public/app/plugins/datasource/elasticsearch/config_ctrl.ts b/public/app/plugins/datasource/elasticsearch/config_ctrl.ts index 21204035ddb..7fad7160ac6 100644 --- a/public/app/plugins/datasource/elasticsearch/config_ctrl.ts +++ b/public/app/plugins/datasource/elasticsearch/config_ctrl.ts @@ -8,7 +8,7 @@ export class ElasticConfigCtrl { current: DataSourceInstanceSettings; /** @ngInject */ - constructor($scope) { + constructor($scope: any) { this.current.jsonData.timeField = this.current.jsonData.timeField || '@timestamp'; this.current.jsonData.esVersion = this.current.jsonData.esVersion || 5; const defaultMaxConcurrentShardRequests = this.current.jsonData.esVersion >= 70 ? 5 : 256; @@ -18,7 +18,7 @@ export class ElasticConfigCtrl { this.current.jsonData.logLevelField = this.current.jsonData.logLevelField || ''; } - indexPatternTypes = [ + indexPatternTypes: any = [ { name: 'No pattern', value: undefined }, { name: 'Hourly', value: 'Hourly', example: '[logstash-]YYYY.MM.DD.HH' }, { name: 'Daily', value: 'Daily', example: '[logstash-]YYYY.MM.DD' }, diff --git a/public/app/plugins/datasource/elasticsearch/datasource.ts b/public/app/plugins/datasource/elasticsearch/datasource.ts index 59dec5cf9a0..dfebbabe3f1 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.ts +++ b/public/app/plugins/datasource/elasticsearch/datasource.ts @@ -63,7 +63,7 @@ export class ElasticDatasource extends DataSourceApi { + return this.request('GET', indexList[0] + url).then((results: any) => { results.data.$$config = results.config; return results.data; }); } else { - return this.request('GET', this.indexPattern.getIndexForToday() + url).then(results => { + return this.request('GET', this.indexPattern.getIndexForToday() + url).then((results: any) => { results.data.$$config = results.config; return results.data; }); } } - private post(url, data) { + private post(url: string, data: any) { return this.request('POST', url, data) - .then(results => { + .then((results: any) => { results.data.$$config = results.config; return results.data; }) - .catch(err => { + .catch((err: any) => { if (err.data && err.data.error) { throw { message: 'Elasticsearch error: ' + err.data.error.reason, @@ -116,14 +116,14 @@ export class ElasticDatasource extends DataSourceApi { + return this.post('_msearch', payload).then((res: any) => { const list = []; const hits = res.responses[0].hits.hits; - const getFieldFromSource = (source, fieldName) => { + const getFieldFromSource = (source: any, fieldName: any) => { if (!fieldName) { return; } @@ -229,7 +229,7 @@ export class ElasticDatasource extends DataSourceApi { + (dateFields: any) => { const timeField: any = _.find(dateFields, { text: this.timeField }); if (!timeField) { return { @@ -239,7 +239,7 @@ export class ElasticDatasource extends DataSourceApi { + (err: any) => { console.log(err); if (err.data && err.data.error) { let message = angular.toJson(err.data.error); @@ -254,7 +254,7 @@ export class ElasticDatasource extends DataSourceApi { + return this.post(url, payload).then((res: any) => { const er = new ElasticResponse(sentTargets, res); if (sentTargets.some(target => target.isLogsQuery)) { return er.getLogs(this.logMessageField, this.logLevelField); @@ -329,10 +329,10 @@ export class ElasticDatasource extends DataSourceApi { - const typeMap = { + return this.get('/_mapping').then((result: any) => { + const typeMap: any = { float: 'number', double: 'number', integer: 'number', @@ -344,7 +344,7 @@ export class ElasticDatasource extends DataSourceApi system.process.cpu.total - const fieldNameParts = []; - const fields = {}; + const fieldNameParts: any = []; + const fields: any = {}; - function getFieldsRecursively(obj) { + function getFieldsRecursively(obj: any) { for (const key in obj) { const subObj = obj[key]; @@ -415,7 +415,7 @@ export class ElasticDatasource extends DataSourceApi= 5 ? 'query_then_fetch' : 'count'; const header = this.getQueryHeader(searchType, range.from, range.to); @@ -427,7 +427,7 @@ export class ElasticDatasource extends DataSourceApi { + return this.post(url, esQuery).then((res: any) => { if (!res.responses[0].aggregations) { return []; } @@ -450,7 +450,7 @@ export class ElasticDatasource extends DataSourceApi { + const addMetricValue = (values: any[], metricName: string, value: any) => { table.addColumn({ text: metricName }); values.push(value); }; @@ -188,8 +189,8 @@ export class ElasticResponse { // This is quite complex // need to recurse down the nested buckets to build series - processBuckets(aggs, target, seriesList, table, props, depth) { - let bucket, aggDef, esAgg, aggId; + processBuckets(aggs: any, target: any, seriesList: any, table: any, props: any, depth: any) { + let bucket, aggDef: any, esAgg, aggId; const maxDepth = target.bucketAggs.length - 1; for (aggId in aggs) { @@ -224,7 +225,7 @@ export class ElasticResponse { } } - private getMetricName(metric) { + private getMetricName(metric: any) { let metricDef: any = _.find(queryDef.metricAggTypes, { value: metric }); if (!metricDef) { metricDef = _.find(queryDef.extendedStats, { value: metric }); @@ -233,13 +234,13 @@ export class ElasticResponse { return metricDef ? metricDef.text : metric; } - private getSeriesName(series, target, metricTypeCount) { + private getSeriesName(series: any, target: any, metricTypeCount: any) { let metricName = this.getMetricName(series.metric); if (target.alias) { const regex = /\{\{([\s\S]+?)\}\}/g; - return target.alias.replace(regex, (match, g1, g2) => { + return target.alias.replace(regex, (match: any, g1: any, g2: any) => { const group = g1 || g2; if (group.indexOf('term ') === 0) { @@ -303,7 +304,7 @@ export class ElasticResponse { return name.trim() + ' ' + metricName; } - nameSeries(seriesList, target) { + nameSeries(seriesList: any, target: any) { const metricTypeCount = _.uniq(_.map(seriesList, 'metric')).length; for (let i = 0; i < seriesList.length; i++) { @@ -312,17 +313,17 @@ export class ElasticResponse { } } - processHits(hits, seriesList) { + processHits(hits: { total: { value: any }; hits: any[] }, seriesList: any[]) { const hitsTotal = typeof hits.total === 'number' ? hits.total : hits.total.value; // <- Works with Elasticsearch 7.0+ - const series = { + const series: any = { target: 'docs', type: 'docs', datapoints: [], total: hitsTotal, filterable: true, }; - let propName, hit, doc, i; + let propName, hit, doc: any, i; for (i = 0; i < hits.hits.length; i++) { hit = hits.hits[i]; @@ -347,7 +348,7 @@ export class ElasticResponse { seriesList.push(series); } - trimDatapoints(aggregations, target) { + trimDatapoints(aggregations: any, target: any) { const histogram: any = _.find(target.bucketAggs, { type: 'date_histogram' }); const shouldDropFirstAndLast = histogram && histogram.settings && histogram.settings.trimEdges; @@ -362,7 +363,7 @@ export class ElasticResponse { } } - getErrorFromElasticResponse(response, err) { + getErrorFromElasticResponse(response: any, err: any) { const result: any = {}; result.data = JSON.stringify(err, null, 4); if (err.root_cause && err.root_cause.length > 0 && err.root_cause[0].reason) { @@ -394,7 +395,7 @@ export class ElasticResponse { if (response.aggregations) { const aggregations = response.aggregations; const target = this.targets[i]; - const tmpSeriesList = []; + const tmpSeriesList: any[] = []; const table = new TableModel(); this.processBuckets(aggregations, target, tmpSeriesList, table, {}, 0); @@ -426,7 +427,7 @@ export class ElasticResponse { const hits = response.hits; let propNames: string[] = []; - let propName, hit, doc, i; + let propName, hit, doc: any, i; for (i = 0; i < hits.hits.length; i++) { hit = hits.hits[i]; @@ -534,7 +535,7 @@ export class ElasticResponse { if (response.aggregations) { const aggregations = response.aggregations; const target = this.targets[n]; - const tmpSeriesList = []; + const tmpSeriesList: any[] = []; const table = new TableModel(); this.processBuckets(aggregations, target, tmpSeriesList, table, {}, 0); diff --git a/public/app/plugins/datasource/elasticsearch/index_pattern.ts b/public/app/plugins/datasource/elasticsearch/index_pattern.ts index 3d62f6661b1..9b8393c220d 100644 --- a/public/app/plugins/datasource/elasticsearch/index_pattern.ts +++ b/public/app/plugins/datasource/elasticsearch/index_pattern.ts @@ -1,6 +1,6 @@ import { toUtc, dateTime } from '@grafana/data'; -const intervalMap = { +const intervalMap: any = { Hourly: { startOf: 'hour', amount: 'hours' }, Daily: { startOf: 'day', amount: 'days' }, Weekly: { startOf: 'isoWeek', amount: 'weeks' }, @@ -9,7 +9,7 @@ const intervalMap = { }; export class IndexPattern { - constructor(private pattern, private interval: string | null) {} + constructor(private pattern: any, private interval: string | null) {} getIndexForToday() { if (this.interval) { @@ -19,7 +19,7 @@ export class IndexPattern { } } - getIndexList(from, to) { + getIndexList(from: any, to: any) { if (!this.interval) { return this.pattern; } diff --git a/public/app/plugins/datasource/elasticsearch/metric_agg.ts b/public/app/plugins/datasource/elasticsearch/metric_agg.ts index 216d88318cf..0b711bf8921 100644 --- a/public/app/plugins/datasource/elasticsearch/metric_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/metric_agg.ts @@ -2,10 +2,11 @@ import coreModule from 'app/core/core_module'; import _ from 'lodash'; import * as queryDef from './query_def'; import { ElasticsearchAggregation } from './types'; +import { IQService } from 'angular'; export class ElasticMetricAggCtrl { /** @ngInject */ - constructor($scope, uiSegmentSrv, $q, $rootScope) { + constructor($scope: any, uiSegmentSrv: any, $q: IQService, $rootScope: any) { const metricAggs: ElasticsearchAggregation[] = $scope.target.metrics; $scope.metricAggTypes = queryDef.getMetricAggTypes($scope.esVersion); $scope.extendedStats = queryDef.extendedStats; diff --git a/public/app/plugins/datasource/elasticsearch/pipeline_variables.ts b/public/app/plugins/datasource/elasticsearch/pipeline_variables.ts index 26c886043b2..c1630674af1 100644 --- a/public/app/plugins/datasource/elasticsearch/pipeline_variables.ts +++ b/public/app/plugins/datasource/elasticsearch/pipeline_variables.ts @@ -14,7 +14,7 @@ export function elasticPipelineVariables() { }; } -const newVariable = index => { +const newVariable = (index: any) => { return { name: 'var' + index, pipelineAgg: 'select metric', @@ -23,7 +23,7 @@ const newVariable = index => { export class ElasticPipelineVariablesCtrl { /** @ngInject */ - constructor($scope) { + constructor($scope: any) { $scope.variables = $scope.variables || [newVariable(1)]; $scope.onChangeInternal = () => { @@ -35,7 +35,7 @@ export class ElasticPipelineVariablesCtrl { $scope.onChange(); }; - $scope.remove = index => { + $scope.remove = (index: number) => { $scope.variables.splice(index, 1); $scope.onChange(); }; diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.ts b/public/app/plugins/datasource/elasticsearch/query_builder.ts index 994a5f91663..5dbfbb12f2d 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.ts +++ b/public/app/plugins/datasource/elasticsearch/query_builder.ts @@ -1,16 +1,17 @@ import * as queryDef from './query_def'; +import { ElasticsearchAggregation } from './types'; export class ElasticQueryBuilder { timeField: string; esVersion: number; - constructor(options) { + constructor(options: any) { this.timeField = options.timeField; this.esVersion = options.esVersion; } getRangeFilter() { - const filter = {}; + const filter: any = {}; filter[this.timeField] = { gte: '$timeFrom', lte: '$timeTo', @@ -20,7 +21,7 @@ export class ElasticQueryBuilder { return filter; } - buildTermsAgg(aggDef, queryNode, target) { + buildTermsAgg(aggDef: ElasticsearchAggregation, queryNode: { terms?: any; aggs?: any }, target: { metrics: any[] }) { let metricRef, metric, y; queryNode.terms = { field: aggDef.field }; @@ -63,7 +64,7 @@ export class ElasticQueryBuilder { return queryNode; } - getDateHistogramAgg(aggDef) { + getDateHistogramAgg(aggDef: ElasticsearchAggregation) { const esAgg: any = {}; const settings = aggDef.settings || {}; esAgg.interval = settings.interval; @@ -87,7 +88,7 @@ export class ElasticQueryBuilder { return esAgg; } - getHistogramAgg(aggDef) { + getHistogramAgg(aggDef: ElasticsearchAggregation) { const esAgg: any = {}; const settings = aggDef.settings || {}; esAgg.interval = settings.interval; @@ -100,8 +101,8 @@ export class ElasticQueryBuilder { return esAgg; } - getFiltersAgg(aggDef) { - const filterObj = {}; + getFiltersAgg(aggDef: ElasticsearchAggregation) { + const filterObj: any = {}; for (let i = 0; i < aggDef.settings.filters.length; i++) { const query = aggDef.settings.filters[i].query; let label = aggDef.settings.filters[i].label; @@ -117,7 +118,7 @@ export class ElasticQueryBuilder { return filterObj; } - documentQuery(query, size) { + documentQuery(query: any, size: number) { query.size = size; query.sort = {}; query.sort[this.timeField] = { order: 'desc', unmapped_type: 'boolean' }; @@ -136,12 +137,12 @@ export class ElasticQueryBuilder { return query; } - addAdhocFilters(query, adhocFilters) { + addAdhocFilters(query: any, adhocFilters: any) { if (!adhocFilters) { return; } - let i, filter, condition, queryCondition; + let i, filter, condition: any, queryCondition: any; for (i = 0; i < adhocFilters.length; i++) { filter = adhocFilters[i]; @@ -183,7 +184,7 @@ export class ElasticQueryBuilder { } } - build(target, adhocFilters?, queryString?) { + build(target: any, adhocFilters?: any, queryString?: string) { // make sure query has defaults; target.metrics = target.metrics || [queryDef.defaultMetricAgg()]; target.bucketAggs = target.bucketAggs || [queryDef.defaultBucketAgg()]; @@ -224,7 +225,7 @@ export class ElasticQueryBuilder { for (i = 0; i < target.bucketAggs.length; i++) { const aggDef = target.bucketAggs[i]; - const esAgg = {}; + const esAgg: any = {}; switch (aggDef.type) { case 'date_histogram': { @@ -265,8 +266,8 @@ export class ElasticQueryBuilder { continue; } - const aggField = {}; - let metricAgg = null; + const aggField: any = {}; + let metricAgg: any = null; if (queryDef.isPipelineAgg(metric.type)) { if (queryDef.isPipelineAggWithMultipleBucketPaths(metric.type)) { @@ -323,7 +324,7 @@ export class ElasticQueryBuilder { return query; } - getTermsQuery(queryDef) { + getTermsQuery(queryDef: any) { const query: any = { size: 0, query: { @@ -368,7 +369,7 @@ export class ElasticQueryBuilder { return query; } - getLogsQuery(target, querystring) { + getLogsQuery(target: any, querystring: string) { let query: any = { size: 0, query: { diff --git a/public/app/plugins/datasource/elasticsearch/query_ctrl.ts b/public/app/plugins/datasource/elasticsearch/query_ctrl.ts index 47382c3e2e0..f8df4e0b689 100644 --- a/public/app/plugins/datasource/elasticsearch/query_ctrl.ts +++ b/public/app/plugins/datasource/elasticsearch/query_ctrl.ts @@ -2,7 +2,7 @@ import './bucket_agg'; import './metric_agg'; import './pipeline_variables'; -import angular from 'angular'; +import angular, { auto } from 'angular'; import _ from 'lodash'; import * as queryDef from './query_def'; import { QueryCtrl } from 'app/plugins/sdk'; @@ -15,7 +15,7 @@ export class ElasticQueryCtrl extends QueryCtrl { rawQueryOld: string; /** @ngInject */ - constructor($scope, $injector, private $rootScope, private uiSegmentSrv) { + constructor($scope: any, $injector: auto.IInjectorService, private $rootScope: any, private uiSegmentSrv: any) { super($scope, $injector); this.esVersion = this.datasource.esVersion; @@ -35,7 +35,7 @@ export class ElasticQueryCtrl extends QueryCtrl { this.queryUpdated(); } - getFields(type) { + getFields(type: any) { const jsonStr = angular.toJson({ find: 'fields', type: type }); return this.datasource .metricFindQuery(jsonStr) @@ -98,7 +98,7 @@ export class ElasticQueryCtrl extends QueryCtrl { return text; } - handleQueryError(err) { + handleQueryError(err: any): any[] { this.error = err.message || 'Failed to issue metric query'; return []; } diff --git a/public/app/plugins/datasource/elasticsearch/query_def.ts b/public/app/plugins/datasource/elasticsearch/query_def.ts index e429183e4ac..4f898e8155b 100644 --- a/public/app/plugins/datasource/elasticsearch/query_def.ts +++ b/public/app/plugins/datasource/elasticsearch/query_def.ts @@ -128,7 +128,7 @@ export const movingAvgModelOptions = [ { text: 'Holt Winters', value: 'holt_winters' }, ]; -export const pipelineOptions = { +export const pipelineOptions: any = { moving_avg: [ { text: 'window', default: 5 }, { text: 'model', default: 'simple' }, @@ -139,7 +139,7 @@ export const pipelineOptions = { bucket_script: [], }; -export const movingAvgModelSettings = { +export const movingAvgModelSettings: any = { simple: [], linear: [], ewma: [{ text: 'Alpha', value: 'alpha', default: undefined }], @@ -153,7 +153,7 @@ export const movingAvgModelSettings = { ], }; -export function getMetricAggTypes(esVersion) { +export function getMetricAggTypes(esVersion: any) { return _.filter(metricAggTypes, f => { if (f.minVersion) { return f.minVersion <= esVersion; @@ -163,7 +163,7 @@ export function getMetricAggTypes(esVersion) { }); } -export function getPipelineOptions(metric) { +export function getPipelineOptions(metric: any) { if (!isPipelineAgg(metric.type)) { return []; } @@ -171,7 +171,7 @@ export function getPipelineOptions(metric) { return pipelineOptions[metric.type]; } -export function isPipelineAgg(metricType) { +export function isPipelineAgg(metricType: any) { if (metricType) { const po = pipelineOptions[metricType]; return po !== null && po !== undefined; @@ -180,7 +180,7 @@ export function isPipelineAgg(metricType) { return false; } -export function isPipelineAggWithMultipleBucketPaths(metricType) { +export function isPipelineAggWithMultipleBucketPaths(metricType: any) { if (metricType) { return metricAggTypes.find(t => t.value === metricType && t.supportsMultipleBucketPaths) !== undefined; } @@ -188,8 +188,8 @@ export function isPipelineAggWithMultipleBucketPaths(metricType) { return false; } -export function getPipelineAggOptions(targets) { - const result = []; +export function getPipelineAggOptions(targets: any) { + const result: any[] = []; _.each(targets.metrics, metric => { if (!isPipelineAgg(metric.type)) { result.push({ text: describeMetric(metric), value: metric.id }); @@ -199,8 +199,8 @@ export function getPipelineAggOptions(targets) { return result; } -export function getMovingAvgSettings(model, filtered) { - const filteredResult = []; +export function getMovingAvgSettings(model: any, filtered: boolean) { + const filteredResult: any[] = []; if (filtered) { _.each(movingAvgModelSettings[model], setting => { if (!setting.isCheckbox) { @@ -212,8 +212,8 @@ export function getMovingAvgSettings(model, filtered) { return movingAvgModelSettings[model]; } -export function getOrderByOptions(target) { - const metricRefs = []; +export function getOrderByOptions(target: any) { + const metricRefs: any[] = []; _.each(target.metrics, metric => { if (metric.type !== 'count') { metricRefs.push({ text: describeMetric(metric), value: metric.id }); @@ -223,12 +223,12 @@ export function getOrderByOptions(target) { return orderByOptions.concat(metricRefs); } -export function describeOrder(order) { +export function describeOrder(order: string) { const def: any = _.find(orderOptions, { value: order }); return def.text; } -export function describeMetric(metric) { +export function describeMetric(metric: { type: string; field: string }) { const def: any = _.find(metricAggTypes, { value: metric.type }); if (!def.requiresField && !isPipelineAgg(metric.type)) { return def.text; @@ -236,7 +236,7 @@ export function describeMetric(metric) { return def.text + ' ' + metric.field; } -export function describeOrderBy(orderBy, target) { +export function describeOrderBy(orderBy: any, target: any) { const def: any = _.find(orderByOptions, { value: orderBy }); if (def) { return def.text; diff --git a/public/app/plugins/datasource/elasticsearch/specs/datasource.test.ts b/public/app/plugins/datasource/elasticsearch/specs/datasource.test.ts index e27bb0be6bc..bfeb1645ded 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/datasource.test.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/datasource.test.ts @@ -69,7 +69,7 @@ describe('ElasticDatasource', function(this: any) { }); it('should translate index pattern to current day', () => { - let requestOptions; + let requestOptions: any; ctx.backendSrv.datasourceRequest = jest.fn(options => { requestOptions = options; return Promise.resolve({ data: {} }); @@ -83,7 +83,7 @@ describe('ElasticDatasource', function(this: any) { }); describe('When issuing metric query with interval pattern', () => { - let requestOptions, parts, header, query, result; + let requestOptions: any, parts: any, header: any, query: any, result: any; beforeEach(async () => { createDatasource({ @@ -154,7 +154,7 @@ describe('ElasticDatasource', function(this: any) { }); describe('When issuing logs query with interval pattern', () => { - let query, queryBuilderSpy; + let query, queryBuilderSpy: any; beforeEach(async () => { createDatasource({ @@ -249,7 +249,7 @@ describe('ElasticDatasource', function(this: any) { }); describe('When issuing document query', () => { - let requestOptions, parts, header; + let requestOptions: any, parts: any, header: any; beforeEach(() => { createDatasource({ @@ -539,7 +539,7 @@ describe('ElasticDatasource', function(this: any) { }); describe('When issuing aggregation query on es5.x', () => { - let requestOptions, parts, header; + let requestOptions: any, parts: any, header: any; beforeEach(() => { createDatasource({ @@ -582,7 +582,7 @@ describe('ElasticDatasource', function(this: any) { }); describe('When issuing metricFind query on es5.x', () => { - let requestOptions, parts, header, body, results; + let requestOptions: any, parts, header: any, body: any, results: any; beforeEach(() => { createDatasource({ @@ -615,7 +615,7 @@ describe('ElasticDatasource', function(this: any) { }); }); - ctx.ds.metricFindQuery('{"find": "terms", "field": "test"}').then(res => { + ctx.ds.metricFindQuery('{"find": "terms", "field": "test"}').then((res: any) => { results = res; }); diff --git a/public/app/plugins/datasource/elasticsearch/specs/elastic_response.test.ts b/public/app/plugins/datasource/elasticsearch/specs/elastic_response.test.ts index b7144534761..25c95d8ab5d 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/elastic_response.test.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/elastic_response.test.ts @@ -2,8 +2,8 @@ import { ElasticResponse } from '../elastic_response'; describe('ElasticResponse', () => { let targets; - let response; - let result; + let response: any; + let result: any; describe('simple query and count', () => { beforeEach(() => { @@ -48,7 +48,7 @@ describe('ElasticResponse', () => { }); describe('simple query count & avg aggregation', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -97,7 +97,7 @@ describe('ElasticResponse', () => { }); describe('single group by query one metric', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -149,7 +149,7 @@ describe('ElasticResponse', () => { }); describe('single group by query two metrics', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -209,7 +209,7 @@ describe('ElasticResponse', () => { }); describe('with percentiles ', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -257,7 +257,7 @@ describe('ElasticResponse', () => { }); describe('with extended_stats', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -333,7 +333,7 @@ describe('ElasticResponse', () => { }); describe('single group by with alias pattern', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -394,7 +394,7 @@ describe('ElasticResponse', () => { }); describe('histogram response', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -426,7 +426,7 @@ describe('ElasticResponse', () => { }); describe('with two filters agg', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -583,7 +583,7 @@ describe('ElasticResponse', () => { }); describe('No group by time with percentiles ', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -720,7 +720,7 @@ describe('ElasticResponse', () => { }); describe('with bucket_script ', () => { - let result; + let result: any; beforeEach(() => { targets = [ @@ -861,7 +861,7 @@ describe('ElasticResponse', () => { expect(result.data[0].fields).toContainEqual({ name: '@timestamp', type: 'time' }); expect(result.data[0].fields).toContainEqual({ name: 'host', type: 'string' }); expect(result.data[0].fields).toContainEqual({ name: 'message', type: 'string' }); - result.data[0].rows.forEach((row, i) => { + result.data[0].rows.forEach((row: any, i: number) => { expect(row).toContain(response.responses[0].hits.hits[i]._id); expect(row).toContain(response.responses[0].hits.hits[i]._type); expect(row).toContain(response.responses[0].hits.hits[i]._index); @@ -869,7 +869,7 @@ describe('ElasticResponse', () => { }); expect(result.data[1]).toHaveProperty('name', 'Count'); - response.responses[0].aggregations['2'].buckets.forEach(bucket => { + response.responses[0].aggregations['2'].buckets.forEach((bucket: any) => { expect(result.data[1].rows).toContainEqual([bucket.doc_count, bucket.key]); }); }); diff --git a/public/app/plugins/datasource/elasticsearch/specs/query_builder.test.ts b/public/app/plugins/datasource/elasticsearch/specs/query_builder.test.ts index ef296543bd3..bf7e54586c6 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/query_builder.test.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/query_builder.test.ts @@ -1,7 +1,7 @@ import { ElasticQueryBuilder } from '../query_builder'; describe('ElasticQueryBuilder', () => { - let builder; + let builder: any; beforeEach(() => { builder = new ElasticQueryBuilder({ timeField: '@timestamp' }); @@ -103,6 +103,7 @@ describe('ElasticQueryBuilder', () => { ], }, 100, + // @ts-ignore 1000 ); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query_ctrl.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query_ctrl.ts index 294900205b7..f5dc9b21742 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query_ctrl.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query_ctrl.ts @@ -1,3 +1,5 @@ +import { auto } from 'angular'; + export class QueryCtrl { target: any; datasource: any; @@ -6,7 +8,7 @@ export class QueryCtrl { hasRawMode: boolean; error: string; - constructor(public $scope, _$injector) { + constructor(public $scope: any, _$injector: auto.IInjectorService) { this.panelCtrl = this.panelCtrl || { panel: {} }; this.target = this.target || { target: '' }; this.panel = this.panelCtrl.panel; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/annotations_query_ctrl.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/annotations_query_ctrl.ts index 555ec8cd9be..6827edc0c82 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/annotations_query_ctrl.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/annotations_query_ctrl.ts @@ -1,3 +1,5 @@ +import { TemplateSrv } from 'app/features/templating/template_srv'; + export class AzureMonitorAnnotationsQueryCtrl { static templateUrl = 'partials/annotations.editor.html'; datasource: any; @@ -9,7 +11,7 @@ export class AzureMonitorAnnotationsQueryCtrl { '\n| where $__timeFilter() \n| project TimeGenerated, Text=YourTitleColumn, Tags="tag1,tag2"'; /** @ngInject */ - constructor(private templateSrv) { + constructor(private templateSrv: TemplateSrv) { this.annotation.queryType = this.annotation.queryType || 'Azure Log Analytics'; this.annotation.rawQuery = this.annotation.rawQuery || this.defaultQuery; this.initDropdowns(); @@ -25,7 +27,7 @@ export class AzureMonitorAnnotationsQueryCtrl { return; } - return this.datasource.azureMonitorDatasource.getSubscriptions().then(subs => { + return this.datasource.azureMonitorDatasource.getSubscriptions().then((subs: any[]) => { this.subscriptions = subs; if (!this.annotation.subscription && this.annotation.queryType === 'Azure Log Analytics') { @@ -45,7 +47,7 @@ export class AzureMonitorAnnotationsQueryCtrl { return this.datasource .getAzureLogAnalyticsWorkspaces(this.annotation.subscription) - .then(list => { + .then((list: any[]) => { this.workspaces = list; if (list.length > 0 && !this.annotation.workspace) { this.annotation.workspace = list[0].value; @@ -72,6 +74,6 @@ export class AzureMonitorAnnotationsQueryCtrl { }; get templateVariables() { - return this.templateSrv.variables.map(t => '$' + t.name); + return this.templateSrv.variables.map((t: any) => '$' + t.name); } } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts index 76d37950467..8eef8e8eece 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.test.ts @@ -1,4 +1,5 @@ import AzureMonitorDatasource from '../datasource'; +// @ts-ignore import Q from 'q'; import { TemplateSrv } from 'app/features/templating/template_srv'; import { toUtc } from '@grafana/data'; @@ -46,7 +47,7 @@ describe('AppInsightsDatasource', () => { }); it('should return success status', () => { - return ctx.ds.testDatasource().then(results => { + return ctx.ds.testDatasource().then((results: any) => { expect(results.status).toEqual('success'); }); }); @@ -71,7 +72,7 @@ describe('AppInsightsDatasource', () => { }); it('should return error status and a detailed error message', () => { - return ctx.ds.testDatasource().then(results => { + return ctx.ds.testDatasource().then((results: any) => { expect(results.status).toEqual('error'); expect(results.message).toEqual( '1. Application Insights: Not Found: Invalid Application Id for Application Insights service. ' @@ -99,7 +100,7 @@ describe('AppInsightsDatasource', () => { }); it('should return error status and a detailed error message', () => { - return ctx.ds.testDatasource().then(results => { + return ctx.ds.testDatasource().then((results: any) => { expect(results.status).toEqual('error'); expect(results.message).toEqual('1. Application Insights: Error: SomeOtherError. An error message. '); }); @@ -149,7 +150,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a single datapoint', () => { - return ctx.ds.query(options).then(results => { + return ctx.ds.query(options).then((results: any) => { expect(results.data.length).toBe(1); expect(results.data[0].datapoints.length).toBe(1); expect(results.data[0].target).toEqual('exceptions/server'); @@ -196,7 +197,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of datapoints', () => { - return ctx.ds.query(options).then(results => { + return ctx.ds.query(options).then((results: any) => { expect(results.data.length).toBe(1); expect(results.data[0].datapoints.length).toBe(2); expect(results.data[0].target).toEqual('exceptions/server'); @@ -267,7 +268,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of datapoints', () => { - return ctx.ds.query(options).then(results => { + return ctx.ds.query(options).then((results: any) => { expect(results.data.length).toBe(3); expect(results.data[0].datapoints.length).toBe(2); expect(results.data[0].target).toEqual('exceptions/server{client/city="Miami"}'); @@ -292,7 +293,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of datapoints', () => { - return ctx.ds.query(options).then(results => { + return ctx.ds.query(options).then((results: any) => { expect(results.data.length).toBe(3); expect(results.data[0].datapoints.length).toBe(2); expect(results.data[0].target).toEqual('exceptions/server + client/city + Miami'); @@ -323,7 +324,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of metric names', () => { - return ctx.ds.metricFindQuery('appInsightsMetricNames()').then(results => { + return ctx.ds.metricFindQuery('appInsightsMetricNames()').then((results: any) => { expect(results.length).toBe(2); expect(results[0].text).toBe('exceptions/server'); expect(results[0].value).toBe('exceptions/server'); @@ -361,7 +362,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of group bys', () => { - return ctx.ds.metricFindQuery('appInsightsGroupBys(requests/count)').then(results => { + return ctx.ds.metricFindQuery('appInsightsGroupBys(requests/count)').then((results: any) => { expect(results[0].text).toContain('client/os'); expect(results[0].value).toContain('client/os'); expect(results[1].text).toContain('client/city'); @@ -389,7 +390,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of metric names', () => { - return ctx.ds.getAppInsightsMetricNames().then(results => { + return ctx.ds.getAppInsightsMetricNames().then((results: any) => { expect(results.length).toBe(2); expect(results[0].text).toBe('exceptions/server'); expect(results[0].value).toBe('exceptions/server'); @@ -427,7 +428,7 @@ describe('AppInsightsDatasource', () => { }); it('should return a list of group bys', () => { - return ctx.ds.getAppInsightsMetricMetadata('requests/count').then(results => { + return ctx.ds.getAppInsightsMetricMetadata('requests/count').then((results: any) => { expect(results.primaryAggType).toEqual('avg'); expect(results.supportedAggTypes).toContain('avg'); expect(results.supportedAggTypes).toContain('sum'); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts index 696baca9352..a686205431a 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/app_insights/app_insights_datasource.ts @@ -6,6 +6,7 @@ import { DataSourceInstanceSettings } from '@grafana/ui'; import { AzureDataSourceJsonData } from '../types'; import { BackendSrv } from 'app/core/services/backend_srv'; import { TemplateSrv } from 'app/features/templating/template_srv'; +import { IQService } from 'angular'; export interface LogAnalyticsColumn { text: string; @@ -24,7 +25,7 @@ export default class AppInsightsDatasource { instanceSettings: DataSourceInstanceSettings, private backendSrv: BackendSrv, private templateSrv: TemplateSrv, - private $q + private $q: IQService ) { this.id = instanceSettings.id; this.applicationId = instanceSettings.jsonData.appInsightsAppId; @@ -36,7 +37,7 @@ export default class AppInsightsDatasource { return !!this.applicationId && this.applicationId.length > 0; } - query(options) { + query(options: any) { const queries = _.filter(options.targets, item => { return item.hide !== true; }).map(target => { @@ -106,6 +107,7 @@ export default class AppInsightsDatasource { }); if (!queries || queries.length === 0) { + // @ts-ignore return; } @@ -130,16 +132,16 @@ export default class AppInsightsDatasource { }); } - doQueries(queries) { + doQueries(queries: any) { return _.map(queries, query => { return this.doRequest(query.url) - .then(result => { + .then((result: any) => { return { result: result, query: query, }; }) - .catch(err => { + .catch((err: any) => { throw { error: err, query: query, @@ -148,7 +150,7 @@ export default class AppInsightsDatasource { }); } - annotationQuery(options) {} + annotationQuery(options: any) {} metricFindQuery(query: string) { const appInsightsMetricNameQuery = query.match(/^AppInsightsMetricNames\(\)/i); @@ -168,7 +170,7 @@ export default class AppInsightsDatasource { testDatasource() { const url = `${this.baseUrl}/metrics/metadata`; return this.doRequest(url) - .then(response => { + .then((response: any) => { if (response.status === 200) { return { status: 'success', @@ -182,7 +184,7 @@ export default class AppInsightsDatasource { message: 'Returned http status code ' + response.status, }; }) - .catch(error => { + .catch((error: any) => { let message = 'Application Insights: '; message += error.statusText ? error.statusText + ': ' : ''; @@ -201,13 +203,13 @@ export default class AppInsightsDatasource { }); } - doRequest(url, maxRetries = 1) { + doRequest(url: any, maxRetries = 1) { return this.backendSrv .datasourceRequest({ url: this.url + url, method: 'GET', }) - .catch(error => { + .catch((error: any) => { if (maxRetries > 0) { return this.doRequest(url, maxRetries - 1); } @@ -223,20 +225,20 @@ export default class AppInsightsDatasource { getMetricMetadata(metricName: string) { const url = `${this.baseUrl}/metrics/metadata`; - return this.doRequest(url).then(result => { + return this.doRequest(url).then((result: any) => { return new ResponseParser(result).parseMetadata(metricName); }); } getGroupBys(metricName: string) { - return this.getMetricMetadata(metricName).then(result => { + return this.getMetricMetadata(metricName).then((result: any) => { return new ResponseParser(result).parseGroupBys(); }); } getQuerySchema() { const url = `${this.baseUrl}/query/schema`; - return this.doRequest(url).then(result => { + return this.doRequest(url).then((result: any) => { const schema = new ResponseParser(result).parseQuerySchema(); // console.log(schema); return schema; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/__mocks__/schema.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/__mocks__/schema.ts index 01b77a894ad..e9f233f5209 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/__mocks__/schema.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/__mocks__/schema.ts @@ -162,7 +162,7 @@ export default class FakeSchemaData { }; } - static getlogAnalyticsFakeMetadata() { + static getlogAnalyticsFakeMetadata(): any { return { tables: [ { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/supported_namespaces.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/supported_namespaces.ts index c454a309fa2..12149778223 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/supported_namespaces.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/supported_namespaces.ts @@ -1,5 +1,5 @@ export default class SupportedNamespaces { - supportedMetricNamespaces = { + supportedMetricNamespaces: any = { azuremonitor: [ 'Microsoft.AnalysisServices/servers', 'Microsoft.ApiManagement/service', diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/KustoQueryField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/KustoQueryField.tsx index c49718056af..d3052691acc 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/KustoQueryField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/editor/KustoQueryField.tsx @@ -43,7 +43,7 @@ const defaultSchema: any = () => ({ }, }); -const cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim(); +const cleanText = (s: string) => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim(); const wrapText = (text: string) => ({ text }); export default class KustoQueryField extends QueryField { @@ -353,11 +353,13 @@ export default class KustoQueryField extends QueryField { } getTableSuggestions(db = 'Default'): SuggestionGroup[] { + // @ts-ignore if (this.schema.Databases[db]) { return [ { prefixMatch: true, label: 'Tables', + // @ts-ignore items: _.map(this.schema.Databases[db].Tables, (t: any) => ({ text: t.Name })), }, ]; diff --git a/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts b/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts index 1e0da604160..5a6beb22d3e 100644 --- a/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts +++ b/public/app/plugins/datasource/graphite/specs/graphite_query.test.ts @@ -10,6 +10,7 @@ describe('Graphite query model', () => { waitForFuncDefsLoaded: jest.fn().mockReturnValue(Promise.resolve(null)), createFuncInstance: gfunc.createFuncInstance, }, + // @ts-ignore templateSrv: new TemplateSrvStub(), targets: [], }; diff --git a/public/app/plugins/datasource/loki/language_provider.test.ts b/public/app/plugins/datasource/loki/language_provider.test.ts index 986f5335821..fd4a84d360e 100644 --- a/public/app/plugins/datasource/loki/language_provider.test.ts +++ b/public/app/plugins/datasource/loki/language_provider.test.ts @@ -111,7 +111,7 @@ describe('Request URL', () => { }; const datasourceWithLabels = { - metadataRequest: url => { + metadataRequest: (url: string) => { if (url.slice(0, 15) === '/api/prom/label') { return { data: { data: ['other'] } }; } else { @@ -154,7 +154,7 @@ describe('Query imports', () => { it('returns empty query from selector query if label is not available', async () => { const datasourceWithLabels = { - metadataRequest: url => + metadataRequest: (url: string) => url.slice(0, 15) === '/api/prom/label' ? { data: { data: ['other'] } } : { data: { data: [] as DataQueryResponseData[] } }, @@ -166,7 +166,7 @@ describe('Query imports', () => { it('returns selector query from selector query with common labels', async () => { const datasourceWithLabels = { - metadataRequest: url => + metadataRequest: (url: string) => url.slice(0, 15) === '/api/prom/label' ? { data: { data: ['foo'] } } : { data: { data: [] as DataQueryResponseData[] } }, @@ -178,7 +178,7 @@ describe('Query imports', () => { it('returns selector query from selector query with all labels if logging label list is empty', async () => { const datasourceWithLabels = { - metadataRequest: url => + metadataRequest: (url: string) => url.slice(0, 15) === '/api/prom/label' ? { data: { data: [] as DataQueryResponseData[] } } : { data: { data: [] as DataQueryResponseData[] } }, diff --git a/scripts/ci-frontend-metrics.sh b/scripts/ci-frontend-metrics.sh index c29aef0d3a1..93bb05c3984 100755 --- a/scripts/ci-frontend-metrics.sh +++ b/scripts/ci-frontend-metrics.sh @@ -3,7 +3,7 @@ echo -e "Collecting code stats (typescript errors & more)" -ERROR_COUNT_LIMIT=2350 +ERROR_COUNT_LIMIT=1670 DIRECTIVES_LIMIT=172 CONTROLLERS_LIMIT=139 From 743f8420bcdbe057cbc685715b50d06b6ca78449 Mon Sep 17 00:00:00 2001 From: Andrej Ocenas Date: Thu, 11 Jul 2019 18:13:01 +0200 Subject: [PATCH 4/6] devenv: Fix typo in nginix docker for mac (#18068) --- devenv/docker/blocks/nginx_proxy_mac/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devenv/docker/blocks/nginx_proxy_mac/docker-compose.yaml b/devenv/docker/blocks/nginx_proxy_mac/docker-compose.yaml index f60a6722fda..a19b3e3faa3 100644 --- a/devenv/docker/blocks/nginx_proxy_mac/docker-compose.yaml +++ b/devenv/docker/blocks/nginx_proxy_mac/docker-compose.yaml @@ -5,7 +5,7 @@ # root_url = %(protocol)s://%(domain)s:10080/grafana/ nginxproxy: - build: docker/blocks/nginx_proxy + build: docker/blocks/nginx_proxy_mac ports: - "10080:10080" From 1cbec50866eeed20ff1cecb41b9a25d18ea02a25 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Thu, 11 Jul 2019 21:55:35 +0300 Subject: [PATCH 5/6] Build: consistently reference go binary (#18059) Before this applied, go binary is referenced inconsistently in makefile. Sometimes with go modules enabled and sometimes not, sometimes through a variable and sometimes not. This change makes all the references in makefile consistent --- Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9347d8647b9..0557dbd378f 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ GO_FILES := ./pkg/... all: deps build deps-go: - go run build.go setup + $(GO) run build.go setup deps-js: node_modules @@ -16,15 +16,15 @@ deps: deps-js build-go: @echo "build go files" - GO111MODULE=on go run build.go build + $(GO) run build.go build build-server: @echo "build server" - GO111MODULE=on go run build.go build-server + $(GO) run build.go build-server build-cli: @echo "build in CI environment" - GO111MODULE=on go run build.go build-cli + $(GO) run build.go build-cli build-js: @echo "build frontend" @@ -35,7 +35,7 @@ build: build-go build-js build-docker-dev: @echo "build development container" @echo "\033[92mInfo:\033[0m the frontend code is expected to be built already." - GO111MODULE=on go run build.go -goos linux -pkg-arch amd64 ${OPT} build pkg-archive latest + $(GO) run build.go -goos linux -pkg-arch amd64 ${OPT} build pkg-archive latest cp dist/grafana-latest.linux-x64.tar.gz packaging/docker cd packaging/docker && docker build --tag grafana/grafana:dev . @@ -45,7 +45,7 @@ build-docker-full: test-go: @echo "test backend" - GO111MODULE=on go test -v ./pkg/... + $(GO) test -v ./pkg/... test-js: @echo "test frontend" @@ -107,7 +107,7 @@ golangci-lint: scripts/go/bin/golangci-lint go-vet: @echo "lint via go vet" - @go vet $(GO_FILES) + @$(GO) vet $(GO_FILES) lint-go: go-vet golangci-lint revive revive-alerting gosec From ca628832ab913f0a79928a37b8204aa4e19a244e Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Fri, 12 Jul 2019 01:25:38 -0700 Subject: [PATCH 6/6] grafana/toolkit: improve CircleCI integration (#18071) * don't actually install grafana in the setup step * updat eversion changes * add report stage * update versions * don't do failing test * upate version * print plugins * update versions * copy docs * Update package.json --- lerna.json | 2 +- packages/grafana-data/package.json | 2 +- packages/grafana-runtime/package.json | 2 +- packages/grafana-toolkit/package.json | 2 +- packages/grafana-toolkit/src/cli/index.ts | 33 ++- .../src/cli/tasks/plugin.ci.ts | 244 +++++++++--------- packages/grafana-ui/package.json | 2 +- 7 files changed, 149 insertions(+), 138 deletions(-) diff --git a/lerna.json b/lerna.json index 1fa5994e34f..f72b0b06cd2 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "npmClient": "yarn", "useWorkspaces": true, "packages": ["packages/*"], - "version": "6.4.0-alpha.6" + "version": "6.4.0-alpha.12" } diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index 73bbc12c020..7163c62f4f9 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -1,6 +1,6 @@ { "name": "@grafana/data", - "version": "6.4.0-alpha.2", + "version": "6.4.0-alpha.12", "description": "Grafana Data Library", "keywords": [ "typescript" diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 7905da52922..d3ef30c938f 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -1,6 +1,6 @@ { "name": "@grafana/runtime", - "version": "6.4.0-alpha.2", + "version": "6.4.0-alpha.12", "description": "Grafana Runtime Library", "keywords": [ "grafana" diff --git a/packages/grafana-toolkit/package.json b/packages/grafana-toolkit/package.json index 78f8438ba56..d28e3b4d41f 100644 --- a/packages/grafana-toolkit/package.json +++ b/packages/grafana-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@grafana/toolkit", - "version": "6.4.0-alpha.6", + "version": "6.4.0-alpha.12", "description": "Grafana Toolkit", "keywords": [ "grafana", diff --git a/packages/grafana-toolkit/src/cli/index.ts b/packages/grafana-toolkit/src/cli/index.ts index ab9efadae40..a8997eba5cb 100644 --- a/packages/grafana-toolkit/src/cli/index.ts +++ b/packages/grafana-toolkit/src/cli/index.ts @@ -15,10 +15,11 @@ import { closeMilestoneTask } from './tasks/closeMilestone'; import { pluginDevTask } from './tasks/plugin.dev'; import { ciBuildPluginTask, + ciBuildPluginDocsTask, ciBundlePluginTask, ciTestPluginTask, + ciPluginReportTask, ciDeployPluginTask, - ciSetupPluginTask, } from './tasks/plugin.ci'; import { buildPackageTask } from './tasks/package.build'; @@ -148,14 +149,21 @@ export const run = (includeInternalScripts = false) => { program .command('plugin:ci-build') - .option('--platform ', 'For backend task, which backend to run') + .option('--backend ', 'For backend task, which backend to run') .description('Build the plugin, leaving artifacts in /dist') .action(async cmd => { await execTask(ciBuildPluginTask)({ - platform: cmd.platform, + backend: cmd.backend, }); }); + program + .command('plugin:ci-docs') + .description('Build the HTML docs') + .action(async cmd => { + await execTask(ciBuildPluginDocsTask)({}); + }); + program .command('plugin:ci-bundle') .description('Create a zip artifact for the plugin') @@ -163,24 +171,23 @@ export const run = (includeInternalScripts = false) => { await execTask(ciBundlePluginTask)({}); }); - program - .command('plugin:ci-setup') - .option('--installer ', 'Name of installer to download and run') - .description('Install and configure grafana') - .action(async cmd => { - await execTask(ciSetupPluginTask)({ - installer: cmd.installer, - }); - }); program .command('plugin:ci-test') + .option('--full', 'run all the tests (even stuff that will break)') .description('end-to-end test using bundle in /artifacts') .action(async cmd => { await execTask(ciTestPluginTask)({ - platform: cmd.platform, + full: cmd.full, }); }); + program + .command('plugin:ci-report') + .description('Build a report for this whole process') + .action(async cmd => { + await execTask(ciPluginReportTask)({}); + }); + program .command('plugin:ci-deploy') .description('Publish plugin CI results') diff --git a/packages/grafana-toolkit/src/cli/tasks/plugin.ci.ts b/packages/grafana-toolkit/src/cli/tasks/plugin.ci.ts index 71cbe4eb20d..85f4313aa60 100644 --- a/packages/grafana-toolkit/src/cli/tasks/plugin.ci.ts +++ b/packages/grafana-toolkit/src/cli/tasks/plugin.ci.ts @@ -9,8 +9,8 @@ import path = require('path'); import fs = require('fs'); export interface PluginCIOptions { - platform?: string; - installer?: string; + backend?: string; + full?: boolean; } const calcJavascriptSize = (base: string, files?: string[]): number => { @@ -48,32 +48,6 @@ const getJobFromProcessArgv = () => { return 'unknown_job'; }; -// /** -// * Like cp -rn... BUT error if an destination file exists -// */ -// async function copyDirErrorIfExists(src:string,dest:string) { -// const entries = await fs.readdirSync(src,{withFileTypes:true}); -// if(!fs.existsSync(dest)) { -// fs.mkdirSync(dest); -// } -// console.log( 'DIR', src ); -// for(let entry of entries) { -// const srcPath = path.join(src,entry.name); -// const destPath = path.join(dest,entry.name); -// if(entry.isDirectory()) { -// await copyDirErrorIfExists(srcPath,destPath); -// } else if(fs.existsSync(destPath)) { -// console.log( 'XXXXXXXXXXXXXXX', destPath ); -// console.log( 'XXXXXXXXXXXXXXX', destPath ); -// throw new Error('Duplicate entry: '+destPath); -// } -// else { -// // console.log( 'COPY', destPath ); -// await fs.copyFileSync(srcPath,destPath); -// } -// } -// } - const job = process.env.CIRCLE_JOB || getJobFromProcessArgv(); const getJobFolder = () => { @@ -117,17 +91,17 @@ const writeJobStats = (startTime: number, workDir: string) => { * Anything that should be put into the final zip file should be put in: * ~/work/build_xxx/dist */ -const buildPluginRunner: TaskRunner = async ({ platform }) => { +const buildPluginRunner: TaskRunner = async ({ backend }) => { const start = Date.now(); const workDir = getJobFolder(); await execa('rimraf', [workDir]); fs.mkdirSync(workDir); - if (platform) { + if (backend) { console.log('TODO, backend support?'); fs.mkdirSync(path.resolve(process.cwd(), 'dist')); - const file = path.resolve(process.cwd(), 'dist', `README_${platform}.txt`); - fs.writeFile(file, `TODO... build ${platform}!`, err => { + const file = path.resolve(process.cwd(), 'dist', `README_${backend}.txt`); + fs.writeFile(file, `TODO... build bakend plugin: ${backend}!`, err => { if (err) { throw new Error('Unable to write: ' + file); } @@ -149,6 +123,40 @@ const buildPluginRunner: TaskRunner = async ({ platform }) => { export const ciBuildPluginTask = new Task('Build Plugin', buildPluginRunner); +/** + * 2. Build Docs + * + * Take /docs/* and format it into /ci/docs/HTML site + * + */ +const buildPluginDocsRunner: TaskRunner = async () => { + const docsSrc = path.resolve(process.cwd(), 'docs'); + if (!fs.existsSync(docsSrc)) { + throw new Error('Docs folder does not exist!'); + } + + const start = Date.now(); + const workDir = getJobFolder(); + await execa('rimraf', [workDir]); + fs.mkdirSync(workDir); + + const docsDest = path.resolve(process.cwd(), 'ci', 'docs'); + fs.mkdirSync(docsDest); + + const exe = await execa('cp', ['-rv', docsSrc + '/.', docsDest]); + console.log(exe.stdout); + + fs.writeFile(path.resolve(docsDest, 'index.html'), `TODO... actually build docs`, err => { + if (err) { + throw new Error('Unable to docs'); + } + }); + + writeJobStats(start, workDir); +}; + +export const ciBuildPluginDocsTask = new Task('Build Plugin Docs', buildPluginDocsRunner); + /** * 2. BUNDLE * @@ -163,6 +171,7 @@ const bundlePluginRunner: TaskRunner = async () => { const ciDir = getCiFolder(); const artifactsDir = path.resolve(ciDir, 'artifacts'); const distDir = path.resolve(ciDir, 'dist'); + const docsDir = path.resolve(ciDir, 'docs'); const grafanaEnvDir = path.resolve(ciDir, 'grafana-test-env'); await execa('rimraf', [artifactsDir, distDir, grafanaEnvDir]); fs.mkdirSync(artifactsDir); @@ -192,8 +201,8 @@ const bundlePluginRunner: TaskRunner = async () => { console.log('Building ZIP'); const pluginInfo = getPluginJson(`${distDir}/plugin.json`); - const zipName = pluginInfo.id + '-' + pluginInfo.info.version + '.zip'; - const zipFile = path.resolve(artifactsDir, zipName); + let zipName = pluginInfo.id + '-' + pluginInfo.info.version + '.zip'; + let zipFile = path.resolve(artifactsDir, zipName); process.chdir(distDir); await execa('zip', ['-r', zipFile, '.']); restoreCwd(); @@ -202,21 +211,49 @@ const bundlePluginRunner: TaskRunner = async () => { if (zipStats.size < 100) { throw new Error('Invalid zip file: ' + zipFile); } - let sha1 = undefined; + + const zipInfo: any = { + name: zipName, + size: zipStats.size, + }; + const info: any = { + plugin: zipInfo, + }; try { const exe = await execa('shasum', [zipFile]); const idx = exe.stdout.indexOf(' '); - sha1 = exe.stdout.substring(0, idx); + const sha1 = exe.stdout.substring(0, idx); fs.writeFile(zipFile + '.sha1', sha1, err => {}); + zipInfo.sha1 = sha1; } catch { console.warn('Unable to read SHA1 Checksum'); } - const info = { - name: zipName, - sha1, - size: zipStats.size, - }; + // If docs exist, zip them into artifacts + if (fs.existsSync(docsDir)) { + zipName = pluginInfo.id + '-' + pluginInfo.info.version + '-docs.zip'; + zipFile = path.resolve(artifactsDir, zipName); + process.chdir(docsDir); + await execa('zip', ['-r', zipFile, '.']); + restoreCwd(); + + const zipStats = fs.statSync(zipFile); + const zipInfo: any = { + name: zipName, + size: zipStats.size, + }; + try { + const exe = await execa('shasum', [zipFile]); + const idx = exe.stdout.indexOf(' '); + const sha1 = exe.stdout.substring(0, idx); + fs.writeFile(zipFile + '.sha1', sha1, err => {}); + zipInfo.sha1 = sha1; + } catch { + console.warn('Unable to read SHA1 Checksum'); + } + info.docs = zipInfo; + } + let p = path.resolve(artifactsDir, 'info.json'); fs.writeFile(p, JSON.stringify(info, null, 2), err => { if (err) { @@ -248,66 +285,15 @@ const bundlePluginRunner: TaskRunner = async () => { export const ciBundlePluginTask = new Task('Bundle Plugin', bundlePluginRunner); /** - * 3. Setup (install grafana and setup provisioning) + * 3. Test (end-to-end) * * deploy the zip to a running grafana instance * */ -const setupPluginRunner: TaskRunner = async ({ installer }) => { - const start = Date.now(); - - if (!installer) { - throw new Error('Missing installer path'); - } - - // Download the grafana installer - const installDir = path.resolve(process.cwd(), '.installer'); - const installFile = path.resolve(installDir, installer); - if (!fs.existsSync(installFile)) { - if (!fs.existsSync(installDir)) { - fs.mkdirSync(installDir); - } - console.log('download', installer); - const exe = await execa('wget', ['-O', installFile, 'https://dl.grafana.com/oss/release/' + installer]); - console.log(exe.stdout); - } - - console.log('Install Grafana'); - let exe = await execa('sudo', ['apt-get', 'install', '-y', 'adduser', 'libfontconfig1']); - exe = await execa('sudo', ['dpkg', '-i', installFile]); - console.log(exe.stdout); - - const customIniFile = path.resolve(getCiFolder(), 'grafana-test-env', 'custom.ini'); - const configDir = '/usr/share/grafana/conf/'; - exe = await execa('sudo', ['cp', '-f', customIniFile, configDir]); - console.log(exe.stdout); - - // sudo service grafana-server start - console.log('Starting Grafana'); - exe = await execa('sudo', ['service', 'grafana-server', 'start']); - console.log(exe.stdout); - // exe = await execa('grafana-cli', ['--version', '--homepath', '/usr/share/grafana']); - // console.log(exe.stdout); - // exe = await execa('grafana-cli', ['plugins', 'ls', '--homepath', '/usr/share/grafana']); - // console.log(exe.stdout); - - const dir = getJobFolder() + '_setup'; - await execa('rimraf', [dir]); - fs.mkdirSync(dir); - writeJobStats(start, dir); -}; - -export const ciSetupPluginTask = new Task('Setup Grafana', setupPluginRunner); - -/** - * 4. Test (end-to-end) - * - * deploy the zip to a running grafana instance - * - */ -const testPluginRunner: TaskRunner = async ({ platform }) => { +const testPluginRunner: TaskRunner = async ({ full }) => { const start = Date.now(); const workDir = getJobFolder(); + const pluginInfo = getPluginJson(`${process.cwd()}/src/plugin.json`); const args = { withCredentials: true, @@ -324,10 +310,22 @@ const testPluginRunner: TaskRunner = async ({ platform }) => { console.log('Grafana Version: ' + JSON.stringify(frontendSettings.data.buildInfo, null, 2)); - const pluginInfo = getPluginJson(`${process.cwd()}/src/plugin.json`); - const pluginSettings = await axios.get(`api/plugins/${pluginInfo.id}/settings`, args); + const allPlugins: any[] = await axios.get('api/plugins', args).data; + // for (const plugin of allPlugins) { + // if (plugin.id === pluginInfo.id) { + // console.log('------------'); + // console.log(plugin); + // console.log('------------'); + // } else { + // console.log('Plugin:', plugin.id, plugin.latestVersion); + // } + // } + console.log('PLUGINS:', allPlugins); - console.log('Plugin Info: ' + JSON.stringify(pluginSettings.data, null, 2)); + if (full) { + const pluginSettings = await axios.get(`api/plugins/${pluginInfo.id}/settings`, args); + console.log('Plugin Info: ' + JSON.stringify(pluginSettings.data, null, 2)); + } console.log('TODO puppeteer'); @@ -347,33 +345,39 @@ const testPluginRunner: TaskRunner = async ({ platform }) => { export const ciTestPluginTask = new Task('Test Plugin (e2e)', testPluginRunner); /** - * 4. Deploy + * 4. Report + * + * Create a report from all the previous steps + * + */ +const pluginReportRunner: TaskRunner = async () => { + const start = Date.now(); + const workDir = getJobFolder(); + const reportDir = path.resolve(process.cwd(), 'ci', 'report'); + await execa('rimraf', [reportDir]); + fs.mkdirSync(reportDir); + + const file = path.resolve(reportDir, `report.txt`); + fs.writeFile(file, `TODO... actually make a report (csv etc)`, err => { + if (err) { + throw new Error('Unable to write: ' + file); + } + }); + + console.log('TODO... real report'); + writeJobStats(start, workDir); +}; + +export const ciPluginReportTask = new Task('Deploy plugin', pluginReportRunner); + +/** + * 5. Deploy * * deploy the zip to a running grafana instance * */ const deployPluginRunner: TaskRunner = async () => { - const start = Date.now(); - - // TASK Time - if (process.env.CIRCLE_INTERNAL_TASK_DATA) { - const timingInfo = fs.readdirSync(`${process.env.CIRCLE_INTERNAL_TASK_DATA}`); - if (timingInfo) { - timingInfo.forEach(file => { - console.log('TIMING INFO: ', file); - }); - } - } - - const elapsed = Date.now() - start; - const stats = { - job, - sha1: `${process.env.CIRCLE_SHA1}`, - startTime: start, - buildTime: elapsed, - endTime: Date.now(), - }; - console.log('TODO DEPLOY??', stats); + console.log('TODO DEPLOY??'); console.log(' if PR => write a comment to github with difference '); console.log(' if master | vXYZ ==> upload artifacts to some repo '); }; diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 6b27f4e3bbd..884f799b5af 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -1,6 +1,6 @@ { "name": "@grafana/ui", - "version": "6.4.0-alpha.2", + "version": "6.4.0-alpha.12", "description": "Grafana Components Library", "keywords": [ "grafana",