Sync with playbooks: install-go-tools, gotestsum, and dynamic versions (#192)
* Revert "Update main.go (#154)" This reverts commitbe4a281d0c
. * Revert "[MM-33506] Use embed package to include plugin manifest (#145)" This reverts commitca9ee3c17c
. * Revert "Don't generate manifest.ts (#127)" This reverts commit18d30b50bc
. * install-go-tools target, adopt gotestsum * bring back make apply + automatic versioning * Update build/manifest/main.go Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com> * suppress git describe error when no tags match * make version/release notes opt-in * fix whitespace in Makefile * document version management options --------- Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com>
This commit is contained in:
parent
376ea7e1f5
commit
de0b31b48a
12 changed files with 198 additions and 50 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
server/manifest.go linguist-generated=true
|
||||||
|
webapp/src/manifest.js linguist-generated=true
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,7 +1,13 @@
|
||||||
|
bin/
|
||||||
dist/
|
dist/
|
||||||
|
webapp/src/manifest.ts
|
||||||
|
server/manifest.go
|
||||||
|
|
||||||
# Mac
|
# Mac
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# Jetbrains
|
# Jetbrains
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# VS Code
|
||||||
|
.vscode
|
||||||
|
|
53
Makefile
53
Makefile
|
@ -2,7 +2,6 @@ GO ?= $(shell command -v go 2> /dev/null)
|
||||||
NPM ?= $(shell command -v npm 2> /dev/null)
|
NPM ?= $(shell command -v npm 2> /dev/null)
|
||||||
CURL ?= $(shell command -v curl 2> /dev/null)
|
CURL ?= $(shell command -v curl 2> /dev/null)
|
||||||
MM_DEBUG ?=
|
MM_DEBUG ?=
|
||||||
MANIFEST_FILE ?= plugin.json
|
|
||||||
GOPATH ?= $(shell go env GOPATH)
|
GOPATH ?= $(shell go env GOPATH)
|
||||||
GO_TEST_FLAGS ?= -race
|
GO_TEST_FLAGS ?= -race
|
||||||
GO_BUILD_FLAGS ?=
|
GO_BUILD_FLAGS ?=
|
||||||
|
@ -13,6 +12,10 @@ DEFAULT_GOARCH := $(shell go env GOARCH)
|
||||||
|
|
||||||
export GO111MODULE=on
|
export GO111MODULE=on
|
||||||
|
|
||||||
|
# We need to export GOBIN to allow it to be set
|
||||||
|
# for processes spawned from the Makefile
|
||||||
|
export GOBIN ?= $(PWD)/bin
|
||||||
|
|
||||||
# You can include assets this directory into the bundle. This can be e.g. used to include profile pictures.
|
# You can include assets this directory into the bundle. This can be e.g. used to include profile pictures.
|
||||||
ASSETS_DIR ?= assets
|
ASSETS_DIR ?= assets
|
||||||
|
|
||||||
|
@ -22,7 +25,6 @@ default: all
|
||||||
|
|
||||||
# Verify environment, and define PLUGIN_ID, PLUGIN_VERSION, HAS_SERVER and HAS_WEBAPP as needed.
|
# Verify environment, and define PLUGIN_ID, PLUGIN_VERSION, HAS_SERVER and HAS_WEBAPP as needed.
|
||||||
include build/setup.mk
|
include build/setup.mk
|
||||||
include build/legacy.mk
|
|
||||||
|
|
||||||
BUNDLE_NAME ?= $(PLUGIN_ID)-$(PLUGIN_VERSION).tar.gz
|
BUNDLE_NAME ?= $(PLUGIN_ID)-$(PLUGIN_VERSION).tar.gz
|
||||||
|
|
||||||
|
@ -41,9 +43,20 @@ endif
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: check-style test dist
|
all: check-style test dist
|
||||||
|
|
||||||
|
## Propagates plugin manifest information into the server/ and webapp/ folders.
|
||||||
|
.PHONY: apply
|
||||||
|
apply:
|
||||||
|
./build/bin/manifest apply
|
||||||
|
|
||||||
|
## Install go tools
|
||||||
|
install-go-tools:
|
||||||
|
@echo Installing go tools
|
||||||
|
$(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.1
|
||||||
|
$(GO) install gotest.tools/gotestsum@v1.7.0
|
||||||
|
|
||||||
## Runs eslint and golangci-lint
|
## Runs eslint and golangci-lint
|
||||||
.PHONY: check-style
|
.PHONY: check-style
|
||||||
check-style: webapp/node_modules
|
check-style: apply webapp/node_modules install-go-tools
|
||||||
@echo Checking for style guide compliance
|
@echo Checking for style guide compliance
|
||||||
|
|
||||||
ifneq ($(HAS_WEBAPP),)
|
ifneq ($(HAS_WEBAPP),)
|
||||||
|
@ -51,14 +64,13 @@ ifneq ($(HAS_WEBAPP),)
|
||||||
cd webapp && npm run check-types
|
cd webapp && npm run check-types
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# It's highly recommended to run go-vet first
|
||||||
|
# to find potential compile errors that could introduce
|
||||||
|
# weird reports at golangci-lint step
|
||||||
ifneq ($(HAS_SERVER),)
|
ifneq ($(HAS_SERVER),)
|
||||||
@if ! [ -x "$$(command -v golangci-lint)" ]; then \
|
|
||||||
echo "golangci-lint is not installed. Please see https://github.com/golangci/golangci-lint#install for installation instructions."; \
|
|
||||||
exit 1; \
|
|
||||||
fi; \
|
|
||||||
|
|
||||||
@echo Running golangci-lint
|
@echo Running golangci-lint
|
||||||
golangci-lint run ./...
|
$(GO) vet ./...
|
||||||
|
$(GOBIN)/golangci-lint run ./...
|
||||||
endif
|
endif
|
||||||
|
|
||||||
## Builds the server, if it exists, for all supported architectures, unless MM_SERVICESETTINGS_ENABLEDEVELOPER is set.
|
## Builds the server, if it exists, for all supported architectures, unless MM_SERVICESETTINGS_ENABLEDEVELOPER is set.
|
||||||
|
@ -104,7 +116,7 @@ endif
|
||||||
bundle:
|
bundle:
|
||||||
rm -rf dist/
|
rm -rf dist/
|
||||||
mkdir -p dist/$(PLUGIN_ID)
|
mkdir -p dist/$(PLUGIN_ID)
|
||||||
cp $(MANIFEST_FILE) dist/$(PLUGIN_ID)/
|
./build/bin/manifest dist
|
||||||
ifneq ($(wildcard $(ASSETS_DIR)/.),)
|
ifneq ($(wildcard $(ASSETS_DIR)/.),)
|
||||||
cp -r $(ASSETS_DIR) dist/$(PLUGIN_ID)/
|
cp -r $(ASSETS_DIR) dist/$(PLUGIN_ID)/
|
||||||
endif
|
endif
|
||||||
|
@ -125,7 +137,7 @@ endif
|
||||||
|
|
||||||
## Builds and bundles the plugin.
|
## Builds and bundles the plugin.
|
||||||
.PHONY: dist
|
.PHONY: dist
|
||||||
dist: server webapp bundle
|
dist: apply server webapp bundle
|
||||||
|
|
||||||
## Builds and installs the plugin to a server.
|
## Builds and installs the plugin to a server.
|
||||||
.PHONY: deploy
|
.PHONY: deploy
|
||||||
|
@ -134,7 +146,7 @@ deploy: dist
|
||||||
|
|
||||||
## Builds and installs the plugin to a server, updating the webapp automatically when changed.
|
## Builds and installs the plugin to a server, updating the webapp automatically when changed.
|
||||||
.PHONY: watch
|
.PHONY: watch
|
||||||
watch: server bundle
|
watch: apply server bundle
|
||||||
ifeq ($(MM_DEBUG),)
|
ifeq ($(MM_DEBUG),)
|
||||||
cd webapp && $(NPM) run build:watch
|
cd webapp && $(NPM) run build:watch
|
||||||
else
|
else
|
||||||
|
@ -188,9 +200,20 @@ detach: setup-attach
|
||||||
|
|
||||||
## Runs any lints and unit tests defined for the server and webapp, if they exist.
|
## Runs any lints and unit tests defined for the server and webapp, if they exist.
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: webapp/node_modules
|
test: apply webapp/node_modules install-go-tools
|
||||||
ifneq ($(HAS_SERVER),)
|
ifneq ($(HAS_SERVER),)
|
||||||
$(GO) test -v $(GO_TEST_FLAGS) ./server/...
|
$(GOBIN)/gotestsum -- -v ./...
|
||||||
|
endif
|
||||||
|
ifneq ($(HAS_WEBAPP),)
|
||||||
|
cd webapp && $(NPM) run test;
|
||||||
|
endif
|
||||||
|
|
||||||
|
## Runs any lints and unit tests defined for the server and webapp, if they exist, optimized
|
||||||
|
## for a CI environment.
|
||||||
|
.PHONY: test-ci
|
||||||
|
test-ci: apply webapp/node_modules install-go-tools
|
||||||
|
ifneq ($(HAS_SERVER),)
|
||||||
|
$(GOBIN)/gotestsum --format standard-verbose --junitfile report.xml -- ./...
|
||||||
endif
|
endif
|
||||||
ifneq ($(HAS_WEBAPP),)
|
ifneq ($(HAS_WEBAPP),)
|
||||||
cd webapp && $(NPM) run test;
|
cd webapp && $(NPM) run test;
|
||||||
|
@ -198,7 +221,7 @@ endif
|
||||||
|
|
||||||
## Creates a coverage report for the server code.
|
## Creates a coverage report for the server code.
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage: webapp/node_modules
|
coverage: apply webapp/node_modules
|
||||||
ifneq ($(HAS_SERVER),)
|
ifneq ($(HAS_SERVER),)
|
||||||
$(GO) test $(GO_TEST_FLAGS) -coverprofile=server/coverage.txt ./server/...
|
$(GO) test $(GO_TEST_FLAGS) -coverprofile=server/coverage.txt ./server/...
|
||||||
$(GO) tool cover -html=server/coverage.txt
|
$(GO) tool cover -html=server/coverage.txt
|
||||||
|
|
|
@ -110,6 +110,15 @@ export MM_ADMIN_TOKEN=j44acwd8obn78cdcx7koid4jkr
|
||||||
make deploy
|
make deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Releasing new versions
|
||||||
|
|
||||||
|
The version of a plugin is determined at compile time, automatically populating a `version` field in the [plugin manifest](plugin.json):
|
||||||
|
* If the current commit matches a tag, the version will match after stripping any leading `v`, e.g. `1.3.1`.
|
||||||
|
* Otherwise, the version will combine the nearest tag with `git rev-parse --short HEAD`, e.g. `1.3.1+d06e53e1`.
|
||||||
|
* If there is no version tag, an empty version will be combined with the short hash, e.g. `0.0.0+76081421`.
|
||||||
|
|
||||||
|
To disable this behaviour, manually populate and maintain the `version` field.
|
||||||
|
|
||||||
## Q&A
|
## Q&A
|
||||||
|
|
||||||
### How do I make a server-only or web app-only plugin?
|
### How do I make a server-only or web app-only plugin?
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
.PHONY: apply
|
|
||||||
apply:
|
|
||||||
@echo make apply is deprecated and has no effect.
|
|
|
@ -4,11 +4,50 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost/server/public/model"
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const pluginIDGoFileTemplate = `// This file is automatically generated. Do not modify it manually.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
var manifest *model.Manifest
|
||||||
|
|
||||||
|
const manifestStr = ` + "`" + `
|
||||||
|
%s
|
||||||
|
` + "`" + `
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
_ = json.NewDecoder(strings.NewReader(manifestStr)).Decode(&manifest)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const pluginIDJSFileTemplate = `// This file is automatically generated. Do not modify it manually.
|
||||||
|
|
||||||
|
const manifest = JSON.parse(` + "`" + `
|
||||||
|
%s
|
||||||
|
` + "`" + `);
|
||||||
|
|
||||||
|
export default manifest;
|
||||||
|
`
|
||||||
|
|
||||||
|
// These build-time vars are read from shell commands and populated in ../setup.mk
|
||||||
|
var (
|
||||||
|
BuildHashShort string
|
||||||
|
BuildTagLatest string
|
||||||
|
BuildTagCurrent string
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) <= 1 {
|
if len(os.Args) <= 1 {
|
||||||
panic("no cmd specified")
|
panic("no cmd specified")
|
||||||
|
@ -37,6 +76,16 @@ func main() {
|
||||||
fmt.Printf("true")
|
fmt.Printf("true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "apply":
|
||||||
|
if err := applyManifest(manifest); err != nil {
|
||||||
|
panic("failed to apply manifest: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
case "dist":
|
||||||
|
if err := distManifest(manifest); err != nil {
|
||||||
|
panic("failed to write manifest to dist directory: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unrecognized command: " + cmd)
|
panic("unrecognized command: " + cmd)
|
||||||
}
|
}
|
||||||
|
@ -62,6 +111,32 @@ func findManifest() (*model.Manifest, error) {
|
||||||
return nil, errors.Wrap(err, "failed to parse manifest")
|
return nil, errors.Wrap(err, "failed to parse manifest")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no version is listed in the manifest, generate one based on the state of the current
|
||||||
|
// commit, and use the first version we find (to prevent causing errors)
|
||||||
|
if manifest.Version == "" {
|
||||||
|
var version string
|
||||||
|
tags := strings.Fields(BuildTagCurrent)
|
||||||
|
for _, t := range tags {
|
||||||
|
if strings.HasPrefix(t, "v") {
|
||||||
|
version = t
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if version == "" {
|
||||||
|
if BuildTagLatest != "" {
|
||||||
|
version = BuildTagLatest + "+" + BuildHashShort
|
||||||
|
} else {
|
||||||
|
version = "v0.0.0+" + BuildHashShort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
manifest.Version = strings.TrimPrefix(version, "v")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no release notes specified, generate one from the latest tag, if present.
|
||||||
|
if manifest.ReleaseNotesURL == "" && BuildTagLatest != "" {
|
||||||
|
manifest.ReleaseNotesURL = manifest.HomepageURL + "releases/tag/" + BuildTagLatest
|
||||||
|
}
|
||||||
|
|
||||||
return &manifest, nil
|
return &manifest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,3 +149,63 @@ func dumpPluginID(manifest *model.Manifest) {
|
||||||
func dumpPluginVersion(manifest *model.Manifest) {
|
func dumpPluginVersion(manifest *model.Manifest) {
|
||||||
fmt.Printf("%s", manifest.Version)
|
fmt.Printf("%s", manifest.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applyManifest propagates the plugin_id into the server and webapp folders, as necessary
|
||||||
|
func applyManifest(manifest *model.Manifest) error {
|
||||||
|
if manifest.HasServer() {
|
||||||
|
// generate JSON representation of Manifest.
|
||||||
|
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
manifestStr := string(manifestBytes)
|
||||||
|
|
||||||
|
// write generated code to file by using Go file template.
|
||||||
|
if err := os.WriteFile(
|
||||||
|
"server/manifest.go",
|
||||||
|
[]byte(fmt.Sprintf(pluginIDGoFileTemplate, manifestStr)),
|
||||||
|
0600,
|
||||||
|
); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to write server/manifest.go")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if manifest.HasWebapp() {
|
||||||
|
// generate JSON representation of Manifest.
|
||||||
|
// JSON is very similar and compatible with JS's object literals. so, what we do here
|
||||||
|
// is actually JS code generation.
|
||||||
|
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
manifestStr := string(manifestBytes)
|
||||||
|
|
||||||
|
// Escape newlines
|
||||||
|
manifestStr = strings.ReplaceAll(manifestStr, `\n`, `\\n`)
|
||||||
|
|
||||||
|
// write generated code to file by using JS file template.
|
||||||
|
if err := os.WriteFile(
|
||||||
|
"webapp/src/manifest.ts",
|
||||||
|
[]byte(fmt.Sprintf(pluginIDJSFileTemplate, manifestStr)),
|
||||||
|
0600,
|
||||||
|
); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to open webapp/src/manifest.ts")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// distManifest writes the manifest file to the dist directory
|
||||||
|
func distManifest(manifest *model.Manifest) error {
|
||||||
|
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(fmt.Sprintf("dist/%s/plugin.json", manifest.Id), manifestBytes, 0600); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to write plugin.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -4,8 +4,13 @@ ifeq ($(GO),)
|
||||||
$(error "go is not available: see https://golang.org/doc/install")
|
$(error "go is not available: see https://golang.org/doc/install")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Gather build variables to inject into the manifest tool
|
||||||
|
BUILD_HASH_SHORT = $(shell git rev-parse --short HEAD)
|
||||||
|
BUILD_TAG_LATEST = $(shell git describe --tags --match 'v*' --abbrev=0 2>/dev/null)
|
||||||
|
BUILD_TAG_CURRENT = $(shell git tag --points-at HEAD)
|
||||||
|
|
||||||
# Ensure that the build tools are compiled. Go's caching makes this quick.
|
# Ensure that the build tools are compiled. Go's caching makes this quick.
|
||||||
$(shell cd build/manifest && $(GO) build -o ../bin/manifest)
|
$(shell cd build/manifest && $(GO) build -ldflags '-X "main.BuildHashShort=$(BUILD_HASH_SHORT)" -X "main.BuildTagLatest=$(BUILD_TAG_LATEST)" -X "main.BuildTagCurrent=$(BUILD_TAG_CURRENT)"' -o ../bin/manifest)
|
||||||
|
|
||||||
# Ensure that the deployment tools are compiled. Go's caching makes this quick.
|
# Ensure that the deployment tools are compiled. Go's caching makes this quick.
|
||||||
$(shell cd build/pluginctl && $(GO) build -o ../bin/pluginctl)
|
$(shell cd build/pluginctl && $(GO) build -o ../bin/pluginctl)
|
||||||
|
|
18
plugin.go
18
plugin.go
|
@ -1,18 +0,0 @@
|
||||||
package root
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed" // Need to embed manifest file
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/mattermost/mattermost/server/public/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed plugin.json
|
|
||||||
var manifestString string
|
|
||||||
|
|
||||||
var Manifest model.Manifest
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
_ = json.NewDecoder(strings.NewReader(manifestString)).Decode(&Manifest)
|
|
||||||
}
|
|
|
@ -4,9 +4,7 @@
|
||||||
"description": "This plugin serves as a starting point for writing a Mattermost plugin.",
|
"description": "This plugin serves as a starting point for writing a Mattermost plugin.",
|
||||||
"homepage_url": "https://github.com/mattermost/mattermost-plugin-starter-template",
|
"homepage_url": "https://github.com/mattermost/mattermost-plugin-starter-template",
|
||||||
"support_url": "https://github.com/mattermost/mattermost-plugin-starter-template/issues",
|
"support_url": "https://github.com/mattermost/mattermost-plugin-starter-template/issues",
|
||||||
"release_notes_url": "https://github.com/mattermost/mattermost-plugin-starter-template/releases/tag/v0.1.0",
|
|
||||||
"icon_path": "assets/starter-template-icon.svg",
|
"icon_path": "assets/starter-template-icon.svg",
|
||||||
"version": "0.1.0",
|
|
||||||
"min_server_version": "6.2.1",
|
"min_server_version": "6.2.1",
|
||||||
"server": {
|
"server": {
|
||||||
"executables": {
|
"executables": {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {Store, Action} from 'redux';
|
||||||
|
|
||||||
import {GlobalState} from '@mattermost/types/lib/store';
|
import {GlobalState} from '@mattermost/types/lib/store';
|
||||||
|
|
||||||
import {manifest} from '@/manifest';
|
import manifest from '@/manifest';
|
||||||
|
|
||||||
import {PluginRegistry} from '@/types/mattermost-webapp';
|
import {PluginRegistry} from '@/types/mattermost-webapp';
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
import {manifest} from './manifest';
|
import manifest from './manifest';
|
||||||
|
|
||||||
test('Plugin manifest, id and version are defined', () => {
|
test('Plugin manifest, id and version are defined', () => {
|
||||||
expect(manifest).toBeDefined();
|
expect(manifest).toBeDefined();
|
||||||
expect(manifest.id).toBeDefined();
|
expect(manifest.id).toBeDefined();
|
||||||
expect(manifest.version).toBeDefined();
|
expect(manifest.version).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
// To ease migration, verify separate export of id and version.
|
|
||||||
test('Plugin id and version are defined', () => {
|
|
||||||
expect(manifest.id).toBeDefined();
|
|
||||||
expect(manifest.version).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import manifest from '@/../../plugin.json';
|
|
||||||
|
|
||||||
export {manifest};
|
|
Reference in a new issue