Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efbcbb838b | ||
|
|
c4d8d0c2ae | ||
|
|
ba06f38b16 | ||
|
|
69e989ea9d | ||
|
|
b58f7741b5 | ||
|
|
d7af398341 | ||
|
|
8a752954c5 | ||
|
|
037682d63b | ||
|
|
497a194abc | ||
|
|
aef8a08d3a | ||
|
|
3d65daa587 | ||
|
|
38bb3e55f3 | ||
|
|
13579a7449 | ||
|
|
45e6acabb3 | ||
|
|
4f58ca11da | ||
|
|
3fb267fe72 | ||
|
|
cdf2fa9ff0 | ||
|
|
79126eb73b | ||
|
|
670c86246e | ||
|
|
d7aa9959a4 | ||
|
|
1ccf307efe | ||
|
|
963e3ba13e | ||
|
|
4b58a532b8 | ||
|
|
a535334c76 | ||
|
|
c9798d75cd | ||
|
|
1d962eefc7 | ||
|
|
c980a43bf7 | ||
|
|
00ee734baf | ||
|
|
f0ab81d0f6 | ||
|
|
b6865b3427 | ||
|
|
4a331327b2 | ||
|
|
8f91e148ae | ||
|
|
e2308871e0 | ||
|
|
1dbdf9b839 | ||
|
|
486ae92279 | ||
|
|
170aba2cfb | ||
|
|
81a4f4addf | ||
|
|
3e09d991fb | ||
|
|
cafb3a14ef | ||
|
|
3224f7587a | ||
|
|
9dbce49c7d | ||
|
|
7fb3d3fa62 | ||
|
|
f5233f32af | ||
|
|
ec2e951cd3 | ||
|
|
9bc12846a2 | ||
|
|
2a34acfa7b | ||
|
|
6c8e42655e | ||
|
|
731c3e918d | ||
|
|
d072718d1a | ||
|
|
fa0855ad4b | ||
|
|
d3c725e4ff | ||
|
|
7a9c0e31ec | ||
|
|
ef5b586d7d | ||
|
|
03306f1220 | ||
|
|
b6cb31a4de | ||
|
|
0b627672ba | ||
|
|
205b7685a8 | ||
|
|
c0a2aceac5 | ||
|
|
63c6284b94 | ||
|
|
bb2201c35e | ||
|
|
820d382e8f | ||
|
|
5310fe837b | ||
|
|
23a42e801f | ||
|
|
2c42ac5df9 | ||
|
|
10c9543038 | ||
|
|
40d7234d02 | ||
|
|
fa0670e734 | ||
|
|
43b65f7d67 | ||
|
|
037b6a45ca | ||
|
|
7b9650ba81 | ||
|
|
28253bb62e | ||
|
|
2fc13ac853 | ||
|
|
e929eab87c | ||
|
|
c1ab56fd8e | ||
|
|
4541dee9e1 | ||
|
|
4ac745ac55 | ||
|
|
4ba0377511 | ||
|
|
298f8b0028 | ||
|
|
fe890a0708 | ||
|
|
a930cba373 | ||
|
|
045b8629a4 | ||
|
|
3b3fbb551d | ||
|
|
9e4d9bed2a | ||
|
|
1ee5fc893c | ||
|
|
f2df0cedd4 | ||
|
|
3256fb87c5 | ||
|
|
f098b4049d | ||
|
|
21f7a9ed1e | ||
|
|
f235cd697d | ||
|
|
0b27b1fb17 | ||
|
|
2d6faa6d99 | ||
|
|
72c7731c42 | ||
|
|
cd507df860 | ||
|
|
afa9aef76a | ||
|
|
aee1438ff2 | ||
|
|
0167f43d74 | ||
|
|
2169fc1a3f | ||
|
|
ca077f31f5 | ||
|
|
2a0138d1d0 | ||
|
|
908af75083 | ||
|
|
575d898955 | ||
|
|
10bf03b221 | ||
|
|
fbd3b4b969 | ||
|
|
91824e2bfa | ||
|
|
014fc0f3f5 | ||
|
|
2422fd7e26 | ||
|
|
01b5032fbc |
1307
.circleci/config.yml
1307
.circleci/config.yml
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
load('scripts/pr.star', 'pr_pipelines')
|
||||
load('scripts/master.star', 'master_pipelines')
|
||||
load('scripts/release.star', 'release_pipelines', 'test_release_pipelines')
|
||||
load('scripts/version.star', 'version_branch_pipelines')
|
||||
|
||||
def main(ctx):
|
||||
edition = 'oss'
|
||||
return pr_pipelines(edition=edition) + master_pipelines(edition=edition) + release_pipelines() + \
|
||||
test_release_pipelines() + version_branch_pipelines()
|
||||
3328
.drone.yml
3328
.drone.yml
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,3 @@ trim_trailing_whitespace = false
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.star]
|
||||
indent_size = 4
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
node_modules
|
||||
compiled
|
||||
build
|
||||
vendor
|
||||
devenv
|
||||
data
|
||||
dist
|
||||
e2e/tmp
|
||||
22
.eslintrc
22
.eslintrc
@@ -1,24 +1,4 @@
|
||||
{
|
||||
"extends": ["@grafana/eslint-config"],
|
||||
"root": true,
|
||||
"plugins": [
|
||||
"no-only-tests"
|
||||
],
|
||||
"rules": {
|
||||
"no-only-tests/no-only-tests": "error",
|
||||
"react/prop-types": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"packages/grafana-ui/**/*/!(*.story).{ts,tsx}",
|
||||
"packages/jaeger-ui-components/**/*.{ts,tsx,js}",
|
||||
"public/app/**/*.{ts,tsx}"
|
||||
],
|
||||
"rules": {
|
||||
"react-hooks/rules-of-hooks": "off",
|
||||
"react-hooks/exhaustive-deps": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
"root": true
|
||||
}
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
52
.github/CODEOWNERS
vendored
52
.github/CODEOWNERS
vendored
@@ -12,56 +12,12 @@
|
||||
# This should make it easy to add new rules without breaking existing ones.
|
||||
|
||||
# Documentation owner: Diana Payton
|
||||
/docs/ @grafana/docs-squad
|
||||
/contribute/ @marcusolsson @grafana/docs-squad
|
||||
/docs/sources/developers/plugins/ @marcusolsson
|
||||
/docs/sources/enterprise/ @osg-grafana
|
||||
/docs/ @oddlittlebird
|
||||
/contribute/ @oddlittlebird @marcusolsson
|
||||
# @grafana/ui component documentation
|
||||
*.mdx @marcusolsson @jessover9000
|
||||
|
||||
# Backend code
|
||||
*.go @grafana/backend-platform
|
||||
go.mod @grafana/backend-platform
|
||||
go.sum @grafana/backend-platform
|
||||
|
||||
# Backend code docs
|
||||
/contribute/style-guides/backend.md @grafana/backend-platform
|
||||
|
||||
/e2e @grafana/grafana-frontend-platform
|
||||
/packages @grafana/grafana-frontend-platform
|
||||
/plugins-bundled @grafana/grafana-frontend-platform
|
||||
/public @grafana/grafana-frontend-platform
|
||||
/scripts/build/release-packages.sh @grafana/grafana-frontend-platform
|
||||
/scripts/circle-release-next-packages.sh @grafana/grafana-frontend-platform
|
||||
/scripts/ci-frontend-metrics.sh @grafana/grafana-frontend-platform
|
||||
/scripts/grunt @grafana/grafana-frontend-platform
|
||||
/scripts/webpack @grafana/grafana-frontend-platform
|
||||
package.json @grafana/grafana-frontend-platform
|
||||
tsconfig.json @grafana/grafana-frontend-platform
|
||||
lerna.json @grafana/grafana-frontend-platform
|
||||
.babelrc @grafana/grafana-frontend-platform
|
||||
.prettierrc.js @grafana/grafana-frontend-platform
|
||||
.eslintrc @grafana/grafana-frontend-platform
|
||||
|
||||
# @grafana/ui component documentation
|
||||
*.mdx @marcusolsson @jessover9000 @grafana/grafana-frontend-platform
|
||||
|
||||
/public/app/features/explore/ @grafana/observability-squad
|
||||
/packages/jaeger-ui-components/ @grafana/observability-squad
|
||||
|
||||
# Core datasources
|
||||
/public/app/plugins/datasource/cloudwatch @grafana/backend-platform @grafana/observability-squad
|
||||
/public/app/plugins/datasource/elasticsearch @grafana/observability-squad
|
||||
/public/app/plugins/datasource/grafana-azure-monitor-datasource @grafana/backend-platform
|
||||
/public/app/plugins/datasource/graphite @grafana/observability-squad
|
||||
/public/app/plugins/datasource/influxdb @grafana/observability-squad
|
||||
/public/app/plugins/datasource/jaeger @grafana/observability-squad
|
||||
/public/app/plugins/datasource/loki @grafana/observability-squad
|
||||
/public/app/plugins/datasource/mssql @grafana/backend-platform
|
||||
/public/app/plugins/datasource/mysql @grafana/backend-platform
|
||||
/public/app/plugins/datasource/opentsdb @grafana/backend-platform
|
||||
/public/app/plugins/datasource/postgres @grafana/backend-platform
|
||||
/public/app/plugins/datasource/prometheus @grafana/observability-squad
|
||||
/public/app/plugins/datasource/cloud-monitoring @grafana/backend-platform
|
||||
/public/app/plugins/datasource/zipkin @grafana/observability-squad
|
||||
|
||||
# Cloud middleware
|
||||
/grafana-mixin/ @grafana/cloud-middleware
|
||||
|
||||
10
.github/ISSUE_TEMPLATE/1-bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/1-bug_report.md
vendored
@@ -5,13 +5,9 @@ labels: 'type: bug'
|
||||
---
|
||||
|
||||
<!--
|
||||
Please use this template to create your bug report. By providing as much info as possible you help us understand the issue, reproduce it and resolve it for you quicker. Therefor take a couple of extra minutes to make sure you have provided all info needed.
|
||||
|
||||
PROTIP: record your screen and attach it as a gif to showcase the issue.
|
||||
|
||||
- Questions should be posted to: https://community.grafana.com
|
||||
- Use query inspector to troubleshoot issues: https://bit.ly/2XNF6YS
|
||||
- How to record and attach gif: https://bit.ly/2Mi8T6K
|
||||
Please use this template while reporting a bug and provide as much info as possible.
|
||||
Questions should be posted to https://community.grafana.com
|
||||
Use query inspector to troubleshoot issues: https://community.grafana.com/t/using-grafanas-query-inspector-to-troubleshoot-issues/2630
|
||||
-->
|
||||
|
||||
**What happened**:
|
||||
|
||||
39
.github/ISSUE_TEMPLATE/4-grafana_ui_component.md
vendored
39
.github/ISSUE_TEMPLATE/4-grafana_ui_component.md
vendored
@@ -1,39 +0,0 @@
|
||||
---
|
||||
name: '@grafana/ui component request'
|
||||
about: Suggest a component for the @grafana/ui package
|
||||
labels: 'area/grafana/ui'
|
||||
---
|
||||
|
||||
<!--
|
||||
By using this template you will make it easier for us to make sure that documentation and implementation stays up to date for every component in @grafana/ui
|
||||
|
||||
Thank you!
|
||||
-->
|
||||
|
||||
**Why is this component needed**:
|
||||
<!-- Explain your use case -->
|
||||
___
|
||||
- [ ] Is/could it be used in more than one place in Grafana?
|
||||
|
||||
**Where is/could it be used?**:
|
||||
|
||||
___
|
||||
- [ ] Post screenshots possible.
|
||||
- [ ] It has a single use case.
|
||||
- [ ] It is/could be used in multiple places.
|
||||
|
||||
**Implementation** (Checklist meant for the person implementing the component)
|
||||
|
||||
- [ ] Component has a story in Storybook.
|
||||
- [ ] Props and naming follows [our style guide](https://github.com/grafana/grafana/blob/master/contribute/style-guides/frontend.md).
|
||||
- [ ] It is extendable (rest props are spread, styles with className work, and so on).
|
||||
- [ ] Uses [theme for spacing, colors, and so on](https://github.com/grafana/grafana/blob/master/contribute/style-guides/themes.md).
|
||||
- [ ] Works with both light and dark theme.
|
||||
|
||||
**Documentation**
|
||||
|
||||
- [ ] Properties are documented.
|
||||
- [ ] Use cases are described.
|
||||
- [ ] Code examples for the different use cases.
|
||||
- [ ] Dos and don'ts.
|
||||
- [ ] Styling guidelines, specific color usage (if applicable).
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -22,7 +22,7 @@ Thank you for sending a pull request! Here are some tips:
|
||||
|
||||
<!--
|
||||
|
||||
- Automatically closes linked issue when the Pull Request is merged.
|
||||
* Automatically closes linked issue when the Pull Request is merged.
|
||||
|
||||
Usage: "Fixes #<issue number>", or "Fixes (paste link of issue)"
|
||||
|
||||
|
||||
7
.github/actions/gha-publish-to-git/Dockerfile
vendored
Normal file
7
.github/actions/gha-publish-to-git/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM alpine
|
||||
RUN apk update
|
||||
RUN apk add rsync git bash
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
||||
21
.github/actions/gha-publish-to-git/LICENSE
vendored
Normal file
21
.github/actions/gha-publish-to-git/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Sean Middleditch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
60
.github/actions/gha-publish-to-git/README.md
vendored
Normal file
60
.github/actions/gha-publish-to-git/README.md
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
publish-to-git
|
||||
==============
|
||||
|
||||
[GitHub Action](https://github.com/features/actions) for publishing a directory
|
||||
and its contents to another git repository.
|
||||
|
||||
This can be especially useful for publishing static website, such as with
|
||||
[GitHub Pages](https://pages.github.com/), from built files in other job
|
||||
steps, such as [Doxygen](http://www.doxygen.nl/) generated HTML files.
|
||||
|
||||
**NOTE**: GitHub currently requires the use of a Personal Access Token for
|
||||
pushing to other repositories. Pushing to the current repository should work
|
||||
with the always-available GitHub Token (available via
|
||||
`{{ secrets.GITHUB_TOKEN }}`. If pushing to another repository, a Personal
|
||||
Access Token will need to be [created](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) and assigned to the
|
||||
workflow [secrets](https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables).
|
||||
|
||||
Inputs
|
||||
------
|
||||
|
||||
- `repository`: Destination repository (default: current repository).
|
||||
- `branch`: Destination branch (required).
|
||||
- `host`: Destination git host (default: `github.com`).
|
||||
- `github_token`: GitHub Token (required; use `secrets.GITHUB_TOKEN`).
|
||||
- `github_pat`: Personal Access Token or other https credentials.
|
||||
- `source_folder`: Source folder in workspace to copy (default: workspace root).
|
||||
- `target_folder`: Target folder in destination branch to copy to (default: repository root).
|
||||
- `commit_author`: Override commit author (default: `{github.actor}@users.noreply.github.com`).
|
||||
- `commit_message`: Set commit message (default: `[workflow] Publish from [repository]:[branch]/[folder]`).
|
||||
- `dry_run`: Does not push if non-empty (default: empty).
|
||||
- `working_directory`: Location to checkout repository (default: random location in `${HOME}`)
|
||||
|
||||
Outputs
|
||||
-------
|
||||
|
||||
- `commit_hash`: SHA hash of the new commit.
|
||||
- `working_directory`: Working directory of git clone of repository.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
MIT License. See [LICENSE](LICENSE) for details.
|
||||
|
||||
Usage Example
|
||||
-------------
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
publish:
|
||||
- uses: actions/checkout@master
|
||||
- run: |
|
||||
sh scripts/build-doxygen-html.sh --out static/html
|
||||
- uses: seanmiddleditch/gha-publish-to-git@master
|
||||
with:
|
||||
branch: gh-pages
|
||||
github_token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
github_pat: '${{ secrets.GH_PAT }}'
|
||||
source_folder: static/html
|
||||
if: success() && github.event == 'push'
|
||||
```
|
||||
60
.github/actions/gha-publish-to-git/action.yml
vendored
Normal file
60
.github/actions/gha-publish-to-git/action.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
name: publish-to-git
|
||||
description: 'Publish files to a git repository'
|
||||
branding:
|
||||
icon: 'git-commit'
|
||||
color: 'blue'
|
||||
inputs:
|
||||
repository:
|
||||
description: 'Destination repository (default: current repository)'
|
||||
default: ''
|
||||
branch:
|
||||
description: 'Destination branch'
|
||||
required: true
|
||||
host:
|
||||
description: 'Destination git host'
|
||||
default: 'github.com'
|
||||
github_token:
|
||||
description: 'GitHub Token (use `secrets.GITHUB_TOKEN`)'
|
||||
required: true
|
||||
github_pat:
|
||||
description: 'Personal Access Token or other https credentials'
|
||||
default: ''
|
||||
source_folder:
|
||||
description: 'Source folder in workspace to copy (default: workspace root)'
|
||||
defaault: ''
|
||||
target_folder:
|
||||
description: 'Target folder in destination branch to copy to (default: repository root)'
|
||||
default: ''
|
||||
commit_author:
|
||||
description: 'User Name <email@address> (default: [github.actor]@users.noreply.github.com)'
|
||||
default: ''
|
||||
commit_message:
|
||||
description: 'Commit message (default: [workflow] Publish from [repository]:[branch]/[folder])'
|
||||
default: ''
|
||||
dry_run:
|
||||
description: 'Do not push to repository (set to non-empty string to make dry-run)'
|
||||
default: ''
|
||||
working_directory:
|
||||
description: 'Working directory for clone (default: random location in `${HOME}`)'
|
||||
default: ''
|
||||
outputs:
|
||||
commit_hash:
|
||||
description: 'Hash of the new commit'
|
||||
working_directory:
|
||||
description: 'Working directory of temporary repository'
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'Dockerfile'
|
||||
args:
|
||||
- ${{ inputs.repository }}
|
||||
- ${{ inputs.branch }}
|
||||
- ${{ inputs.host }}
|
||||
- ${{ inputs.github_token }}
|
||||
- ${{ inputs.github_pat }}
|
||||
- ${{ inputs.source_folder }}
|
||||
- ${{ inputs.target_folder }}
|
||||
- ${{ inputs.commit_author }}
|
||||
- ${{ inputs.commit_message }}
|
||||
- ${{ inputs.dry_run }}
|
||||
- ${{ inputs.working_directory }}
|
||||
99
.github/actions/gha-publish-to-git/entrypoint.sh
vendored
Normal file
99
.github/actions/gha-publish-to-git/entrypoint.sh
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
#/bin/bash
|
||||
|
||||
# Name the Docker inputs.
|
||||
#
|
||||
INPUT_REPOSITORY="$1"
|
||||
INPUT_BRANCH="$2"
|
||||
INPUT_HOST="$3"
|
||||
INPUT_GITHUB_TOKEN="$4"
|
||||
INPUT_GITHUB_PAT="$5"
|
||||
INPUT_SOURCE_FOLDER="$6"
|
||||
INPUT_TARGET_FOLDER="$7"
|
||||
INPUT_COMMIT_AUTHOR="$8"
|
||||
INPUT_COMMIT_MESSAGE="$9"
|
||||
INPUT_DRYRUN="${10}"
|
||||
INPUT_WORKDIR="${11}"
|
||||
|
||||
# Check for required inputs.
|
||||
#
|
||||
[ -z "$INPUT_BRANCH" ] && echo >&2 "::error::'branch' is required" && exit 1
|
||||
[ -z "$INPUT_GITHUB_TOKEN" -a -z "$INPUT_GITHUB_PAT" ] && echo >&2 "::error::'github_token' or 'github_pat' is required" && exit 1
|
||||
|
||||
# Set state from inputs or defaults.
|
||||
#
|
||||
REPOSITORY="${INPUT_REPOSITORY:-${GITHUB_REPOSITORY}}"
|
||||
BRANCH="${INPUT_BRANCH}"
|
||||
HOST="${INPUT_GIT_HOST:-github.com}"
|
||||
TOKEN="${INPUT_GITHUB_PAT:-${INPUT_GITHUB_TOKEN}}"
|
||||
REMOTE="${INPUT_REMOTE:-https://${TOKEN}@${HOST}/${REPOSITORY}.git}"
|
||||
|
||||
SOURCE_FOLDER="${INPUT_SOURCE_FOLDER:-.}"
|
||||
TARGET_FOLDER="${INPUT_TARGET_FOLDER}"
|
||||
|
||||
REF="${GITHUB_BASE_REF:-${GITHUB_REF}}"
|
||||
REF_BRANCH=$(echo "${REF}" | rev | cut -d/ -f1 | rev)
|
||||
[ -z "$REF_BRANCH" ] && echo 2>&1 "No ref branch" && exit 1
|
||||
|
||||
COMMIT_AUTHOR="${INPUT_AUTHOR:-${GITHUB_ACTOR} <${GITHUB_ACTOR}@users.noreply.github.com>}"
|
||||
COMMIT_MESSAGE="${INPUT_COMMIT_MESSAGE:-[${GITHUB_WORKFLOW}] Publish from ${GITHUB_REPOSITORY}:${REF_BRANCH}/${SOURCE_FOLDER}}"
|
||||
|
||||
# Calculate the real source path.
|
||||
#
|
||||
SOURCE_PATH="$(realpath "${SOURCE_FOLDER}")"
|
||||
[ -z "${SOURCE_PATH}" ] && exit 1
|
||||
echo "::debug::SOURCE_PATH=${SOURCE_PATH}"
|
||||
|
||||
# Let's start doing stuff.
|
||||
echo "Publishing ${SOURCE_FOLDER} to ${REMOTE}:${BRANCH}/${TARGET_FOLDER}"
|
||||
|
||||
# Create a working directory; the workspace may be filled with other important
|
||||
# files.
|
||||
#
|
||||
WORK_DIR="${INPUT_WORKDIR:-$(mktemp -d "${HOME}/gitrepo.XXXXXX")}"
|
||||
[ -z "${WORK_DIR}" ] && echo >&2 "::error::Failed to create temporary working directory" && exit 1
|
||||
cd "${WORK_DIR}"
|
||||
|
||||
# Initialize git repo and configure for remote access.
|
||||
#
|
||||
echo "Initializing repository with remote ${REMOTE}"
|
||||
git init || exit 1
|
||||
git config --local user.email "${GITHUB_ACTOR}@users.noreply.github.com" || exit 1
|
||||
git config --local user.name "${GITHUB_ACTOR}" || exit 1
|
||||
git remote add origin "${REMOTE}" || exit 1
|
||||
git remote -v
|
||||
|
||||
# Fetch initial (current contents).
|
||||
#
|
||||
echo "Fetching ${REMOTE}:${BRANCH}"
|
||||
git fetch --depth 1 origin "${BRANCH}" || exit 1
|
||||
git checkout -b "${BRANCH}" || exit 1
|
||||
git pull origin "${BRANCH}" || exit 1
|
||||
|
||||
# Create the target directory (if necessary) and copy files from source.
|
||||
#
|
||||
TARGET_PATH="${WORK_DIR}/${TARGET_FOLDER}"
|
||||
echo "Populating ${TARGET_PATH}"
|
||||
mkdir -p "${TARGET_PATH}" || exit 1
|
||||
rsync -a --quiet --delete "${SOURCE_PATH}/" "${TARGET_PATH}" || exit 1
|
||||
|
||||
# Create commit with changes.
|
||||
#
|
||||
echo "Creating commit"
|
||||
git add "${TARGET_PATH}" || exit 1
|
||||
git commit -m "${COMMIT_MESSAGE}" --author "${COMMIT_AUTHOR}" || exit 1
|
||||
COMMIT_HASH="$(git rev-parse HEAD)"
|
||||
echo "Created commit ${COMMIT_HASH}"
|
||||
|
||||
# Publish output variables.
|
||||
#
|
||||
echo "::set-output name=commit_hash::${COMMIT_HASH}"
|
||||
echo "::set-output name=working_directory::${WORK_DIR}"
|
||||
|
||||
# Push if not a dry-run.
|
||||
#
|
||||
if [ -z "${INPUT_DRYRUN}" ] ; then
|
||||
echo "Pushing to ${REMOTE}:${BRANCH}"
|
||||
git push origin "${BRANCH}" || exit 1
|
||||
else
|
||||
echo "[DRY-RUN] Not pushing to ${REMOTE}:${BRANCH}"
|
||||
fi
|
||||
30
.github/bot.md
vendored
30
.github/bot.md
vendored
@@ -1,30 +0,0 @@
|
||||
# GitHub & grafanabot automation
|
||||
|
||||
The bot is configured via [commands.json](https://github.com/grafana/grafana/blob/master/.github/commands.json) and some other GitHub workflows [workflows](https://github.com/grafana/grafana/tree/master/.github/workflows).
|
||||
|
||||
Comment commands:
|
||||
|
||||
* Write the word `/duplicate #<number>` anywhere in a comment and the bot will add the correct label and standard message.
|
||||
* Write the word `/needsMoreInfo` anywhere in a comment and the bot will add the correct label and standard message.
|
||||
|
||||
Label commands:
|
||||
|
||||
* Add label `bot/question` the the bot will close with standard question message and add label `type/question`
|
||||
* Add label `bot/duplicate` the the bot will close with standard duplicate message and add label `type/duplicate`
|
||||
* Add label `bot/needs more info` for bot to request more info (or use comment command mentioned above)
|
||||
* Add label `bot/close feature request` for bot to close a feature request with standard message and adds label `not implemented`
|
||||
* Add label `bot/no new info` for bot to close an issue where we asked for more info but has not received any updates in at least 14 days.
|
||||
|
||||
## Metrics
|
||||
|
||||
Metrics are configured in [metrics-collector.json](https://github.com/grafana/grafana/blob/master/.github/metrics-collector.json) and are also defined in the
|
||||
[metrics-collector](https://github.com/grafana/grafana-github-actions/blob/main/metrics-collector/index.ts) GitHub action.
|
||||
|
||||
## Backport PR
|
||||
|
||||
To automatically backport a PR to a release branch like v7.3.x add a label named `backport v7.3.x`. The label name should follow the pattern `backport <branch-name>`. Once merged grafanabot will automatically
|
||||
try to cherry-pick the PR merge commit into that branch and open a PR. It will sync the milestone with the source PR so make sure the source PR also is assigned the milestone for the patch release. If the PR is already merged you can still add this label and trigger the backport automation.
|
||||
|
||||
If there are merge conflicts the bot will write a comment on the source PR saying the cherry-pick failed. In this case you have to do the cherry pick and backport PR manually.
|
||||
|
||||
The backport logic is written [here](https://github.com/grafana/grafana-github-actions/blob/main/backport/backport.ts)
|
||||
53
.github/commands.json
vendored
53
.github/commands.json
vendored
@@ -1,53 +0,0 @@
|
||||
[
|
||||
{
|
||||
"type": "label",
|
||||
"name": "bot/question",
|
||||
"addLabel": "type/question",
|
||||
"removeLabel": "bot/question",
|
||||
"action": "close",
|
||||
"comment": "Please ask your question on [community.grafana.com/](https://community.grafana.com/). To avoid having your issue closed in the future, please read our [CONTRIBUTING](https://github.com/grafana/grafana/blob/master/CONTRIBUTING.md) guidelines.\n\nHappy graphing!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "duplicate",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "type/duplicate"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "bot/duplicate",
|
||||
"addLabel": "type/duplicate",
|
||||
"removeLabel": "bot/duplicate",
|
||||
"action": "close",
|
||||
"comment": "Thanks for creating this issue! It looks like this has already been reported by another user. We’ve closed this in favor of the existing one. Please consider adding any details you think is missing to that issue.\n\nTo avoid having your issue closed in the future, please read our [CONTRIBUTING](https://github.com/grafana/grafana/blob/master/CONTRIBUTING.md) guidelines.\n\nHappy graphing!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "needsMoreInfo",
|
||||
"allowUsers": [],
|
||||
"action": "updateLabels",
|
||||
"addLabel": "bot/needs more info"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "bot/needs more info",
|
||||
"action": "updateLabels",
|
||||
"addLabel": "needs more info",
|
||||
"removeLabel": "bot/needs more info",
|
||||
"comment": "Thanks for creating this issue! We think it's missing some basic information. \r\n\r\nFollow the issue template and add additional information that will help us replicate the problem. \r\nFor data visualization issues: \r\n- Query results from the inspect drawer (data tab & query inspector)\r\n- Panel settings can be extracted in the panel inspect drawer JSON tab\r\n\r\nFor dashboard related issues: \r\n- Dashboard JSON can be found in the dashboard settings JSON model view\r\n\r\nFor authentication and alerting issues, Grafana server logs are useful. \r\n\r\nHappy graphing!"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "bot/no new info",
|
||||
"action": "close",
|
||||
"comment": "We've closed this issue since it needs more information and hasn't had any activity recently. We can re-open it after you you add more information. To avoid having your issue closed in the future, please read our [CONTRIBUTING](https://github.com/grafana/grafana/blob/master/CONTRIBUTING.md) guidelines.\n\nHappy graphing!"
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "bot/close feature request",
|
||||
"action": "close",
|
||||
"addLabel": "not implemented",
|
||||
"comment": "This feature request has been open for a long time with few received upvotes or comments, so we are closing it. We're trying to limit open GitHub issues in order to better track planned work and features. \r\n\r\nThis doesn't mean that we'll never ever implement it or that we will never accept a PR for it. A closed issue can still attract upvotes and act as a ticket to track feature demand\/interest. \r\n\r\nThank You to you for taking the time to create this issue!"
|
||||
}
|
||||
]
|
||||
10
.github/dependabot.yml
vendored
10
.github/dependabot.yml
vendored
@@ -1,10 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
32
.github/metrics-collector.json
vendored
32
.github/metrics-collector.json
vendored
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"queries": [
|
||||
{
|
||||
"name": "type_bug",
|
||||
"query": "label:\"type/bug\" is:open"
|
||||
},
|
||||
{
|
||||
"name": "type_docs",
|
||||
"query": "label:\"type/docs\" is:open"
|
||||
},
|
||||
{
|
||||
"name": "needs_investigation",
|
||||
"query": "label:\"needs investigation\" is:open"
|
||||
},
|
||||
{
|
||||
"name": "needs_more_info",
|
||||
"query": "label:\"needs more info\" is:open"
|
||||
},
|
||||
{
|
||||
"name": "unlabeled",
|
||||
"query": "is:open is:issue no:label"
|
||||
},
|
||||
{
|
||||
"name": "open_prs",
|
||||
"query": "is:open is:pr"
|
||||
},
|
||||
{
|
||||
"name": "milestone_7_4_open",
|
||||
"query": "is:open is:issue milestone:7.4"
|
||||
}
|
||||
]
|
||||
}
|
||||
26
.github/workflows/backport.yml
vendored
26
.github/workflows/backport.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Backport PR Creator
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
ref: main
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run backport
|
||||
uses: ./actions/backport
|
||||
with:
|
||||
metricsWriteAPIKey: ${{secrets.GRAFANA_MISC_STATS_API_KEY}}
|
||||
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}
|
||||
labelsToAdd: "backport"
|
||||
title: "[{{base}}] {{originalTitle}}"
|
||||
27
.github/workflows/bump-version.yml
vendored
27
.github/workflows/bump-version.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Bump version
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
default: '7.x.x'
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
ref: main
|
||||
- uses: actions/setup-node@v2.1.4
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run bump version
|
||||
uses: ./actions/bump-version
|
||||
with:
|
||||
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}
|
||||
metricsWriteAPIKey: ${{secrets.GRAFANA_MISC_STATS_API_KEY}}
|
||||
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@@ -1,71 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, v1.8.x, v2.0.x, v2.1.x, v2.6.x, v3.0.x, v3.1.x, v4.0.x, v4.1.x, v4.2.x, v4.3.x, v4.4.x, v4.5.x, v4.6.x, v4.7.x, v5.0.x, v5.1.x, v5.2.x, v5.3.x, v5.4.x, v6.0.x, v6.1.x, v6.2.x, v6.3.x, v6.4.x, v6.5.x, v6.6.x, v6.7.x, v7.0.x, v7.1.x, v7.2.x]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 4 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript', 'go', 'python']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
25
.github/workflows/commands.yml
vendored
25
.github/workflows/commands.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: Run commands when issues are labeled or comments added
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
ref: main
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run Commands
|
||||
uses: ./actions/commands
|
||||
with:
|
||||
metricsWriteAPIKey: ${{secrets.GRAFANA_MISC_STATS_API_KEY}}
|
||||
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}
|
||||
configPath: commands
|
||||
24
.github/workflows/github-release.yml
vendored
24
.github/workflows/github-release.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: Create or update GitHub release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
description: Needs to match, exactly, the name of a milestone (NO v prefix)
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
ref: main
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run github release action
|
||||
uses: ./actions/github-release
|
||||
with:
|
||||
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}
|
||||
metricsWriteAPIKey: ${{secrets.GRAFANA_MISC_STATS_API_KEY}}
|
||||
35
.github/workflows/metrics-collector.yml
vendored
35
.github/workflows/metrics-collector.yml
vendored
@@ -1,35 +0,0 @@
|
||||
#
|
||||
# When triggered by the cron job it will also collect metrics for:
|
||||
# * number of issues without label
|
||||
# * number of issues with "needs more info"
|
||||
# * number of issues with "needs investigation"
|
||||
# * number of issues with label type/bug
|
||||
# * number of open issues in current milestone
|
||||
#
|
||||
# https://github.com/grafana/grafana-github-actions/blob/main/metrics-collector/index.ts
|
||||
#
|
||||
name: Github issue metrics collection
|
||||
on:
|
||||
schedule:
|
||||
- cron: "*/10 * * * *"
|
||||
issues:
|
||||
types: [opened, closed]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
ref: main
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run metrics collector
|
||||
uses: ./actions/metrics-collector
|
||||
with:
|
||||
metricsWriteAPIKey: ${{secrets.GRAFANA_MISC_STATS_API_KEY}}
|
||||
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}
|
||||
configPath: "metrics-collector"
|
||||
18
.github/workflows/publish.yml
vendored
18
.github/workflows/publish.yml
vendored
@@ -6,7 +6,6 @@ on:
|
||||
- master
|
||||
paths:
|
||||
- 'docs/sources/**'
|
||||
- 'packages/grafana-*/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -15,20 +14,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- run: git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.GH_BOT_ACCESS_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: '**/node_modules'
|
||||
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
|
||||
- name: generate-packages-docs
|
||||
uses: actions/setup-node@v2.1.4
|
||||
id: generate-docs
|
||||
with:
|
||||
node-version: '14'
|
||||
- run: yarn install --pure-lockfile --no-progress
|
||||
- run: ./scripts/ci-reference-docs-build.sh
|
||||
- name: publish-to-git
|
||||
uses: ./.github/actions/website-sync
|
||||
uses: ./.github/actions/gha-publish-to-git
|
||||
id: publish
|
||||
with:
|
||||
repository: grafana/website
|
||||
@@ -37,8 +24,7 @@ jobs:
|
||||
github_pat: '${{ secrets.GH_BOT_ACCESS_TOKEN }}'
|
||||
source_folder: docs/sources
|
||||
target_folder: content/docs/grafana/latest
|
||||
allow_no_changes: 'true'
|
||||
- shell: bash
|
||||
run: |
|
||||
test -n "${{ steps.publish.outputs.commit_hash }}"
|
||||
test -n "${{ steps.publish.outputs.working_directory }}"
|
||||
test -n "${{ steps.publish.outputs.working_directory }}"
|
||||
24
.github/workflows/update-changelog.yml
vendored
24
.github/workflows/update-changelog.yml
vendored
@@ -1,24 +0,0 @@
|
||||
name: Update changelog
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
description: Needs to match, exactly, the name of a milestone
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: ./actions
|
||||
ref: main
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: Run update changelog
|
||||
uses: ./actions/update-changelog
|
||||
with:
|
||||
token: ${{secrets.GH_BOT_ACCESS_TOKEN}}
|
||||
metricsWriteAPIKey: ${{secrets.GRAFANA_MISC_STATS_API_KEY}}
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -20,9 +20,6 @@ vendor/
|
||||
/emails/templates/enterprise_*
|
||||
/public/emails/enterprise_*
|
||||
|
||||
# Enterprise reporting fonts
|
||||
/public/fonts/dejavu
|
||||
|
||||
# Enterprise devenv
|
||||
/devenv/docker/blocks/grafana-enterprise
|
||||
|
||||
@@ -49,7 +46,6 @@ public/css/*.min.css
|
||||
.DS_Store
|
||||
.vscode/
|
||||
.vs/
|
||||
.eslintcache
|
||||
|
||||
/data/*
|
||||
/bin/*
|
||||
@@ -116,11 +112,8 @@ compilation-stats.json
|
||||
/packages/grafana-e2e/cypress/logs
|
||||
/e2e/server.log
|
||||
/e2e/**/screenshots
|
||||
!/e2e/**/screenshots/expected/*
|
||||
!/e2e/**/screenshots/expeced/*
|
||||
/e2e/**/videos/*
|
||||
|
||||
# report dumping the whole system env
|
||||
/report.*.json
|
||||
|
||||
# auto generated frontend docs
|
||||
/docs/sources/packages_api
|
||||
|
||||
@@ -6,4 +6,4 @@ node_modules
|
||||
public/vendor/
|
||||
vendor/
|
||||
data/
|
||||
e2e/tmp
|
||||
|
||||
|
||||
3147
CHANGELOG.md
3147
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
2257
CHANGELOG_ARCHIVE.md
2257
CHANGELOG_ARCHIVE.md
File diff suppressed because it is too large
Load Diff
@@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at conduct@grafana.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@grafana.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
|
||||
@@ -19,20 +19,9 @@ For more ways to contribute, check out the [Open Source Guides](https://opensour
|
||||
|
||||
### Report bugs
|
||||
|
||||
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
|
||||
|
||||
Report a bug by submitting a [bug report](https://github.com/grafana/grafana/issues/new?labels=type%3A+bug&template=1-bug_report.md). Make sure that you provide as much information as possible on how to reproduce the bug.
|
||||
|
||||
Follow the issue template and add additional information that will help us replicate the problem.
|
||||
|
||||
For data visualization issues:
|
||||
- Query results from the inspect drawer (data tab & query inspector)
|
||||
- Panel settings can be extracted in the panel inspect drawer JSON tab
|
||||
|
||||
For a dashboard related issues:
|
||||
- Dashboard JSON can be found in the dashboard settings JSON model view
|
||||
|
||||
For authentication and alerting Grafana server logs are useful.
|
||||
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
|
||||
|
||||
#### Security issues
|
||||
|
||||
@@ -69,11 +58,10 @@ When you're ready to contribute, it's time to [Create a pull request](/contribut
|
||||
|
||||
#### Contributor License Agreement (CLA)
|
||||
|
||||
Before we can accept your pull request, you need to [sign our CLA](https://grafana.com/docs/grafana/latest/developers/cla/). If you haven't, our CLA assistant prompts you to when you create your pull request.
|
||||
Before we can accept your pull request, you need to [sign our CLA](https://grafana.com/docs/contribute/cla/). If you haven't, our CLA assistant prompts you to when you create your pull request.
|
||||
|
||||
## Where do I go from here?
|
||||
|
||||
- Set up your [development environment](contribute/developer-guide.md).
|
||||
- Learn how to [contribute documentation](contribute/documentation.md).
|
||||
- Get started [developing plugins](https://grafana.com/docs/grafana/latest/developers/plugins/) for Grafana.
|
||||
- Look through the resources in the [contribute](https://github.com/grafana/grafana/tree/master/contribute) folder.
|
||||
- Get started [developing plugins](https://grafana.com/docs/plugins/developing/development/) for Grafana.
|
||||
|
||||
27
Dockerfile
27
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:14.15.1-alpine3.12 as js-builder
|
||||
FROM node:12.16.3-alpine3.11 as js-builder
|
||||
|
||||
WORKDIR /usr/src/app/
|
||||
|
||||
@@ -7,16 +7,16 @@ COPY packages packages
|
||||
|
||||
RUN yarn install --pure-lockfile --no-progress
|
||||
|
||||
COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./
|
||||
COPY Gruntfile.js tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./
|
||||
COPY public public
|
||||
COPY tools tools
|
||||
COPY scripts scripts
|
||||
COPY emails emails
|
||||
|
||||
ENV NODE_ENV production
|
||||
RUN yarn build
|
||||
RUN ./node_modules/.bin/grunt build
|
||||
|
||||
FROM golang:1.15.1-alpine3.12 as go-builder
|
||||
FROM golang:1.14.2-alpine3.11 as go-builder
|
||||
|
||||
RUN apk add --no-cache gcc g++
|
||||
|
||||
@@ -32,12 +32,12 @@ COPY build.go package.json ./
|
||||
RUN go run build.go build
|
||||
|
||||
# Final stage
|
||||
FROM alpine:3.12
|
||||
FROM alpine:3.11
|
||||
|
||||
LABEL maintainer="Grafana team <hello@grafana.com>"
|
||||
|
||||
ARG GF_UID="472"
|
||||
ARG GF_GID="0"
|
||||
ARG GF_GID="472"
|
||||
|
||||
ENV PATH="/usr/share/grafana/bin:$PATH" \
|
||||
GF_PATHS_CONFIG="/etc/grafana/grafana.ini" \
|
||||
@@ -50,27 +50,22 @@ ENV PATH="/usr/share/grafana/bin:$PATH" \
|
||||
WORKDIR $GF_PATHS_HOME
|
||||
|
||||
RUN apk add --no-cache ca-certificates bash tzdata && \
|
||||
apk add --no-cache openssl musl-utils
|
||||
apk add --no-cache --upgrade openssl musl-utils
|
||||
|
||||
COPY conf ./conf
|
||||
|
||||
RUN if [ ! $(getent group "$GF_GID") ]; then \
|
||||
addgroup -S -g $GF_GID grafana; \
|
||||
fi
|
||||
|
||||
RUN export GF_GID_NAME=$(getent group $GF_GID | cut -d':' -f1) && \
|
||||
mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
adduser -S -u $GF_UID -G "$GF_GID_NAME" grafana && \
|
||||
RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
addgroup -S -g $GF_GID grafana && \
|
||||
adduser -S -u $GF_UID -G grafana grafana && \
|
||||
mkdir -p "$GF_PATHS_PROVISIONING/datasources" \
|
||||
"$GF_PATHS_PROVISIONING/dashboards" \
|
||||
"$GF_PATHS_PROVISIONING/notifiers" \
|
||||
"$GF_PATHS_PROVISIONING/plugins" \
|
||||
"$GF_PATHS_LOGS" \
|
||||
"$GF_PATHS_PLUGINS" \
|
||||
"$GF_PATHS_DATA" && \
|
||||
cp "$GF_PATHS_HOME/conf/sample.ini" "$GF_PATHS_CONFIG" && \
|
||||
cp "$GF_PATHS_HOME/conf/ldap.toml" /etc/grafana/ldap.toml && \
|
||||
chown -R "grafana:$GF_GID_NAME" "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
|
||||
chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
|
||||
chmod -R 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING"
|
||||
|
||||
COPY --from=go-builder /go/src/github.com/grafana/grafana/bin/linux-amd64/grafana-server /go/src/github.com/grafana/grafana/bin/linux-amd64/grafana-cli ./bin/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:14.15.1-slim AS js-builder
|
||||
FROM node:12.16.3-slim AS js-builder
|
||||
|
||||
WORKDIR /usr/src/app/
|
||||
|
||||
@@ -7,16 +7,16 @@ COPY packages packages
|
||||
|
||||
RUN yarn install --pure-lockfile
|
||||
|
||||
COPY tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./
|
||||
COPY Gruntfile.js tsconfig.json .eslintrc .editorconfig .browserslistrc .prettierrc.js ./
|
||||
COPY public public
|
||||
COPY tools tools
|
||||
COPY scripts scripts
|
||||
COPY emails emails
|
||||
|
||||
ENV NODE_ENV production
|
||||
RUN yarn build
|
||||
RUN ./node_modules/.bin/grunt build
|
||||
|
||||
FROM golang:1.15.1 AS go-builder
|
||||
FROM golang:1.14.2 AS go-builder
|
||||
|
||||
WORKDIR /src/grafana
|
||||
|
||||
@@ -50,7 +50,7 @@ WORKDIR $GF_PATHS_HOME
|
||||
COPY conf conf
|
||||
|
||||
# curl should be part of the image
|
||||
RUN apt-get update && apt-get install -y ca-certificates curl
|
||||
RUN apt-get update && apt-get upgrade -y && apt-get install -y ca-certificates curl
|
||||
|
||||
RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
addgroup --system --gid $GF_GID grafana && \
|
||||
@@ -58,7 +58,6 @@ RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
mkdir -p "$GF_PATHS_PROVISIONING/datasources" \
|
||||
"$GF_PATHS_PROVISIONING/dashboards" \
|
||||
"$GF_PATHS_PROVISIONING/notifiers" \
|
||||
"$GF_PATHS_PROVISIONING/plugins" \
|
||||
"$GF_PATHS_LOGS" \
|
||||
"$GF_PATHS_PLUGINS" \
|
||||
"$GF_PATHS_DATA" && \
|
||||
@@ -67,6 +66,7 @@ RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
|
||||
chmod -R 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING"
|
||||
|
||||
|
||||
COPY --from=go-builder /src/grafana/bin/linux-amd64/grafana-server /src/grafana/bin/linux-amd64/grafana-cli bin/
|
||||
COPY --from=js-builder /usr/src/app/public public
|
||||
COPY --from=js-builder /usr/src/app/tools tools
|
||||
|
||||
205
GOVERNANCE.md
205
GOVERNANCE.md
@@ -1,205 +0,0 @@
|
||||
# Governance
|
||||
|
||||
This document describes the rules and governance of the project. It is meant to be followed by all the developers of the project and the Grafana community. Common terminology used in this governance document are listed below:
|
||||
|
||||
- **Team members**: Any members of the private [grafana-team][team] Google group.
|
||||
|
||||
- **Maintainers**: Maintainers lead an individual project or parts thereof ([`MAINTAINERS.md`][maintainers]).
|
||||
|
||||
- **Projects**: A single repository in the Grafana GitHub organization and listed below is referred to as a project:
|
||||
|
||||
- clock-panel
|
||||
- devtools
|
||||
- gel-app
|
||||
- grafana
|
||||
- grafana-github-datasource
|
||||
- grafana-image-renderer
|
||||
- grafana-kiosk
|
||||
- grafana-plugin-sdk-go
|
||||
- grafana-polystat-panel
|
||||
- grafonnet-lib
|
||||
- kairosdb-datasource
|
||||
- piechart-panel
|
||||
- simple-angular-panel
|
||||
- simple-app-plugin
|
||||
- simple-datasource
|
||||
- simple-datasource-backend
|
||||
- simple-json-backend-datasource
|
||||
- simple-json-datasource
|
||||
- simple-react-panel
|
||||
- strava-datasource
|
||||
- tutorials
|
||||
- worldmap-panel
|
||||
|
||||
- **The Grafana project**: The sum of all activities performed under this governance, concerning one or more repositories or the community.
|
||||
|
||||
## Values
|
||||
|
||||
The Grafana developers and community are expected to follow the values defined in the Grafana Code of Conduct. Furthermore, the Grafana community strives for kindness, giving feedback effectively, and building a welcoming environment. The Grafana developers generally decide by consensus and only resort to conflict resolution by a majority vote if consensus cannot be reached.
|
||||
|
||||
## Projects
|
||||
|
||||
Each project must have a [`MAINTAINERS.md`][maintainers] file with at least one maintainer. Where a project has a release process, access and documentation should be such that more than one person can perform a release. Releases should be announced on the Grafana Labs blog. Any new projects should be first proposed on the [team mailing list][team] following the voting procedures listed below.
|
||||
|
||||
## Decision making
|
||||
|
||||
### Team members
|
||||
|
||||
Team member status may be given to those who have made ongoing contributions to the Grafana project for at least 3 months. This is usually in the form of code improvements and/or notable work on documentation, but organizing events or user support could also be taken into account.
|
||||
|
||||
New members may be proposed by any existing member by email to [grafana-team][team]. It is highly desirable to reach consensus about acceptance of a new member. However, the proposal is ultimately voted on by a formal [supermajority vote](#supermajority-vote).
|
||||
|
||||
If the new member proposal is accepted, the proposed team member should be contacted privately via email to confirm or deny their acceptance of team membership. This email will also be CC'd to [grafana-team][team] for record-keeping purposes.
|
||||
|
||||
If they choose to accept, the [onboarding](#onboarding) procedure is followed.
|
||||
|
||||
Team members may retire at any time by emailing [the team][team].
|
||||
|
||||
Team members can be removed by [supermajority vote](#supermajority-vote) on [the team mailing list][team].
|
||||
For this vote, the member in question is not eligible to vote and does not count towards the quorum.
|
||||
Any removal vote can cover only one single person.
|
||||
|
||||
Upon death of a member, they leave the team automatically.
|
||||
|
||||
In case a member leaves, the [offboarding](#offboarding) procedure is applied.
|
||||
|
||||
The current team members are:
|
||||
|
||||
- Alexander Zobnin ([Grafana Labs](https://grafana.com/))
|
||||
- Alex Khomenko ([Grafana Labs](https://grafana.com/))
|
||||
- Andrej Ocenas ([Grafana Labs](https://grafana.com/))
|
||||
- Arve Knudsen ([Grafana Labs](https://grafana.com/))
|
||||
- Brian Gann ([Grafana Labs](https://grafana.com/))
|
||||
- Carl Bergquist ([Grafana Labs](https://grafana.com/))
|
||||
- Chris Trott ([Grafana Labs](https://grafana.com/))
|
||||
- Daniel Lee ([Grafana Labs](https://grafana.com/))
|
||||
- David Kaltschmidt ([Grafana Labs](https://grafana.com/))
|
||||
- Diana Payton ([Grafana Labs](https://grafana.com/))
|
||||
- Diana Sarlinska ([Grafana Labs](https://grafana.com/))
|
||||
- Dominik Prokop ([Grafana Labs](https://grafana.com/))
|
||||
- Emil Tullstedt ([Grafana Labs](https://grafana.com/))
|
||||
- Fredrik Enestad ([Soundtrack Your Brand](https://www.soundtrackyourbrand.com/))
|
||||
- Hugo Häggmark ([Grafana Labs](https://grafana.com/))
|
||||
- Ivana Huckova ([Grafana Labs](https://grafana.com/))
|
||||
- Jeroen Op 't Eynde ([Grafana Labs](https://grafana.com/))
|
||||
- Jessica Müller ([Grafana Labs](https://grafana.com/))
|
||||
- Julien Pivotto ([Inuits](https://inuits.eu/))
|
||||
- Kay Delaney ([Grafana Labs](https://grafana.com/))
|
||||
- Kyle Brandt ([Grafana Labs](https://grafana.com/))
|
||||
- Leonard Gram ([Grafana Labs](https://grafana.com/))
|
||||
- Lukas Siatka ([Grafana Labs](https://grafana.com/))
|
||||
- Malcolm Holmes ([Grafana Labs](https://grafana.com/))
|
||||
- Marcus Andersson ([Grafana Labs](https://grafana.com/))
|
||||
- Marcus Efraimsson ([Grafana Labs](https://grafana.com/))
|
||||
- Marcus Olsson ([Grafana Labs](https://grafana.com/))
|
||||
- Mitsuhiro Tanda ([GREE](https://corp.gree.net/jp/en/))
|
||||
- Patrick O’Carroll ([Grafana Labs](https://grafana.com/))
|
||||
- Peter Holmberg ([Grafana Labs](https://grafana.com/))
|
||||
- Richard Hartmann ([Grafana Labs](https://grafana.com/))
|
||||
- Ryan McKinley ([Grafana Labs](https://grafana.com/))
|
||||
- Sofia Papagiannaki ([Grafana Labs](https://grafana.com/))
|
||||
- Stephanie Closson ([Grafana Labs](https://grafana.com/))
|
||||
- Tobias Skarhed ([Grafana Labs](https://grafana.com/))
|
||||
- Torkel Ödegaard ([Grafana Labs](https://grafana.com/))
|
||||
- Utkarsh Bhatnagar ([Tinder](https://www.tinder.com/))
|
||||
|
||||
### Maintainers
|
||||
|
||||
Maintainers lead one or more project(s) or parts thereof and serve as a point of conflict resolution amongst the contributors to this project. Ideally, maintainers are also team members, but exceptions are possible for suitable maintainers that, for whatever reason, are not yet team members.
|
||||
|
||||
Changes in maintainership have to be announced on the [developers mailing list][devs]. They are decided by [rough consensus](#consensus) and formalized by changing the [`MAINTAINERS.md`][maintainers] file of the respective repository.
|
||||
|
||||
Maintainers are granted commit rights to all projects covered by this governance.
|
||||
|
||||
A maintainer or committer may resign by notifying the [team mailing list][team]. A maintainer with no project activity for a year is considered to have resigned. Maintainers that wish to resign are encouraged to propose another team member to take over the project.
|
||||
|
||||
A project may have multiple maintainers, as long as the responsibilities are clearly agreed upon between them. This includes coordinating who handles which issues and pull requests.
|
||||
|
||||
### Technical decisions
|
||||
|
||||
Technical decisions that only affect a single project are made informally by the maintainer of this project, and [rough consensus](#consensus) is assumed. Technical decisions that span multiple parts of the Grafana project should be discussed and made on the [Grafana developer mailing list][devs].
|
||||
|
||||
Decisions are usually made by [rough consensus](#consensus). If no consensus can be reached, the matter may be resolved by [majority vote](#majority-vote).
|
||||
|
||||
### Governance changes
|
||||
|
||||
Changes to this document are made by Grafana Labs.
|
||||
|
||||
### Other matters
|
||||
|
||||
Any matter that needs a decision may be called to a vote by any member if they deem it necessary. For private or personnel matters, discussion and voting takes place on the [team mailing list][team], otherwise on the [developer mailing list][devs].
|
||||
|
||||
## Voting
|
||||
|
||||
The Grafana project usually runs by informal consensus, however sometimes a formal decision must be made.
|
||||
|
||||
Depending on the subject matter, as laid out [above](#decision-making), different methods of voting are used.
|
||||
|
||||
For all votes, voting must be open for at least one week. The end date should be clearly stated in the call to vote. A vote may be called and closed early if enough votes have come in one way so that further votes cannot change the final decision.
|
||||
|
||||
In all cases, all and only [team members](#team-members) are eligible to vote, with the sole exception of the forced removal of a team member, in which said member is not eligible to vote.
|
||||
|
||||
Discussion and votes on personnel matters (including but not limited to team membership and maintainership) are held in private on the [team mailing list][team]. All other discussion and votes are held in public on the [developer mailing list][devs].
|
||||
|
||||
For public discussions, anyone interested is encouraged to participate. Formal power to object or vote is limited to [team members](#team-members).
|
||||
|
||||
### Consensus
|
||||
|
||||
The default decision making mechanism for the Grafana project is [rough][rough] consensus. This means that any decision on technical issues is considered supported by the [team][team] as long as nobody objects or the objection has been considered but not necessarily accommodated.
|
||||
|
||||
Silence on any consensus decision is implicit agreement and equivalent to explicit agreement. Explicit agreement may be stated at will. Decisions may, but do not need to be called out and put up for decision on the [developers mailing list][devs] at any time and by anyone.
|
||||
|
||||
Consensus decisions can never override or go against the spirit of an earlier explicit vote.
|
||||
|
||||
If any [team member](#team-members) raises objections, the team members work together towards a solution that all involved can accept. This solution is again subject to rough consensus.
|
||||
|
||||
In case no consensus can be found, but a decision one way or the other must be made, any [team member](#team-members) may call a formal [majority vote](#majority-vote).
|
||||
|
||||
### Majority vote
|
||||
|
||||
Majority votes must be called explicitly in a separate thread on the appropriate mailing list. The subject must be prefixed with `[VOTE]`. In the body, the call to vote must state the proposal being voted on. It should reference any discussion leading up to this point.
|
||||
|
||||
Votes may take the form of a single proposal, with the option to vote yes or no, or the form of multiple alternatives.
|
||||
|
||||
A vote on a single proposal is considered successful if more vote in favor than against.
|
||||
|
||||
If there are multiple alternatives, members may vote for one or more alternatives, or vote “no” to object to all alternatives. It is not possible to cast an “abstain” vote. A vote on multiple alternatives is considered decided in favor of one alternative if it has received the most votes in favor, and a vote from more than half of those voting. Should no alternative reach this quorum, another vote on a reduced number of options may be called separately.
|
||||
|
||||
### Supermajority vote
|
||||
|
||||
Supermajority votes must be called explicitly in a separate thread on the appropriate mailing list. The subject must be prefixed with `[VOTE]`. In the body, the call to vote must state the proposal being voted on. It should reference any discussion leading up to this point.
|
||||
|
||||
Votes may take the form of a single proposal, with the option to vote yes or no, or the form of multiple alternatives.
|
||||
|
||||
A vote on a single proposal is considered successful if at least two thirds of those eligible to vote vote in favor.
|
||||
|
||||
If there are multiple alternatives, members may vote for one or more alternatives, or vote “no” to object to all alternatives. A vote on multiple alternatives is considered decided in favor of one alternative if it has received the most votes in favor, and a vote from at least two thirds of those eligible to vote. Should no alternative reach this quorum, another vote on a reduced number of options may be called separately.
|
||||
|
||||
## On- / Offboarding
|
||||
|
||||
### Onboarding
|
||||
|
||||
The new member is
|
||||
|
||||
- added to the list of [team members](#team-members). Ideally by sending a PR of their own, at least approving said PR.
|
||||
- announced on the [developers mailing list][devs] by an existing team member. Ideally, the new member replies in this thread, acknowledging team membership.
|
||||
- added to the projects with commit rights.
|
||||
- added to the [team mailing list][team].
|
||||
|
||||
### Offboarding
|
||||
|
||||
The ex-member is
|
||||
|
||||
- removed from the list of [team members](#team-members). Ideally by sending a PR of their own, at least approving said PR. In case of forced removal, no approval is needed.
|
||||
- removed from the projects. Optionally, they can retain maintainership of one or more repositories if the [team](#team-members) agrees.
|
||||
- removed from the team mailing list and demoted to a normal member of the other mailing lists.
|
||||
- not allowed to call themselves an active team member any more, nor allowed to imply this to be the case.
|
||||
- added to a list of previous members if they so choose.
|
||||
|
||||
If needed, we reserve the right to publicly announce removal.
|
||||
|
||||
[coc]: https://github.com/grafana/grafana/blob/master/CODE_OF_CONDUCT.md
|
||||
[devs]: https://groups.google.com/forum/#!forum/grafana-developers
|
||||
[maintainers]: https://github.com/grafana/grafana/blob/master/MAINTAINERS.md
|
||||
[rough]: https://tools.ietf.org/html/rfc7282
|
||||
[team]: https://groups.google.com/forum/#!forum/grafana-team
|
||||
64
Gruntfile.js
Normal file
64
Gruntfile.js
Normal file
@@ -0,0 +1,64 @@
|
||||
'use strict';
|
||||
module.exports = function (grunt) {
|
||||
var os = require('os');
|
||||
var config = {
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
baseDir: '.',
|
||||
srcDir: 'public',
|
||||
genDir: 'public_gen',
|
||||
destDir: 'dist',
|
||||
tempDir: 'tmp',
|
||||
platform: process.platform.replace('win32', 'windows'),
|
||||
enterprise: false,
|
||||
libc: null,
|
||||
};
|
||||
|
||||
if (grunt.option('platform')) {
|
||||
config.platform = grunt.option('platform');
|
||||
}
|
||||
|
||||
if (grunt.option('enterprise')) {
|
||||
config.enterprise = true;
|
||||
}
|
||||
|
||||
if (grunt.option('arch')) {
|
||||
config.arch = grunt.option('arch');
|
||||
} else {
|
||||
config.arch = os.arch();
|
||||
|
||||
if (process.platform.match(/^win/)) {
|
||||
config.arch = process.env.hasOwnProperty('ProgramFiles(x86)') ? 'x64' : 'x86';
|
||||
}
|
||||
}
|
||||
|
||||
if (grunt.option('libc')) {
|
||||
config.libc = grunt.option('libc');
|
||||
}
|
||||
|
||||
config.pkg.version = grunt.option('pkgVer') || config.pkg.version;
|
||||
|
||||
console.log('Version', config.pkg.version);
|
||||
|
||||
// load plugins
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
// load task definitions
|
||||
grunt.loadTasks('./scripts/grunt');
|
||||
|
||||
// Utility function to load plugin settings into config
|
||||
function loadConfig(config, path) {
|
||||
require('glob').sync('*', {cwd: path}).forEach(function(option) {
|
||||
var key = option.replace(/\.js$/,'');
|
||||
// If key already exists, extend it. It is your responsibility to avoid naming collisions
|
||||
config[key] = config[key] || {};
|
||||
grunt.util._.extend(config[key], require(path + option)(config,grunt));
|
||||
});
|
||||
// technically not required
|
||||
return config;
|
||||
}
|
||||
|
||||
// Merge that object with what with whatever we have here
|
||||
loadConfig(config,'./scripts/grunt/options/');
|
||||
// pass the config to grunt
|
||||
grunt.initConfig(config);
|
||||
};
|
||||
138
ISSUE_TRIAGE.md
138
ISSUE_TRIAGE.md
@@ -2,16 +2,16 @@
|
||||
|
||||
The main goal of issue triage is to categorize all incoming Grafana issues and make sure each issue has all basic information needed for anyone else to understand and be able to start working on it.
|
||||
|
||||
> **Note:** This information is for Grafana project Maintainers, Owners, and Admins. If you are a Contributor, then you will not be able to perform most of the tasks in this topic.
|
||||
**Note:** This information is for Grafana project Maintainers, Owners, and Admins. If you are a Contributor, then you will not be able to perform most of the tasks in this topic.
|
||||
|
||||
The core maintainers of the Grafana project are responsible for categorizing all incoming issues and delegating any critical or important issue to other maintainers. Currently one maintainer each week is responsible. Besides that part, triage provides an important way to contribute to an open source project.
|
||||
|
||||
Triage helps ensure issues resolve quickly by:
|
||||
|
||||
- Ensuring the issue's intent and purpose is conveyed precisely. This is necessary because it can be difficult for an issue to explain how an end user experiences a problem and what actions they took.
|
||||
- Giving a contributor the information they need before they commit to resolving an issue.
|
||||
- Lowering the issue count by preventing duplicate issues.
|
||||
- Streamlining the development process by preventing duplicate discussions.
|
||||
* Ensuring the issue's intent and purpose is conveyed precisely. This is necessary because it can be difficult for an issue to explain how an end user experiences a problem and what actions they took.
|
||||
* Giving a contributor the information they need before they commit to resolving an issue.
|
||||
* Lowering the issue count by preventing duplicate issues.
|
||||
* Streamlining the development process by preventing duplicate discussions.
|
||||
|
||||
If you don't have the knowledge or time to code, consider helping with triage. The community will thank you for saving them time by spending some of yours.
|
||||
|
||||
@@ -32,7 +32,7 @@ If you don't have the knowledge or time to code, consider helping with triage. T
|
||||
| | |
|
||||
+------+-------+-------------+ +------------+---------+ +----------------------------+
|
||||
| | | | | |
|
||||
| label: needs more info | | Needs investigation? +--YES---+ label: needs investigation |
|
||||
| label: needs more details | | Needs investigation? +--YES---+ label: needs investigation |
|
||||
| | | | | |
|
||||
+----------------------------+ +----------------+-----+ +--------------+-------------+
|
||||
NO | |
|
||||
@@ -82,7 +82,7 @@ Before triaging an issue very far, make sure that the issue's author provided th
|
||||
|
||||
Given a certain [issue template]([template](https://github.com/grafana/grafana/issues/new/choose)) have been used by the issue author or depending how the issue is perceived by the issue triage responsible, the following should help you understand what standard issue information that must be included.
|
||||
|
||||
#### Bug reports
|
||||
#### Bug report?
|
||||
|
||||
Should explain what happened, what was expected and how to reproduce it together with any additional information that may help giving a complete picture of what happened such as screenshots, [query inspector](https://community.grafana.com/t/using-grafanas-query-inspector-to-troubleshoot-issues/2630) output and any environment related information that's applicable and/or maybe related to the reported problem:
|
||||
- Grafana version
|
||||
@@ -96,15 +96,15 @@ Should explain what happened, what was expected and how to reproduce it together
|
||||
- Non-default configuration settings
|
||||
- Development environment like Go and Node versions, if applicable
|
||||
|
||||
#### Enhancement requests
|
||||
#### Enhancement request?
|
||||
|
||||
Should explain what enhancement or feature that the author wants to be added and why that is needed.
|
||||
|
||||
#### Accessibility issues
|
||||
#### Accessibility issue?
|
||||
|
||||
This is a mix between a bug report and enhancement request but focused on accessibility issues to help make Grafana improve keyboard navigation, screen-reader support and being accessible to everyone. The report should include relevant WCAG criteria, if applicable.
|
||||
|
||||
#### Support requests
|
||||
#### Support request?
|
||||
|
||||
In general, if the issue description and title is perceived as a question no more information is needed.
|
||||
|
||||
@@ -112,11 +112,11 @@ In general, if the issue description and title is perceived as a question no mor
|
||||
|
||||
To make it easier for everyone to understand and find issues they're searching for it's suggested as a general rule of thumbs to:
|
||||
|
||||
- Make sure that issue titles are named to explain the subject of the issue, has a correct spelling and doesn't include irrelevant information and/or sensitive information.
|
||||
- Make sure that issue descriptions doesn't include irrelevant information, information from template that haven't been filled out and/or sensitive information.
|
||||
- Do your best effort to change title and description or request suggested changes by adding a comment.
|
||||
* Make sure that issue titles are named to explain the subject of the issue, has a correct spelling and doesn't include irrelevant information and/or sensitive information.
|
||||
* Make sure that issue descriptions doesn't include irrelevant information, information from template that haven't been filled out and/or sensitive information.
|
||||
* Do your best effort to change title and description or request suggested changes by adding a comment.
|
||||
|
||||
> **Note:** Above rules is applicable to both new and existing issues of the Grafana project.
|
||||
Note: Above rules is applicable to both new and existing issues of the Grafana project.
|
||||
|
||||
### Do you have all the information needed to categorize an issue?
|
||||
|
||||
@@ -137,28 +137,29 @@ An issue can have multiple of the following labels. Typically, a properly catego
|
||||
- One label identifying its type (`type/*`).
|
||||
- One or multiple labels identifying the functional areas of interest or component (`area/*`) and/or data source (`datasource/*`), if applicable.
|
||||
|
||||
| Label | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------- |
|
||||
| `type/bug` | A feature isn't working as expected given design or documentation. |
|
||||
| `type/feature-request` | Request for a new feature or enhancement. |
|
||||
| `type/docs` | Documentation problem or enhancement. |
|
||||
| `type/accessibility` | Accessibility problem or enhancement. |
|
||||
| `type/question` | Issue is a question or is perceived as such. |
|
||||
| `type/duplicate` | An existing issue of the same subject/request have already been reported. |
|
||||
| `type/works-as-intended` | A reported bug works as intended/by design. |
|
||||
| `type/build-packaging` | Build or packaging problem or enhancement. |
|
||||
| `area/*` | Subject is related to a functional area of interest or component. |
|
||||
| `datasource/*` | Subject is related to a core data source plugin. |
|
||||
Label | Description
|
||||
------- | --------
|
||||
`type/bug` | A feature isn't working as expected given design or documentation.
|
||||
`type/feature-request` | Request for a new feature or enhancement.
|
||||
`type/docs` | Documentation problem or enhancement.
|
||||
`type/accessibility` | Accessibility problem or enhancement.
|
||||
`type/question` | Issue is or perceived as a question.
|
||||
`type/duplicate` | An existing issue of the same subject/request have already been reported.
|
||||
`type/works-as-intended` | A reported bug works as intended/by design.
|
||||
`type/build-packaging` | Build or packaging problem or enhancement.
|
||||
`area/*` | Subject is related to a functional area of interest or component.
|
||||
`datasource/*` | Subject is related to a core data source plugin.
|
||||
|
||||
### Duplicate issues
|
||||
### Duplicate issue?
|
||||
|
||||
Make sure it's not a duplicate by searching existing issues using related terms from the issue title and description. If you think you know there is an existing issue, but can't find it, please reach out to one of the maintainers and ask for help. If you identify that the issue is a duplicate of an existing issue:
|
||||
Make sure that it's not a duplicate by searching existing issues using related terms from the issue title and description. If you think you know there are an existing issue, but can't find it please reach out to one of the maintainers and ask for help. If you identify that the issue is a duplicate of an existing issue:
|
||||
|
||||
1. Add a comment `/duplicate of #<issue number>`. GitHub will recognize this and add some additional context to the issue activity.
|
||||
2. The Grafana bot will do the rest, adding the correct label and closing comment
|
||||
1. Add a comment `Duplicate of #<issue number>`. GitHub will recognize this and add some additional context to the issue activity.
|
||||
2. Close the issue and label it with `type/duplicate`.
|
||||
3. Optionally add any related `area/*` or `datasource/*` labels.
|
||||
4. If applicable, add a comment with additional information.
|
||||
|
||||
### Bug reports
|
||||
### Bug report?
|
||||
|
||||
If it's not perfectly clear that it's an actual bug, quickly try to reproduce it.
|
||||
|
||||
@@ -187,8 +188,8 @@ If it's not perfectly clear that it's an actual bug, quickly try to reproduce it
|
||||
First, evaluate if the documentation makes sense to be included in the Grafana project:
|
||||
|
||||
- Is this something we want/can maintain as a project?
|
||||
- Is this referring to usage of some specific integration/tool and in that case is that a popular use case in combination with Grafana?
|
||||
- If unsure, kindly and politely add a comment explaining that we would need [upvotes](https://help.github.com/en/articles/about-conversations-on-github#reacting-to-ideas-in-comments) to identify that lots of other users want/need this.
|
||||
- Is this referring to usage of some specific integration/tool and in that case are those a popular use case in combination with Grafana?
|
||||
- If unsure, kindly and politely add a comment explaining that we would need [upvotes](https://help.github.com/en/articles/about-conversations-on-github#reacting-to-ideas-in-comments) to identify that lots of other users wants/needs this.
|
||||
|
||||
Second, label the issue `type/docs` and at least one `area/*` or `datasource/*` label.
|
||||
|
||||
@@ -203,11 +204,11 @@ There's a minor typo/error/lack of information that adds a lot of confusion for
|
||||
1. Label the issue with `help wanted` and `beginner friendly`, if applicable, to signal that we find this important to fix and we would appreciate any help we can get from the community.
|
||||
2. Move on to [prioritizing the issue](#4-prioritization-of-issues).
|
||||
|
||||
### Accessibility issues
|
||||
### Accessibility issue?
|
||||
|
||||
1. Label the issue `type/accessibility` and at least one `area/*` or `datasource/*` label.
|
||||
|
||||
### Support requests
|
||||
### Support request?
|
||||
|
||||
1. Kindly and politely direct the issue author to the [community site](https://community.grafana.com/) and explain that GitHub is mainly used for tracking bugs and feature requests. If possible, it's usually a good idea to add some pointers to the issue author's question.
|
||||
2. Close the issue and label it with `type/question`.
|
||||
@@ -218,23 +219,23 @@ In general bugs and enhancement issues should be labeled with a priority.
|
||||
|
||||
This is the most difficult thing with triaging issues since it requires a lot of knowledge, context and experience before being able to think of and start feel comfortable adding a certain priority label.
|
||||
|
||||
The key here is asking for help and discuss issues to understand how more experienced project members think and reason. By doing that you learn more and eventually be more and more comfortable with prioritizing issues.
|
||||
The key here is asking for help and discuss issues to understand how more experienced project members thinks and reason. By doing that you learn more and eventually be more and more comfortable with prioritizing issues.
|
||||
|
||||
In case there is an uncertainty around the prioritization of an issue, please ask the maintainers for help.
|
||||
In any case there are uncertainty around the priorization of an issue, please ask the maintainers for help.
|
||||
|
||||
| Label | Description |
|
||||
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `priority/critical` | Highest priority. Must be actively worked on as someone's top priority right now. |
|
||||
| `priority/support-subscription` | This is important for one or several customers having a paid Grafana support subscription. |
|
||||
| `priority/important-soon` | Must be staffed and worked on either currently, or very soon, ideally in time for the next release. |
|
||||
| `priority/important-longterm` | Important over the long term, but may not be staffed and/or may need multiple releases to complete. |
|
||||
| `priority/nice-to-have` | It's a good idea, but not scheduled for any release. |
|
||||
| `priority/awaiting-more-evidence` | Lowest priority. Possibly useful, but not yet enough interest in it. |
|
||||
| `priority/unscheduled` | Something to look into before and to be discussed during the planning of the next (upcoming) major/minor stable release. |
|
||||
Label | Description
|
||||
------- | --------
|
||||
`priority/critical` | Highest priority. Must be actively worked on as someone's top priority right now.
|
||||
`priority/support-subscription` | This is important for one or several customers having a paid Grafana support subscription.
|
||||
`priority/important-soon` | Must be staffed and worked on either currently, or very soon, ideally in time for the next release.
|
||||
`priority/important-longterm` | Important over the long term, but may not be staffed and/or may need multiple releases to complete.
|
||||
`priority/nice-to-have` | It's a good idea, but not scheduled for any release.
|
||||
`priority/awaiting-more-evidence` | Lowest priority. Possibly useful, but not yet enough interest in it.
|
||||
`priority/unscheduled` | Something to look into before and to be discussed during the planning of the next (upcoming) major/minor stable release.
|
||||
|
||||
**Critical bugs**
|
||||
**Critical bug?**
|
||||
|
||||
1. If a bug has been categorized and any of the following criteria apply, the bug should be labeled as critical and must be actively worked on as someone's top priority right now.
|
||||
1. If a bug have been categorized and any of the following problems applies the bug should be labeled as critical and must be actively worked on as someone's top priority right now.
|
||||
|
||||
- Results in any data loss
|
||||
- Critical security or performance issues
|
||||
@@ -247,7 +248,7 @@ In case there is an uncertainty around the prioritization of an issue, please as
|
||||
5. Escalate the problem to the maintainers.
|
||||
6. Assign or ask a maintainer for help assigning someone to make this issue their top priority right now.
|
||||
|
||||
**Important short-term**
|
||||
**Important short-term?**
|
||||
|
||||
1. Label the issue `priority/important-soon`.
|
||||
2. If applicable, label the issue `priority/support-subscription`.
|
||||
@@ -255,12 +256,12 @@ In case there is an uncertainty around the prioritization of an issue, please as
|
||||
4. Make sure to add the issue to a suitable backlog of a GitHub project and prioritize it or assign someone to work on it now or very soon.
|
||||
5. Consider requesting [help from the community](#5-requesting-help-from-the-community), even though it may be problematic given a short amount of time until it should be released.
|
||||
|
||||
**Important long-term**
|
||||
**Important long-term?**
|
||||
|
||||
1. Label the issue `priority/important-longterm`.
|
||||
2. Consider requesting [help from the community](#5-requesting-help-from-the-community).
|
||||
|
||||
**Nice to have**
|
||||
**Nice to have?**
|
||||
|
||||
1. Label the issue `priority/nice-to-have`.
|
||||
2. Consider requesting [help from the community](#5-requesting-help-from-the-community).
|
||||
@@ -272,9 +273,9 @@ In case there is an uncertainty around the prioritization of an issue, please as
|
||||
|
||||
## 5. Requesting help from the community
|
||||
|
||||
Depending on the issue and/or priority, it's always a good idea to consider signalling to the community that help from community is appreciated and needed in case an issue is not prioritized to be worked on by maintainers. Use your best judgement. In general, requesting help from the community means that a contribution has a good chance of getting accepted and merged.
|
||||
Depending on the issue and/or priority, it's always a good idea to consider signalling to the community that help from community is appreciated and needed in case an issue is not prioritized to be worked on by maintainers. Use your best judgement. In general, when requesting help from the community it means a contribution has a good chance of getting accepted and merged.
|
||||
|
||||
In many cases the issue author or community as a whole is more suitable to contribute changes since they're experts in their domain. It's also quite common that someone has tried to get something to work using the documentation without success and made an effort to get it to work and/or reached out to the [community site](https://community.grafana.com/) to get the missing information. Particularly in these areas it's more likely that there exist experts in their own domain and it is usually a good idea to request help from contributors:
|
||||
In many cases the issue author or community as a whole is more suitable to contribute changes since they're experts in their domain. It's also quite common that someone has tried to get something to work using the documentation without success and made an effort to get it to work and/or reached out to the [community site](https://community.grafana.com/) to get the missing information. In especially these areas it's more likely that there exists experts in their own domain and usually a good idea to request help from contributors:
|
||||
|
||||
- Database setups
|
||||
- Authentication like OAuth providers and LDAP setups
|
||||
@@ -283,7 +284,7 @@ In many cases the issue author or community as a whole is more suitable to contr
|
||||
- Alert notifiers
|
||||
|
||||
1. Kindly and politely add a comment to signal to users subscribed to updates of the issue.
|
||||
- Explain that the issue would be nice to get resolved, but it isn't prioritized to work on by maintainers for an unforeseen future.
|
||||
- Explain that the issue would be nice to get resolved, but it isn't prioritized to work on by maintainers for an unforseen future.
|
||||
- If possible or applicable, try to help contributors getting starting by adding pointers and references to what code/files need to be changed and/or ideas of a good way to solve/implement the issue.
|
||||
2. Label the issue with `help wanted`.
|
||||
3. If applicable, label the issue with `beginner friendly` to denote that the issue is suitable for a beginner to work on.
|
||||
@@ -291,37 +292,28 @@ In many cases the issue author or community as a whole is more suitable to contr
|
||||
|
||||
## Investigation of issues
|
||||
|
||||
When an issue has all basic information provided, but the triage responsible haven't been able to reproduce the reported problem at a first glance, the issue is labeled [Needs investigation](https://github.com/grafana/grafana/labels/needs%20investigation). Depending on the perceived severity and/or number of [upvotes](https://help.github.com/en/articles/about-conversations-on-github#reacting-to-ideas-in-comments), the investigation will either be delegated to another maintainer for further investigation or put on hold until someone else (maintainer or contributor) picks it up and eventually starts investigating it.
|
||||
When an issue has all basic information provided, but the triage responsible haven't been able to reproduce the reported problem at a first glance, the issue is labeled [Needs investigation](https://github.com/grafana/grafana/labels/needs%20investigation). Depending of the perceived severity and/or number of [upvotes](https://help.github.com/en/articles/about-conversations-on-github#reacting-to-ideas-in-comments), the investigation will either be delegated to another maintainer for further investigation or either put on hold until someone else (maintainer or contributor) picks it up and eventually start investigating it.
|
||||
|
||||
Investigating issues can be a very time consuming task, especially for the maintainers, given the huge number of combinations of plugins, data sources, platforms, databases, browsers, tools, hardware, integrations, versions and cloud services, etc that are being used with Grafana. There is a certain number of combinations that are more common than others, and these are in general easier for maintainers to investigate.
|
||||
Investigating issues can be a very time consuming task, especially for the maintainers given the huge number of combinations of plugins, data sources, platforms, databases, browsers, tools, hardware, integrations, versions and cloud services etc that are being used with Grafana. There are a certain amount of combinations that are more common than others and these are in general easier for maintainers to investigate.
|
||||
|
||||
For some other combinations it may not be possible at all for a maintainer to setup a proper test environment to investigate the issue. In these cases we really appreciate any help we can get from the community. Otherwise the issue is highly likely to be closed.
|
||||
For some other combinations there may not be possible at all for a maintainer to setup a proper test environment for being able to investigate. In these cases we really appreciate any help we can get from the community. Otherwise the issue is highly likely to be closed.
|
||||
|
||||
Even if you don't have the time or knowledge to investigate an issue we highly recommend that you [upvote](https://help.github.com/en/articles/about-conversations-on-github#reacting-to-ideas-in-comments) the issue if you happen to have the same problem. If you have further details that may help investigating the issue please provide as much information as possible.
|
||||
|
||||
## Automation
|
||||
|
||||
We have some automation that triggers on comments or labels being added to issues. Many of these automated behaviors are defined in [commands.json](https://github.com/grafana/grafana/blob/master/.github/commands.json). Or in other [GitHub Actions](https://github.com/grafana/grafana/tree/master/.github/workflows)
|
||||
|
||||
* Add /duplicate `#<issue number>` to have Grafana label & close issue with an appropriate message.
|
||||
* Add `bot/question` and the bot will close it with an appropriate message.
|
||||
|
||||
[Read more on bot actions](https://github.com/grafana/grafana/blob/master/.github/bot.md)
|
||||
|
||||
## External PRs
|
||||
|
||||
Part of issue triage should also be triaging of external PRs. Main goal should be to make sure PRs from external contributors have an owner/reviewer and are not forgotten.
|
||||
|
||||
1. Check new external PRs which do not have a reviewer.
|
||||
1. Check if there is a link to an existing issue.
|
||||
1. If not and you know which issue it is solving, add the link yourself, otherwise ask the author to link the issue or create one.
|
||||
1. If not and you know which issue it is solving add the link yourself, otherwise ask the author to link the issue or create one.
|
||||
1. Assign a reviewer based on who was handling the linked issue or what code or feature does the PR touches (look at who was the last to make changes there if all else fails).
|
||||
|
||||
## Appendix
|
||||
|
||||
### Setting up Gmail filters
|
||||
|
||||
If you're using Gmail it's highly recommended that you setup filters to automatically remove email from the inbox and label them accordingly to make it easy for you to understand when you need to act upon a notification or process all incoming issues that haven't been triaged.
|
||||
If you're using Gmail it's highly recommened that you setup filters to automatically remove email from the inbox and label them accordingly to make it easy for you to understand when you need to act upon a notification or process all incoming issues that haven't been triaged.
|
||||
|
||||
This may be setup by personal preference, but here's a working configuration for reference.
|
||||
1. Follow instructions in [gist](https://gist.github.com/marefr/9167c2e31466f6316c1cba118874e74f)
|
||||
@@ -335,14 +327,14 @@ This will give you a structure of labels in the sidebar similar to the following
|
||||
```
|
||||
- Inbox
|
||||
...
|
||||
- GitHub (mine)
|
||||
- Github (mine)
|
||||
- activity
|
||||
- assigned
|
||||
- mentions
|
||||
- GitHub (other)
|
||||
- Github (other)
|
||||
- Grafana
|
||||
```
|
||||
|
||||
- All notifications you’ll need to read/take action on show up as unread in GitHub (mine) and its sub-labels.
|
||||
- All other notifications you don’t need to take action on show up as unread in GitHub (other) and its sub-labels
|
||||
- This is convenient for issue triage and to follow the activity in the Grafana project.
|
||||
* All notifications you’ll need to read/take action on shows up as unread in Github (mine) and its sub-labels.
|
||||
* All other notifications you don’t need to take action on shows up as unread in Github (other) and its sub-labels
|
||||
* This is convenient for issue triage and to follow the activity in the Grafana project.
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
@torkelo is the main/default maintainer, some parts of the codebase have other maintainers:
|
||||
|
||||
- Backend:
|
||||
- @bergquist
|
||||
- Plugins:
|
||||
- @ryantxu
|
||||
- UX/UI:
|
||||
- @davkal
|
||||
36
Makefile
36
Makefile
@@ -4,7 +4,7 @@
|
||||
|
||||
-include local/Makefile
|
||||
|
||||
.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go revive golangci-lint tidy-check test-go test-js test run run-frontend clean devenv devenv-down revive-strict protobuf help
|
||||
.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go gosec revive golangci-lint go-vet test-go test-js test run run-frontend clean devenv devenv-down revive-alerting protobuf help
|
||||
|
||||
GO = GO111MODULE=on go
|
||||
GO_FILES ?= ./pkg/...
|
||||
@@ -42,7 +42,6 @@ build-cli: ## Build Grafana CLI application.
|
||||
build-js: ## Build frontend assets.
|
||||
@echo "build frontend"
|
||||
yarn run build
|
||||
yarn run plugins:build-bundled
|
||||
|
||||
build: build-go build-js ## Build backend and frontend.
|
||||
|
||||
@@ -81,9 +80,14 @@ revive: scripts/go/bin/revive
|
||||
-config ./scripts/go/configs/revive.toml \
|
||||
$(GO_FILES)
|
||||
|
||||
revive-strict: scripts/go/bin/revive
|
||||
@echo "lint via revive (strict)"
|
||||
@scripts/revive-strict scripts/go/bin/revive
|
||||
revive-alerting: scripts/go/bin/revive
|
||||
@echo "lint alerting via revive"
|
||||
@scripts/go/bin/revive \
|
||||
-formatter stylish \
|
||||
-config ./scripts/go/configs/revive-strict.toml \
|
||||
./pkg/services/alerting/... \
|
||||
./pkg/services/provisioning/datasources/... \
|
||||
./pkg/services/provisioning/dashboards/...
|
||||
|
||||
scripts/go/bin/golangci-lint: scripts/go/go.mod
|
||||
@cd scripts/go; \
|
||||
@@ -92,14 +96,26 @@ scripts/go/bin/golangci-lint: scripts/go/go.mod
|
||||
golangci-lint: scripts/go/bin/golangci-lint
|
||||
@echo "lint via golangci-lint"
|
||||
@scripts/go/bin/golangci-lint run \
|
||||
--config ./scripts/go/configs/.golangci.toml \
|
||||
--config ./scripts/go/configs/.golangci.yml \
|
||||
$(GO_FILES)
|
||||
|
||||
tidy-check:
|
||||
@echo "check whether go.mod and go.sum are consistent"
|
||||
@scripts/tidy-check.sh
|
||||
scripts/go/bin/gosec: scripts/go/go.mod
|
||||
@cd scripts/go; \
|
||||
$(GO) build -o ./bin/gosec github.com/securego/gosec/cmd/gosec
|
||||
|
||||
lint-go: golangci-lint revive revive-strict tidy-check # Run all code checks for backend.
|
||||
# TODO recheck the rules and leave only necessary exclusions
|
||||
gosec: scripts/go/bin/gosec
|
||||
@echo "lint via gosec"
|
||||
@scripts/go/bin/gosec -quiet \
|
||||
-exclude=G104,G107,G108,G201,G202,G204,G301,G304,G401,G402,G501 \
|
||||
-conf=./scripts/go/configs/gosec.json \
|
||||
$(GO_FILES)
|
||||
|
||||
go-vet:
|
||||
@echo "lint via go vet"
|
||||
@$(GO) vet $(GO_FILES)
|
||||
|
||||
lint-go: go-vet golangci-lint revive revive-alerting gosec ## Run all code checks for backend.
|
||||
|
||||
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
|
||||
shellcheck: $(SH_FILES) ## Run checks for shell scripts.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
Copyright 2014-2021 Grafana Labs
|
||||
Copyright 2014-2018 Grafana Labs
|
||||
|
||||
This software is based on Kibana:
|
||||
Copyright 2012-2013 Elasticsearch BV
|
||||
|
||||
15
README.md
15
README.md
@@ -8,13 +8,22 @@ The open-source platform for monitoring and observability.
|
||||
|
||||
Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data driven culture:
|
||||
|
||||
- **Visualize:** Fast and flexible client side graphs with a multitude of options. Panel plugins offer many different ways to visualize metrics and logs.
|
||||
- **Visualize:** Fast and flexible client side graphs with a multitude of options. Panel plugins for many different way to visualize metrics and logs.
|
||||
- **Dynamic Dashboards:** Create dynamic & reusable dashboards with template variables that appear as dropdowns at the top of the dashboard.
|
||||
- **Explore Metrics:** Explore your data through ad-hoc queries and dynamic drilldown. Split view and compare different time ranges, queries and data sources side by side.
|
||||
- **Explore Logs:** Experience the magic of switching from metrics to logs with preserved label filters. Quickly search through all your logs or streaming them live.
|
||||
- **Alerting:** Visually define alert rules for your most important metrics. Grafana will continuously evaluate and send notifications to systems like Slack, PagerDuty, VictorOps, OpsGenie.
|
||||
- **Mixed Data Sources:** Mix different data sources in the same graph! You can specify a data source on a per-query basis. This works for even custom datasources.
|
||||
|
||||
### Grafana 7.0 and GrafanaCONline
|
||||
|
||||
- Grafana 7.0 Beta is [available for download](https://grafana.com/grafana/download).
|
||||
- Read [what's is new](https://grafana.com/docs/grafana/latest/guides/whats-new-in-v7-0/).
|
||||
|
||||
Want to learn more about Grafana 7 and more? Sign up for our online conference!
|
||||
|
||||
[](https://grafana.com/about/events/grafanacon/2020/?source=grafana-readme)
|
||||
|
||||
## Get started
|
||||
|
||||
- [Get Grafana](https://grafana.com/get)
|
||||
@@ -36,8 +45,8 @@ If you're interested in contributing to the Grafana project:
|
||||
|
||||
## Get involved
|
||||
|
||||
- Follow [@grafana on Twitter](https://twitter.com/grafana/).
|
||||
- Read and subscribe to the [Grafana blog](https://grafana.com/blog/).
|
||||
- Follow [@grafana on Twitter](https://twitter.com/grafana/)
|
||||
- Read and subscribe to the [Grafana blog](https://grafana.com/blog/)
|
||||
- If you have a specific question, check out our [discussion forums](https://community.grafana.com/).
|
||||
- For general discussions, join us on the [official Slack](http://slack.raintank.io/) team.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Please encrypt your message to us; please use our PGP key. The key fingerprint i
|
||||
|
||||
F988 7BEA 027A 049F AE8E 5CAA D125 8932 BE24 C5CA
|
||||
|
||||
The key is available from [keyserver.ubuntu.com](https://keyserver.ubuntu.com/pks/lookup?search=0xF9887BEA027A049FAE8E5CAAD1258932BE24C5CA&fingerprint=on&op=index).
|
||||
The key is available from [pgp.mit.edu](https://pgp.mit.edu/pks/lookup?op=get&search=0xF9887BEA027A049FAE8E5CAAD1258932BE24C5CA) by searching for [grafana](https://pgp.mit.edu/pks/lookup?search=grafana&op=index).
|
||||
|
||||
Grafana Labs will send you a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Upgrading Go or Node.js requires making changes in many different files. See bel
|
||||
|
||||
The Grafana project uses [Go modules](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) to manage dependencies on external packages. This requires a working Go environment with version 1.11 or greater installed.
|
||||
|
||||
> **Note:** Since most developers of Grafana still use the `GOPATH` we need to specify `GO111MODULE=on` to make `go mod` and `got get` work as intended. If you have setup Grafana outside of the `GOPATH` on your machine you can skip `GO111MODULE=on` when running the commands below.
|
||||
_Note:_ Since most developers of Grafana still use the `GOPATH` we need to specify `GO111MODULE=on` to make `go mod` and `got get` work as intended. If you have setup Grafana outside of the `GOPATH` on your machine you can skip `GO111MODULE=on` when running the commands below.
|
||||
|
||||
To add or update a new dependency, use the `go get` command:
|
||||
|
||||
|
||||
77
WORKFLOW.md
77
WORKFLOW.md
@@ -1,77 +0,0 @@
|
||||
# Grafana workflow
|
||||
|
||||
This document is based on [GOVERNANCE.md](GOVERNANCE.md). We assume good faith and intend to keep all processes as lightweight as possible but as specific as required. In case of disagreements about anything in this document, GOVERNANCE.md applies.
|
||||
|
||||
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC2119](http://tools.ietf.org/html/rfc2119).
|
||||
|
||||
Git and [GitHub terminology](https://help.github.com/en/github/getting-started-with-github/github-glossary) are used throughout this document.
|
||||
|
||||
Team members and their access to repositories is maintained through [GitHub teams](https://help.github.com/en/github/setting-up-and-managing-organizations-and-teams/about-teams). Team maintainers add and remove team members as outlined in GOVERNANCE.md.
|
||||
|
||||
# Code changes
|
||||
|
||||
## Proposing changes
|
||||
|
||||
Examples of proposed changes are overarching architecture, component design, and specific code or graphical elements. Proposed changes SHOULD cover the big picture and intention, but individual parts SHOULD be split into the smallest possible changes. Changes SHOULD be based on and target the master branch. Depending on size of the proposed change, each change SHOULD be discussed, in increasing order of change size and complexity:
|
||||
- Directly in a RR (Pull Request) - this MAY be done, but SHOULD not be the common case.
|
||||
- Issue
|
||||
- Developer mailing list
|
||||
- Design document, shared via Google Docs, accessible to at least all team members.
|
||||
|
||||
Significant changes MUST be discussed and agreed upon with the relevant subsystem maintainers.
|
||||
|
||||
## Merging PRs (Pull Requests)
|
||||
|
||||
Depending on the size and complexity of a PR, different requirements MUST be applied. Any team member contributing substantially to a PR MUST NOT count against review requirements.
|
||||
Commits MUST be merged into master using PRs. They MUST NOT be merged into master directly.
|
||||
- Every merge MUST be approved by at least one team member.
|
||||
- Non-trivial changes MUST be approved by at least
|
||||
- two team members, or
|
||||
- one subsystem maintainer.
|
||||
- Significant changes MUST be approved by at least
|
||||
- two team members, AND
|
||||
- the relevant subsystem maintainer.
|
||||
|
||||
PRs MUST be [reviewed](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/reviewing-changes-in-pull-requests) and [approved](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/approving-a-pull-request-with-required-reviews) via GitHub’s review system.
|
||||
- Reviewers MAY write comments if approving
|
||||
- Reviewers MUST write comments if rejecting a PR or if requesting changes.
|
||||
|
||||
Once a PR is approved as per above, any team member MAY merge the PR.
|
||||
|
||||
## Backporting a PR
|
||||
|
||||
PRs intended for inclusion in the next PATCH release they must be backported to the release branch. The bot can do this automatically. [Read more on backport PRs](https://github.com/grafana/grafana/blob/master/.github/bot.md). Both the source PR and the backport PR should be assigned to the patch release milestone, unless you are backporting to many releases then it can differ.
|
||||
|
||||
Backport PRs are also needed during the beta period to get fixes into the stable release.
|
||||
|
||||
# Release workflow
|
||||
|
||||
## Branch structure
|
||||
|
||||
Grafana uses trunk-based development.
|
||||
|
||||
In particular, we found that the following principles match how we work:
|
||||
- Master and release branches MUST always build without failure.
|
||||
- Branches SHOULD be merged often. Larger changes SHOULD be activated with feature flags until they are ready. Long-lived development branches SHOULD be avoided.
|
||||
- Changes MAY be enabled by default once they are in a complete state
|
||||
- Changes which span multiple PRs MUST be described in an overarching issue or Google Doc.
|
||||
|
||||
## Releases
|
||||
|
||||
Releases MUST follow [Semantic Versioning](https://semver.org/) in naming and SHOULD follow Semantic Versioning as closely as reasonably possible for non-library software.
|
||||
|
||||
Release branches MUST be split from the following branches.
|
||||
- MAJOR release branches MUST be based on master.
|
||||
- MINOR release branches MUST be based on master.
|
||||
- PATCH release branches MUST be split from the relevant MINOR release branch’s most current PATCH
|
||||
|
||||
Security releases follow the same process but MUST be prepared in secret. Security releases MUST NOT include changes which are not related to the security fix. Normal release processes MUST accommodate the security release process. SECURITY.md MUST be followed.
|
||||
|
||||
Releases follow the following cadence
|
||||
- MAJOR: Yearly
|
||||
- MINOR: Every 4-6 weeks
|
||||
- PATCH: As needed
|
||||
|
||||
Releases SHOULD NOT be delayed by pending changes.
|
||||
|
||||
Releases MUST be coordinated with the relevant subsystem maintainers.
|
||||
309
build.go
309
build.go
@@ -9,7 +9,6 @@ import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
@@ -30,14 +29,13 @@ const (
|
||||
|
||||
var (
|
||||
//versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`)
|
||||
goarch string
|
||||
goos string
|
||||
gocc string
|
||||
cgo bool
|
||||
libc string
|
||||
pkgArch string
|
||||
version string = "v1"
|
||||
buildTags []string
|
||||
goarch string
|
||||
goos string
|
||||
gocc string
|
||||
cgo bool
|
||||
libc string
|
||||
pkgArch string
|
||||
version string = "v1"
|
||||
// deb & rpm does not support semver so have to handle their version a little differently
|
||||
linuxPackageVersion string = "v1"
|
||||
linuxPackageIteration string = ""
|
||||
@@ -59,14 +57,14 @@ func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(0)
|
||||
|
||||
ensureGoPath()
|
||||
|
||||
var buildIdRaw string
|
||||
var buildTagsRaw string
|
||||
|
||||
flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH")
|
||||
flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS")
|
||||
flag.StringVar(&gocc, "cc", "", "CC")
|
||||
flag.StringVar(&libc, "libc", "", "LIBC")
|
||||
flag.StringVar(&buildTagsRaw, "build-tags", "", "Sets custom build tags")
|
||||
flag.BoolVar(&cgo, "cgo-enabled", cgo, "Enable cgo")
|
||||
flag.StringVar(&pkgArch, "pkg-arch", "", "PKG ARCH")
|
||||
flag.BoolVar(&race, "race", race, "Use race detector")
|
||||
@@ -92,10 +90,6 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
if len(buildTagsRaw) > 0 {
|
||||
buildTags = strings.Split(buildTagsRaw, ",")
|
||||
}
|
||||
|
||||
log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, linuxPackageVersion, linuxPackageIteration)
|
||||
|
||||
if flag.NArg() == 0 {
|
||||
@@ -112,20 +106,47 @@ func main() {
|
||||
|
||||
case "build-srv", "build-server":
|
||||
clean()
|
||||
doBuild("grafana-server", "./pkg/cmd/grafana-server", buildTags)
|
||||
build("grafana-server", "./pkg/cmd/grafana-server", []string{})
|
||||
|
||||
case "build-cli":
|
||||
clean()
|
||||
doBuild("grafana-cli", "./pkg/cmd/grafana-cli", buildTags)
|
||||
build("grafana-cli", "./pkg/cmd/grafana-cli", []string{})
|
||||
|
||||
case "build":
|
||||
//clean()
|
||||
for _, binary := range binaries {
|
||||
doBuild(binary, "./pkg/cmd/"+binary, buildTags)
|
||||
build(binary, "./pkg/cmd/"+binary, []string{})
|
||||
}
|
||||
|
||||
case "build-frontend":
|
||||
yarn("build")
|
||||
grunt(gruntBuildArg("build")...)
|
||||
|
||||
case "test":
|
||||
test("./pkg/...")
|
||||
grunt("test")
|
||||
|
||||
case "package":
|
||||
grunt(gruntBuildArg("build")...)
|
||||
grunt(gruntBuildArg("package")...)
|
||||
if goos == linux {
|
||||
createLinuxPackages()
|
||||
}
|
||||
|
||||
case "package-only":
|
||||
grunt(gruntBuildArg("package")...)
|
||||
if goos == linux {
|
||||
createLinuxPackages()
|
||||
}
|
||||
case "pkg-archive":
|
||||
grunt(gruntBuildArg("package")...)
|
||||
|
||||
case "pkg-rpm":
|
||||
grunt(gruntBuildArg("release")...)
|
||||
createRpmPackages()
|
||||
|
||||
case "pkg-deb":
|
||||
grunt(gruntBuildArg("release")...)
|
||||
createDebPackages()
|
||||
|
||||
case "sha-dist":
|
||||
shaFilesInDist()
|
||||
@@ -206,8 +227,214 @@ func readVersionFromPackageJson() {
|
||||
}
|
||||
}
|
||||
|
||||
func yarn(params ...string) {
|
||||
runPrint(`yarn run`, params...)
|
||||
type linuxPackageOptions struct {
|
||||
packageType string
|
||||
packageArch string
|
||||
homeDir string
|
||||
homeBinDir string
|
||||
binPath string
|
||||
serverBinPath string
|
||||
cliBinPath string
|
||||
configDir string
|
||||
ldapFilePath string
|
||||
etcDefaultPath string
|
||||
etcDefaultFilePath string
|
||||
initdScriptFilePath string
|
||||
systemdServiceFilePath string
|
||||
|
||||
postinstSrc string
|
||||
initdScriptSrc string
|
||||
defaultFileSrc string
|
||||
systemdFileSrc string
|
||||
cliBinaryWrapperSrc string
|
||||
|
||||
depends []string
|
||||
}
|
||||
|
||||
func createDebPackages() {
|
||||
debPkgArch := pkgArch
|
||||
if pkgArch == "armv7" || pkgArch == "armv6" {
|
||||
debPkgArch = "armhf"
|
||||
}
|
||||
|
||||
createPackage(linuxPackageOptions{
|
||||
packageType: "deb",
|
||||
packageArch: debPkgArch,
|
||||
homeDir: "/usr/share/grafana",
|
||||
homeBinDir: "/usr/share/grafana/bin",
|
||||
binPath: "/usr/sbin",
|
||||
configDir: "/etc/grafana",
|
||||
etcDefaultPath: "/etc/default",
|
||||
etcDefaultFilePath: "/etc/default/grafana-server",
|
||||
initdScriptFilePath: "/etc/init.d/grafana-server",
|
||||
systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
|
||||
|
||||
postinstSrc: "packaging/deb/control/postinst",
|
||||
initdScriptSrc: "packaging/deb/init.d/grafana-server",
|
||||
defaultFileSrc: "packaging/deb/default/grafana-server",
|
||||
systemdFileSrc: "packaging/deb/systemd/grafana-server.service",
|
||||
cliBinaryWrapperSrc: "packaging/wrappers/grafana-cli",
|
||||
|
||||
depends: []string{"adduser", "libfontconfig1"},
|
||||
})
|
||||
}
|
||||
|
||||
func createRpmPackages() {
|
||||
rpmPkgArch := pkgArch
|
||||
switch {
|
||||
case pkgArch == "armv7":
|
||||
rpmPkgArch = "armhfp"
|
||||
case pkgArch == "arm64":
|
||||
rpmPkgArch = "aarch64"
|
||||
}
|
||||
createPackage(linuxPackageOptions{
|
||||
packageType: "rpm",
|
||||
packageArch: rpmPkgArch,
|
||||
homeDir: "/usr/share/grafana",
|
||||
homeBinDir: "/usr/share/grafana/bin",
|
||||
binPath: "/usr/sbin",
|
||||
configDir: "/etc/grafana",
|
||||
etcDefaultPath: "/etc/sysconfig",
|
||||
etcDefaultFilePath: "/etc/sysconfig/grafana-server",
|
||||
initdScriptFilePath: "/etc/init.d/grafana-server",
|
||||
systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
|
||||
|
||||
postinstSrc: "packaging/rpm/control/postinst",
|
||||
initdScriptSrc: "packaging/rpm/init.d/grafana-server",
|
||||
defaultFileSrc: "packaging/rpm/sysconfig/grafana-server",
|
||||
systemdFileSrc: "packaging/rpm/systemd/grafana-server.service",
|
||||
cliBinaryWrapperSrc: "packaging/wrappers/grafana-cli",
|
||||
|
||||
depends: []string{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
|
||||
})
|
||||
}
|
||||
|
||||
func createLinuxPackages() {
|
||||
if !skipDebGen {
|
||||
createDebPackages()
|
||||
}
|
||||
|
||||
if !skipRpmGen {
|
||||
createRpmPackages()
|
||||
}
|
||||
}
|
||||
|
||||
func createPackage(options linuxPackageOptions) {
|
||||
packageRoot, _ := ioutil.TempDir("", "grafana-linux-pack")
|
||||
|
||||
// create directories
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.homeDir))
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.configDir))
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, "/etc/init.d"))
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.etcDefaultPath))
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/lib/systemd/system"))
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/sbin"))
|
||||
|
||||
// copy grafana-cli wrapper
|
||||
runPrint("cp", "-p", options.cliBinaryWrapperSrc, filepath.Join(packageRoot, "/usr/sbin/"+cliBinary))
|
||||
|
||||
// copy grafana-server binary
|
||||
runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+serverBinary), filepath.Join(packageRoot, "/usr/sbin/"+serverBinary))
|
||||
|
||||
// copy init.d script
|
||||
runPrint("cp", "-p", options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath))
|
||||
// copy environment var file
|
||||
runPrint("cp", "-p", options.defaultFileSrc, filepath.Join(packageRoot, options.etcDefaultFilePath))
|
||||
// copy systemd file
|
||||
runPrint("cp", "-p", options.systemdFileSrc, filepath.Join(packageRoot, options.systemdServiceFilePath))
|
||||
// copy release files
|
||||
runPrint("cp", "-a", filepath.Join(workingDir, "tmp")+"/.", filepath.Join(packageRoot, options.homeDir))
|
||||
// remove bin path
|
||||
runPrint("rm", "-rf", filepath.Join(packageRoot, options.homeDir, "bin"))
|
||||
|
||||
// create /bin within home
|
||||
runPrint("mkdir", "-p", filepath.Join(packageRoot, options.homeBinDir))
|
||||
// The grafana-cli binary is exposed through a wrapper to ensure a proper
|
||||
// configuration is in place. To enable that, we need to store the original
|
||||
// binary in a separate location to avoid conflicts.
|
||||
runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+cliBinary), filepath.Join(packageRoot, options.homeBinDir, cliBinary))
|
||||
|
||||
args := []string{
|
||||
"-s", "dir",
|
||||
"--description", "Grafana",
|
||||
"-C", packageRoot,
|
||||
"--url", "https://grafana.com",
|
||||
"--maintainer", "contact@grafana.com",
|
||||
"--config-files", options.initdScriptFilePath,
|
||||
"--config-files", options.etcDefaultFilePath,
|
||||
"--config-files", options.systemdServiceFilePath,
|
||||
"--after-install", options.postinstSrc,
|
||||
|
||||
"--version", linuxPackageVersion,
|
||||
"-p", "./dist",
|
||||
}
|
||||
|
||||
name := "grafana"
|
||||
if enterprise {
|
||||
name += "-enterprise"
|
||||
args = append(args, "--replaces", "grafana")
|
||||
}
|
||||
fmt.Printf("pkgArch is set to '%s', generated arch is '%s'\n", pkgArch, options.packageArch)
|
||||
if pkgArch == "armv6" {
|
||||
name += "-rpi"
|
||||
args = append(args, "--replaces", "grafana")
|
||||
}
|
||||
args = append(args, "--name", name)
|
||||
|
||||
description := "Grafana"
|
||||
if enterprise {
|
||||
description += " Enterprise"
|
||||
}
|
||||
|
||||
if !enterprise {
|
||||
args = append(args, "--license", "\"Apache 2.0\"")
|
||||
}
|
||||
|
||||
if options.packageType == "rpm" {
|
||||
args = append(args, "--rpm-posttrans", "packaging/rpm/control/posttrans")
|
||||
}
|
||||
|
||||
if options.packageType == "deb" {
|
||||
args = append(args, "--deb-no-default-config-files")
|
||||
}
|
||||
|
||||
if options.packageArch != "" {
|
||||
args = append(args, "-a", options.packageArch)
|
||||
}
|
||||
|
||||
if linuxPackageIteration != "" {
|
||||
args = append(args, "--iteration", linuxPackageIteration)
|
||||
}
|
||||
|
||||
// add dependencies
|
||||
for _, dep := range options.depends {
|
||||
args = append(args, "--depends", dep)
|
||||
}
|
||||
|
||||
args = append(args, ".")
|
||||
|
||||
fmt.Println("Creating package: ", options.packageType)
|
||||
runPrint("fpm", append([]string{"-t", options.packageType}, args...)...)
|
||||
}
|
||||
|
||||
func ensureGoPath() {
|
||||
if os.Getenv("GOPATH") == "" {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
gopath := filepath.Clean(filepath.Join(cwd, "../../../../"))
|
||||
log.Println("GOPATH is", gopath)
|
||||
os.Setenv("GOPATH", gopath)
|
||||
}
|
||||
}
|
||||
|
||||
func grunt(params ...string) {
|
||||
if runtime.GOOS == windows {
|
||||
runPrint(`.\node_modules\.bin\grunt`, params...)
|
||||
} else {
|
||||
runPrint("./node_modules/.bin/grunt", params...)
|
||||
}
|
||||
}
|
||||
|
||||
func genPackageVersion() string {
|
||||
@@ -218,13 +445,26 @@ func genPackageVersion() string {
|
||||
}
|
||||
}
|
||||
|
||||
func setup() {
|
||||
args := []string{"install", "-v"}
|
||||
if goos == windows {
|
||||
args = append(args, "-buildmode=exe")
|
||||
func gruntBuildArg(task string) []string {
|
||||
args := []string{task}
|
||||
args = append(args, fmt.Sprintf("--pkgVer=%v", genPackageVersion()))
|
||||
if pkgArch != "" {
|
||||
args = append(args, fmt.Sprintf("--arch=%v", pkgArch))
|
||||
}
|
||||
args = append(args, "./pkg/cmd/grafana-server")
|
||||
runPrint("go", args...)
|
||||
if libc != "" {
|
||||
args = append(args, fmt.Sprintf("--libc=%s", libc))
|
||||
}
|
||||
if enterprise {
|
||||
args = append(args, "--enterprise")
|
||||
}
|
||||
|
||||
args = append(args, fmt.Sprintf("--platform=%v", goos))
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func setup() {
|
||||
runPrint("go", "install", "-v", "./pkg/cmd/grafana-server")
|
||||
}
|
||||
|
||||
func printGeneratedVersion() {
|
||||
@@ -233,15 +473,10 @@ func printGeneratedVersion() {
|
||||
|
||||
func test(pkg string) {
|
||||
setBuildEnv()
|
||||
args := []string{"test", "-short", "-timeout", "60s"}
|
||||
if goos == windows {
|
||||
args = append(args, "-buildmode=exe")
|
||||
}
|
||||
args = append(args, pkg)
|
||||
runPrint("go", args...)
|
||||
runPrint("go", "test", "-short", "-timeout", "60s", pkg)
|
||||
}
|
||||
|
||||
func doBuild(binaryName, pkg string, tags []string) {
|
||||
func build(binaryName, pkg string, tags []string) {
|
||||
libcPart := ""
|
||||
if libc != "" {
|
||||
libcPart = fmt.Sprintf("-%s", libc)
|
||||
@@ -260,10 +495,6 @@ func doBuild(binaryName, pkg string, tags []string) {
|
||||
rmr(binary, binary+".md5")
|
||||
}
|
||||
args := []string{"build", "-ldflags", ldflags()}
|
||||
if goos == windows {
|
||||
// Work around a linking error on Windows: "export ordinal too large"
|
||||
args = append(args, "-buildmode=exe")
|
||||
}
|
||||
if len(tags) > 0 {
|
||||
args = append(args, "-tags", strings.Join(tags, ","))
|
||||
}
|
||||
@@ -323,7 +554,7 @@ func clean() {
|
||||
|
||||
rmr("dist")
|
||||
rmr("tmp")
|
||||
rmr(filepath.Join(build.Default.GOPATH, fmt.Sprintf("pkg/%s_%s/github.com/grafana", goos, goarch)))
|
||||
rmr(filepath.Join(os.Getenv("GOPATH"), fmt.Sprintf("pkg/%s_%s/github.com/grafana", goos, goarch)))
|
||||
}
|
||||
|
||||
func setBuildEnv() {
|
||||
|
||||
@@ -66,9 +66,6 @@ cert_key =
|
||||
# Unix socket path
|
||||
socket = /tmp/grafana.sock
|
||||
|
||||
# CDN Url
|
||||
cdn_url =
|
||||
|
||||
#################################### Database ############################
|
||||
[database]
|
||||
# You can configure the database connection by specifying type, host, name, user and password
|
||||
@@ -133,25 +130,7 @@ logging = false
|
||||
# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set.
|
||||
timeout = 30
|
||||
|
||||
# How many seconds the data proxy waits before sending a keepalive request.
|
||||
keep_alive_seconds = 30
|
||||
|
||||
# How many seconds the data proxy waits for a successful TLS Handshake before timing out.
|
||||
tls_handshake_timeout_seconds = 10
|
||||
|
||||
# How many seconds the data proxy will wait for a server's first response headers after
|
||||
# fully writing the request headers if the request has an "Expect: 100-continue"
|
||||
# header. A value of 0 will result in the body being sent immediately, without
|
||||
# waiting for the server to approve.
|
||||
expect_continue_timeout_seconds = 1
|
||||
|
||||
# The maximum number of idle connections that Grafana will keep alive.
|
||||
max_idle_connections = 100
|
||||
|
||||
# How many seconds the data proxy keeps an idle connection open before timing out.
|
||||
idle_conn_timeout_seconds = 90
|
||||
|
||||
# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request.
|
||||
# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false.
|
||||
send_user_header = false
|
||||
|
||||
#################################### Analytics ###########################
|
||||
@@ -162,9 +141,6 @@ send_user_header = false
|
||||
# Change this option to false to disable reporting.
|
||||
reporting_enabled = true
|
||||
|
||||
# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs
|
||||
reporting_distributor = grafana-labs
|
||||
|
||||
# Set to false to disable all checks to https://grafana.com
|
||||
# for new versions (grafana itself and plugins), check is used
|
||||
# in some UI views to notify that grafana or plugin update exists
|
||||
@@ -213,6 +189,7 @@ allow_embedding = false
|
||||
# Set to true if you want to enable http strict transport security (HSTS) response header.
|
||||
# This is only sent when HTTPS is enabled in this configuration.
|
||||
# HSTS tells browsers that the site should only be accessed using HTTPS.
|
||||
# The default will change to true in the next minor release, 6.3.
|
||||
strict_transport_security = false
|
||||
|
||||
# Sets how long a browser should cache HSTS. Only applied if strict_transport_security is enabled.
|
||||
@@ -226,20 +203,13 @@ strict_transport_security_subdomains = false
|
||||
|
||||
# Set to true to enable the X-Content-Type-Options response header.
|
||||
# The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types advertised
|
||||
# in the Content-Type headers should not be changed and be followed.
|
||||
x_content_type_options = true
|
||||
# in the Content-Type headers should not be changed and be followed. The default will change to true in the next minor release, 6.3.
|
||||
x_content_type_options = false
|
||||
|
||||
# Set to true to enable the X-XSS-Protection header, which tells browsers to stop pages from loading
|
||||
# when they detect reflected cross-site scripting (XSS) attacks.
|
||||
x_xss_protection = true
|
||||
# when they detect reflected cross-site scripting (XSS) attacks. The default will change to true in the next minor release, 6.3.
|
||||
x_xss_protection = false
|
||||
|
||||
# Enable adding the Content-Security-Policy header to your requests.
|
||||
# CSP allows to control resources the user agent is allowed to load and helps prevent XSS attacks.
|
||||
content_security_policy = false
|
||||
|
||||
# Set Content Security Policy template used when adding the Content-Security-Policy header to your requests.
|
||||
# $NONCE in the template includes a random nonce.
|
||||
content_security_policy_template = """script-src 'unsafe-eval' 'strict-dynamic' $NONCE;object-src 'none';font-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data:;base-uri 'self';connect-src 'self' grafana.com;manifest-src 'self';media-src 'none';form-action 'self';"""
|
||||
|
||||
#################################### Snapshots ###########################
|
||||
[snapshots]
|
||||
@@ -268,11 +238,6 @@ min_refresh_interval = 5s
|
||||
# Path to the default home dashboard. If this value is empty, then Grafana uses StaticRootPath + "dashboards/home.json"
|
||||
default_home_dashboard_path =
|
||||
|
||||
################################### Data sources #########################
|
||||
[datasources]
|
||||
# Upper limit of data sources that Grafana will return. This limit is a temporary configuration and it will be deprecated when pagination will be introduced on the list data sources API.
|
||||
datasource_limit = 5000
|
||||
|
||||
#################################### Users ###############################
|
||||
[users]
|
||||
# disable user signup / registration
|
||||
@@ -311,21 +276,15 @@ viewers_can_edit = false
|
||||
# Editors can administrate dashboard, folders and teams they create
|
||||
editors_can_admin = false
|
||||
|
||||
# The duration in time a user invitation remains valid before expiring. This setting should be expressed as a duration. Examples: 6h (hours), 2d (days), 1w (week). Default is 24h (24 hours). The minimum supported duration is 15m (15 minutes).
|
||||
user_invite_max_lifetime_duration = 24h
|
||||
|
||||
# Enter a comma-separated list of usernames to hide them in the Grafana UI. These users are shown to Grafana admins and to themselves.
|
||||
hidden_users =
|
||||
|
||||
[auth]
|
||||
# Login cookie name
|
||||
login_cookie_name = grafana_session
|
||||
|
||||
# The maximum lifetime (duration) an authenticated user can be inactive before being required to login at next visit. Default is 7 days (7d). This setting should be expressed as a duration, e.g. 5m (minutes), 6h (hours), 10d (days), 2w (weeks), 1M (month). The lifetime resets at each successful token rotation (token_rotation_interval_minutes).
|
||||
login_maximum_inactive_lifetime_duration =
|
||||
# The lifetime (days) an authenticated user can be inactive before being required to login at next visit. Default is 7 days.
|
||||
login_maximum_inactive_lifetime_days = 7
|
||||
|
||||
# The maximum lifetime (duration) an authenticated user can be logged in since login time before being required to login. Default is 30 days (30d). This setting should be expressed as a duration, e.g. 5m (minutes), 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
login_maximum_lifetime_duration =
|
||||
# The maximum lifetime (days) an authenticated user can be logged in since login time before being required to login. Default is 30 days.
|
||||
login_maximum_lifetime_days = 30
|
||||
|
||||
# How often should auth tokens be rotated for authenticated users when being active. The default is each 10 minutes.
|
||||
token_rotation_interval_minutes = 10
|
||||
@@ -343,15 +302,12 @@ signout_redirect_url =
|
||||
# This setting is ignored if multiple OAuth providers are configured.
|
||||
oauth_auto_login = false
|
||||
|
||||
# OAuth state max age cookie duration in seconds. Defaults to 600 seconds.
|
||||
oauth_state_cookie_max_age = 600
|
||||
# OAuth state max age cookie duration. Defaults to 60 seconds.
|
||||
oauth_state_cookie_max_age = 60
|
||||
|
||||
# limit of api_key seconds to live before expiration
|
||||
api_key_max_seconds_to_live = -1
|
||||
|
||||
# Set to true to enable SigV4 authentication option for HTTP-based datasources
|
||||
sigv4_auth_enabled = false
|
||||
|
||||
#################################### Anonymous Auth ######################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
@@ -363,15 +319,12 @@ org_name = Main Org.
|
||||
# specify role for unauthenticated users
|
||||
org_role = Viewer
|
||||
|
||||
# mask the Grafana version number for unauthenticated users
|
||||
hide_version = false
|
||||
|
||||
#################################### GitHub Auth #########################
|
||||
#################################### Github Auth #########################
|
||||
[auth.github]
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_id
|
||||
client_secret =
|
||||
client_secret = some_secret
|
||||
scopes = user:email,read:org
|
||||
auth_url = https://github.com/login/oauth/authorize
|
||||
token_url = https://github.com/login/oauth/access_token
|
||||
@@ -385,7 +338,7 @@ allowed_organizations =
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_id
|
||||
client_secret =
|
||||
client_secret = some_secret
|
||||
scopes = api
|
||||
auth_url = https://gitlab.com/oauth/authorize
|
||||
token_url = https://gitlab.com/oauth/token
|
||||
@@ -398,7 +351,7 @@ allowed_groups =
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_client_id
|
||||
client_secret =
|
||||
client_secret = some_client_secret
|
||||
scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
|
||||
auth_url = https://accounts.google.com/o/oauth2/auth
|
||||
token_url = https://accounts.google.com/o/oauth2/token
|
||||
@@ -412,7 +365,7 @@ hosted_domain =
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_id
|
||||
client_secret =
|
||||
client_secret = some_secret
|
||||
scopes = user:email
|
||||
allowed_organizations =
|
||||
|
||||
@@ -420,7 +373,7 @@ allowed_organizations =
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_id
|
||||
client_secret =
|
||||
client_secret = some_secret
|
||||
scopes = user:email
|
||||
allowed_organizations =
|
||||
|
||||
@@ -430,7 +383,7 @@ name = Azure AD
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_client_id
|
||||
client_secret =
|
||||
client_secret = some_client_secret
|
||||
scopes = openid email profile
|
||||
auth_url = https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize
|
||||
token_url = https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
|
||||
@@ -443,7 +396,7 @@ name = Okta
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_id
|
||||
client_secret =
|
||||
client_secret = some_secret
|
||||
scopes = openid profile email groups
|
||||
auth_url = https://<tenant-id>.okta.com/oauth2/v1/authorize
|
||||
token_url = https://<tenant-id>.okta.com/oauth2/v1/token
|
||||
@@ -458,14 +411,11 @@ name = OAuth
|
||||
enabled = false
|
||||
allow_sign_up = true
|
||||
client_id = some_id
|
||||
client_secret =
|
||||
client_secret = some_secret
|
||||
scopes = user:email
|
||||
email_attribute_name = email:primary
|
||||
email_attribute_path =
|
||||
login_attribute_path =
|
||||
name_attribute_path =
|
||||
role_attribute_path =
|
||||
id_token_attribute_name =
|
||||
auth_url =
|
||||
token_url =
|
||||
api_url =
|
||||
@@ -500,7 +450,7 @@ enabled = false
|
||||
config_file = /etc/grafana/ldap.toml
|
||||
allow_sign_up = true
|
||||
|
||||
# LDAP background sync (Enterprise only)
|
||||
# LDAP backround sync (Enterprise only)
|
||||
# At 1 am every day
|
||||
sync_cron = "0 0 1 * * *"
|
||||
active_sync_enabled = true
|
||||
@@ -518,7 +468,6 @@ skip_verify = false
|
||||
from_address = admin@grafana.localhost
|
||||
from_name = Grafana
|
||||
ehlo_identity =
|
||||
startTLS_policy =
|
||||
|
||||
[emails]
|
||||
welcome_email_on_sign_up = false
|
||||
@@ -581,25 +530,6 @@ facility =
|
||||
# Syslog tag. By default, the process' argv[0] is used.
|
||||
tag =
|
||||
|
||||
[log.frontend]
|
||||
# Should Sentry javascript agent be initialized
|
||||
enabled = false
|
||||
|
||||
# Sentry DSN if you want to send events to Sentry.
|
||||
sentry_dsn =
|
||||
|
||||
# Custom HTTP endpoint to send events captured by the Sentry agent to. Default will log the events to stdout.
|
||||
custom_endpoint = /log
|
||||
|
||||
# Rate of events to be reported between 0 (none) and 1 (all), float
|
||||
sample_rate = 1.0
|
||||
|
||||
# Requests per second limit enforced per an extended period, for Grafana backend log ingestion endpoint (/log).
|
||||
log_endpoint_requests_per_second_limit = 3
|
||||
|
||||
# Max requests accepted per short interval of time for Grafana backend log ingestion endpoint (/log)
|
||||
log_endpoint_burst_limit = 15
|
||||
|
||||
#################################### Usage Quotas ########################
|
||||
[quota]
|
||||
enabled = false
|
||||
@@ -664,36 +594,6 @@ max_attempts = 3
|
||||
# Makes it possible to enforce a minimal interval between evaluations, to reduce load on the backend
|
||||
min_interval_seconds = 1
|
||||
|
||||
# Configures for how long alert annotations are stored. Default is 0, which keeps them forever.
|
||||
# This setting should be expressed as an duration. Ex 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
max_annotation_age =
|
||||
|
||||
# Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
|
||||
max_annotations_to_keep =
|
||||
|
||||
#################################### Annotations #########################
|
||||
|
||||
[annotations.dashboard]
|
||||
# Dashboard annotations means that annotations are associated with the dashboard they are created on.
|
||||
|
||||
# Configures how long dashboard annotations are stored. Default is 0, which keeps them forever.
|
||||
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
max_age =
|
||||
|
||||
# Configures max number of dashboard annotations that Grafana stores. Default value is 0, which keeps all dashboard annotations.
|
||||
max_annotations_to_keep =
|
||||
|
||||
[annotations.api]
|
||||
# API annotations means that the annotations have been created using the API without any
|
||||
# association with a dashboard.
|
||||
|
||||
# Configures how long Grafana stores API annotations. Default is 0, which keeps them forever.
|
||||
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
max_age =
|
||||
|
||||
# Configures max number of API annotations that Grafana keeps. Default value is 0, which keeps all API annotations.
|
||||
max_annotations_to_keep =
|
||||
|
||||
#################################### Explore #############################
|
||||
[explore]
|
||||
# Enable the Explore section
|
||||
@@ -711,12 +611,6 @@ disable_total_stats = false
|
||||
basic_auth_username =
|
||||
basic_auth_password =
|
||||
|
||||
# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
|
||||
# can expose more information about the Grafana instance.
|
||||
[metrics.environment_info]
|
||||
#exampleLabel1 = exampleValue1
|
||||
#exampleLabel2 = exampleValue2
|
||||
|
||||
# Send internal Grafana metrics to graphite
|
||||
[metrics.graphite]
|
||||
# Enable by setting the address setting (ex localhost:2003)
|
||||
@@ -746,8 +640,6 @@ sampler_type = const
|
||||
# and indicates the initial sampling rate before the actual one
|
||||
# is received from the mothership
|
||||
sampler_param = 1
|
||||
# sampling_server_url is the URL of a sampling manager providing a sampling strategy.
|
||||
sampling_server_url =
|
||||
# Whether or not to use Zipkin span propagation (x-b3- HTTP headers).
|
||||
zipkin_propagation = false
|
||||
# Setting this to true disables shared RPC spans.
|
||||
@@ -780,8 +672,6 @@ public_url =
|
||||
key_file =
|
||||
bucket =
|
||||
path =
|
||||
enable_signed_urls = false
|
||||
signed_url_expiration =
|
||||
|
||||
[external_image_storage.azure_blob]
|
||||
account_name =
|
||||
@@ -811,7 +701,6 @@ enable_alpha = false
|
||||
app_tls_skip_verify_insecure = false
|
||||
# Enter a comma-separated list of plugin identifiers to identify plugins that are allowed to be loaded even if they lack a valid signature.
|
||||
allow_loading_unsigned_plugins =
|
||||
marketplace_url = https://grafana.com/grafana/plugins/
|
||||
|
||||
#################################### Grafana Image Renderer Plugin ##########################
|
||||
[plugin.grafana-image-renderer]
|
||||
@@ -863,7 +752,7 @@ rendering_clustering_mode =
|
||||
# When rendering_mode = clustered you can define maximum number of browser instances/incognito pages that can execute concurrently..
|
||||
rendering_clustering_max_concurrency =
|
||||
|
||||
# Limit the maximum viewport width, height and device scale factor that can be requested.
|
||||
# Limit the maxiumum viewport width, height and device scale factor that can be requested.
|
||||
rendering_viewport_max_width =
|
||||
rendering_viewport_max_height =
|
||||
rendering_viewport_max_device_scale_factor =
|
||||
@@ -879,27 +768,3 @@ license_path =
|
||||
[feature_toggles]
|
||||
# enable features, separated by spaces
|
||||
enable =
|
||||
|
||||
[date_formats]
|
||||
# For information on what formatting patterns that are supported https://momentjs.com/docs/#/displaying/
|
||||
|
||||
# Default system date format used in time range picker and other places where full time is displayed
|
||||
full_date = YYYY-MM-DD HH:mm:ss
|
||||
|
||||
# Used by graph and other places where we only show small intervals
|
||||
interval_second = HH:mm:ss
|
||||
interval_minute = HH:mm
|
||||
interval_hour = MM/DD HH:mm
|
||||
interval_day = MM/DD
|
||||
interval_month = YYYY-MM
|
||||
interval_year = YYYY
|
||||
|
||||
# Experimental feature
|
||||
use_browser_locale = false
|
||||
|
||||
# Default timezone for user preferences. Options are 'browser' for the browser local timezone or a timezone name from IANA Time Zone database, e.g. 'UTC' or 'Europe/Amsterdam' etc.
|
||||
default_timezone = browser
|
||||
|
||||
[expressions]
|
||||
# Enable or disable the expressions functionality.
|
||||
enabled = true
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
host = "127.0.0.1"
|
||||
# Default port is 389 or 636 if use_ssl = true
|
||||
port = 389
|
||||
# Set to true if LDAP server should use an encrypted TLS connection (either with STARTTLS or LDAPS)
|
||||
# Set to true if ldap server supports TLS
|
||||
use_ssl = false
|
||||
# If set to true, use LDAP with STARTTLS instead of LDAPS
|
||||
# Set to true if connect ldap server with STARTTLS pattern (create connection in insecure, then upgrade to secure connection with TLS)
|
||||
start_tls = false
|
||||
# set to true if you want to skip ssl cert validation
|
||||
ssl_skip_verify = false
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# # config file version
|
||||
apiVersion: 1
|
||||
|
||||
# apps:
|
||||
# - type: grafana-example-app
|
||||
# org_name: Main Org.
|
||||
# disabled: true
|
||||
# - type: raintank-worldping-app
|
||||
# org_id: 1
|
||||
# jsonData:
|
||||
# apiKey: "API KEY"
|
||||
163
conf/sample.ini
163
conf/sample.ini
@@ -67,9 +67,6 @@
|
||||
# Unix socket path
|
||||
;socket =
|
||||
|
||||
# CDN Url
|
||||
;cdn_url =
|
||||
|
||||
#################################### Database ####################################
|
||||
[database]
|
||||
# You can configure the database connection by specifying type, host, name, user and password
|
||||
@@ -113,11 +110,6 @@
|
||||
# For "sqlite3" only. cache mode setting used for connecting to the database. (private, shared)
|
||||
;cache_mode = private
|
||||
|
||||
################################### Data sources #########################
|
||||
[datasources]
|
||||
# Upper limit of data sources that Grafana will return. This limit is a temporary configuration and it will be deprecated when pagination will be introduced on the list data sources API.
|
||||
;datasource_limit = 5000
|
||||
|
||||
#################################### Cache server #############################
|
||||
[remote_cache]
|
||||
# Either "redis", "memcached" or "database" default is "database"
|
||||
@@ -139,24 +131,6 @@
|
||||
# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set.
|
||||
;timeout = 30
|
||||
|
||||
# How many seconds the data proxy waits before sending a keepalive probe request.
|
||||
;keep_alive_seconds = 30
|
||||
|
||||
# How many seconds the data proxy waits for a successful TLS Handshake before timing out.
|
||||
;tls_handshake_timeout_seconds = 10
|
||||
|
||||
# How many seconds the data proxy will wait for a server's first response headers after
|
||||
# fully writing the request headers if the request has an "Expect: 100-continue"
|
||||
# header. A value of 0 will result in the body being sent immediately, without
|
||||
# waiting for the server to approve.
|
||||
;expect_continue_timeout_seconds = 1
|
||||
|
||||
# The maximum number of idle connections that Grafana will keep alive.
|
||||
;max_idle_connections = 100
|
||||
|
||||
# How many seconds the data proxy keeps an idle connection open before timing out.
|
||||
;idle_conn_timeout_seconds = 90
|
||||
|
||||
# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false.
|
||||
;send_user_header = false
|
||||
|
||||
@@ -168,11 +142,8 @@
|
||||
# Change this option to false to disable reporting.
|
||||
;reporting_enabled = true
|
||||
|
||||
# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs
|
||||
;reporting_distributor = grafana-labs
|
||||
|
||||
# Set to false to disable all checks to https://grafana.net
|
||||
# for new versions (grafana itself and plugins), check is used
|
||||
# for new vesions (grafana itself and plugins), check is used
|
||||
# in some UI views to notify that grafana or plugin update exists
|
||||
# This option does not cause any auto updates, nor send any information
|
||||
# only a GET request to http://grafana.com to get latest versions
|
||||
@@ -219,6 +190,7 @@
|
||||
# Set to true if you want to enable http strict transport security (HSTS) response header.
|
||||
# This is only sent when HTTPS is enabled in this configuration.
|
||||
# HSTS tells browsers that the site should only be accessed using HTTPS.
|
||||
# The default version will change to true in the next minor release, 6.3.
|
||||
;strict_transport_security = false
|
||||
|
||||
# Sets how long a browser should cache HSTS. Only applied if strict_transport_security is enabled.
|
||||
@@ -232,20 +204,12 @@
|
||||
|
||||
# Set to true to enable the X-Content-Type-Options response header.
|
||||
# The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types advertised
|
||||
# in the Content-Type headers should not be changed and be followed.
|
||||
;x_content_type_options = true
|
||||
# in the Content-Type headers should not be changed and be followed. The default will change to true in the next minor release, 6.3.
|
||||
;x_content_type_options = false
|
||||
|
||||
# Set to true to enable the X-XSS-Protection header, which tells browsers to stop pages from loading
|
||||
# when they detect reflected cross-site scripting (XSS) attacks.
|
||||
;x_xss_protection = true
|
||||
|
||||
# Enable adding the Content-Security-Policy header to your requests.
|
||||
# CSP allows to control resources the user agent is allowed to load and helps prevent XSS attacks.
|
||||
;content_security_policy = false
|
||||
|
||||
# Set Content Security Policy template used when adding the Content-Security-Policy header to your requests.
|
||||
# $NONCE in the template includes a random nonce.
|
||||
;content_security_policy_template = """script-src 'unsafe-eval' 'strict-dynamic' $NONCE;object-src 'none';font-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' data:;base-uri 'self';connect-src 'self' grafana.com;manifest-src 'self';media-src 'none';form-action 'self';"""
|
||||
# when they detect reflected cross-site scripting (XSS) attacks. The default will change to true in the next minor release, 6.3.
|
||||
;x_xss_protection = false
|
||||
|
||||
#################################### Snapshots ###########################
|
||||
[snapshots]
|
||||
@@ -311,21 +275,15 @@
|
||||
# Editors can administrate dashboard, folders and teams they create
|
||||
;editors_can_admin = false
|
||||
|
||||
# The duration in time a user invitation remains valid before expiring. This setting should be expressed as a duration. Examples: 6h (hours), 2d (days), 1w (week). Default is 24h (24 hours). The minimum supported duration is 15m (15 minutes).
|
||||
;user_invite_max_lifetime_duration = 24h
|
||||
|
||||
# Enter a comma-separated list of users login to hide them in the Grafana UI. These users are shown to Grafana admins and themselves.
|
||||
; hidden_users =
|
||||
|
||||
[auth]
|
||||
# Login cookie name
|
||||
;login_cookie_name = grafana_session
|
||||
|
||||
# The maximum lifetime (duration) an authenticated user can be inactive before being required to login at next visit. Default is 7 days (7d). This setting should be expressed as a duration, e.g. 5m (minutes), 6h (hours), 10d (days), 2w (weeks), 1M (month). The lifetime resets at each successful token rotation.
|
||||
;login_maximum_inactive_lifetime_duration =
|
||||
# The lifetime (days) an authenticated user can be inactive before being required to login at next visit. Default is 7 days,
|
||||
;login_maximum_inactive_lifetime_days = 7
|
||||
|
||||
# The maximum lifetime (duration) an authenticated user can be logged in since login time before being required to login. Default is 30 days (30d). This setting should be expressed as a duration, e.g. 5m (minutes), 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
;login_maximum_lifetime_duration =
|
||||
# The maximum lifetime (days) an authenticated user can be logged in since login time before being required to login. Default is 30 days.
|
||||
;login_maximum_lifetime_days = 30
|
||||
|
||||
# How often should auth tokens be rotated for authenticated users when being active. The default is each 10 minutes.
|
||||
;token_rotation_interval_minutes = 10
|
||||
@@ -343,15 +301,12 @@
|
||||
# This setting is ignored if multiple OAuth providers are configured.
|
||||
;oauth_auto_login = false
|
||||
|
||||
# OAuth state max age cookie duration in seconds. Defaults to 600 seconds.
|
||||
;oauth_state_cookie_max_age = 600
|
||||
# OAuth state max age cookie duration. Defaults to 60 seconds.
|
||||
;oauth_state_cookie_max_age = 60
|
||||
|
||||
# limit of api_key seconds to live before expiration
|
||||
;api_key_max_seconds_to_live = -1
|
||||
|
||||
# Set to true to enable SigV4 authentication option for HTTP-based datasources.
|
||||
;sigv4_auth_enabled = false
|
||||
|
||||
#################################### Anonymous Auth ######################
|
||||
[auth.anonymous]
|
||||
# enable anonymous access
|
||||
@@ -363,10 +318,7 @@
|
||||
# specify role for unauthenticated users
|
||||
;org_role = Viewer
|
||||
|
||||
# mask the Grafana version number for unauthenticated users
|
||||
;hide_version = false
|
||||
|
||||
#################################### GitHub Auth ##########################
|
||||
#################################### Github Auth ##########################
|
||||
[auth.github]
|
||||
;enabled = false
|
||||
;allow_sign_up = true
|
||||
@@ -453,9 +405,6 @@
|
||||
;scopes = user:email,read:org
|
||||
;email_attribute_name = email:primary
|
||||
;email_attribute_path =
|
||||
;login_attribute_path =
|
||||
;name_attribute_path =
|
||||
;id_token_attribute_name =
|
||||
;auth_url = https://foo.bar/login/oauth/authorize
|
||||
;token_url = https://foo.bar/login/oauth/access_token
|
||||
;api_url = https://foo.bar/user
|
||||
@@ -490,7 +439,7 @@
|
||||
;config_file = /etc/grafana/ldap.toml
|
||||
;allow_sign_up = true
|
||||
|
||||
# LDAP background sync (Enterprise only)
|
||||
# LDAP backround sync (Enterprise only)
|
||||
# At 1 am every day
|
||||
;sync_cron = "0 0 1 * * *"
|
||||
;active_sync_enabled = true
|
||||
@@ -573,25 +522,6 @@
|
||||
# Syslog tag. By default, the process' argv[0] is used.
|
||||
;tag =
|
||||
|
||||
[log.frontend]
|
||||
# Should Sentry javascript agent be initialized
|
||||
;enabled = false
|
||||
|
||||
# Sentry DSN if you want to send events to Sentry.
|
||||
;sentry_dsn =
|
||||
|
||||
# Custom HTTP endpoint to send events captured by the Sentry agent to. Default will log the events to stdout.
|
||||
;custom_endpoint = /log
|
||||
|
||||
# Rate of events to be reported between 0 (none) and 1 (all), float
|
||||
;sample_rate = 1.0
|
||||
|
||||
# Requests per second limit enforced an extended period, for Grafana backend log ingestion endpoint (/log).
|
||||
;log_endpoint_requests_per_second_limit = 3
|
||||
|
||||
# Max requests accepted per short interval of time for Grafana backend log ingestion endpoint (/log).
|
||||
;log_endpoint_burst_limit = 15
|
||||
|
||||
#################################### Usage Quotas ########################
|
||||
[quota]
|
||||
; enabled = false
|
||||
@@ -657,36 +587,6 @@
|
||||
# Makes it possible to enforce a minimal interval between evaluations, to reduce load on the backend
|
||||
;min_interval_seconds = 1
|
||||
|
||||
# Configures for how long alert annotations are stored. Default is 0, which keeps them forever.
|
||||
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
;max_annotation_age =
|
||||
|
||||
# Configures max number of alert annotations that Grafana stores. Default value is 0, which keeps all alert annotations.
|
||||
;max_annotations_to_keep =
|
||||
|
||||
#################################### Annotations #########################
|
||||
|
||||
[annotations.dashboard]
|
||||
# Dashboard annotations means that annotations are associated with the dashboard they are created on.
|
||||
|
||||
# Configures how long dashboard annotations are stored. Default is 0, which keeps them forever.
|
||||
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
;max_age =
|
||||
|
||||
# Configures max number of dashboard annotations that Grafana stores. Default value is 0, which keeps all dashboard annotations.
|
||||
;max_annotations_to_keep =
|
||||
|
||||
[annotations.api]
|
||||
# API annotations means that the annotations have been created using the API without any
|
||||
# association with a dashboard.
|
||||
|
||||
# Configures how long Grafana stores API annotations. Default is 0, which keeps them forever.
|
||||
# This setting should be expressed as a duration. Examples: 6h (hours), 10d (days), 2w (weeks), 1M (month).
|
||||
;max_age =
|
||||
|
||||
# Configures max number of API annotations that Grafana keeps. Default value is 0, which keeps all API annotations.
|
||||
;max_annotations_to_keep =
|
||||
|
||||
#################################### Explore #############################
|
||||
[explore]
|
||||
# Enable the Explore section
|
||||
@@ -706,12 +606,6 @@
|
||||
; basic_auth_username =
|
||||
; basic_auth_password =
|
||||
|
||||
# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
|
||||
# can expose more information about the Grafana instance.
|
||||
[metrics.environment_info]
|
||||
#exampleLabel1 = exampleValue1
|
||||
#exampleLabel2 = exampleValue2
|
||||
|
||||
# Send internal metrics to Graphite
|
||||
[metrics.graphite]
|
||||
# Enable by setting the address setting (ex localhost:2003)
|
||||
@@ -739,8 +633,6 @@
|
||||
# and indicates the initial sampling rate before the actual one
|
||||
# is received from the mothership
|
||||
;sampler_param = 1
|
||||
# sampling_server_url is the URL of a sampling manager providing a sampling strategy.
|
||||
;sampling_server_url =
|
||||
# Whether or not to use Zipkin propagation (x-b3- HTTP headers).
|
||||
;zipkin_propagation = false
|
||||
# Setting this to true disables shared RPC spans.
|
||||
@@ -800,7 +692,6 @@
|
||||
;app_tls_skip_verify_insecure = false
|
||||
# Enter a comma-separated list of plugin identifiers to identify plugins that are allowed to be loaded even if they lack a valid signature.
|
||||
;allow_loading_unsigned_plugins =
|
||||
;marketplace_url = https://grafana.com/grafana/plugins/
|
||||
|
||||
#################################### Grafana Image Renderer Plugin ##########################
|
||||
[plugin.grafana-image-renderer]
|
||||
@@ -852,7 +743,7 @@
|
||||
# When rendering_mode = clustered you can define maximum number of browser instances/incognito pages that can execute concurrently..
|
||||
;rendering_clustering_max_concurrency =
|
||||
|
||||
# Limit the maximum viewport width, height and device scale factor that can be requested.
|
||||
# Limit the maxiumum viewport width, height and device scale factor that can be requested.
|
||||
;rendering_viewport_max_width =
|
||||
;rendering_viewport_max_height =
|
||||
;rendering_viewport_max_device_scale_factor =
|
||||
@@ -869,27 +760,3 @@
|
||||
[feature_toggles]
|
||||
# enable features, separated by spaces
|
||||
;enable =
|
||||
|
||||
[date_formats]
|
||||
# For information on what formatting patterns that are supported https://momentjs.com/docs/#/displaying/
|
||||
|
||||
# Default system date format used in time range picker and other places where full time is displayed
|
||||
;full_date = YYYY-MM-DD HH:mm:ss
|
||||
|
||||
# Used by graph and other places where we only show small intervals
|
||||
;interval_second = HH:mm:ss
|
||||
;interval_minute = HH:mm
|
||||
;interval_hour = MM/DD HH:mm
|
||||
;interval_day = MM/DD
|
||||
;interval_month = YYYY-MM
|
||||
;interval_year = YYYY
|
||||
|
||||
# Experimental feature
|
||||
;use_browser_locale = false
|
||||
|
||||
# Default timezone for user preferences. Options are 'browser' for the browser local timezone or a timezone name from IANA Time Zone database, e.g. 'UTC' or 'Europe/Amsterdam' etc.
|
||||
;default_timezone = browser
|
||||
|
||||
[expressions]
|
||||
# Enable or disable the expressions functionality.
|
||||
;enabled = true
|
||||
|
||||
@@ -8,6 +8,3 @@ Learn more about the backend architecture:
|
||||
- Part 2: [Communication](communication.md)
|
||||
- Part 3: [Database](database.md)
|
||||
|
||||
Learn more about the frontend architecture:
|
||||
- Part 1: [Data requests](frontend-data-requests.md)
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ if err := s.bus.Dispatch(cmd); err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** `Dispatch` will return an error if no handler is registered for that command.
|
||||
**Note:** `Dispatch` will return an error if no handler is registered for that command.
|
||||
|
||||
**Tip:** Browse the available commands in the `models` package.
|
||||
|
||||
@@ -87,7 +87,7 @@ func (s *MyService) SendStickers(cmd *models.SendStickersCommand) error {
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** The handler method may return an error if unable to complete the command.
|
||||
**Note:** The handler method may return an error if unable to complete the command.
|
||||
|
||||
## Queries
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ Grafana supports the [following databases](https://grafana.com/docs/installation
|
||||
- [PostgreSQL](https://www.postgresql.org/)
|
||||
- [SQLite3](https://www.sqlite.org/)
|
||||
|
||||
Grafana uses the [XORM](https://xorm.io) framework for persisting objects to the database. For more information on how to use XORM, refer to the [documentation](https://gobook.io/read/gitea.com/xorm/manual-en-US/).
|
||||
Grafana uses the [XORM](https://xorm.io) framework for persisting objects to the database. For more information on how to use XORM, refer to the [documentation](http://gobook.io/read/github.com/go-xorm/manual-en-US/).
|
||||
|
||||
[Services](services.md) don't use XORM directly. Instead, services use the _SQL store_, a special type of service that provides an abstraction for the database layer. There are two ways of using the `sqlstore`: using `sqlstore` handlers, and using the `SQLStore` instance.
|
||||
[Services](services.md) don't use XORM directly. Instead, services use the _SQL store_, a special type of service that provides an abstraction for the database layer. There are two ways of using the `sqlstore`: using `sqlstore` handlers, and using the `SqlStore` instance.
|
||||
|
||||
## `sqlstore` handlers
|
||||
|
||||
> **Deprecated:** We are deprecating `sqlstore` handlers in favor of using the `SQLStore` object directly in each service. Since most services still use the `sqlstore` handlers, we still want to explain how they work.
|
||||
> **Deprecated:** We are deprecating `sqlstore` handlers in favor of using the `SqlStore` object directly in each service. Since most services still use the `sqlstore` handlers, we still want to explain how they work.
|
||||
|
||||
The `sqlstore` package allows you to register [command handlers](communication.md#handle-commands) that either store, or retrieve objects from the database. `sqlstore` handlers are similar to services:
|
||||
|
||||
@@ -46,15 +46,15 @@ func DeleteDashboard(cmd *models.DeleteDashboardCommand) error {
|
||||
|
||||
Here, `inTransaction` is a helper function in the `sqlstore` package that provides a session, that lets you execute SQL statements.
|
||||
|
||||
## `SQLStore`
|
||||
## `SqlStore`
|
||||
|
||||
As opposed to a `sqlstore` handler, the `SQLStore` is a service itself. The `SQLStore` has the same responsibility however: to store and retrieve objects, to and from the database.
|
||||
As opposed to a `sqlstore` handler, the `SqlStore` is a service itself. The `SqlStore` has the same responsibility however: to store and retrieve objects, to and from the database.
|
||||
|
||||
To use the `SQLStore`, inject it in your service struct:
|
||||
To use the `SqlStore`, inject the `SQLStore` in your service struct:
|
||||
|
||||
```go
|
||||
type MyService struct {
|
||||
SQLStore *sqlstore.SQLStore `inject:""`
|
||||
SQLStore *sqlstore.SqlStore `inject:""`
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# Data requests
|
||||
|
||||
[BackendSrv](https://grafana.com/docs/grafana/latest/packages_api/runtime/backendsrv) handles all outgoing HTTP requests from Grafana. This document explains the high-level concepts used by `BackendSrv`.
|
||||
|
||||
## Canceling requests
|
||||
This section describes how canceling requests work in Grafana. While data sources can implement their own cancellation concept, we recommend that you use the method we describe here.
|
||||
|
||||
A data request can take a long time to finish. During the time between when a request starts and finishes, the user can change context. For example, the user may navigate away or issue the same request again.
|
||||
|
||||
If we wait for canceled requests to complete, it might create unnecessary load on data sources.
|
||||
|
||||
Grafana uses a concept called _request cancelation_ to cancel any ongoing request that Grafana doesn't need.
|
||||
|
||||
#### Before Grafana 7.2
|
||||
Before Grafana can cancel any data request, it has to identify that request. Grafana identifies a request using the property `requestId` [passed as options](https://github.com/grafana/grafana/blob/master/docs/sources/packages_api/runtime/backendsrvrequest.md) when you use [BackendSrv](https://grafana.com/docs/grafana/latest/packages_api/runtime/backendsrv).
|
||||
|
||||
The cancellation logic is as follows:
|
||||
- When an ongoing request discovers that an additional request with the same `requestId` has started, then Grafana will cancel the ongoing request.
|
||||
- When an ongoing request discovers that the special "cancel all requests" `requestId` was sent, then Grafana will cancel the ongoing request.
|
||||
|
||||
#### After Grafana 7.2
|
||||
Grafana 7.2 introduced an additional way of canceling requests using [RxJs](https://github.com/ReactiveX/rxjs). To support the new cancellation functionality, the data source needs to use the new `fetch` function in [BackendSrv](https://grafana.com/docs/grafana/latest/packages_api/runtime/backendsrv).
|
||||
|
||||
Migrating the core data sources to the new `fetch` function [is an ongoing process that you can read about in this issue.](https://github.com/grafana/grafana/issues/27222)
|
||||
|
||||
## Request queue
|
||||
Depending on how the web browser implements the protocol for HTTP 1.1, it will limit the number of parallel requests, lets call this limit _max_parallel_browser_request_.
|
||||
|
||||
Unless you have configured Grafana to use HTTP2, the browser limits parallel data requests according to the browser's implementation. For more information on how to enable HTTP2, refer to [Configuration](https://grafana.com/docs/grafana/latest/administration/configuration/#protocol).
|
||||
|
||||
Because there is a _max_parallel_browser_request_ limit, if some of the requests take a long time, they will block later requests and make interacting with Grafana very slow.
|
||||
|
||||
#### Before Grafana 7.2
|
||||
Not supported.
|
||||
|
||||
#### After Grafana 7.2
|
||||
Grafana uses a _request queue_ to process all incoming data requests in order while reserving a free "spot" for any requests to the Grafana API.
|
||||
|
||||
Since the first implementation of the request queue doesn't take into account what browser the user uses, the _request queue_ limit for parallel data source requests is hard-coded to 5.
|
||||
|
||||
> **Note:** Grafana instances [configured with HTTP2 ](https://grafana.com/docs/grafana/latest/administration/configuration/#protocol) will have a hard coded limit of 1000.
|
||||
@@ -40,7 +40,7 @@ func init() {
|
||||
}
|
||||
```
|
||||
|
||||
`init` functions are only run whenever a package is imported, so we also need to import the package in the application. In the `server.go` file under `pkg/server`, import the package we just created:
|
||||
`init` functions are only run whenever a package is imported, so we also need to import the package in the application. In the `server.go` file under `pkg/cmd/grafana-server`, import the package we just created:
|
||||
|
||||
```go
|
||||
import _ "github.com/grafana/grafana/pkg/services/mysvc"
|
||||
@@ -66,4 +66,4 @@ type MyService struct {
|
||||
}
|
||||
```
|
||||
|
||||
> **Note:** Any injected dependency needs to be an exported field. Any unexported fields result in a runtime error.
|
||||
**Note:** Any injected dependency needs to be an exported field. Any unexported fields result in a runtime error.
|
||||
|
||||
@@ -20,21 +20,18 @@ We recommend using [Homebrew](https://brew.sh/) for installing any missing depen
|
||||
```
|
||||
brew install git
|
||||
brew install go
|
||||
brew install node@14
|
||||
brew install node@12
|
||||
|
||||
npm install -g yarn
|
||||
```
|
||||
|
||||
## Download Grafana
|
||||
|
||||
We recommend using the Git command-line interface to download the source code for the Grafana project:
|
||||
We recommend using Go to download the source code for the Grafana project:
|
||||
|
||||
1. Open a terminal and run `git clone https://github.com/grafana/grafana.git`. This command downloads Grafana to a new `grafana` directory in your current directory.
|
||||
1. Open the `grafana` directory in your favorite code editor.
|
||||
|
||||
For alternative ways of cloning the Grafana repository, please refer to [GitHub's cloning a repository](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository) documentation.
|
||||
|
||||
**Warning:** Do not use `go get` to download Grafana. Recent versions of Go have added behavior which isn't compatible with the way the Grafana repository is structured.
|
||||
1. Add `export GOPATH=$HOME/go/` to the bottom of your `$HOME/.bash_profile`.
|
||||
1. Open a terminal and run `go get github.com/grafana/grafana` in your terminal. This command downloads, and installs Grafana to your `$GOPATH`.
|
||||
1. Open `$GOPATH/src/github.com/grafana/grafana` in your favorite code editor.
|
||||
|
||||
## Build Grafana
|
||||
|
||||
@@ -76,10 +73,7 @@ When you log in for the first time, Grafana asks you to change your password.
|
||||
|
||||
#### Building on Windows
|
||||
|
||||
The Grafana backend includes SQLite which requires GCC to compile. So in order to compile Grafana on Windows you need to install GCC. We recommend [TDM-GCC](http://tdm-gcc.tdragon.net/download). Eventually, if you use [Scoop](https://scoop.sh), you can install GCC through that.
|
||||
|
||||
You can simply build the back-end as follows: `go run build.go build`. The Grafana binaries will be in bin\\windows-amd64.
|
||||
Alternately, if you wish to use the `make` command, install [Make for Windows](http://gnuwin32.sourceforge.net/packages/make.htm) and use it in a Unix shell (f.ex. Git Bash).
|
||||
The Grafana backend includes Sqlite3 which requires GCC to compile. So in order to compile Grafana on Windows you need to install GCC. We recommend [TDM-GCC](http://tdm-gcc.tdragon.net/download).
|
||||
|
||||
## Test Grafana
|
||||
|
||||
@@ -90,7 +84,7 @@ The test suite consists of three types of tests: _Frontend tests_, _backend test
|
||||
We use [jest](https://jestjs.io/) for our frontend tests. Run them using Yarn:
|
||||
|
||||
```
|
||||
yarn test
|
||||
yarn jest
|
||||
```
|
||||
|
||||
### Run backend tests
|
||||
@@ -101,13 +95,6 @@ If you're developing for the backend, run the tests with the standard Go tool:
|
||||
go test -v ./pkg/...
|
||||
```
|
||||
|
||||
#### On Windows
|
||||
Running the backend tests on Windows currently needs some tweaking, so use the build.go script:
|
||||
|
||||
```
|
||||
go run build.go test
|
||||
```
|
||||
|
||||
### Run end-to-end tests
|
||||
|
||||
The end to end tests in Grafana use [Cypress](https://www.cypress.io/) to run automated scripts in a headless Chromium browser. Read more about our [e2e framework](/contribute/style-guides/e2e.md).
|
||||
@@ -138,7 +125,7 @@ yarn e2e:dev
|
||||
|
||||
## Configure Grafana for development
|
||||
|
||||
The default configuration, `defaults.ini`, is located in the `conf` directory.
|
||||
The default configuration, `grafana.ini`, is located in the `conf` directory.
|
||||
|
||||
To override the default configuration, create a `custom.ini` file in the `conf` directory. You only need to add the options you wish to override.
|
||||
|
||||
@@ -184,7 +171,7 @@ make build-docker-full
|
||||
|
||||
The resulting image will be tagged as grafana/grafana:dev.
|
||||
|
||||
> **Note:** If you've already set up a local development environment, and you're running a `linux/amd64` machine, you can speed up building the Docker image:
|
||||
**Note:** If you've already set up a local development environment, and you're running a `linux/amd64` machine, you can speed up building the Docker image:
|
||||
|
||||
1. Build the frontend: `go run build.go build-frontend`.
|
||||
1. Build the Docker image: `make build-docker-dev`.
|
||||
@@ -197,7 +184,7 @@ Are you having issues with setting up your environment? Here are some tips that
|
||||
|
||||
### Too many open files when running `make run`
|
||||
|
||||
Depending on your environment, you may have to increase the maximum number of open files allowed. For the rest of this section, we will assume you are on a Unix like OS (e.g. Linux/macOS), where you can control the maximum number of open files through the [ulimit](https://ss64.com/bash/ulimit.html) shell command.
|
||||
Depending on your environment, you may have to increase the maximum number of open files allowed. For the rest of this section, we will assume you are on a Unix like OS (e.g. Linux/MacOS), where you can control the maximum number of open files through the [ulimit](https://ss64.com/bash/ulimit.html) shell command.
|
||||
|
||||
To see how many open files are allowed, run:
|
||||
|
||||
@@ -221,8 +208,8 @@ Another alternative is to limit the files being watched. The directories that ar
|
||||
|
||||
To retain your `ulimit` configuration, i.e. so it will be remembered for future sessions, you need to commit it to your command line shell initialization file. Which file this will be depends on the shell you are using, here are some examples:
|
||||
|
||||
- zsh -> ~/.zshrc
|
||||
- bash -> ~/.bashrc
|
||||
* zsh -> ~/.zshrc
|
||||
* bash -> ~/.bashrc
|
||||
|
||||
Commit your ulimit configuration to your shell initialization file as follows ($LIMIT being your chosen limit and $INIT_FILE being the initialization file for your shell):
|
||||
|
||||
@@ -238,7 +225,7 @@ For some people, typically using the bash shell, ulimit fails with an error simi
|
||||
ulimit: open files: cannot modify limit: Operation not permitted
|
||||
```
|
||||
|
||||
If that happens to you, chances are you've already set a lower limit and your shell won't let you set a higher one. Try looking in your shell initialization files (~/.bashrc typically), if there's already a ulimit command that you can tweak.
|
||||
If that happens to you, chances are you've already set a lower limit and your shell won't let you set a higher one. Try looking in your shell initalization files (~/.bashrc typically), if there's already a ulimit command that you can tweak.
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Backend style guide
|
||||
|
||||
Grafana's backend has been developed for a long time with a mix of code styles. This guide explains how we want to write Go code in the future.
|
||||
Grafanas backend has been developed for a long time with a mix of code styles. This guide explains how we want to write Go code in the future.
|
||||
|
||||
Unless stated otherwise, use the guidelines listed in the following articles:
|
||||
|
||||
@@ -39,62 +39,3 @@ Tests must use the standard library, `testing`. For assertions, prefer using [te
|
||||
The majority of our tests uses [GoConvey](http://goconvey.co/) but that's something we want to avoid going forward.
|
||||
|
||||
In the `sqlstore` package we do database operations in tests and while some might say that's not suited for unit tests. We think they are fast enough and provide a lot of value.
|
||||
|
||||
### Assertions
|
||||
|
||||
Use respectively [`assert.*`](https://github.com/stretchr/testify#assert-package) functions to make assertions that
|
||||
should _not_ halt the test ("soft checks") and [`require.*`](https://github.com/stretchr/testify#require-package)
|
||||
functions to make assertions that _should_ halt the test ("hard checks"). Typically you want to use the latter type of
|
||||
check to assert that errors have or have not happened, since continuing the test after such an assertion fails is
|
||||
chaotic (the system under test will be in an undefined state) and you'll often have segfaults in practice.
|
||||
|
||||
### Sub-tests
|
||||
|
||||
Use [`t.Run`](https://golang.org/pkg/testing/#T.Run) to group sub-test cases, since it allows common setup and teardown
|
||||
code, plus lets you run each test case in isolation when debugging. Don't use `t.Run` to e.g. group assertions.
|
||||
|
||||
### Cleanup
|
||||
|
||||
Use [`t.Cleanup`](https://golang.org/pkg/testing/#T.Cleanup) to clean up resources in tests. It's a less fragile choice than `defer`, since it's independent of which
|
||||
function you call it in. It will always execute after the test is over in reverse call order (last `t.Cleanup` first, same as `defer`).
|
||||
|
||||
## Globals
|
||||
|
||||
As a general rule of thumb, avoid using global variables, since they make the code difficult to maintain and reason
|
||||
about, and to write tests for. The Grafana codebase currently does use a lot of global variables, especially when
|
||||
it comes to configuration, but that is a problem we're trying to solve.
|
||||
|
||||
## Pointers
|
||||
|
||||
In general, use value types and only reach for pointers when there's a real need. The reason being that pointers
|
||||
increase the risk of bugs, since a pointer can be nil and dereferencing a nil pointer leads to a panic (AKA segfault).
|
||||
Valid reasons to use a pointer include (but not necessarily limited to):
|
||||
|
||||
* You might need to pass a modifiable argument to a function
|
||||
* Copying an object might incur a performance hit (benchmark to check your assumptions, copying is often faster than
|
||||
allocating heap memory)
|
||||
* You might *need* `nil` to tell if a variable isn't set, although usually it's better to use the type's zero
|
||||
value to tell instead
|
||||
|
||||
## Database
|
||||
|
||||
In database related code, we follow certain patterns.
|
||||
|
||||
### Foreign keys
|
||||
|
||||
While they can be useful, we don't generally use foreign key constraints in Grafana, for historical and
|
||||
technical reasons. See this [comment](https://github.com/grafana/grafana/issues/3269#issuecomment-383328548) by Torkel
|
||||
for context.
|
||||
|
||||
### Unique columns
|
||||
|
||||
If a column, or column combination, should be unique, add a corresponding uniqueness constraint through a migration.
|
||||
|
||||
## JSON
|
||||
|
||||
The simplejson package is used a lot throughout the backend codebase, but it's legacy, so if at all possible
|
||||
avoid using it in new code. Use [json-iterator](https://github.com/json-iterator/go) instead, which is a more performant
|
||||
drop-in alternative to the standard [encoding/json](https://golang.org/pkg/encoding/json/) package. While encoding/json
|
||||
is a fine choice, profiling shows that json-iterator may be 3-4 times more efficient for encoding. We haven't profiled
|
||||
its parsing performance yet, but according to json-iterator's own benchmarks, it appears even more superior in this
|
||||
department.
|
||||
|
||||
@@ -25,7 +25,7 @@ All `exported` apis from the package should have a release tag to indicate its s
|
||||
|
||||
- [`@alpha`](https://api-extractor.com/pages/tsdoc/tag_alpha/) - early draft of api and will probably change.
|
||||
- [`@beta`](https://api-extractor.com/pages/tsdoc/tag_beta/) - close to being stable but might change.
|
||||
- [`@public`](https://api-extractor.com/pages/tsdoc/tag_public/) - ready for usage in production.
|
||||
- [`@public`](https://api-extractor.com/pages/tsdoc/tag_public/) - ready for useage in production.
|
||||
- [`@internal`](https://api-extractor.com/pages/tsdoc/tag_internal/) - for internal use only.
|
||||
|
||||
### Main stability of APIs
|
||||
@@ -139,7 +139,7 @@ This attribute can be skipped if the type provided by `typescript` and the funct
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Will help to create a resource resolver depending
|
||||
* Will help to create a resource resovler depending
|
||||
* on the current execution context.
|
||||
*
|
||||
* @param context - The current execution context.
|
||||
@@ -179,7 +179,7 @@ This attribute can be skipped if the type provided by `typescript` and the funct
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Will help to create a resource resolver depending
|
||||
* Will help to create a resource resovler depending
|
||||
* on the current execution context.
|
||||
*
|
||||
* @param context - The current execution context.
|
||||
@@ -206,4 +206,4 @@ export const factory = (context: Context): IResolver => {
|
||||
export const isEqual = (x: number, y: number): boolean => {
|
||||
return x === y;
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -1,41 +1,46 @@
|
||||
# Markdown style guide
|
||||
|
||||
This guide for Markdown style helps keep contributions consistent across all documentation created for Grafana products. Refer to the guide and update its sections as needed when a Subject Matter Expert answers a question on Markdown style, or a decision is made about how to apply Markdown.
|
||||
This guide for Markdown style helps keep contributions consistent across all documentation
|
||||
created for Grafana products. Refer to the guide and update its sections as needed when a
|
||||
Subject Matter Expert answers a question on Markdown style, or a decision is made about
|
||||
how to apply Markdown.
|
||||
|
||||
## Headers
|
||||
|
||||
In Markdown, the number of "#" symbols creates different heading levels, similar to HTML heading levels:
|
||||
In Markdown, the number of "#" symbols creates different heading levels, similar to
|
||||
HTML heading levels:
|
||||
|
||||
**Example**
|
||||
|
||||
- \# is \<h1>.
|
||||
- \#\# is \<h2>.
|
||||
- \#\#\# is \<h3>.
|
||||
* \# is \<h1>.
|
||||
* \#\# is \<h2>.
|
||||
* \#\#\# is \<h3>.
|
||||
|
||||
Start your document with a single ``#`` for the title of the page. Add the sub-headings with two ``##``.
|
||||
|
||||
## Bold and emphasis
|
||||
|
||||
- Make text **bold** using two asterisks.
|
||||
* Make text **bold** using two asterisks.
|
||||
|
||||
**Example:** It is ``**important**`` to use GitHub-flavored Markdown emoji consistently.
|
||||
**Example:** It is ``**important**`` to use Github Flavored Markdown emoji consistently.
|
||||
|
||||
- Make text ``_emphasized_`` using single `` _underscores_``. Do not use the single asterisk, it can be easily confused with bold.
|
||||
* Make text ``*emphasized*`` using single `` _underscores_`` or a single asterisk.
|
||||
|
||||
**Example:** GitHub-flavored markdown emoji should _only_ appear in specific cases.
|
||||
**Example:** Github Flavored Markdown emoji should _only_ appear in specific cases.
|
||||
|
||||
|
||||
## Links and references
|
||||
|
||||
Create links to other website by wrapping the display text in square brackets, and the web URL in curved brackets.
|
||||
Create links to other website by wrapping the display text in square brackets, and
|
||||
the web URL in curved brackets.
|
||||
|
||||
\[text to display](www.website.com)
|
||||
|
||||
**Example:** For more information on including emoji in GitHub-flavored markdown, refer to the [webfx page on emoji](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of emoji.
|
||||
**Example:** For more information on including emoji in Github flavored Markdown, refer to the [webfx page on emoji](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of emoji.
|
||||
|
||||
## Block quotes
|
||||
|
||||
Include block quotes inside text using right-facing arrows:
|
||||
Include Block quotes inside text using right-facing arrows:
|
||||
|
||||
**Example**
|
||||
|
||||
@@ -45,7 +50,8 @@ Include block quotes inside text using right-facing arrows:
|
||||
|
||||
## Code blocks
|
||||
|
||||
Code blocks written with markdown can show off syntax highlighting specific to different languages. Use three back tics to create a code block:
|
||||
Code blocks written with markdown can show off syntax highlighting specific
|
||||
to different languages. Use three back tics to create a code block:
|
||||
|
||||
```
|
||||
function testNum(a) {
|
||||
@@ -57,7 +63,8 @@ function testNum(a) {
|
||||
}
|
||||
```
|
||||
|
||||
Write the name of the language after the first set of back tics, no spaces, to show specific syntax highlighting. For example; "\```javascript" produces the following:
|
||||
Write the name of the language after the first set of back tics, no spaces,
|
||||
to show specific syntax highlighting. For example; "\```javascript" produces the following:
|
||||
|
||||
```javascript
|
||||
function testNum(a) {
|
||||
@@ -70,7 +77,10 @@ function testNum(a) {
|
||||
```
|
||||
## Tables
|
||||
|
||||
Construct a table by typing the table headings, and separating them with a "|" character. Then, add a second line of dashes ("-") separated by another "|" character. When constructing the table cells, separate each cell data with another "|".
|
||||
Construct a table by typing the table headings, and separating them with
|
||||
a "|" character. Then, add a second line of dashes ("-") separated by
|
||||
another "|" character. When constructing the table cells, separate each cell data with another
|
||||
"|".
|
||||
|
||||
**Example**
|
||||
|
||||
@@ -106,46 +116,29 @@ The list above will always display as:
|
||||
|
||||
### Unordered lists
|
||||
|
||||
Build a list of points - an unordered or unnumbered list - by using "\-" (hyphen) characters.
|
||||
Build a list of points - an unordered or unnumbered list - by
|
||||
using "\*" characters.
|
||||
|
||||
**Example**
|
||||
|
||||
- First
|
||||
- Another item
|
||||
- The last list item
|
||||
* First
|
||||
* Another item
|
||||
* The last list item
|
||||
|
||||
## Images
|
||||
|
||||
_Do not_ use image shortcodes at this time.
|
||||
|
||||
Include images in a document using the following syntax:
|
||||
|
||||
```
|
||||

|
||||
```
|
||||
|
||||
> **Note:** Alt text does not appear when the user hovers the mouse over the image, but title text does.
|
||||
|
||||
**Examples:**
|
||||
|
||||
- \!\[Grafana logo](/link/to/grafanalogo/logo.png)
|
||||
- \!\[Example](/img/docs/folder_name/alert_test_rule.png)
|
||||
**Example** \!\[Grafana Logo](/link/to/grafanalogo/logo.png)
|
||||
|
||||
This follows the format of "!", alt text wrapped in "[]" and the link URL wrapped in "()".
|
||||
|
||||
You can also use HTML such as the following:
|
||||
```
|
||||
<img src="example.png"
|
||||
alt="Example image"
|
||||
style="float: left; margin-right: 5px;" />
|
||||
```
|
||||
|
||||
In most cases, use the markdown syntax rather than the HTML syntax. Only use the HTML if you need to change the image in ways unsupported by Markdown.
|
||||
|
||||
## Comments
|
||||
|
||||
You can include comments that will not appear in published markdown using the following syntax:
|
||||
You can include comments that will not appear in published markdown using the
|
||||
following syntax:
|
||||
|
||||
\[comment]: <> (Comment text to display)
|
||||
|
||||
The word "comment" wrapped in "[]" followed by a ":", a space, "<>", and then the comment itself wrapped in "()".
|
||||
The word "comment" wrapped in "[]" followed by a ":", a space, "<>", and then
|
||||
the comment itself wrapped in "()".
|
||||
|
||||
@@ -4,7 +4,7 @@ This style guide applies to all documentation created for Grafana products.
|
||||
|
||||
For information about how to write technical documentation, we suggest reviewing the content of the [Google Technical Writing courses](https://developers.google.com/tech-writing).
|
||||
|
||||
The [Divio documentation system](https://documentation.divio.com/) site and the [Vue writing principles](https://v3.vuejs.org/guide/contributing/writing-guide.html#principles) are also good resources.
|
||||
The [Divio documentation system](https://documentation.divio.com/) site is also a good resource.
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -18,131 +18,64 @@ For all items not covered in this guide, refer to the [Microsoft Style Guide](ht
|
||||
|
||||
The [codespell](https://github.com/codespell-project/codespell) tool is run for every change to catch common misspellings.
|
||||
|
||||
## Inclusive language
|
||||
|
||||
This section provides guidelines on how to avoid using charged language in documentation.
|
||||
|
||||
### Allowing and blocking
|
||||
|
||||
Don't use "whitelist" or "blacklist" when referring to allowing or blocking content or traffic.
|
||||
|
||||
- When used as a noun, use "allowlist" or "blocklist".
|
||||
- When used as a verb, use "allow" or "block"
|
||||
|
||||
Example: _To **allow** outgoing traffic, add the IP to the **allowlist**._
|
||||
|
||||
### Leader and follower
|
||||
|
||||
Don't use "master" or "slave" to describe relationships between nodes or processes.
|
||||
|
||||
- Use "leader", "main" or "primary," instead of "master."
|
||||
- Use "follower" or "secondary," instead of "slave."
|
||||
|
||||
### Exceptions
|
||||
|
||||
When referring to a configuration or settings used by third-party libraries och technologies outside the Grafana project, prefer the original name to avoid confusion.
|
||||
|
||||
For example, use "master" when referring to the default Git branch.
|
||||
|
||||
## Grafana-specific style
|
||||
|
||||
The following sections provide general guidelines on topics specific to Grafana documentation. Note that for the most part, these are *guidelines*, not rigid rules. If you have questions, ask in the #docs channel of Grafana Slack.
|
||||
|
||||
### General
|
||||
|
||||
- Use active voice. Avoid passive voice.
|
||||
- Use active: Grafana displays the heatmap visualization.
|
||||
- Avoid passive: The heatmap visualization is displayed.
|
||||
- Write directly to the reader.
|
||||
- Use: "After you create a dashboard, you can add a panel to it."
|
||||
- Avoid: "After you create a dashboard, it is possible to add a panel to it."
|
||||
- Write in the imperative second person. Examples: You can write a query. Click the panel. Close the window.
|
||||
- Write in present tense.
|
||||
- Use: The panel opens. Grafana opens the panel.
|
||||
* Use active voice. Avoid passive voice.
|
||||
- Passive: The heatmap visualization is displayed.
|
||||
- Active: Grafana displays the heatmap visualization.
|
||||
* Write in the imperative second person. Examples: You can write a query. Click the panel. Close the window.
|
||||
* Write in present tense.
|
||||
- Not: The panel will open.
|
||||
- Do not use an ampersand (&) as an abbreviation for "and."
|
||||
- Use: The panel opens. Grafana opens the panel.
|
||||
* Do not use an ampersand (&) as an abbreviation for "and."
|
||||
- **Exceptions:** If an ampersand is used in the Grafana UI, then match the UI.
|
||||
- Avoid using internal slang and jargon in technical documentation.
|
||||
- Do not use two spaces after a period. Only add one space after each sentence. Do not add a space at the end of the paragraph.
|
||||
- Sentence length should be 25 words or less. If your thought is longer than 25 words, consider breaking up the sentence or changing the format to a list.
|
||||
- Paragraphs should be three sentences or fewer. Break up long paragraphs.
|
||||
* Avoid using internal slang and jargon in technical documentation.
|
||||
|
||||
### File naming conventions
|
||||
|
||||
- Files that are displayed in the help system should have names that are all lowercase, no spaces. Use hyphens instead of spaces. Example: glossary.md
|
||||
- Documentation file names should match the title. **Note:** This only applies to new files at this time. Do not change the names of older files unless directed to do so.
|
||||
- Internal reference file names should be all uppercase except the file extension. Example: CONTRIBUTING.md
|
||||
- Image file names should be descriptive and unique. Also, add the software version number that the image applies to or the screenshot was taken in. Example: share-dashboard-link-7-3.png
|
||||
|
||||
### Headings
|
||||
|
||||
- Write headings in sentence case, not title case.
|
||||
* Write headings in sentence case, not title case.
|
||||
- This is sentence case
|
||||
- This is Title Case
|
||||
- Task topic headings start with a verb.
|
||||
- Write a query
|
||||
- Create a dashboard
|
||||
- Concept and reference topic headings should be nouns or gerunds. Examples: Contributing to docs, Visualizations, Style guide
|
||||
|
||||
#### Heading don'ts
|
||||
|
||||
- Avoid stacked headings, which is following one heading with another heading.
|
||||
- Avoid skipping heading levels. For example, an h1 should be followed by an h2 rather than an h3.
|
||||
- Avoid having just one lower-level heading. For example, h1, h2, h2, h3, h3, h2, h2 is a good order. Do not go h1, h2, h3, h2, h3, h2.
|
||||
- Avoid using hyphens in headings.
|
||||
- Do not include parenthetical words like (Important!) in headings.
|
||||
|
||||
#### Step-by-step headings
|
||||
|
||||
In most cases, headings should not be numbered steps.
|
||||
|
||||
However, sometimes we need to use headings as numbered steps. This is mostly in cases where each step is complex or a series of other procedures. For example, in [Getting started with Grafana and Prometheus](https://grafana.com/docs/grafana/latest/getting-started/getting-started-prometheus/).
|
||||
|
||||
If that is the case, then use the following format for headings:
|
||||
|
||||
##### Step 1. Install the software
|
||||
##### Step 2. Run the software
|
||||
- This Is Title Case
|
||||
* Task topic headings start with a verb.
|
||||
- Write a query. Create a dashboard.
|
||||
* Concept and reference topic headings should be nouns or gerunds. Examples: Contributing to docs, Visualizations, Style guide
|
||||
* Avoid following one heading with another heading.
|
||||
* Avoid skipping heading levels. For example, an h1 should be followed by an h2 rather than an h3.
|
||||
* Avoid having just one lower-level heading. For example, h1, h2, h2, h3, h3, h2 is a good order. Do no go h1, h2, h3, h2, h3, h2.
|
||||
* Don't include parenthetical words like (Important!) in headings.
|
||||
|
||||
### Images
|
||||
|
||||
- Preferred format is .png
|
||||
- File extension should be all lowercase.
|
||||
- Preferred DPI is 72.
|
||||
- Assume all graphics will be exclusively viewed on the web.
|
||||
- Maximum image size is 3840px X 2160px.
|
||||
- Screenshots should be readable, but not too large.
|
||||
- _Do not_ use image shortcodes. Follow the guidance in the [Grafana markdown guide](https://github.com/grafana/grafana/blob/master/contribute/style-guides/documentation-markdown-guide.md#images).
|
||||
- Markdown image links are preferred. Only use the HTML image links if you need to style the image in ways unsupported in Markdown.
|
||||
- When you name a file, follow the [file naming conventions](#file-naming-conventions). Example: image-name-7-3.png
|
||||
* Preferred format is .png
|
||||
* File extension should be all lowercase.
|
||||
* Preferred DPI is 72.
|
||||
* Assume all graphics will be exclusively viewed on the web.
|
||||
* Maximum image size is 3840px X 2160px.
|
||||
* Screenshots should be readable, but not too large.
|
||||
|
||||
### Capitalization
|
||||
|
||||
- Grafana, Loki, and Prometheus are always capitalized unless part of a code block.
|
||||
- API names are always Title Case, followed by "API"—for example, "Dashboard Permissions API"
|
||||
- Abbreviations are always capitalized (such as API, HTTP, ID, JSON, SQL, or URL) unless they are part of a code block.
|
||||
- Menu and submenu titles always use sentence case: capitalize the first word, and lowercase the rest.
|
||||
* Grafana, Loki, and Prometheus are always capitalized unless part of a code block.
|
||||
* API names are always Title Case, followed by "API"—for example, "Dashboard Permissions API"
|
||||
* Git is always capitalized, unless part of a code block.
|
||||
* Abbreviations are always capitalized (such as API, HTTP, ID, JSON, SQL, or URL) unless they are part of a code block.
|
||||
* Menu and submenu titles always use sentence case: capitalize the first word, and lowercase the rest.
|
||||
- "Dashboards" when referring to the submenu title.
|
||||
- "Keyboard shortcuts" when referring to the submenu topic.
|
||||
- Generic and plural versions are always lowercase.
|
||||
* Generic and plural versions are always lowercase.
|
||||
- Lowercase "dashboard" when referring to a dashboard generally.
|
||||
- Lowercase "dashboards" when referring to multiple dashboards.
|
||||
- **Exceptions:** If a term is lowercased in the Grafana UI, then match the UI.
|
||||
|
||||
#### Git, GitHub
|
||||
|
||||
Git is always capitalized, unless part of a code block. GitHub is the correct spelling and capitalization.
|
||||
|
||||
#### Integrations
|
||||
|
||||
In general, "integration" is not capitalized. Only capitalize it if it is capitalized in the UI or part of a proper noun, like the name of a specific integration.
|
||||
|
||||
The first letter of the name of an integration is always capitalized, even if the original named source is lowercase.
|
||||
|
||||
**Examples:**
|
||||
- MySQL Integration
|
||||
- CockroachDB Integration
|
||||
- Etcd Integration
|
||||
- I installed an integration on my local Grafana.
|
||||
* **Exceptions:** If a term is lowercased in the Grafana UI, then match the UI.
|
||||
|
||||
### Links and references
|
||||
|
||||
@@ -155,45 +88,16 @@ When possible, use the exact title of the page or section you are linking to as
|
||||
**Example**
|
||||
Refer to the [Documentation style guide](documentation-style-guide.md) for information about word usage and capitalization guidelines.
|
||||
|
||||
### Notes, tips, cautions, and warnings
|
||||
|
||||
Grafana documentation uses notes, tips, cautions, and warnings. Notes are the most common. The format for all of them is indented, bold, sentence case:
|
||||
|
||||
```
|
||||
> **Note:**
|
||||
```
|
||||
|
||||
#### Notes
|
||||
|
||||
Notes provide additional information that the user should be extra aware of. For example:
|
||||
|
||||
> **Note:** This page describes a feature for Grafana 7.0 beta.
|
||||
|
||||
#### Tips
|
||||
|
||||
Tips describe alternate or more efficient ways of doing things. Rarely used.
|
||||
|
||||
#### Cautions
|
||||
|
||||
Cautions warn the user that they should proceed with caution. Use cautions to emphasize the potential downside of a course of action.
|
||||
|
||||
> **Caution:** If you turn off authentication requirements, then anyone can access your Grafana instance. This poses a considerable security risk.
|
||||
|
||||
#### Warnings
|
||||
|
||||
Warnings tell the user not to do something. For example:
|
||||
|
||||
> **Warning:** Grafana does not back up your dashboards. If you delete a dashboard, then you might not be able to recover it.
|
||||
|
||||
### Command line examples
|
||||
|
||||
- Do not assume everyone is using Linux. Make sure instructions include enough information for Windows and Mac users to successfully complete procedures.
|
||||
* Do not assume everyone is using Linux. Make sure instructions include enough information for Windows and Mac users to successfully complete procedures.
|
||||
|
||||
- Do not add `$` before commands. Make it easy for users to copy and paste commands.
|
||||
- **Right:** `sudo yum install grafana`
|
||||
- **Wrong:** `$ sudo yum install grafana`
|
||||
* Do not add `$` before commands. Make it easy for users to copy and paste commands.
|
||||
|
||||
- Include `sudo` before commands that require `sudo` to work.
|
||||
* **Wrong:** `$ sudo yum install grafana`
|
||||
* **Right:** `sudo yum install grafana`
|
||||
|
||||
* Include `sudo` before commands that require `sudo` to work.
|
||||
|
||||
For terminal examples and Grafana configuration, use a `bash` code block:
|
||||
```bash
|
||||
@@ -211,44 +115,32 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
Grafana products has some words, abbreviations, and terms particular to the Grafana discourse community.
|
||||
|
||||
#### changelog
|
||||
|
||||
One word, not two.
|
||||
|
||||
**Example**
|
||||
|
||||
- Read the full changelog.
|
||||
|
||||
**Exception:**
|
||||
|
||||
- When referring to the file containing the official changelog, use the filename: `CHANGELOG.md`.
|
||||
|
||||
#### checkout, check out
|
||||
|
||||
Two words if used as a verb, one word if used as a noun.
|
||||
|
||||
**Examples**
|
||||
|
||||
- Check out these new features!
|
||||
- Proceed to checkout.
|
||||
* Check out these new features!
|
||||
* Proceed to checkout.
|
||||
|
||||
#### data source
|
||||
|
||||
Two words, not one.
|
||||
Two words, not one
|
||||
|
||||
**Exceptions:**
|
||||
- "datasource" used as an identifier
|
||||
- "datasource" in a URL
|
||||
- Use "data source" instead of "datasource" unless used as an identifier, in code, or as part of a URL.
|
||||
- Spell out "repository" and avoid the shorter "repo."
|
||||
- Use "Unix" as the preferred spelling (as opposed to "UNIX", or "unix") when referring to the family of operating systems.
|
||||
* "datasource" used as an identifier
|
||||
* "datasource" in a URL
|
||||
* Use "data source" instead of "datasource" unless used as an identifier, in code, or as part of a URL.
|
||||
* Spell out "repository" and avoid the shorter "repo."
|
||||
* Use "Unix" as the preferred spelling (as opposed to "UNIX", or "unix") when referring to the family of operating systems.
|
||||
|
||||
#### display (verb)
|
||||
|
||||
*Display* is a transitive verb, which means it always needs a direct object.
|
||||
- Correct, active voice: Grafana displays your list of active alarms.
|
||||
- Correct, but passive voice: Your list of active alarms is displayed.
|
||||
- Incorrect: The list of active alarms displays.
|
||||
* Correct, active voice: Grafana displays your list of active alarms.
|
||||
* Correct, but passive voice: Your list of active alarms is displayed.
|
||||
* Incorrect: The list of active alarms displays.
|
||||
|
||||
#### drawer
|
||||
|
||||
@@ -262,13 +154,9 @@ Do not use. This is developer jargon that refers to a UI panel. Refer to the pan
|
||||
|
||||
One word, not two.
|
||||
|
||||
#### mixin
|
||||
|
||||
One word, not two. Also, not hyphenated.
|
||||
|
||||
#### open source, open-source
|
||||
|
||||
Do not hyphenate when used as an adjective unless the lack of hyphen would cause confusion. For example: _Open source software design is the most open open-source system I can imagine._
|
||||
Do not hyphenate when used as an adjective unless the lack of hyphen would cause confusion. For example: _Open source software design is the most open open-source system I can imagine._
|
||||
|
||||
Do not hyphenate when it is used as a noun. For example: _Open source is the best way to develop software._
|
||||
|
||||
@@ -278,17 +166,5 @@ Two words if used as a verb, one word if used as a noun.
|
||||
|
||||
**Examples**
|
||||
|
||||
- Set up the workspace.
|
||||
- Initial setup might take five minutes.
|
||||
|
||||
### node_exporter, windows_exporter
|
||||
|
||||
When referencing the Prometheus data source exporters, always use "node_exporter" and "windows_exporter" when referring to those tools.
|
||||
|
||||
**Correct:** node_exporter, windows_exporter
|
||||
**Incorrect:** Node Exporter, node exporter, Windows Exporter, Windows exporter, windows exporter.
|
||||
|
||||
### MS SQL Server
|
||||
Always use "MS SQL" when referring to MS SQL Server application.
|
||||
|
||||
Incorrect UI spellings will be corrected in a later version of Grafana.
|
||||
* Set up the workspace.
|
||||
* Initial setup might take five minutes.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# End-to-End Tests for core Grafana
|
||||
|
||||
This document is specific to the [Grafana repository](https://github.com/grafana/grafana). Be sure that you've read the [generalized E2E document](e2e.md).
|
||||
|
||||
## Commands
|
||||
|
||||
- `yarn e2e` Creates an isolated `grafana-server` home under _\<repo-root>/e2e/tmp_ with provisioned data sources and dashboards. This copies locally build binary and frontend assets from your repo root so you need to have a built backend and frontend for this to run locally. The server starts on port 3001 so it does not conflict with your normal dev server.
|
||||
- `yarn e2e:debug` Same as above but runs the tests in chrome and does not shutdown after completion.
|
||||
- `yarn e2e:dev` Same as above but does not run any tests on startup. It lets you pick a test first.
|
||||
|
||||
If you already have a Grafana instance running, you can provide a specific URL by setting the `BASE_URL` environment variable:
|
||||
|
||||
```shell
|
||||
BASE_URL=http://172.0.10.2:3333 yarn e2e
|
||||
```
|
||||
|
||||
The above commands use some utils scripts under [_\<repo-root>/e2e_](../../e2e) that can also be used for more control.
|
||||
|
||||
- `./e2e/start-server` This creates a fresh new grafana server working dir, setup's config and starts the server. It will also kill any previously started server that is still running using pid file at _\<repo-root>/e2e/tmp/pid_.
|
||||
- `./e2e/wait-for-grafana` waits for `$HOST` and `$PORT` to be available. Per default localhost and 3001.
|
||||
- `./e2e/run-suite <debug|dev|noarg>` Starts cypress in different modes.
|
||||
|
||||
## Test suites
|
||||
|
||||
All the integration tests are located at _\<repo-root>/e2e/suite\<x>/specs_. The page objects and reusable flows are in the [_\<repo-root>/packages/grafana-e2e_](../../packages/grafana-e2e) package.
|
||||
@@ -1,28 +0,0 @@
|
||||
# End-to-End Tests for plugins
|
||||
|
||||
Be sure that you've read the [generalized E2E document](e2e.md).
|
||||
|
||||
## Commands
|
||||
|
||||
- `yarn test:e2e` will run [Grafana's E2E utility](../../packages/grafana-e2e) against an already running Grafana server.
|
||||
- `yarn test:e2e:update` will run `test:e2e` but instead of asserting that screenshots match their expected fixtures, they'll be replaced with new ones.
|
||||
|
||||
Your running Grafana instance can be targeted by setting the `CYPRESS_BASE_URL`, `CYPRESS_USERNAME` and `CYPRESS_PASSWORD` environment variableS:
|
||||
|
||||
```shell
|
||||
CYPRESS_BASE_URL=https://localhost:3000 CYPRESS_USERNAME=admin CYPRESS_PASSWORD=admin yarn test:e2e
|
||||
```
|
||||
|
||||
## Test suites
|
||||
|
||||
All tests are located at _\<repo-root>/cypress/integration_ by default.
|
||||
|
||||
## Things to test
|
||||
|
||||
- Add data source (if applicable)
|
||||
- Add panel
|
||||
- Edit panel
|
||||
- Annotations (if applicable)
|
||||
- Aliases (if applicable)
|
||||
- Template variables
|
||||
- "Explore" view
|
||||
@@ -1,122 +1,139 @@
|
||||
# End-to-End tests
|
||||
# End to end test framework
|
||||
|
||||
Grafana Labs uses a minimal [homegrown solution](../../packages/grafana-e2e) built on top of [Cypress](https://cypress.io) for its end-to-end (E2E) tests.
|
||||
Grafana Labs uses a minimal home grown solution built on top of Cypress for our end to end (e2e) tests.
|
||||
|
||||
Important notes:
|
||||
## Commands
|
||||
|
||||
- We generally store all element identifiers ([CSS selectors](https://mdn.io/docs/Web/CSS/CSS_Selectors)) within the framework for reuse and maintainability.
|
||||
- We generally do not use stubs or mocks as to fully simulate a real user.
|
||||
- Cypress' promises [do not behave as you'd expect](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Mixing-Async-and-Sync-code).
|
||||
- [Testing core Grafana](e2e-core.md) is slightly different than [testing plugins](e2e-plugins.md).
|
||||
- `yarn e2e` Creates an isolated grafana-server home under `<repo-root>/e2e/tmp` with provisioned data sources and dashboards. This
|
||||
copies locally build binary and frontend assets from your repo root so you need to have a built backend and frontend
|
||||
for this to run locally. The server starts on port 3001 so it does not conflict with your normal dev server.
|
||||
- `yarn e2e:debug` Same as above but runs the tests in chrome and does not shutdown after completion.
|
||||
- `yarn e2e:dev` Same as above but does not run any tests on startup. It lets you pick a test first.
|
||||
|
||||
## Framework structure
|
||||
If you already have a Grafana instance running, you can provide a specific URL by setting the `BASE_URL` environment variable:
|
||||
|
||||
Inspired by https://martinfowler.com/bliki/PageObject.html
|
||||
```
|
||||
BASE_URL=http://172.0.10.2:3333 yarn e2e
|
||||
```
|
||||
|
||||
- `Selector`: A unique identifier that is used from the E2E framework to retrieve an element from the Browser
|
||||
The above commands use some utils scripts under `<repo-root>/e2e` that can also be used for more control.
|
||||
|
||||
- `./e2e/start-server` This creates a fresh new grafana server working dir, setup's config and starts the server. It
|
||||
will also kill any previously started server that is still running using pid file at `<repo-root>/e2e/tmp/pid`.
|
||||
- `./e2e/wait-for-grafana` waits for `$HOST` and `$PORT` to be available. Per default localhost and 3001.
|
||||
- `./e2e/run-suite <debug|dev|noarg>` Starts cypress in different modes.
|
||||
|
||||
## Test Suites
|
||||
|
||||
All the integration tests are located at `e2e/suite<x>/specs`. The page objects and reusable flows are in the
|
||||
`packages/grafana-e2e` package.
|
||||
|
||||
## Basic concepts
|
||||
|
||||
Here is a good introduction to e2e best practices: https://martinfowler.com/bliki/PageObject.html.
|
||||
|
||||
- `Selector`: A unique identifier that is used from the e2e framework to retrieve an element from the Browser
|
||||
- `Page`: An abstraction for an object that contains one or more `Selectors` with `visit` function to navigate to the page.
|
||||
- `Component`: An abstraction for an object that contains one or more `Selectors` but without `visit` function
|
||||
- `Flow`: An abstraction that contains a sequence of actions on one or more `Pages` that can be reused and shared between tests
|
||||
|
||||
## Basic example
|
||||
|
||||
Let's start with a simple [JSX](https://reactjs.org/docs/introducing-jsx.html) example containing a single input field that we want to populate during our E2E test:
|
||||
Let's start with a simple example with a single selector. For simplicity, all examples are in JSX.
|
||||
|
||||
```jsx
|
||||
<input
|
||||
className="gf-form-input login-form-input"
|
||||
type="text"
|
||||
/>
|
||||
In our example app, we have an input that we want to type some text into during our e2e test.
|
||||
|
||||
```jsx harmony
|
||||
<div>
|
||||
<input type="text" className="gf-form-input login-form-input" />
|
||||
</div>
|
||||
```
|
||||
|
||||
We _could_ target the field with a CSS selector like `.gf-form-input.login-form-input` but that would be brittle as style changes occur frequently. Furthermore there is nothing that signals to future developers that this input is part of an E2E test. At Grafana, we use `aria-label` attributes as our preferred way of defining selectors instead of [`data-*`](https://mdn.io/docs/Web/HTML/Global_attributes/data-*) as they also aid in [accessibility](https://mdn.io/docs/Learn/Accessibility/What_is_accessibility):
|
||||
We could define a selector using `JQuery` [type selectors](https://api.jquery.com/category/selectors/) with a string like `'.gf-form-input.login-form-input'` but that would be brittle as style changes occur frequently. Furthermore there is nothing that signals to future developers that this input is part of an e2e test.
|
||||
|
||||
```jsx
|
||||
<input
|
||||
aria-label="Username input field"
|
||||
className="gf-form-input login-form-input"
|
||||
type="text"
|
||||
/>
|
||||
At Grafana, we use `aria-label` as our preferred way of defining selectors instead of `data-*` attributes. This also aids in accessibility.
|
||||
Let's add a descriptive `aria-label` to our simple example.
|
||||
|
||||
```jsx harmony
|
||||
<div>
|
||||
<input type="text" className="gf-form-input login-form-input" aria-label="Username input field" />
|
||||
</div>
|
||||
```
|
||||
|
||||
The next step is to create a `Page` representation in our E2E framework to glue the test with the real implementation using the `pageFactory` function. For that function we can supply a `url` and `selectors` like in the example below:
|
||||
Now that we added the `aria-label` we suddenly get more information about this particular field. It's an input field that represents a username, but there it's still not really signaling that it's part of an e2e test.
|
||||
|
||||
The next step is to create a `Page` representation in our e2e test framework to glue the test with the real implementation using the `pageFactory` function. For that function we can supply a `url` and `selectors` like in the example below:
|
||||
|
||||
```typescript
|
||||
export const Login = {
|
||||
// Called via `Login.visit()`
|
||||
url: '/login',
|
||||
|
||||
// Called via `Login.username()`
|
||||
username: 'Username input field',
|
||||
url: "/login", // used when called from Login.visit()
|
||||
username: "Username input field", // used when called from Login.username().type('Hello World')
|
||||
};
|
||||
```
|
||||
|
||||
The next step is to add the `Login` page to the `Pages` export within [_\<repo-root>/packages/grafana-e2e-selectors/src/selectors/pages.ts_](../../packages/grafana-e2e-selectors/src/selectors/pages.ts) so that it appears when we type `e2e.pages` in our IDE.
|
||||
The next step is to add the `Login` page to the exported const `Pages` in `packages/grafana-e2e-selectors/src/selectors/pages.ts` so that it appears when we type `e2e.pages` in our IDE.
|
||||
|
||||
```typescript
|
||||
```ecmascript 6
|
||||
export const Pages = {
|
||||
Login,
|
||||
…,
|
||||
…,
|
||||
…,
|
||||
...,
|
||||
...,
|
||||
...,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
Now that we have a `Page` called `Login` in our `Pages` const we can use that to add a selector in our html like shown below and now this really signals to future developers that it is part of an E2E test.
|
||||
Now that we have a `Page` called `Login` in our `Pages` const we can use that to add a selector in our html like shown below and now this really signals to future developers that it is part of an e2e test.
|
||||
|
||||
```jsx
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
<input
|
||||
aria-label={selectors.pages.Login.username}
|
||||
className="gf-form-input login-form-input"
|
||||
type="text"
|
||||
/>
|
||||
```jsx harmony
|
||||
<div>
|
||||
<input type="text" className="gf-form-input login-form-input" aria-label={selectors.pages.Login.username} />
|
||||
</div>
|
||||
```
|
||||
|
||||
The last step in our example is to use our `Login` page as part of a test.
|
||||
|
||||
- The `url` property is used whenever we call the `visit` function and is equivalent to the Cypress' [`cy.visit()`](https://docs.cypress.io/api/commands/visit.html#Syntax).
|
||||
- The `url` property is used whenever we call the `visit` function and is equivalent to the Cypress function [cy.visit()](https://docs.cypress.io/api/commands/visit.html#Syntax).
|
||||
> Best practice after calling `visit` is to always call `should` on a selector to prevent flaky tests when you try to access an element that isn't ready. For more information, refer to [Commands vs. assertions](https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions).
|
||||
- Any defined selector can be accessed from the `Login` page by invoking it. This is equivalent to the result of the Cypress function [cy.get(...)](https://docs.cypress.io/api/commands/get.html#Syntax).
|
||||
|
||||
- Any defined selector can be accessed from the `Login` page by invoking it. This is equivalent to the result of the Cypress function [`cy.get(…)`](https://docs.cypress.io/api/commands/get.html#Syntax).
|
||||
|
||||
```typescript
|
||||
```ecmascript 6
|
||||
describe('Login test', () => {
|
||||
it('passes', () => {
|
||||
it('Should pass', () => {
|
||||
e2e.pages.Login.visit();
|
||||
// To prevent flaky tests, always do a `.should` on any selector that you expect to be in the DOM.
|
||||
// To prevent flaky tests, always do a .should on any selector that you expect to be in the DOM.
|
||||
// Read more here: https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions
|
||||
e2e.pages.Login.username()
|
||||
.should('be.visible')
|
||||
.type('admin');
|
||||
e2e.pages.Login.username().should('be.visible');
|
||||
e2e.pages.Login.username().type('admin');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced example
|
||||
|
||||
Let's take a look at an example that uses the same `selector` for multiple items in a list for instance. In this example app we have a list of data sources that we want to click on during an E2E test.
|
||||
Let's take a look at an example that uses the same `selector` for multiple items in a list for instance. In this example app we have a list of data sources that we want to click on during an e2e test.
|
||||
|
||||
```jsx
|
||||
```jsx harmony
|
||||
<ul>
|
||||
{dataSources.map(({ id, name }) => (
|
||||
<li className="card-item-wrapper" key={id}>
|
||||
<a className="card-item" href={`datasources/edit/${id}`}>
|
||||
<div className="card-item-name">{name}</div>
|
||||
{dataSources.map(dataSource => (
|
||||
<li className="card-item-wrapper" key={dataSource.id}>
|
||||
<a className="card-item" href={`datasources/edit/${dataSource.id}`}>
|
||||
<div className="card-item-name">{dataSource.name}</div>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
```
|
||||
|
||||
Just as before in the basic example we'll start by creating a page abstraction using the `pageFactory` function:
|
||||
````
|
||||
|
||||
Just as before in the basic example we'll start by creating a page abstraction using the `pageFactory` function:
|
||||
```typescript
|
||||
export const DataSources = {
|
||||
url: '/datasources',
|
||||
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`,
|
||||
};
|
||||
```
|
||||
````
|
||||
|
||||
You might have noticed that instead of a simple `string` as the `selector`, we're using a `function` that takes a string parameter as an argument and returns a formatted string using the argument.
|
||||
|
||||
@@ -124,13 +141,13 @@ Just as before we need to add the `DataSources` page to the exported const `Page
|
||||
|
||||
The next step is to use the `dataSources` selector function as in our example below:
|
||||
|
||||
```jsx
|
||||
```jsx harmony
|
||||
<ul>
|
||||
{dataSources.map(({ id, name }) => (
|
||||
<li className="card-item-wrapper" key={id}>
|
||||
<a className="card-item" href={`datasources/edit/${id}`}>
|
||||
<div className="card-item-name" aria-label={selectors.pages.DataSources.dataSources(name)}>
|
||||
{name}
|
||||
{dataSources.map(dataSource => (
|
||||
<li className="card-item-wrapper" key={dataSource.id}>
|
||||
<a className="card-item" href={`datasources/edit/${dataSource.id}`}>
|
||||
<div className="card-item-name" aria-label={selectors.pages.DataSources.dataSources(dataSource.name)}>
|
||||
{dataSource.name}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -138,25 +155,55 @@ The next step is to use the `dataSources` selector function as in our example be
|
||||
</ul>
|
||||
```
|
||||
|
||||
When this list is rendered with the data sources with names `A`, `B` and `C` ,the resulting HTML would look like:
|
||||
When this list is rendered with the data sources with names `A`, `B`, `C` the resulting html would become:
|
||||
|
||||
```html
|
||||
<div class="card-item-name" aria-label="Data source list item A">A</div>
|
||||
<div class="card-item-name" aria-label="Data source list item B">B</div>
|
||||
<div class="card-item-name" aria-label="Data source list item C">C</div>
|
||||
```jsx harmony
|
||||
<div class="card-item-name" aria-label="Data source list item A">
|
||||
A
|
||||
</div>
|
||||
...
|
||||
<div class="card-item-name" aria-label="Data source list item B">
|
||||
B
|
||||
</div>
|
||||
...
|
||||
<div class="card-item-name" aria-label="Data source list item C">
|
||||
C
|
||||
</div>
|
||||
```
|
||||
|
||||
Now we can write our test. The one thing that differs from the [basic example](#basic-example) above is that we pass in which data source we want to click on as an argument to the selector function:
|
||||
Now we can write our test. The one thing that differs from the `Basic example` is that we pass in which data source we want to click on as an argument to the selector function:
|
||||
|
||||
```typescript
|
||||
> Best practice after calling `visit` is to always call `should` on a selector to prevent flaky tests when you try to access an element that isn't ready. For more information, refer to [Commands vs. assertions](https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions).
|
||||
|
||||
```ecmascript 6
|
||||
describe('List test', () => {
|
||||
it('clicks on data source named B', () => {
|
||||
it('Clicking on data source named B', () => {
|
||||
e2e.pages.DataSources.visit();
|
||||
// To prevent flaky tests, always do a .should on any selector that you expect to be in the DOM.
|
||||
// Read more here: https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions
|
||||
e2e.pages.DataSources.dataSources('B')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
e2e.pages.DataSources.dataSources('B').should('be.visible');
|
||||
e2e.pages.DataSources.dataSources('B').click();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Debugging PhantomJS image rendering
|
||||
|
||||
### Common Error
|
||||
|
||||
The most common error with PhantomJs image rendering is when a PR introduces an import that has functionality that's not supported by PhantomJs. To quickly identify which new import causes this you can use a tool like `es-check`.
|
||||
|
||||
1. Run > `npx es-check es5 './public/build/*.js'`
|
||||
2. Check the output for files that break es5 compatibility.
|
||||
3. Lazy load the failing imports if possible.
|
||||
|
||||
### Debugging
|
||||
|
||||
There is no easy or comprehensive way to debug PhantomJS smoke test (image rendering) failures. However, PhantomJS exposes remote debugging interface which can give you a sense of what is going wrong in the smoke test. Before performing the steps described below make sure your local Grafana instance is running:
|
||||
|
||||
1. Go to `tools/phantomjs` directory
|
||||
2. Execute `phantomjs` binary against `render.js` file: `./phantomjs --remote-debugger-port=9009 --remote-debugger-autorun=yes ./render.js url="http://localhost:3000"`
|
||||
3. In your browser navigate to `http://localhost:9009/`
|
||||
4. Select `http://localhost:3000/login` from the list. You will get access to Webkit's inspector to see the console's output from the smoke test.
|
||||
|
||||
The method described above is not perfect, but is helpful to evaluate smoke tests breaking due to bundle errors.
|
||||
|
||||
@@ -7,34 +7,14 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/jav
|
||||
- [Frontend Style Guide](#frontend-style-guide)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Basic rules](#basic-rules)
|
||||
- [Naming conventions](#naming-conventions)
|
||||
- [Use `PascalCase` for:](#use-pascalcase-for)
|
||||
- [Typescript class names](#typescript-class-names)
|
||||
- [Types and interfaces](#types-and-interfaces)
|
||||
- [Enums](#enums)
|
||||
- [Use `camelCase` for:](#use-camelcase-for)
|
||||
- [Functions](#functions)
|
||||
- [Methods](#methods)
|
||||
- [Variables](#variables)
|
||||
- [React state and properties](#react-state-and-properties)
|
||||
- [Emotion class names](#emotion-class-names)
|
||||
- [Use `ALL_CAPS` for constants.](#use-all_caps-for-constants)
|
||||
- [Use BEM convention for SASS styles.](#use-bem-convention-for-sass-styles)
|
||||
- [Typing](#typing)
|
||||
- [File and directory naming conventions](#file-and-directory-naming-conventions)
|
||||
- [Code organization](#code-organization)
|
||||
- [Exports](#exports)
|
||||
- [Comments](#comments)
|
||||
- [Linting](#linting)
|
||||
- [Naming conventions](#naming-conventions)
|
||||
- [File and directory naming conventions](#file-and-directory-naming-conventions)
|
||||
- [Code organization](#code-organization)
|
||||
- [Exports](#exports)
|
||||
- [Comments](#comments)
|
||||
- [React](#react)
|
||||
- [Props](#props)
|
||||
- [Name callback props and handlers with an "on" prefix.](#name-callback-props-and-handlers-with-an-on-prefix)
|
||||
- [React Component definitions](#react-component-definitions)
|
||||
- [React Component constructor](#react-component-constructor)
|
||||
- [React Component defaultProps](#react-component-defaultprops)
|
||||
- [State management](#state-management)
|
||||
|
||||
- [Proposal for removing or replacing Angular dependencies](https://github.com/grafana/grafana/pull/23048)
|
||||
|
||||
## Basic rules
|
||||
|
||||
@@ -127,7 +107,7 @@ class DateCalculator {
|
||||
}
|
||||
class DateCalculator {
|
||||
// bad
|
||||
calculate_time_range () {...}
|
||||
calculate_timee_range () {...}
|
||||
}
|
||||
|
||||
class DateCalculator {
|
||||
@@ -167,7 +147,7 @@ interface ModalState {
|
||||
```typescript
|
||||
const getStyles = = () => ({
|
||||
// bad
|
||||
ElementWrapper: css`...`,
|
||||
ElementWraper: css`...`,
|
||||
// bad
|
||||
["element-wrapper"]: css`...`,
|
||||
|
||||
@@ -210,7 +190,7 @@ const stringArray: string[] = [];
|
||||
|
||||
Specify function return types explicitly in new code. This improves readability by being able to tell what a function returns just by looking at the signature. It also prevents errors when a function's return type is broader than expected by the author.
|
||||
|
||||
> **Note:** We don't have linting for this enabled because of lots of old code that needs to be fixed first.
|
||||
> Note: We don't have linting for this enabled because of lots of old code that needs to be fixed first.
|
||||
|
||||
```typescript
|
||||
// bad
|
||||
@@ -344,6 +324,6 @@ static defaultProps: Partial<Props> = { ... }
|
||||
## State management
|
||||
|
||||
- Don't mutate state in reducers or thunks.
|
||||
- Use `createSlice`. See [Redux Toolkit](https://redux-toolkit.js.org/) for more details.
|
||||
- Use helpers `actionCreatorFactory` and `reducerFactory` instead of traditional `switch statement` reducers in Redux. See [Redux framework](redux.md) for more details.
|
||||
- Use `reducerTester` to test reducers. See [Redux framework](redux.md) for more details.
|
||||
- Use state selectors to access state instead of accessing state directly.
|
||||
|
||||
@@ -46,37 +46,3 @@ const dispatchedActions = await thunkTester(initialState)
|
||||
|
||||
expect(dispatchedActions).toEqual([someAction('reducer tests')]);
|
||||
```
|
||||
|
||||
## Typing of connected props
|
||||
|
||||
It is possible to infer connected props automatically from `mapStateToProps` and `mapDispatchToProps` using a helper type `ConnectedProps` from Redux. For this to work the `connect` call has to be split into two parts.
|
||||
|
||||
```typescript
|
||||
import { connect, ConnectedProps } from 'react-redux'
|
||||
|
||||
const mapStateToProps = (state: StoreState) => {
|
||||
return {
|
||||
location: state.location,
|
||||
initDone: state.panelEditor.initDone,
|
||||
uiState: state.panelEditor.ui,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
updateLocation,
|
||||
initPanelEditor,
|
||||
panelEditorCleanUp,
|
||||
setDiscardChanges,
|
||||
updatePanelEditorUIState,
|
||||
updateTimeZoneForSession,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
class PanelEditorUnconnected extends PureComponent<Props> {};
|
||||
|
||||
export const PanelEditor = connector(PanelEditorUnconnected);
|
||||
```
|
||||
For more examples, refer to the [Redux docs](https://react-redux.js.org/using-react-redux/static-typing#inferring-the-connected-props-automatically).
|
||||
|
||||
@@ -64,13 +64,13 @@ To link a component’s stories with an MDX file you have to do this:
|
||||
```jsx
|
||||
// In TabsBar.story.tsx
|
||||
|
||||
import { TabsBar } from './TabsBar';
|
||||
import { TabsBar } from "./TabsBar";
|
||||
|
||||
// Import the MDX file
|
||||
import mdx from './TabsBar.mdx';
|
||||
import mdx from "./TabsBar.mdx";
|
||||
|
||||
export default {
|
||||
title: 'General/Tabs/TabsBar',
|
||||
title: "General/Tabs/TabsBar",
|
||||
component: TabsBar,
|
||||
parameters: {
|
||||
docs: {
|
||||
@@ -93,8 +93,8 @@ There are some things that the MDX file should contain:
|
||||
```jsx
|
||||
// In MyComponent.mdx
|
||||
|
||||
import { Props } from '@storybook/addon-docs/blocks';
|
||||
import { MyComponent } from './MyComponent';
|
||||
import { Props } from "@storybook/addon-docs/blocks";
|
||||
import { MyComponent } from "./MyComponent";
|
||||
|
||||
<Props of={MyComponent} />;
|
||||
```
|
||||
@@ -141,66 +141,39 @@ interface MyProps {
|
||||
}
|
||||
```
|
||||
|
||||
### Controls
|
||||
### Knobs
|
||||
|
||||
The [controls addon](https://storybook.js.org/docs/react/essentials/controls) provides a way to interact with a component's properties dynamically and requires much less code than knobs. We're deprecating knobs in favor of using controls.
|
||||
Knobs is an [addon to Storybook](https://github.com/storybookjs/storybook/tree/master/addons/knobs) which can be used to easily switch values in the UI. A good use case for it is to try different props for the component. Using knobs is easy. Grafana is set up so knobs can be used straight out of the box. Here is an example of how you might use it.
|
||||
|
||||
#### Migrating a story from Knobs to Controls
|
||||
```jsx
|
||||
// In MyComponent.story.tsx
|
||||
|
||||
As a test, we migrated the [button story](https://github.com/grafana/grafana/blob/master/packages/grafana-ui/src/components/Button/Button.story.tsx). Here's the guide on how to migrate a story to controls.
|
||||
import { number, text } from "@storybook/addon-knobs";
|
||||
|
||||
1. Remove the `@storybook/addon-knobs` dependency.
|
||||
2. Import the Story type from `@storybook/react`
|
||||
export const basicStory = () => (
|
||||
<MyComponent
|
||||
max={number("Max value", 10)}
|
||||
min={number("Min value", -10)}
|
||||
title={text("Title", "Look at the value!")}
|
||||
/>
|
||||
);
|
||||
```
|
||||
|
||||
`import { Story } from @storybook/react`
|
||||
The general convention is that the first parameter of the knob is its name and the second is the default value. There are some more types:
|
||||
|
||||
3. Import the props interface from the component you're working on (these must be exported in the component).
|
||||
|
||||
`import { Props } from './Component'`
|
||||
|
||||
4. Add the Story type to all stories in the file, then replace the props sent to the component
|
||||
and remove any knobs.
|
||||
|
||||
Before
|
||||
|
||||
```tsx
|
||||
export const Simple = () => {
|
||||
const prop1 = text('Prop1', 'Example text');
|
||||
const prop2 = select('Prop2', ['option1', 'option2'], 'option1');
|
||||
|
||||
return <Component prop1={prop1} prop2={prop2} />;
|
||||
};
|
||||
```
|
||||
|
||||
After
|
||||
|
||||
```tsx
|
||||
export const Simple: Story<Props> = ({ prop1, prop2 }) => {
|
||||
return <Component prop1={prop1} prop2={prop2} />;
|
||||
};
|
||||
```
|
||||
|
||||
5. Add default props (or args in Storybook language).
|
||||
|
||||
```tsx
|
||||
Simple.args = {
|
||||
prop1: 'Example text',
|
||||
prop2: 'option 1',
|
||||
};
|
||||
```
|
||||
|
||||
6. If the component has advanced props type (ie. other than string, number, boolean), you need to
|
||||
specify these in an `argTypes`. This is done in the default export of the story.
|
||||
|
||||
```tsx
|
||||
export default {
|
||||
title: 'Component/Component',
|
||||
component: Component,
|
||||
argTypes: {
|
||||
prop2: { control: { type: 'select', options: ['option1', 'option2'] } },
|
||||
},
|
||||
};
|
||||
```
|
||||
| Knob | Description |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `text` | Any text field |
|
||||
| `number` | Any number input. Also [available as range](https://github.com/storybookjs/storybook/tree/master/addons/knobs#number-bound-by-range) |
|
||||
| `boolean` | A switch between true/false |
|
||||
| `color` | Color picker |
|
||||
| `object` | JSON input or array. Good to use if the property requires more complex data structures. |
|
||||
| `array` | Array of strings separated by a comma |
|
||||
| `select` | Select a value from an options object. Good for trying different test cases. |
|
||||
| `options` | Configurable UI for selecting a range of options |
|
||||
| `files` | File selector |
|
||||
| `date` | Select date as stringified Unix timestamp |
|
||||
| `button` | Has a handler which is called when clicked |
|
||||
|
||||
## Best practices
|
||||
|
||||
|
||||
@@ -23,27 +23,6 @@ const ComponentA = () => (
|
||||
);
|
||||
```
|
||||
|
||||
### Styling with theme
|
||||
|
||||
To access the theme in your styles, use the `useStyles` hook. It provides basic memoization and access to the theme object.
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { useStyles } from '@grafana/ui';
|
||||
import { css } from 'emotion';
|
||||
|
||||
const getComponentStyles = (theme: GrafanaTheme) => css`
|
||||
padding: ${theme.spacing.md};
|
||||
`;
|
||||
|
||||
const Foo: FC<FooProps> = () => {
|
||||
const styles = useStyles(getComponentsStyles);
|
||||
|
||||
// Use styles with className
|
||||
};
|
||||
```
|
||||
|
||||
### Styling complex components
|
||||
|
||||
In more complex cases, especially when you need to style multiple DOM elements in one component, or when using styles that depend on properties and/or state, you should create a helper function that returns an object of styles. This function should also be wrapped in the `stylesFactory` helper function, which will provide basic memoization.
|
||||
@@ -57,7 +36,10 @@ import { GrafanaTheme } from '@grafana/data';
|
||||
import { selectThemeVariant, stylesFactory, useTheme } from '@grafana/ui';
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
const backgroundColor = selectThemeVariant({ light: theme.colors.red, dark: theme.colors.blue }, theme.type);
|
||||
const backgroundColor = selectThemeVariant(
|
||||
{ light: theme.colors.red, dark: theme.colors.blue },
|
||||
theme.type
|
||||
);
|
||||
|
||||
return {
|
||||
wrapper: css`
|
||||
|
||||
@@ -18,40 +18,6 @@ This section provides usage guidelines.
|
||||
|
||||
Here's how to use Grafana themes in React components.
|
||||
|
||||
#### useStyles hook
|
||||
|
||||
`useStyles` memoizes the function and provides access to the theme.
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { useStyles } from '@grafana/ui';
|
||||
import { css } from 'emotion';
|
||||
|
||||
const getComponentStyles = (theme: GrafanaTheme) => css`
|
||||
padding: ${theme.spacing.md};
|
||||
`;
|
||||
|
||||
const Foo: FC<FooProps> = () => {
|
||||
const styles = useStyles(getComponentsStyles);
|
||||
|
||||
// Use styles with className
|
||||
};
|
||||
```
|
||||
|
||||
#### Get the theme object
|
||||
|
||||
```tsx
|
||||
import React, { FC } from 'react';
|
||||
import { useTheme } from '@grafana/ui';
|
||||
|
||||
const Foo: FC<FooProps> = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
// Your component has access to the theme variables now
|
||||
};
|
||||
```
|
||||
|
||||
#### Using `ThemeContext` directly
|
||||
|
||||
```tsx
|
||||
@@ -60,6 +26,19 @@ import { ThemeContext } from '@grafana/ui';
|
||||
<ThemeContext.Consumer>{theme => <Foo theme={theme} />}</ThemeContext.Consumer>;
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```tsx
|
||||
import React, { useContext } from 'react';
|
||||
import { ThemeContext } from '@grafana/ui';
|
||||
|
||||
const Foo: React.FunctionComponent<FooProps> = () => {
|
||||
const theme = useContext(ThemeContext);
|
||||
|
||||
// Your component has access to the theme variables now
|
||||
}
|
||||
```
|
||||
|
||||
#### Using `withTheme` higher-order component (HOC)
|
||||
|
||||
With this method your component will be automatically wrapped in `ThemeContext.Consumer` and provided with current theme via `theme` prop. Components used with `withTheme` must implement the `Themeable` interface.
|
||||
@@ -97,38 +76,69 @@ describe('MyComponent', () => {
|
||||
restoreThemeContext();
|
||||
});
|
||||
|
||||
|
||||
it('renders correctly', () => {
|
||||
it('renders correctyl', () => {
|
||||
const wrapper = mount(<MyComponent />)
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Using themes in [Storybook](https://storybook.js.org/)
|
||||
|
||||
All stories are wrapped with `ThemeContext.Provider` using a global decorator. To render a `Themeable` component that isn't wrapped by a `withTheme` HOC, either create a new component in your story, or use the `renderComponentWithTheme` helper.
|
||||
|
||||
#### Create a new component:
|
||||
|
||||
```tsx
|
||||
// Foo.story.tsx
|
||||
const FooWithTheme = withTheme(Foo);
|
||||
|
||||
FooStories.add('Story' () => {
|
||||
return <FooWithTheme />
|
||||
});
|
||||
```
|
||||
|
||||
#### Use `renderComponentWithTheme` helper:
|
||||
|
||||
```tsx
|
||||
// Bar.story.tsx
|
||||
|
||||
BarStories.add('Story' () => {
|
||||
return renderComponentWithTheme(Bar, /* pass props here */)
|
||||
});
|
||||
```
|
||||
|
||||
### Using themes in Angular code
|
||||
|
||||
There should be very few cases where a theme would be used in an Angular context. For this purpose, there is a function available that retrieves the current theme:
|
||||
|
||||
```ts
|
||||
import { getCurrentTheme } from app/core/utils/ConfigProvider
|
||||
```
|
||||
|
||||
Angular components should be migrated to React, or if that's not possible at the moment, styled using Sass.
|
||||
|
||||
## FAQ
|
||||
|
||||
This section provides insight into frequently-asked questions.
|
||||
|
||||
### How can I modify Sass variable files?
|
||||
|
||||
**If possible, migrate styles to Emotion**
|
||||
|
||||
> For the following to apply you need to run `yarn dev` task.
|
||||
|
||||
`[_variables|_variables.dark|_variables.light].generated.scss` files are the ones that are referenced in the main Sass files for Sass variables to be available. **These files are automatically generated and should never be modified by hand!**
|
||||
|
||||
#### If you need to modify a _Sass variable value_ you need to modify the corresponding Typescript file that is the source of the variables:
|
||||
|
||||
#### If you need to modify a *Sass variable value* you need to modify the corresponding Typescript file that is the source of the variables:
|
||||
- `_variables.generated.scss` - modify `grafana-ui/src/themes/default.ts`
|
||||
- `_variables.light.generated.scss` - modify `grafana-ui/src/themes/light.ts`
|
||||
- `_variables.dark.generated.scss` - modify `grafana-ui/src/themes/dark.ts`
|
||||
|
||||
#### If you need to _add new variable_ to Sass variables you need to modify corresponding template file:
|
||||
|
||||
#### If you need to *add new variable* to Sass variables you need to modify corresponding template file:
|
||||
- `_variables.generated.scss` - modify `grafana-ui/src/themes/_variables.scss.tmpl.ts`
|
||||
- `_variables.light.generated.scss` - modify `grafana-ui/src/themes/_variables.light.scss.tmpl.ts`
|
||||
- `_variables.dark.generated.scss` - modify `grafana-ui/src/themes/_variables.dark.scss.tmpl.ts`
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
This section describes limitations with Grafana's theming system.
|
||||
|
||||
@@ -26,19 +26,19 @@ Try to *chunk* your content. This means you should organize the document so that
|
||||
If I was writing content for a site called *Doggie handbook*, I might organize it like this.
|
||||
|
||||
**Concept**
|
||||
- What a dog is
|
||||
- Brief history of dogs
|
||||
- Why you might want a dog
|
||||
- Tasks dogs can be trained to do
|
||||
* What a dog is
|
||||
* Brief history of dogs
|
||||
* Why you might want a dog
|
||||
* Tasks dogs can be trained to do
|
||||
|
||||
**Tasks**
|
||||
- Feed the dog
|
||||
- Groom the dog
|
||||
- Train the dog
|
||||
* Feed the dog
|
||||
* Groom the dog
|
||||
* Train the dog
|
||||
|
||||
**Reference**
|
||||
- List of dog equipment you will need
|
||||
- Table of breeds that includes breed name, size range, short or long hair, and type of dog
|
||||
* List of dog equipment you will need
|
||||
* Table of breeds that includes breed name, size range, short or long hair, and type of dog
|
||||
|
||||
### Audience
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ Concept topics or sections explain *what* and *why*. They do not explain *how*.
|
||||
Continuing the example in the previous section, here is a sample Grafana workflow.
|
||||
|
||||
1. Install Grafana. <link to task for installing Grafana>
|
||||
1. Set up data sources. <link to data sources concept topic, which links to data source task topics>
|
||||
1. Create panels. <link to panel concept topic, which links to tasks>
|
||||
1. Create dashboards. <link to panel concept topic, which links to tasks>
|
||||
1. Enter queries. <link to query editor concept topic>
|
||||
1. Add users. <link to user management concept topic, which links to tasks>
|
||||
1. Create playlists. <link to Playlist topic that contains concept information and tasks>
|
||||
2. Set up data sources. <link to data sources concept topic, which links to data source task topics>
|
||||
3. Create panels. <link to panel concept topic, which links to tasks>
|
||||
4. Create dashboards. <link to panel concept topic, which links to tasks>
|
||||
5. Enter queries. <link to query editor concept topic>
|
||||
6. Add users. <link to user management concept topic, which links to tasks>
|
||||
7. Create playlists. <link to Playlist topic that contains concept information and tasks>
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ Often reference topics are linked from *task* topics, because they contain infor
|
||||
|
||||
Lists of commands or parameters are often organized in reference topics. The information you need to present will dictate the format.
|
||||
|
||||
- They might
|
||||
- be in
|
||||
- unordered lists.
|
||||
* They might
|
||||
* be in
|
||||
* unordered lists.
|
||||
|
||||
[Configuration](https://grafana.com/docs/grafana/latest/installation/configuration/) is an example of lists.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ Write one-step tasks as simple sentences, not as unordered lists or numbered lis
|
||||
Short tasks can be grouped. How short constitutes "short" is a judgment call based on number of steps and how long individual steps are.
|
||||
|
||||
1. Use your judgment.
|
||||
1. Ask your coworkers or someone on the Comm team for advice if you aren't sure.
|
||||
2. Ask your coworkers or someone on the Comm team for advice if you aren't sure.
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package main
|
||||
|
||||
#Dashboard: {
|
||||
// Unique numeric identifier for the dashboard. (generated by the db)
|
||||
id: int
|
||||
// Unique dashboard identifier that can be generated by anyone. string (8-40)
|
||||
uid: string
|
||||
// Title of dashboard.
|
||||
title?: string
|
||||
// Description of dashboard.
|
||||
description?: string
|
||||
// Tags associated with dashboard.
|
||||
tags?: [...string]
|
||||
// Theme of dashboard.
|
||||
style: *"light" | "dark"
|
||||
// Timezone of dashboard,
|
||||
timezone?: *"browser" | "utc"
|
||||
// Whether a dashboard is editable or not.
|
||||
editable: bool | *true
|
||||
// 0 for no shared crosshair or tooltip (default).
|
||||
// 1 for shared crosshair.
|
||||
// 2 for shared crosshair AND shared tooltip.
|
||||
graphTooltip: int >= 0 <= 2 | *0
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
time?: {
|
||||
from: string | *"now-6h"
|
||||
to: string | *"now"
|
||||
}
|
||||
// Timepicker metadata.
|
||||
timepicker?: {
|
||||
// Whether timepicker is collapsed or not.
|
||||
collapse: bool | *false
|
||||
// Whether timepicker is enabled or not.
|
||||
enable: bool | *true
|
||||
// Whether timepicker is visible or not.
|
||||
hidden: bool | *false
|
||||
// Selectable intervals for auto-refresh.
|
||||
refresh_intervals: [...string] | *["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
}
|
||||
// Templating.
|
||||
templating?: list: [...{}]
|
||||
// Annotations.
|
||||
annotations?: list: [...{
|
||||
builtIn: int | *0
|
||||
// Datasource to use for annotation.
|
||||
datasource: string
|
||||
// Whether annotation is enabled.
|
||||
enable?: bool | *true
|
||||
// Whether to hide annotation.
|
||||
hide?: bool | *false
|
||||
// Annotation icon color.
|
||||
iconColor?: string
|
||||
// Name of annotation.
|
||||
name?: string
|
||||
// Query for annotation data.
|
||||
rawQuery: string
|
||||
showIn: int | *0
|
||||
}] | *[]
|
||||
// Auto-refresh interval.
|
||||
refresh: string
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
schemaVersion: int | *25
|
||||
// Version of the dashboard, incremented each time the dashboard is updated.
|
||||
version: string
|
||||
// Dashboard panels.
|
||||
panels?: [...{}]
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
# Dashboard Schemas
|
||||
|
||||
Schema description documents for [Grafana Dashboard
|
||||
JSON](https://grafana.com/docs/grafana/latest/reference/dashboard/) and core
|
||||
panels.
|
||||
|
||||
> **Note:** This directory is experimental. The schemas are not currently
|
||||
> implemented or enforced in Grafana.
|
||||
|
||||
Schemas are defined in [Cue](https://cuelang.org/). Cue was chosen because it
|
||||
strongly facilitates our primary use cases - [schema
|
||||
definition](https://cuelang.org/docs/usecases/datadef/), [data
|
||||
validation](https://cuelang.org/docs/usecases/validation/), and [code
|
||||
generation/extraction](https://cuelang.org/docs/usecases/generate/).
|
||||
|
||||
## Schema Organization
|
||||
|
||||
Each schema describes part of a dashboard. `Dashboard.cue` is the main dashboard
|
||||
schema object. All other schemas describe nested objects within a dashboard.
|
||||
They are grouped in the following directories:
|
||||
|
||||
* `panels` - schemas for
|
||||
[panels](https://grafana.com/docs/grafana/latest/panels/panels-overview/).
|
||||
* `targets` - targets represent
|
||||
[queries](https://grafana.com/docs/grafana/latest/panels/queries/). Each [data
|
||||
source](https://grafana.com/docs/grafana/latest/datasources/) type has a
|
||||
unique target schema.
|
||||
* `variables` - schemas for
|
||||
[variables](https://grafana.com/docs/grafana/latest/variables/variable-types/).
|
||||
* `transformations` - schemas for
|
||||
[transformations](https://grafana.com/docs/grafana/latest/panels/transformations/types-options/).
|
||||
|
||||
The following somewhat conveys how they fit together when constructing a
|
||||
dashboard:
|
||||
|
||||
```
|
||||
+-----------+ +-----------+
|
||||
| Dashboard +------> Variables |
|
||||
+---------+-+ +-----------+
|
||||
| +--------+ +---------+
|
||||
+----> Panels +----> Targets |
|
||||
+------+-+ +---------+
|
||||
| +-----------------+
|
||||
+------> Transformations |
|
||||
+-----------------+
|
||||
```
|
||||
|
||||
## Definitions
|
||||
|
||||
All schemas are [Cue
|
||||
definitions](https://cuelang.org/docs/references/spec/#definitions-and-hidden-fields).
|
||||
Schemas intended to be exported must begin with a capital letter. For example,
|
||||
[Gauge](./panels/Gauge.cue). Definitions beginning with a lowercase letter will
|
||||
not be exported. These are reusable components for constructing the exported
|
||||
definitions. For example, [`#panel`](./panels/panel.cue) is intended to
|
||||
be a base schema for panels. `#Gauge` extends `#panel` with the following:
|
||||
|
||||
```
|
||||
#Gauge: panel & {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Exporting OpenAPI
|
||||
|
||||
[OpenAPI](https://www.openapis.org/) schemas can be exported from these CUE
|
||||
sources.
|
||||
|
||||
### Command Line
|
||||
|
||||
While you can use `cue export` to output OpenAPI documents, it does not expand
|
||||
references which makes the output unusable.
|
||||
|
||||
```
|
||||
cue export --out openapi -o - ./...
|
||||
```
|
||||
|
||||
### Using Go
|
||||
|
||||
You need to use Go to generate useable OpenAPI schemas. This directory contains
|
||||
a Go program that will output just the OpenAPI schemas for one or many Cue
|
||||
packages.
|
||||
|
||||
```
|
||||
go run . <entrypoint> ...
|
||||
```
|
||||
@@ -1 +0,0 @@
|
||||
module: "github.com/grafana/grafana/dashboard-schemas"
|
||||
@@ -1,5 +0,0 @@
|
||||
module github.com/grafana/grafana/dashboard-schemas
|
||||
|
||||
go 1.15
|
||||
|
||||
require cuelang.org/go v0.2.2
|
||||
@@ -1,185 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cuelang.org/go v0.2.2 h1:i/wFo48WDibGHKQTRZ08nB8PqmGpVpQ2sRflZPj73nQ=
|
||||
cuelang.org/go v0.2.2/go.mod h1:Dyjk8Y/B3CfFT1jQKJU0g5PpCeMiDe0yMOhk57oXwqo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/apd/v2 v2.0.1 h1:y1Rh3tEU89D+7Tgbw+lp52T6p/GJLpDmNvr10UWqLTE=
|
||||
github.com/cockroachdb/apd/v2 v2.0.1/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/emicklei/proto v1.6.15 h1:XbpwxmuOPrdES97FrSfpyy67SSCV/wBIKXqgJzh6hNw=
|
||||
github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto=
|
||||
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c h1:g6oFfz6Cmw68izP3xsdud3Oxu145IPkeFzyRg58AKHM=
|
||||
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -1,58 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/load"
|
||||
"cuelang.org/go/encoding/openapi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, err := openAPISchemas(os.Args[1:])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
// openAPISchemas returns OpenAPI schema JSON of the Cue entrypoints passed to
|
||||
// it. It is not a valid OpenAPI document - just the schemas.
|
||||
func openAPISchemas(entrypoints []string) ([]byte, error) {
|
||||
|
||||
var r cue.Runtime
|
||||
cfg := openapi.Config{
|
||||
ExpandReferences: true,
|
||||
}
|
||||
bis := load.Instances(entrypoints, nil)
|
||||
|
||||
// collect all schemas
|
||||
var pairs []openapi.KeyValue
|
||||
for _, bi := range bis {
|
||||
if bi.Err != nil {
|
||||
return nil, bi.Err
|
||||
}
|
||||
inst, err := r.Build(bi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
om, err := cfg.Schemas(inst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pairs = append(pairs, om.Pairs()...)
|
||||
}
|
||||
|
||||
// add all schemas to new ordered map
|
||||
om := openapi.OrderedMap{}
|
||||
om.SetAll(pairs)
|
||||
|
||||
j, err := om.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return j, nil
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOpenAPISchemas(t *testing.T) {
|
||||
|
||||
tests := map[string]struct {
|
||||
entrypoints []string
|
||||
}{
|
||||
"All packages": {
|
||||
entrypoints: []string{"./..."},
|
||||
},
|
||||
"One package": {
|
||||
entrypoints: []string{"./panels"},
|
||||
},
|
||||
"Many packags": {
|
||||
entrypoints: []string{
|
||||
"./panels",
|
||||
"./targets",
|
||||
"./transformations",
|
||||
"./variables",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for testName, test := range tests {
|
||||
|
||||
t.Logf("Running test case %s...", testName)
|
||||
|
||||
j, err := openAPISchemas(test.entrypoints)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// We don't want to validate the JSON content since it's expected to change
|
||||
// often. Only that it is valid JSON by unmarshalling it.
|
||||
|
||||
var iface interface{}
|
||||
err = json.Unmarshal(j, &iface)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package panels
|
||||
|
||||
// Gauge is a single value panel that can repeat a gauge for every series,
|
||||
// column or row.
|
||||
#Gauge: _panel & {
|
||||
// Field config.
|
||||
fieldConfig: {
|
||||
// Defaults.
|
||||
defaults: {
|
||||
// Custom.
|
||||
custom: {}
|
||||
// Unit.
|
||||
unit: string
|
||||
// Min.
|
||||
min: int
|
||||
// Max.
|
||||
max: int
|
||||
// Decimals.
|
||||
decimals: int
|
||||
// Change the field or series name.
|
||||
displayName: string
|
||||
// What to show when there is no value.
|
||||
noValue: string
|
||||
// Threshold config.
|
||||
thresholds: _thresholds
|
||||
// Mappings.
|
||||
mappings: [..._mapping]
|
||||
// Data Links.
|
||||
links: [..._dataLink]
|
||||
}
|
||||
// Overrides.
|
||||
overrides: [..._override]
|
||||
}
|
||||
// Options.
|
||||
options: {
|
||||
// Reduce options.
|
||||
reduceOptions: {
|
||||
// * `true` - Show a calculated value based on all rows.
|
||||
// * `false` - Show a separate stat for every row.
|
||||
values: bool | *false
|
||||
// If values is false, sets max number of rows to
|
||||
// display.
|
||||
limit: int
|
||||
// Reducer function/calculation.
|
||||
calcs: [
|
||||
"allIsZero",
|
||||
"allIsNull",
|
||||
"changeCount",
|
||||
"count",
|
||||
"delta",
|
||||
"diff",
|
||||
"distinctCount",
|
||||
"first",
|
||||
"firstNotNull",
|
||||
"lastNotNull",
|
||||
"last",
|
||||
"logmin",
|
||||
"max",
|
||||
"min",
|
||||
"range",
|
||||
"step",
|
||||
"sum",
|
||||
] | *["mean"]
|
||||
// Fields that should be included in the panel.
|
||||
fields: string | *""
|
||||
}
|
||||
// Render the threshold values around the gauge bar.
|
||||
showThresholdLabels: bool | *false
|
||||
// Render the thresholds as an outer bar.
|
||||
showThresholdMarkers: bool | *true
|
||||
}
|
||||
// Panel type.
|
||||
type: string | *"gauge"
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
package panels
|
||||
|
||||
#Graph: _panel & {
|
||||
// Display values as a bar chart.
|
||||
bars: bool | *false
|
||||
// Dashed line length.
|
||||
dashLength: int | *10
|
||||
// Show line with dashes.
|
||||
dashes: bool | *false
|
||||
// Dashed line spacing when `dashes` is true.
|
||||
spaceLength: int | *10
|
||||
// Controls how many decimals are displayed for legend values and graph hover
|
||||
// tooltips.
|
||||
decimals: int
|
||||
// Field config.
|
||||
fieldConfig: {
|
||||
// Defaults.
|
||||
defaults: custom: {}
|
||||
// Overrides.
|
||||
overrides: [..._override]
|
||||
}
|
||||
// Amount of color fill for a series. Expects a value between 0 and 1.
|
||||
fill: number >= 0 <= 1 | *1
|
||||
// Degree of gradient on the area fill. 0 is no gradient, 10 is a steep
|
||||
// gradient.
|
||||
fillGradient: int >= 0 <= 10 | *0
|
||||
// Hide the series.
|
||||
hiddenSeries: bool | *false
|
||||
// Lengend options.
|
||||
legend: {
|
||||
// Whether to display legend in table.
|
||||
alignAsTable: bool | *false
|
||||
// Average of all values returned from the metric query.
|
||||
avg: bool | *false
|
||||
// Last value returned from the metric query.
|
||||
current: bool | *false
|
||||
// Maximum of all values returned from the metric query.
|
||||
max: bool | *false
|
||||
// Minimum of all values returned from the metric query.
|
||||
min: bool | *false
|
||||
// Display legend to the right.
|
||||
rightSide: bool | *false
|
||||
// Show or hide the legend.
|
||||
show: bool | *true
|
||||
// Available when `rightSide` is true. The minimum width for the legend in
|
||||
// pixels.
|
||||
sideWidth?: int
|
||||
// Sum of all values returned from the metric query.
|
||||
total: bool | *false
|
||||
// Values.
|
||||
values: bool | *true
|
||||
}
|
||||
// Display values as a line graph.
|
||||
lines: bool | *true
|
||||
// The width of the line for a series.
|
||||
linewidth: int | *1
|
||||
// How null values are displayed.
|
||||
// * 'null' - If there is a gap in the series, meaning a null value, then the
|
||||
// line in the graph will be broken and show the gap.
|
||||
// * 'null as zero' - If there is a gap in the series, meaning a null value,
|
||||
// then it will be displayed as a zero value in the graph panel.
|
||||
// * 'connected' - If there is a gap in the series, meaning a null value or
|
||||
// values, then the line will skip the gap and connect to the next non-null
|
||||
// value.
|
||||
nullPointMode: string | *"null"
|
||||
// Options.
|
||||
options: {
|
||||
// Data links.
|
||||
dataLinks: [..._dataLink]
|
||||
}
|
||||
// Available when `stack` is true. Each series is drawn as a percentage of the
|
||||
// total of all series.
|
||||
percentage: bool | *false
|
||||
// Controls how large the points are.
|
||||
pointradius: int
|
||||
// Display points for values.
|
||||
points: bool | *true
|
||||
// Renderer.
|
||||
renderer: string | *"flot"
|
||||
// Series overrides allow a series in a graph panel to be rendered
|
||||
// differently from the others. You can customize display options on a
|
||||
// per-series bases or by using regex rules. For example, one series can have
|
||||
// a thicker line width to make it stand out or be moved to the right Y-axis.
|
||||
seriesOverrides: [...{
|
||||
// Alias or regex matching the series you'd like to target.
|
||||
alias?: string
|
||||
bars?: bool
|
||||
lines?: bool
|
||||
fill?: int
|
||||
fillGradient?: int
|
||||
linewidth?: int
|
||||
nullPointMode?: string
|
||||
fillBelowTo?: string
|
||||
steppedLine?: bool
|
||||
dashes?: bool
|
||||
hiddenSeries?: bool
|
||||
dashLength?: int
|
||||
spaceLength?: int
|
||||
points?: bool
|
||||
pointradius?: int
|
||||
stack?: int
|
||||
color?: string
|
||||
yaxis?: int
|
||||
zindex?: int
|
||||
transform?: string
|
||||
legend?: bool
|
||||
hideTooltip?: bool
|
||||
}]
|
||||
// Each series is stacked on top of another.
|
||||
stack: bool | *false
|
||||
// Draws adjacent points as staircase.
|
||||
steppedLine: bool | *false
|
||||
// Threshold config.
|
||||
thresholds: _thresholds
|
||||
// Time from.
|
||||
timeFrom: string
|
||||
// Time regions.
|
||||
timeRegions: [...string]
|
||||
// Time shift
|
||||
timeShift: string
|
||||
// Tooltip settings.
|
||||
tooltip: {
|
||||
// * true - The hover tooltip shows all series in the graph. Grafana
|
||||
// highlights the series that you are hovering over in bold in the series
|
||||
// list in the tooltip.
|
||||
// * false - The hover tooltip shows only a single series, the one that you
|
||||
// are hovering over on the graph.
|
||||
shared: bool | *true
|
||||
// * 0 (none) - The order of the series in the tooltip is determined by the
|
||||
// sort order in your query. For example, they could be alphabetically
|
||||
// sorted by series name.
|
||||
// * 1 (increasing) - The series in the hover tooltip are sorted by value
|
||||
// and in increasing order, with the lowest value at the top of the list.
|
||||
// * 2 (decreasing) - The series in the hover tooltip are sorted by value
|
||||
// and in decreasing order, with the highest value at the top of the list.
|
||||
sort: int >= 0 <= 2 | *2
|
||||
// Value type.
|
||||
value_type: string | *"individual"
|
||||
}
|
||||
// Panel type.
|
||||
type: string | *"graph"
|
||||
xaxis: {
|
||||
// Buckets.
|
||||
buckets: string
|
||||
// The display mode completely changes the visualization of the graph
|
||||
// panel. It’s like three panels in one. The main mode is the time series
|
||||
// mode with time on the X-axis. The other two modes are a basic bar chart
|
||||
// mode with series on the X-axis instead of time and a histogram mode.
|
||||
// * 'time' - The X-axis represents time and that the data is grouped by
|
||||
// time (for example, by hour, or by minute).
|
||||
// * 'series' - The data is grouped by series and not by time. The Y-axis
|
||||
// still represents the value.
|
||||
// * 'histogram' - Converts the graph into a histogram. A histogram is a
|
||||
// kind of bar chart that groups numbers into ranges, often called buckets
|
||||
// or bins. Taller bars show that more data falls in that range.
|
||||
mode: string | *"time"
|
||||
// Name.
|
||||
name: string
|
||||
// Show or hide the axis.
|
||||
show: bool | *true
|
||||
// Values
|
||||
values: [...number]
|
||||
}
|
||||
yaxes: [...{
|
||||
// Defines how many decimals are displayed for Y value.
|
||||
decimals: int
|
||||
// The display unit for the Y value.
|
||||
format: string | *"short"
|
||||
// The Y axis label.
|
||||
label: string
|
||||
// The scale to use for the Y value - linear, or logarithmic.
|
||||
// * 1 - linear
|
||||
// * 2 - log (base 2)
|
||||
// * 10 - log (base 10)
|
||||
// * 32 - log (base 32)
|
||||
// * 1024 - log (base 1024)
|
||||
logBase: int | *1
|
||||
// The maximum Y value.
|
||||
max?: int
|
||||
// The minimum Y value.
|
||||
min?: int
|
||||
// Show or hide the axis.
|
||||
show: bool | *true
|
||||
}]
|
||||
yaxis: {
|
||||
// Align left and right Y-axes by value.
|
||||
align: bool | *false
|
||||
// Available when align is true. Value to use for alignment of left and
|
||||
// right Y-axes, starting from Y=0.
|
||||
alignLevel: int | *0
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package panels
|
||||
|
||||
// A row is a logical divider within a dashboard. It is used
|
||||
// to group panels together.
|
||||
#Row: {
|
||||
// Whether the row is collapsed or not.
|
||||
collapsed: bool | *true
|
||||
// Name of default data source.
|
||||
datasource?: string
|
||||
// Grid position.
|
||||
gridPos?: _gridPos
|
||||
// Dashboard panels.
|
||||
panels?: [...{}]
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
// Whether to display the title.
|
||||
showTitle: bool | *true
|
||||
// Title.
|
||||
title?: string
|
||||
// Size of title.
|
||||
titleSize: string | *"h6"
|
||||
// Panel type.
|
||||
type: string | *"row"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package panels
|
||||
|
||||
_gridPos: {
|
||||
// Panel height.
|
||||
h?: int > 0 | *9
|
||||
// Panel width.
|
||||
w?: int > 0 <= 24 | *12
|
||||
// Panel x position.
|
||||
x?: int >= 0 < 24 | *0
|
||||
// Panel y position.
|
||||
y?: int >= 0 | *0
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package panels
|
||||
|
||||
_link: {
|
||||
// Link title.
|
||||
title?: string
|
||||
// Whether to open link in new browser tab.
|
||||
targetBlank: bool | *true
|
||||
// URL of link.
|
||||
url: string
|
||||
}
|
||||
|
||||
_panelLink: _link
|
||||
|
||||
_dataLink: _link
|
||||
@@ -1,11 +0,0 @@
|
||||
package panels
|
||||
|
||||
_mapping: {
|
||||
id: int
|
||||
from: string
|
||||
operator: string
|
||||
to: string
|
||||
text: string
|
||||
type: int
|
||||
value: string
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package panels
|
||||
|
||||
_override: {
|
||||
matcher: {
|
||||
id: string
|
||||
options: string
|
||||
}
|
||||
properties: [...{
|
||||
id: string
|
||||
value: int
|
||||
}]
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package panels
|
||||
|
||||
_panel: {
|
||||
// Panel title.
|
||||
title?: string
|
||||
// Description.
|
||||
description?: string
|
||||
// Whether to display the panel without a background.
|
||||
transparent: bool | *false
|
||||
// Name of default datasource.
|
||||
datasource?: string
|
||||
// Grid position.
|
||||
gridPos?: _gridPos
|
||||
// Panel links.
|
||||
links?: [..._panelLink]
|
||||
// Name of template variable to repeat for.
|
||||
repeat?: string
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
repeatDirection: *"h" | "v"
|
||||
// Panel targets - datasource and query configurations to use as
|
||||
// a basis for vizualization.
|
||||
targets?: [...{}]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package panels
|
||||
|
||||
_thresholds: {
|
||||
// Threshold mode.
|
||||
mode: string | *"absolute"
|
||||
// Threshold steps.
|
||||
steps: [...{
|
||||
color: string
|
||||
value: number
|
||||
}]
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package targets
|
||||
|
||||
#Prometheus: {
|
||||
// Query expression.
|
||||
expr: string
|
||||
// Controls the name of the time series, using name or pattern.
|
||||
legendFormat?: string
|
||||
// Interval.
|
||||
interval?: int | *1
|
||||
// Target reference ID.
|
||||
refId: string
|
||||
// Perform an “instant” query, to return only the latest value that
|
||||
// Prometheus has scraped for the requested time series.
|
||||
instant: bool | *false
|
||||
// Resolution.
|
||||
intervalFactor?: int
|
||||
// Format.
|
||||
format: *"time_series" | "table" | "heat_map"
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package transformations
|
||||
|
||||
// Add field from calculation.
|
||||
#CalculateField: {
|
||||
// Transformation ID.
|
||||
id: string | *"calculateField"
|
||||
// Configuration options.
|
||||
options: {
|
||||
// The name of your new field. If you leave this blank, then the field will
|
||||
// be named to match the calculation.
|
||||
alias: string
|
||||
// Binary options.
|
||||
binary: {
|
||||
// Field or number for left side of equation.
|
||||
left: string
|
||||
// Field or number for right side of equation.
|
||||
right: string
|
||||
// Operator.
|
||||
operator: string | *"+"
|
||||
// Calculation to use.
|
||||
reducer: string | *"sum"
|
||||
}
|
||||
// 'reduceRow' - apply selected calculation on each row of selected fields
|
||||
// independently.
|
||||
// 'binary' - apply basic math operation(sum, multiply, etc) on values in a
|
||||
// single row from two selected fields.
|
||||
mode: *"reduceRow" | "binary"
|
||||
// Reduce options.
|
||||
reduce: {
|
||||
// Calculation to use.
|
||||
reducer: string
|
||||
// Fields to include in calculation.
|
||||
include: [...string]
|
||||
}
|
||||
// Hide all other fields and display only your calculated field in the
|
||||
// visualization.
|
||||
replaceFields: bool | *false
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package transformations
|
||||
|
||||
// Reorder, hide, or rename fields/columns.
|
||||
#Organize: {
|
||||
// Transformation ID.
|
||||
id: string | *"organize"
|
||||
// Configuration options.
|
||||
options: {
|
||||
// Exclude fields by name.
|
||||
excludeByName: {}
|
||||
// Set field order by name.
|
||||
indexByName: {}
|
||||
// Rename a field by name.
|
||||
renameByName: {}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package variables
|
||||
|
||||
// Custom variables are for values that do not change.
|
||||
#Custom: _variable & {
|
||||
// Options as comma separated values.
|
||||
query: string
|
||||
// Variable type.
|
||||
type: string | *"custom"
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package variables
|
||||
|
||||
// Data source variables allow you to quickly change the data source for an
|
||||
// entire dashboard.
|
||||
#Datasource: _variable & {
|
||||
// Data source type.
|
||||
query: string
|
||||
// Query value.
|
||||
queryValue: string | *""
|
||||
// Refresh.
|
||||
refresh: int | *1
|
||||
// Regex filter for which data source instances to choose
|
||||
// from in the variable value dropdown. Leave empty for
|
||||
// all.
|
||||
regex: string
|
||||
// Variable type.
|
||||
type: string | *"datasource"
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package variables
|
||||
|
||||
// Query variables allow you to write a data source query that can return a
|
||||
// list of metric names, tag values, or keys.
|
||||
#Query: _variable & {
|
||||
// Data source to use.
|
||||
datasource: string
|
||||
// Definition.
|
||||
definition?: string
|
||||
// Query.
|
||||
query: string
|
||||
// Refresh.
|
||||
refresh: int | *1
|
||||
// Regex.
|
||||
regex?: string
|
||||
// * 0 - Disabled.
|
||||
// * 1 - Alphabetical (asc).
|
||||
// * 2 - Alphabetical (desc).
|
||||
// * 3 - Numerical (asc).
|
||||
// * 4 - Numerical (desc).
|
||||
// * 5 - Alphabetical (case-insensitive, asc).
|
||||
// * 6 - Alphabetical (case-insensitive, desc).
|
||||
sort: int >= 0 <= 6 | *0
|
||||
tagValuesQuery?: string
|
||||
tags: [...string] | *[]
|
||||
tagsQuery?: string
|
||||
// Variable type.
|
||||
type: "query"
|
||||
useTags: bool | *false
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package variables
|
||||
|
||||
_variable: {
|
||||
// Currently selected value.
|
||||
current: {
|
||||
selected: bool | *false
|
||||
text: string | [...string]
|
||||
value: string | [...string]
|
||||
}
|
||||
// Whether to hide the label and variable.
|
||||
// * 0 - Show all.
|
||||
// * 1 - Hide label.
|
||||
// * 2 - Hide label and variable.
|
||||
hide: int >= 0 <= 2 | *0
|
||||
// Enable include all option.
|
||||
includeAll: bool | *false
|
||||
// When includeAll is enabled, this sets its value.
|
||||
allValue?: string
|
||||
// Optional display name.
|
||||
label?: string
|
||||
// Allows mutltiple values to be selected at the same time.
|
||||
multi: bool | *false
|
||||
// Variable name.
|
||||
name: string
|
||||
// Options for variable.
|
||||
options: [...{
|
||||
selected: bool
|
||||
text: string
|
||||
value: string
|
||||
}]
|
||||
// Skip URL sync.
|
||||
skipUrlSync: bool | *false
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
This folder contains useful scripts and configuration so you can:
|
||||
|
||||
- Configure data sources in Grafana for development.
|
||||
- Configure dashboards for development and test scenarios.
|
||||
- Create docker-compose file with databases and fake data.
|
||||
* Configure data sources in Grafana for development.
|
||||
* Configure dashboards for development and test scenarios.
|
||||
* Create docker-compose file with databases and fake data.
|
||||
|
||||
## Install Docker
|
||||
|
||||
@@ -47,16 +47,3 @@ The grafana block is pre-configured with the dev-datasources and dashboards.
|
||||
|
||||
#### Jaeger
|
||||
Jaeger block runs both Jaeger and Loki container. Loki container sends traces to Jaeger and also logs its own logs into itself so it is possible to setup derived field for traceID from Loki to Jaeger. You need to install a docker plugin for the self logging to work, without it the container won't start. See https://github.com/grafana/loki/tree/master/cmd/docker-driver#plugin-installation for installation instructions.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Containers fail to start (Mac OS)
|
||||
|
||||
```
|
||||
ERROR: for <service_name> Cannot start service <service_name>: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting ... merged/var/log/grafana: operation not permitted\\\"\"": unknown
|
||||
ERROR: Encountered errors while bringing up the project.
|
||||
```
|
||||
|
||||
If running Mac OSX the above error might be encountered when starting certain Docker containers that mount `/var/log/`. When first run this causes Docker to try to create the folder `/var/log/grafana` however by default Docker for Mac does not have permission to create folders at this location as it runs as the current user.
|
||||
|
||||
To solve this issue manually create the folder `/var/log/grafana` and give your user write permissions then try starting the containers again.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
@@ -225,7 +226,6 @@ datasources:
|
||||
jsonData:
|
||||
authType: credentials
|
||||
defaultRegion: eu-west-2
|
||||
customMetricsNamespaces: "CWAgent"
|
||||
|
||||
# Keep to test old /api/prom API
|
||||
- name: gdev-loki-0.3
|
||||
@@ -270,3 +270,5 @@ datasources:
|
||||
access: proxy
|
||||
url: http://localhost:9411
|
||||
editable: false
|
||||
|
||||
|
||||
|
||||
@@ -454,7 +454,7 @@
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "percent",
|
||||
"label": "Percent",
|
||||
"label": "Perecent",
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
@@ -1632,7 +1632,10 @@
|
||||
"revision": 8,
|
||||
"schemaVersion": 16,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "panel-tests"],
|
||||
"tags": [
|
||||
"gdev",
|
||||
"panel-tests"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
@@ -1641,8 +1644,29 @@
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
],
|
||||
"time_options": [
|
||||
"5m",
|
||||
"15m",
|
||||
"1h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"2d",
|
||||
"7d",
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"timezone": "browser",
|
||||
"title": "Panel Tests - Graph",
|
||||
|
||||
@@ -436,10 +436,6 @@
|
||||
{
|
||||
"text": "Micro Bitcoin (μBTC)",
|
||||
"value": "currencyμBTC"
|
||||
},
|
||||
{
|
||||
"text": "Vietnamese Dong (VND)",
|
||||
"value": "currencyVND"
|
||||
}
|
||||
],
|
||||
"text": "currency"
|
||||
@@ -1539,10 +1535,6 @@
|
||||
{
|
||||
"text": "Bitcoin (฿)",
|
||||
"value": "currencyBTC"
|
||||
},
|
||||
{
|
||||
"text": "Vietnamese Dong (VND)",
|
||||
"value": "currencyVND"
|
||||
}
|
||||
],
|
||||
"text": "currency"
|
||||
@@ -2622,10 +2614,6 @@
|
||||
{
|
||||
"text": "Bitcoin (฿)",
|
||||
"value": "currencyBTC"
|
||||
},
|
||||
{
|
||||
"text": "Vietnamese Dong (VND)",
|
||||
"value": "currencyVND"
|
||||
}
|
||||
],
|
||||
"text": "currency"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user