mirror of
https://github.com/foomo/contentfulvalidation.git
synced 2025-10-16 12:25:37 +00:00
feat: initial commit
This commit is contained in:
commit
a5f121ca76
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = tab
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.{yaml,yml,md,mdx}]
|
||||||
|
indent_style = space
|
||||||
15
.github/dependabot.yml
vendored
Normal file
15
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
- package-ecosystem: "gomod"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
33
.github/workflows/release.yml
vendored
Normal file
33
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
name: Release Tag
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v*.*.*
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GOFLAGS: -mod=readonly
|
||||||
|
GOPROXY: https://proxy.golang.org
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- run: git fetch --force --tags
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
check-latest: true
|
||||||
|
go-version-file: 'go.mod'
|
||||||
|
|
||||||
|
- uses: goreleaser/goreleaser-action@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --clean
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
34
.github/workflows/test.yml
vendored
Normal file
34
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
name: Test Branch
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
merge_group:
|
||||||
|
branches: [ main ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GOFLAGS: -mod=readonly
|
||||||
|
GOPROXY: https://proxy.golang.org
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
check-latest: true
|
||||||
|
go-version-file: 'go.mod'
|
||||||
|
|
||||||
|
- uses: golangci/golangci-lint-action@v3
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: go test -v ./...
|
||||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.*
|
||||||
|
*.log
|
||||||
|
!.github/
|
||||||
|
!.husky/
|
||||||
|
!.editorconfig
|
||||||
|
!.gitignore
|
||||||
|
!.golangci.yml
|
||||||
|
!.goreleaser.yml
|
||||||
|
!.husky.yaml
|
||||||
|
/coverage.out
|
||||||
|
/coverage.html
|
||||||
|
/tmp/
|
||||||
60
.golangci.yml
Normal file
60
.golangci.yml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
importas:
|
||||||
|
alias:
|
||||||
|
- pkg: '^github.com\/foomo\/contentfulvalidation\/(.*\/)?([^\/]+)\/?$'
|
||||||
|
alias: '${2}x' # enforce `x` suffix
|
||||||
|
no-unaliased: true
|
||||||
|
|
||||||
|
linters:
|
||||||
|
enable:
|
||||||
|
# Enabled by default linters:
|
||||||
|
- errcheck
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- staticcheck
|
||||||
|
|
||||||
|
# Disabled by default linters:
|
||||||
|
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers [fast: true, auto-fix: false]
|
||||||
|
- bidichk # Checks for dangerous unicode character sequences [fast: true, auto-fix: false]
|
||||||
|
- depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false]
|
||||||
|
- dupl # Tool for code clone detection [fast: true, auto-fix: false]
|
||||||
|
- forcetypeassert # finds forced type assertions [fast: true, auto-fix: false]
|
||||||
|
- gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false]
|
||||||
|
- goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false]
|
||||||
|
- gocritic # Provides diagnostics that check for bugs, performance and style issues. [fast: false, auto-fix: false]
|
||||||
|
- goimports # In addition to fixing imports, goimports also formats your code in the same style as gofmt. [fast: true, auto-fix: true]
|
||||||
|
- gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. [fast: true, auto-fix: false]
|
||||||
|
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. [fast: true, auto-fix: false]
|
||||||
|
- goprintffuncname # Checks that printf-like functions are named with `f` at the end [fast: true, auto-fix: false]
|
||||||
|
- gosec # (gas): Inspects source code for security problems [fast: false, auto-fix: false]
|
||||||
|
- grouper # An analyzer to analyze expression groups. [fast: true, auto-fix: false]
|
||||||
|
- importas # Enforces consistent import aliases [fast: false, auto-fix: false]
|
||||||
|
- maintidx # maintidx measures the maintainability index of each function. [fast: true, auto-fix: false]
|
||||||
|
- makezero # Finds slice declarations with non-zero initial length [fast: false, auto-fix: false]
|
||||||
|
- misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true]
|
||||||
|
- nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false]
|
||||||
|
- nestif # Reports deeply nested if statements [fast: true, auto-fix: false]
|
||||||
|
- nilerr # Finds the code that returns nil even if it checks that the error is not nil. [fast: false, auto-fix: false]
|
||||||
|
- nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. [fast: false, auto-fix: false]
|
||||||
|
- noctx # noctx finds sending http request without context.Context [fast: false, auto-fix: false]
|
||||||
|
- nolintlint # Reports ill-formed or insufficient nolint directives [fast: true, auto-fix: false]
|
||||||
|
- nonamedreturns # Reports all named returns [fast: false, auto-fix: false]
|
||||||
|
- nosprintfhostport # Checks for misuse of Sprintf to construct a host with port in a URL. [fast: true, auto-fix: false]
|
||||||
|
- prealloc # Finds slice declarations that could potentially be pre-allocated [fast: true, auto-fix: false]
|
||||||
|
- predeclared # find code that shadows one of Go's predeclared identifiers [fast: true, auto-fix: false]
|
||||||
|
- promlinter # Check Prometheus metrics naming via promlint [fast: true, auto-fix: false]
|
||||||
|
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint. [fast: false, auto-fix: false]
|
||||||
|
- tagliatelle # Checks the struct tags. [fast: true, auto-fix: false]
|
||||||
|
- testpackage # linter that makes you use a separate _test package [fast: true, auto-fix: false]
|
||||||
|
- thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers [fast: false, auto-fix: false]
|
||||||
|
- unconvert # Remove unnecessary type conversions [fast: false, auto-fix: false]
|
||||||
|
- unparam # Reports unused function parameters [fast: false, auto-fix: false]
|
||||||
|
- usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library. [fast: true, auto-fix: false]
|
||||||
|
- wastedassign # wastedassign finds wasted assignment statements. [fast: false, auto-fix: false]
|
||||||
|
- whitespace # Tool for detection of leading and trailing whitespace [fast: true, auto-fix: true]
|
||||||
|
disable:
|
||||||
|
- unused
|
||||||
34
.goreleaser.yml
Normal file
34
.goreleaser.yml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
builds:
|
||||||
|
- skip: true
|
||||||
|
|
||||||
|
changelog:
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- "^wip"
|
||||||
|
- "^test"
|
||||||
|
- "^docs"
|
||||||
|
- "^chore"
|
||||||
|
- "^style"
|
||||||
|
- "go mod tidy"
|
||||||
|
- "merge conflict"
|
||||||
|
- "Merge pull request"
|
||||||
|
- "Merge remote-tracking branch"
|
||||||
|
- "Merge branch"
|
||||||
|
groups:
|
||||||
|
- title: Features
|
||||||
|
regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$'
|
||||||
|
order: 0
|
||||||
|
- title: Dependency updates
|
||||||
|
regexp: '^.*?(feat|fix)\(deps\)!?:.+$'
|
||||||
|
order: 100
|
||||||
|
- title: "Bug fixes"
|
||||||
|
regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$'
|
||||||
|
order: 150
|
||||||
|
- title: "Security"
|
||||||
|
regexp: '^.*?sec(\([[:word:]]+\))??!?:.+$'
|
||||||
|
order: 200
|
||||||
|
- title: "Performace"
|
||||||
|
regexp: '^.*?perf(\([[:word:]]+\))??!?:.+$'
|
||||||
|
order: 250
|
||||||
|
- title: Other
|
||||||
|
order: 999
|
||||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
info@bestbytes.de.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Foomo web framework
|
||||||
|
|
||||||
|
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.
|
||||||
91
Makefile
Normal file
91
Makefile
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
.DEFAULT_GOAL:=help
|
||||||
|
-include .makerc
|
||||||
|
|
||||||
|
# --- Targets -----------------------------------------------------------------
|
||||||
|
|
||||||
|
# This allows us to accept extra arguments
|
||||||
|
%: .husky
|
||||||
|
@:
|
||||||
|
|
||||||
|
.PHONY: .husky
|
||||||
|
# Configure git hooks for husky
|
||||||
|
.husky:
|
||||||
|
@if ! command -v husky &> /dev/null; then \
|
||||||
|
echo "ERROR: missing executeable 'husky', please run:"; \
|
||||||
|
echo "\n$ go install github.com/go-courier/husky/cmd/husky@latest\n"; \
|
||||||
|
fi
|
||||||
|
@git config core.hooksPath .husky
|
||||||
|
|
||||||
|
## === Tasks ===
|
||||||
|
|
||||||
|
.PHONY: doc
|
||||||
|
## Run tests
|
||||||
|
doc:
|
||||||
|
@open "http://localhost:6060/pkg/github.com/foomo/contentfulvalidation/"
|
||||||
|
@godoc -http=localhost:6060 -play
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
## Run tests
|
||||||
|
test:
|
||||||
|
@set -euo pipefail && go test -json -v ./... | gotestfmt
|
||||||
|
|
||||||
|
.PHONY: test.cover
|
||||||
|
## Run tests with coverage
|
||||||
|
test.cover:
|
||||||
|
@go test -v -coverprofile=coverage.out ./...
|
||||||
|
@go tool cover -func=coverage.out
|
||||||
|
@go tool cover -html=coverage.out
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
## Run linter
|
||||||
|
lint:
|
||||||
|
@golangci-lint run
|
||||||
|
|
||||||
|
.PHONY: lint.fix
|
||||||
|
## Run linter and fix violations
|
||||||
|
lint.fix:
|
||||||
|
@golangci-lint run --fix
|
||||||
|
|
||||||
|
.PHONY: tidy
|
||||||
|
## Run go mod tidy
|
||||||
|
tidy:
|
||||||
|
@go mod tidy
|
||||||
|
|
||||||
|
.PHONY: outdated
|
||||||
|
## Show outdated direct dependencies
|
||||||
|
outdated:
|
||||||
|
@go list -u -m -json all | go-mod-outdated -update -direct
|
||||||
|
|
||||||
|
## === Utils ===
|
||||||
|
|
||||||
|
## Show help text
|
||||||
|
help:
|
||||||
|
@awk '{ \
|
||||||
|
if ($$0 ~ /^.PHONY: [a-zA-Z\-\_0-9]+$$/) { \
|
||||||
|
helpCommand = substr($$0, index($$0, ":") + 2); \
|
||||||
|
if (helpMessage) { \
|
||||||
|
printf "\033[36m%-23s\033[0m %s\n", \
|
||||||
|
helpCommand, helpMessage; \
|
||||||
|
helpMessage = ""; \
|
||||||
|
} \
|
||||||
|
} else if ($$0 ~ /^[a-zA-Z\-\_0-9.]+:/) { \
|
||||||
|
helpCommand = substr($$0, 0, index($$0, ":")); \
|
||||||
|
if (helpMessage) { \
|
||||||
|
printf "\033[36m%-23s\033[0m %s\n", \
|
||||||
|
helpCommand, helpMessage"\n"; \
|
||||||
|
helpMessage = ""; \
|
||||||
|
} \
|
||||||
|
} else if ($$0 ~ /^##/) { \
|
||||||
|
if (helpMessage) { \
|
||||||
|
helpMessage = helpMessage"\n "substr($$0, 3); \
|
||||||
|
} else { \
|
||||||
|
helpMessage = substr($$0, 3); \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
if (helpMessage) { \
|
||||||
|
print "\n "helpMessage"\n" \
|
||||||
|
} \
|
||||||
|
helpMessage = ""; \
|
||||||
|
} \
|
||||||
|
}' \
|
||||||
|
$(MAKEFILE_LIST)
|
||||||
11
README.md
Normal file
11
README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# contentfulvalidation
|
||||||
|
|
||||||
|
[](https://godoc.org/github.com/foomo/go)
|
||||||
|
[](https://goreportcard.com/report/github.com/foomo/contentfulvalidation)
|
||||||
|
[](https://github.com/foomo/contentfulvalidation/actions/workflows/test.yml)
|
||||||
|
|
||||||
|
Framework to kickstart a entity validation service for contentful content models.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Distributed under MIT License, please see license file within the code for more details.
|
||||||
20
contants/constants.go
Normal file
20
contants/constants.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package contants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/foomo/contentfulvalidation/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SeverityFatal validator.Severity = "fatal"
|
||||||
|
SeverityError validator.Severity = "error"
|
||||||
|
SeverityWarn validator.Severity = "warn"
|
||||||
|
SeverityInfo validator.Severity = "info"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
HealthError validator.Health = "error"
|
||||||
|
HealthWarn validator.Health = "warn"
|
||||||
|
HealthOk validator.Health = "ok"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DateFormat = "02 Jan 2006"
|
||||||
28
errors/errors.go
Normal file
28
errors/errors.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
const (
|
||||||
|
ValidationErrorUnknownType ValidationError = "UNKNOWN_MODEL_TYPE"
|
||||||
|
ValidationErrorContentfulLoading ValidationError = "CONTENTFUL_LOADING_ERROR"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrValidationErrorUnknownType = NewError(ValidationErrorUnknownType)
|
||||||
|
ErrValidationErrorContentfulLoading = NewError(ValidationErrorContentfulLoading)
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
ValidationError string
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidationError constructor
|
||||||
|
func NewError(e ValidationError) *ValidationError {
|
||||||
|
return &e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error api method
|
||||||
|
func (e *ValidationError) Error() string {
|
||||||
|
if e != nil {
|
||||||
|
return string(*e)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
3
generate.go
Normal file
3
generate.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package contentfulvalidation
|
||||||
|
|
||||||
|
//go:generate gotsrpc gotsrpc.yml
|
||||||
46
go.mod
Normal file
46
go.mod
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
module github.com/foomo/contentfulvalidation
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bestbytes/catalogue v0.39.0
|
||||||
|
github.com/foomo/contentful v0.4.4
|
||||||
|
github.com/foomo/contentserver v1.10.2
|
||||||
|
github.com/foomo/gotsrpc/v2 v2.7.2
|
||||||
|
github.com/foomo/keel v0.16.1
|
||||||
|
github.com/go-co-op/gocron v1.33.0
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
go.uber.org/zap v1.25.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/RoaringBitmap/roaring v1.3.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
github.com/google/uuid v1.3.1 // indirect
|
||||||
|
github.com/iancoleman/strcase v0.2.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.3.0 // indirect
|
||||||
|
github.com/prometheus/common v0.42.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.10.1 // indirect
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||||
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
golang.org/x/mod v0.11.0 // indirect
|
||||||
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
|
golang.org/x/tools v0.10.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
moul.io/http2curl v1.0.0 // indirect
|
||||||
|
)
|
||||||
141
go.sum
Normal file
141
go.sum
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
github.com/RoaringBitmap/roaring v1.3.0 h1:aQmu9zQxDU0uhwR8SXOH/OrqEf+X8A0LQmwW3JX8Lcg=
|
||||||
|
github.com/RoaringBitmap/roaring v1.3.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
|
||||||
|
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bestbytes/catalogue v0.39.0 h1:UYUhABB7ByGuxZNdr+9CqK4DZtmC9UIB37MpTJyDmAk=
|
||||||
|
github.com/bestbytes/catalogue v0.39.0/go.mod h1:eyZEeaZJSqc/r78jejYM+h8fkLnS1Kzd+IPzG0hxLH0=
|
||||||
|
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||||
|
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||||
|
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/foomo/contentful v0.4.4 h1:5/jWA8ep0cuVZvByY0Vq7G5PVGUs5GGtM6zrzy4T1kk=
|
||||||
|
github.com/foomo/contentful v0.4.4/go.mod h1:zBLj5DDYdLL6gZ0t1/lqYLtOUmkbCc8OylajvB8wXfE=
|
||||||
|
github.com/foomo/contentserver v1.10.2 h1:a0bWTAI/aVQjXM8otuDHY8mML+7rXTU4L6j7ratfycw=
|
||||||
|
github.com/foomo/contentserver v1.10.2/go.mod h1:ycAEPcUR+v6rL5rPinOanLeHLfcRuab28n/2JYMwSYg=
|
||||||
|
github.com/foomo/gotsrpc/v2 v2.7.2 h1:a94V/a8LSssq+aRN3Fv1lJPjWoyMilOvRq+yEaDTHVM=
|
||||||
|
github.com/foomo/gotsrpc/v2 v2.7.2/go.mod h1:n5SiKVNCZ7Tob6wcROWT5Sx1i/W42+ErpTbNqT3etM8=
|
||||||
|
github.com/foomo/keel v0.16.1 h1:nGPjprqqj96Nuu0LpiNjLSs+a2Cs/ad/px3hGKgE8iA=
|
||||||
|
github.com/foomo/keel v0.16.1/go.mod h1:ExaBRf52e3Z7vzuC+DTbs4i2NYVj49LIvaXFiV6+R84=
|
||||||
|
github.com/go-co-op/gocron v1.33.0 h1:lqQMwewbTIlh2/3l+1ieEjgseZ1AITe6YQQ5bCf0mhY=
|
||||||
|
github.com/go-co-op/gocron v1.33.0/go.mod h1:NLi+bkm4rRSy1F8U7iacZOz0xPseMoIOnvabGoSe/no=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||||
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
|
||||||
|
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
||||||
|
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.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 v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||||
|
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||||
|
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||||
|
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||||
|
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||||
|
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||||
|
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||||
|
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
|
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||||
|
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||||
|
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||||
|
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
|
||||||
|
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||||
|
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
|
||||||
|
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
|
||||||
|
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||||
|
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||||
|
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||||
|
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||||
13
gotsrpc.yml
Normal file
13
gotsrpc.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module:
|
||||||
|
name: github.com/foomo/contentfulvalidation
|
||||||
|
path: ./
|
||||||
|
|
||||||
|
targets:
|
||||||
|
services:
|
||||||
|
services:
|
||||||
|
/services/contenfulvalidation/validation: Validation
|
||||||
|
/services/contenfulvalidation/webhook: Webhook
|
||||||
|
package: github.com/foomo/contentfulvalidation/services
|
||||||
|
tsrpc:
|
||||||
|
- Validation
|
||||||
|
- Webhook
|
||||||
69
utils/utils.go
Normal file
69
utils/utils.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
catvo "github.com/bestbytes/catalogue/vo"
|
||||||
|
"github.com/foomo/contentfulvalidation/contants"
|
||||||
|
"github.com/foomo/contentfulvalidation/validator"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/contentful"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAssetImage(asset *contentful.AssetNoLocale) *contentful.FileImage {
|
||||||
|
if asset != nil && asset.Fields != nil && asset.Fields.File != nil && asset.Fields.File.Detail != nil && asset.Fields.File.Detail.Image != nil {
|
||||||
|
return asset.Fields.File.Detail.Image
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAspectRatio(asset *contentful.AssetNoLocale) (float64, error) {
|
||||||
|
var aspectRatio float64
|
||||||
|
image := GetAssetImage(asset)
|
||||||
|
if image == nil {
|
||||||
|
return aspectRatio, errors.New("No linked image available")
|
||||||
|
}
|
||||||
|
if image.Width == 0 || image.Height == 0 {
|
||||||
|
return aspectRatio, errors.New("Width or height are zero")
|
||||||
|
}
|
||||||
|
aspectRatio = float64(image.Width) / float64(image.Height)
|
||||||
|
return aspectRatio, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadQuery(rawQuery any) (*catvo.Query, error) {
|
||||||
|
query := &catvo.Query{}
|
||||||
|
errMarshal := loadInterfaceAsJSON(rawQuery, query)
|
||||||
|
if errMarshal != nil {
|
||||||
|
return nil, errMarshal
|
||||||
|
}
|
||||||
|
return query, nil
|
||||||
|
}
|
||||||
|
func loadInterfaceAsJSON(source interface{}, target interface{}) error {
|
||||||
|
jsonBytes, errMarshal := json.Marshal(source)
|
||||||
|
if errMarshal != nil {
|
||||||
|
return errMarshal
|
||||||
|
}
|
||||||
|
return json.Unmarshal(jsonBytes, &target)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertTimeFormat(timeToFormat string, parseTemplate string, formatTemplate string) (string, error) {
|
||||||
|
p, err := time.Parse(parseTemplate, timeToFormat)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return p.Format(formatTemplate), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitEmptyValidationResult(modelType validator.ModelType, modelID validator.ModelID, title string, internalTitle string, lastUpdatedDate string) *validator.ValidationResult {
|
||||||
|
var messages []*validator.ValidationResultMessage
|
||||||
|
return &validator.ValidationResult{
|
||||||
|
ID: modelID,
|
||||||
|
Title: title,
|
||||||
|
InternalTitle: internalTitle,
|
||||||
|
LastUpdatedDate: lastUpdatedDate,
|
||||||
|
ModelType: modelType,
|
||||||
|
Health: contants.HealthOk,
|
||||||
|
Messages: messages,
|
||||||
|
}
|
||||||
|
}
|
||||||
13
validation/validation.go
Normal file
13
validation/validation.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/foomo/contentfulvalidation/errors"
|
||||||
|
"github.com/foomo/contentfulvalidation/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Validation interface {
|
||||||
|
ValidationResult(modelType validator.ModelType, modelID validator.ModelID) (validationResult *validator.ValidationResult, validationError *errors.ValidationError)
|
||||||
|
ValidationResults(modelType validator.ModelType) (validationResults map[validator.ModelID]*validator.ValidationResult, validationError *errors.ValidationError)
|
||||||
|
ValidateEntity(modelType validator.ModelType, modelID validator.ModelID, commit bool) (validationResult *validator.ValidationResult, validationError *errors.ValidationError)
|
||||||
|
ListModelTypes() (availableModelTypes []*validator.ModelTypeInfo)
|
||||||
|
}
|
||||||
22
validations/asset.go
Normal file
22
validations/asset.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package validations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/foomo/contentful"
|
||||||
|
"github.com/foomo/contentfulvalidation/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsLandscapeRatio(asset *contentful.AssetNoLocale) bool {
|
||||||
|
aspectRatio, err := utils.GetAspectRatio(asset)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return aspectRatio >= 1.00
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPortraitRatio(asset *contentful.AssetNoLocale) bool {
|
||||||
|
aspectRatio, err := utils.GetAspectRatio(asset)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return aspectRatio <= 1.00
|
||||||
|
}
|
||||||
66
validations/query.go
Normal file
66
validations/query.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package validations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
catvo "github.com/bestbytes/catalogue/vo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsAttributeExpired(query *catvo.Query, attributes catvo.Attributes) bool {
|
||||||
|
|
||||||
|
// TODO is this ok?
|
||||||
|
isValueExpired := func(value string, def catvo.AttributeDefinition) bool {
|
||||||
|
if _, ok := def.EnumStrings[catvo.AttributeValueID(value)]; !ok {
|
||||||
|
// thow error
|
||||||
|
// provide contex on value with this id ....
|
||||||
|
fmt.Println("Attribute NOT found: ", ok)
|
||||||
|
return true
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fmt.Println("Attribute found: ", ok)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
areValuesExpired := func(values []string, def catvo.AttributeDefinition) bool {
|
||||||
|
expired := false
|
||||||
|
for _, v := range values {
|
||||||
|
if isValueExpired(v, def) {
|
||||||
|
expired = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expired
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range query.Elements {
|
||||||
|
fmt.Println("THE Matcher: ", e.Matcher)
|
||||||
|
|
||||||
|
// @TODO validate if there is even an attribute set, or is empty string
|
||||||
|
if e.Matcher != nil {
|
||||||
|
if def, ok := attributes[e.Matcher.Attribute]; ok {
|
||||||
|
switch {
|
||||||
|
case e.Matcher.StringIn != nil:
|
||||||
|
return areValuesExpired(e.Matcher.StringIn.Values, def)
|
||||||
|
case e.Matcher.StringAllIn != nil:
|
||||||
|
return areValuesExpired(e.Matcher.StringAllIn.Values, def)
|
||||||
|
case e.Matcher.StringNotIn != nil:
|
||||||
|
return areValuesExpired(e.Matcher.StringNotIn.Values, def)
|
||||||
|
case e.Matcher.StringEquals != nil:
|
||||||
|
return isValueExpired(e.Matcher.StringEquals.Value, def)
|
||||||
|
case e.Matcher.StringNotEquals != nil:
|
||||||
|
return isValueExpired(e.Matcher.StringNotEquals.Value, def)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// throw error
|
||||||
|
fmt.Println("NO attribute within ALL ATTRIBUTES: ")
|
||||||
|
// TODO uncomment once catalogue attr are in, maybe a different validation for this
|
||||||
|
// return true
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fmt.Println("MATCHER is NIL e.matcher: ")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
46
validator/attributeprovider.go
Normal file
46
validator/attributeprovider.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bestbytes/catalogue/vo"
|
||||||
|
"github.com/foomo/keel/log"
|
||||||
|
"github.com/go-co-op/gocron"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AttributeProviderFunc func() vo.Attributes
|
||||||
|
type AttributeUpdateFunc func(ctx context.Context) vo.Attributes
|
||||||
|
|
||||||
|
type AttributeProvider struct {
|
||||||
|
l *zap.Logger
|
||||||
|
ctx context.Context
|
||||||
|
attributes vo.Attributes
|
||||||
|
updateFunc AttributeUpdateFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAttributeProvider(ctx context.Context, l *zap.Logger, uf AttributeUpdateFunc) *AttributeProvider {
|
||||||
|
return &AttributeProvider{
|
||||||
|
l: l,
|
||||||
|
ctx: ctx,
|
||||||
|
updateFunc: uf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AttributeProvider) Init() error {
|
||||||
|
ap.attributes = ap.updateFunc(ap.ctx)
|
||||||
|
|
||||||
|
// TODO: make configurable
|
||||||
|
s := gocron.NewScheduler(time.Local)
|
||||||
|
_, err := s.Every(1).Day().At("03:00").Do(func() {
|
||||||
|
ap.attributes = ap.updateFunc(ap.ctx)
|
||||||
|
})
|
||||||
|
log.Must(ap.l, err, "failed to ...")
|
||||||
|
s.StartAsync()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AttributeProvider) GetAttributes() vo.Attributes {
|
||||||
|
return ap.attributes
|
||||||
|
}
|
||||||
56
validator/cache.go
Normal file
56
validator/cache.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cache struct {
|
||||||
|
sync.RWMutex
|
||||||
|
l *zap.Logger
|
||||||
|
pool ValidationResults
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCache(l *zap.Logger) (*Cache, error) {
|
||||||
|
logger := l.With(zap.String("routine", "contentfulvalidation-cache"))
|
||||||
|
c := &Cache{
|
||||||
|
RWMutex: sync.RWMutex{},
|
||||||
|
l: logger,
|
||||||
|
pool: map[ModelType]map[ModelID]*ValidationResult{},
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Get(modelType ModelType, modelID ModelID) (*ValidationResult, bool) {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
// check if the modelType is populated at all
|
||||||
|
_, typeMapExists := c.pool[modelType]
|
||||||
|
if !typeMapExists {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
// check if the modelID has a validation result and return it
|
||||||
|
validationResult, ok := c.pool[modelType][modelID]
|
||||||
|
return validationResult, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) GetForType(modelType ModelType) map[ModelID]*ValidationResult {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
results, typeMapExists := c.pool[modelType]
|
||||||
|
if !typeMapExists {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) SetForType(modelType ModelType, results map[ModelID]*ValidationResult) {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
c.pool[modelType] = results
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) GetPool() ValidationResults {
|
||||||
|
return c.pool
|
||||||
|
}
|
||||||
12
validator/interfaces.go
Normal file
12
validator/interfaces.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import "github.com/foomo/contentfulvalidation/errors"
|
||||||
|
|
||||||
|
type ModelValidator interface {
|
||||||
|
Validate(modelID ModelID) (*ValidationResult, *errors.ValidationError)
|
||||||
|
ValidateAll() (map[ModelID]*ValidationResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidatorProvider interface {
|
||||||
|
GetValidators() map[ModelType]ModelValidator
|
||||||
|
}
|
||||||
42
validator/validationresult.go
Normal file
42
validator/validationresult.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import "github.com/foomo/contentfulvalidation/contants"
|
||||||
|
|
||||||
|
type ValidationResult struct {
|
||||||
|
ID ModelID `json:"id"`
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
InternalTitle string `json:"internalTitle,omitempty"`
|
||||||
|
LastUpdatedDate string `json:"lastUpdatedDate,omitempty"`
|
||||||
|
ModelType ModelType `json:"modelType"`
|
||||||
|
Health Health `json:"health"`
|
||||||
|
Messages []*ValidationResultMessage `json:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidationResultMessage struct {
|
||||||
|
Code MessageCode `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Severity Severity `json:"severity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (result *ValidationResult) Log(severity Severity, message string, code MessageCode) {
|
||||||
|
msg := &ValidationResultMessage{
|
||||||
|
Code: code,
|
||||||
|
Message: message,
|
||||||
|
Severity: severity,
|
||||||
|
}
|
||||||
|
result.Messages = append(result.Messages, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (result *ValidationResult) UpdateHealth() {
|
||||||
|
if len(result.Messages) > 0 {
|
||||||
|
for _, msg := range result.Messages {
|
||||||
|
if msg.Severity == contants.SeverityError || msg.Severity == contants.SeverityFatal {
|
||||||
|
result.Health = contants.HealthError
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if msg.Severity == contants.SeverityWarn {
|
||||||
|
result.Health = contants.HealthWarn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
161
validator/validator.go
Normal file
161
validator/validator.go
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/foomo/contentfulvalidation/contants"
|
||||||
|
"github.com/foomo/contentfulvalidation/errors"
|
||||||
|
"github.com/foomo/contentfulvalidation/utils"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/foomo/contentserver/client"
|
||||||
|
keellog "github.com/foomo/keel/log"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Validator struct {
|
||||||
|
l *zap.Logger
|
||||||
|
csClient *client.Client
|
||||||
|
Validators map[ModelType]ModelValidator
|
||||||
|
Cache *Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewValidator(
|
||||||
|
l *zap.Logger,
|
||||||
|
csClient *client.Client,
|
||||||
|
validatorProvider ValidatorProvider,
|
||||||
|
) (*Validator, error) {
|
||||||
|
logger := l.With(zap.String("routine", "contentfulvalidation-validator"))
|
||||||
|
cache, err := NewCache(l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Validator{
|
||||||
|
l: logger,
|
||||||
|
csClient: csClient,
|
||||||
|
Validators: validatorProvider.GetValidators(),
|
||||||
|
Cache: cache,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) Get(modelType ModelType, modelID ModelID) (
|
||||||
|
*ValidationResult,
|
||||||
|
*errors.ValidationError,
|
||||||
|
) {
|
||||||
|
result, ok := v.Cache.Get(modelType, modelID)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) Validate(modelType ModelType, modelID ModelID) (
|
||||||
|
*ValidationResult,
|
||||||
|
*errors.ValidationError,
|
||||||
|
) {
|
||||||
|
// select validator
|
||||||
|
validator, err := v.getValidatorByType(modelType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result, err := validator.Validate(modelID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) List(modelType ModelType) (
|
||||||
|
map[ModelID]*ValidationResult,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
v.l.Debug("getting all validation results for model type", keellog.FValue(modelType))
|
||||||
|
results := v.Cache.GetForType(modelType)
|
||||||
|
v.l.Debug("got validation results", keellog.FValue(modelType), keellog.FValue(len(results)))
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) MapListToCSV(modelType ModelType) (
|
||||||
|
string,
|
||||||
|
error,
|
||||||
|
) {
|
||||||
|
r, err := v.List(modelType)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
csvString := ""
|
||||||
|
rows := []string{"ID;Link;Element;Internal Title;Last Updated;Status;Details"}
|
||||||
|
|
||||||
|
for i := range r {
|
||||||
|
v, err := v.Get(modelType, i)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Health != contants.HealthOk {
|
||||||
|
date, err := utils.ConvertTimeFormat(v.LastUpdatedDate, time.RFC3339, contants.DateFormat)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
idString := string(v.ID)
|
||||||
|
hyperLink := `=HYPERLINK("https://app.contentful.com/spaces/qfsyzz7ytbcy/entries/` + idString + `")`
|
||||||
|
details := []string{}
|
||||||
|
for _, m := range v.Messages {
|
||||||
|
details = append(details, m.Message)
|
||||||
|
}
|
||||||
|
cells := []string{
|
||||||
|
idString,
|
||||||
|
hyperLink,
|
||||||
|
v.Title,
|
||||||
|
v.InternalTitle,
|
||||||
|
date,
|
||||||
|
string(v.Health),
|
||||||
|
strings.Join(details, " "),
|
||||||
|
}
|
||||||
|
rows = append(rows, strings.Join(cells, ";"))
|
||||||
|
csvString = strings.Join(rows, "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return csvString, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) ListModelTypes() []ModelType {
|
||||||
|
availableTypes := []ModelType{}
|
||||||
|
for modelType := range v.Cache.GetPool() {
|
||||||
|
availableTypes = append(availableTypes, modelType)
|
||||||
|
}
|
||||||
|
return availableTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) ValidateAll() error {
|
||||||
|
v.l.Debug("running validation on all model types")
|
||||||
|
for modelType, modelValidator := range v.Validators {
|
||||||
|
results, err := modelValidator.ValidateAll()
|
||||||
|
if err != nil {
|
||||||
|
keellog.WithError(v.l, err).Error("error on running validation", keellog.FValue(modelType))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v.l.Debug("successful validation run", keellog.FValue(modelType), keellog.FValue(len(results)))
|
||||||
|
// set the whole result to the cache
|
||||||
|
v.Cache.SetForType(modelType, results)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) Update() {
|
||||||
|
v.l.Debug("received update signal")
|
||||||
|
err := v.ValidateAll()
|
||||||
|
if err != nil {
|
||||||
|
keellog.WithError(v.l, err).Error("error on validate all update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validator) getValidatorByType(modelType ModelType) (ModelValidator, *errors.ValidationError) {
|
||||||
|
validator, ok := v.Validators[modelType]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.ErrValidationErrorUnknownType
|
||||||
|
}
|
||||||
|
return validator, nil
|
||||||
|
}
|
||||||
15
validator/vo.go
Normal file
15
validator/vo.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package validator
|
||||||
|
|
||||||
|
type SysType string
|
||||||
|
type ModelType string
|
||||||
|
type ModelID string
|
||||||
|
type MessageCode string
|
||||||
|
type Severity string
|
||||||
|
type Health string
|
||||||
|
|
||||||
|
type ValidationResults map[ModelType]map[ModelID]*ValidationResult
|
||||||
|
|
||||||
|
type ModelTypeInfo struct {
|
||||||
|
ModelType ModelType `json:"modelType"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
9
webhook/webhook.go
Normal file
9
webhook/webhook.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package webhook
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/foomo/contentfulvalidation/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Webhook interface {
|
||||||
|
UpdateCache(sysType validator.SysType, modelType validator.ModelType, modelID validator.ModelID)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user