mirror of
https://github.com/nabbar/golib.git
synced 2026-04-22 15:07:19 +08:00
Package Status:
- FIX missing info statement to expose in result - UPDATE documentation, test
This commit is contained in:
@@ -20,6 +20,10 @@
|
||||
coverage*.out
|
||||
coverage*.txt
|
||||
coverage*.log
|
||||
res_*.log
|
||||
res_*.svg
|
||||
res_*.out
|
||||
res_*.txt
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Nicolas JUHEL
|
||||
Copyright (c) 2020-2026 Nicolas JUHEL
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -51,8 +51,9 @@ func (c *Mode) unmarshall(val []byte) error {
|
||||
// (e.g., "Must", "Should").
|
||||
//
|
||||
// Example:
|
||||
// data, _ := json.Marshal(control.Must)
|
||||
// // data is []byte(`"Must"`)
|
||||
//
|
||||
// data, _ := json.Marshal(control.Must)
|
||||
// // data is []byte(`"Must"`)
|
||||
func (c Mode) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(c.String())
|
||||
}
|
||||
@@ -63,9 +64,10 @@ func (c Mode) MarshalJSON() ([]byte, error) {
|
||||
// it defaults to `Ignore`.
|
||||
//
|
||||
// Example:
|
||||
// var m control.Mode
|
||||
// json.Unmarshal([]byte(`"must"`), &m)
|
||||
// // m is control.Must
|
||||
//
|
||||
// var m control.Mode
|
||||
// json.Unmarshal([]byte(`"must"`), &m)
|
||||
// // m is control.Must
|
||||
func (c *Mode) UnmarshalJSON(bytes []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(bytes, &s); err != nil {
|
||||
|
||||
+2
-2
@@ -353,9 +353,9 @@ encountered, following this hierarchy: `KO` > `WARN` > `OK`.
|
||||
2. **Iteration**: The system iterates through all registered monitors.
|
||||
3. **Mode Application**: For each component, its control mode is determined.
|
||||
- If a component is part of a `Must` group and its status is `KO`, the global status
|
||||
immediately becomes `KO`.
|
||||
immediately becomes `KO`.
|
||||
- If a component is part of a `Must` or `Should` group and its status is `WARN`, the
|
||||
global status is elevated to `WARN` (if it was previously `OK`).
|
||||
global status is elevated to `WARN` (if it was previously `OK`).
|
||||
- `AnyOf` and `Quorum` groups are evaluated based on their specific rules.
|
||||
4. **Finalization**: The final aggregated status is cached and returned.
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
type encMod struct {
|
||||
Mode stsctr.Mode `json:"mode"`
|
||||
Name string `json:"name"`
|
||||
Info map[string]interface{} `json:"info"`
|
||||
Sts monsts.Status `json:"status"`
|
||||
Cpt map[string]montps.MonitorStatus `json:"components"`
|
||||
}
|
||||
@@ -112,6 +113,7 @@ func (o modControl) getEncControl() []encMod {
|
||||
var ctr = encMod{
|
||||
Mode: m.GetMode(),
|
||||
Name: m.GetName(),
|
||||
Info: m.GetInfo(),
|
||||
Cpt: make(map[string]montps.MonitorStatus),
|
||||
}
|
||||
|
||||
@@ -136,6 +138,7 @@ func (o modControl) getEncControl() []encMod {
|
||||
var ctr = encMod{
|
||||
Mode: stsctr.Ignore,
|
||||
Name: "not-defined",
|
||||
Info: make(map[string]interface{}),
|
||||
Sts: monsts.OK,
|
||||
Cpt: make(map[string]montps.MonitorStatus),
|
||||
}
|
||||
|
||||
@@ -83,6 +83,10 @@ func (o *sts) SetVersion(v libver.Version) {
|
||||
o.m.Lock()
|
||||
defer o.m.Unlock()
|
||||
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.fn = v.GetPackage
|
||||
o.fr = v.GetRelease
|
||||
o.fh = v.GetBuild
|
||||
|
||||
+4
-3
@@ -209,8 +209,8 @@ type Status interface {
|
||||
//
|
||||
// The returned instance is thread-safe but requires further configuration before it
|
||||
// can be used effectively. At a minimum, you must:
|
||||
// 1. Call `SetInfo` or `SetVersion` to provide application identity.
|
||||
// 2. Call `RegisterPool` to link a monitor pool for health checks.
|
||||
// 1. Call `SetInfo` or `SetVersion` to provide application identity.
|
||||
// 2. Call `RegisterPool` to link a monitor pool for health checks.
|
||||
//
|
||||
// You can also optionally call `SetConfig` to define custom health policies and
|
||||
// `SetErrorReturn` to customize error formatting.
|
||||
@@ -219,7 +219,8 @@ type Status interface {
|
||||
// - ctx: The root `context.Context` for the application.
|
||||
//
|
||||
// Returns:
|
||||
// A new `Status` instance.
|
||||
//
|
||||
// A new `Status` instance.
|
||||
func New(ctx context.Context) Status {
|
||||
s := &sts{
|
||||
m: sync.RWMutex{},
|
||||
|
||||
+26
-26
@@ -53,33 +53,33 @@
|
||||
// The following diagram illustrates how the `Mandatory` package interacts with the
|
||||
// broader status monitoring workflow:
|
||||
//
|
||||
// +------------------+ +--------------------+
|
||||
// | Configuration | | Status Monitor |
|
||||
// | (Static/Dynamic) | | (Poller) |
|
||||
// +--------+---------+ +---------+----------+
|
||||
// | |
|
||||
// v v
|
||||
// +--------+-----------------------------+----------+
|
||||
// | Mandatory |
|
||||
// | |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | | Key Set | <------- | Is Key Mandatory? | |
|
||||
// | | {A, B, C} | | (KeyHas) | |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | ^ |
|
||||
// | | Add/Del |
|
||||
// | v |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | | Validation | -------> | Get Strategy | |
|
||||
// | | Mode | | (GetMode) | |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | |
|
||||
// +-------------------------------------------------+
|
||||
// +------------------+ +--------------------+
|
||||
// | Configuration | | Status Monitor |
|
||||
// | (Static/Dynamic) | | (Poller) |
|
||||
// +--------+---------+ +---------+----------+
|
||||
// | |
|
||||
// v v
|
||||
// +--------+-----------------------------+----------+
|
||||
// | Mandatory |
|
||||
// | |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | | Key Set | <------- | Is Key Mandatory? | |
|
||||
// | | {A, B, C} | | (KeyHas) | |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | ^ |
|
||||
// | | Add/Del |
|
||||
// | v |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | | Validation | -------> | Get Strategy | |
|
||||
// | | Mode | | (GetMode) | |
|
||||
// | +------------+ +-------------------+ |
|
||||
// | |
|
||||
// +-------------------------------------------------+
|
||||
//
|
||||
// 1. **Configuration Phase**: The application defines groups (e.g., "Critical Services")
|
||||
// and populates them with component keys using `KeyAdd`. The validation strategy
|
||||
// is set using `SetMode` (e.g., `control.Must`), and descriptive metadata is
|
||||
// added via `SetInfo` or `AddInfo`.
|
||||
// 1. **Configuration Phase**: The application defines groups (e.g., "Critical Services")
|
||||
// and populates them with component keys using `KeyAdd`. The validation strategy
|
||||
// is set using `SetMode` (e.g., `control.Must`), and descriptive metadata is
|
||||
// added via `SetInfo` or `AddInfo`.
|
||||
//
|
||||
// 2. **Monitoring Phase**: When the status system evaluates the overall health:
|
||||
// - It iterates over registered components.
|
||||
|
||||
+8
-4
@@ -110,7 +110,8 @@ func (o *sts) IsCacheStrictlyHealthy() bool {
|
||||
// - name: An optional list of component names to check. If empty, checks all components.
|
||||
//
|
||||
// Returns:
|
||||
// `true` if the aggregated status is `OK` or `WARN`, `false` otherwise.
|
||||
//
|
||||
// `true` if the aggregated status is `OK` or `WARN`, `false` otherwise.
|
||||
func (o *sts) IsHealthy(name ...string) bool {
|
||||
s, _ := o.getStatus(name...)
|
||||
return s >= monsts.Warn
|
||||
@@ -126,7 +127,8 @@ func (o *sts) IsHealthy(name ...string) bool {
|
||||
// - name: An optional list of component names to check. If empty, checks all components.
|
||||
//
|
||||
// Returns:
|
||||
// `true` only if the aggregated status is `OK`, `false` otherwise.
|
||||
//
|
||||
// `true` only if the aggregated status is `OK`, `false` otherwise.
|
||||
func (o *sts) IsStrictlyHealthy(name ...string) bool {
|
||||
s, _ := o.getStrictStatus(name...)
|
||||
return s == monsts.OK
|
||||
@@ -148,7 +150,8 @@ func (o *sts) IsStrictlyHealthy(name ...string) bool {
|
||||
// If empty, all configured components are considered.
|
||||
//
|
||||
// Returns:
|
||||
// The computed `monsts.Status` and a message from the component that caused the degradation.
|
||||
//
|
||||
// The computed `monsts.Status` and a message from the component that caused the degradation.
|
||||
func (o *sts) getStatus(keys ...string) (monsts.Status, string) {
|
||||
stt := monsts.OK
|
||||
msg := ""
|
||||
@@ -262,7 +265,8 @@ func (o *sts) getStatus(keys ...string) (monsts.Status, string) {
|
||||
// If empty, all configured components are considered.
|
||||
//
|
||||
// Returns:
|
||||
// The "worst" `monsts.Status` found among the checked components and its corresponding message.
|
||||
//
|
||||
// The "worst" `monsts.Status` found among the checked components and its corresponding message.
|
||||
func (o *sts) getStrictStatus(keys ...string) (monsts.Status, string) {
|
||||
stt := monsts.OK
|
||||
msg := ""
|
||||
|
||||
@@ -636,6 +636,69 @@ var _ = Describe("Status/Route", func() {
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(lst).To(HaveKey("test-service"))
|
||||
})
|
||||
|
||||
It("should include mandatory group info in map mode", func() {
|
||||
status := libsts.New(globalCtx)
|
||||
status.SetInfo("route-test", "v1.0.0", "abc123")
|
||||
|
||||
pool := newPool()
|
||||
status.RegisterPool(func() montps.Pool { return pool })
|
||||
|
||||
router := ginsdk.New()
|
||||
router.GET("/status", func(c *ginsdk.Context) {
|
||||
status.MiddleWare(c)
|
||||
})
|
||||
|
||||
// Configure mandatory group with Info
|
||||
cfg := libsts.Config{
|
||||
Component: []libsts.Mandatory{
|
||||
{
|
||||
Name: "info-group",
|
||||
Mode: stsctr.Must,
|
||||
Keys: []string{"test-service"},
|
||||
Info: map[string]interface{}{
|
||||
"description": "Critical Service Group",
|
||||
"link": "https://example.com/docs",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
status.SetConfig(cfg)
|
||||
|
||||
m := newHealthyMonitor("test-service")
|
||||
err := pool.MonitorAdd(m)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
time.Sleep(testMonitorStabilizeDelay)
|
||||
|
||||
req := httptest.NewRequest("GET", "/status?map=true", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
Expect(w.Code).To(Equal(http.StatusOK))
|
||||
|
||||
var result map[string]interface{}
|
||||
err = json.Unmarshal(w.Body.Bytes(), &result)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
val, ok := result["component"]
|
||||
Expect(ok).To(BeTrue())
|
||||
itm, ok := val.([]interface{})
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(itm).To(HaveLen(1))
|
||||
|
||||
sub, ok := itm[0].(map[string]interface{})
|
||||
Expect(ok).To(BeTrue())
|
||||
|
||||
// Verify the info field exists and contains correct data
|
||||
infoField, ok := sub["info"]
|
||||
Expect(ok).To(BeTrue(), "info field should exist in map mode output")
|
||||
|
||||
infoMap, ok := infoField.(map[string]interface{})
|
||||
Expect(ok).To(BeTrue(), "info field should be a map")
|
||||
Expect(infoMap).To(HaveKeyWithValue("description", "Critical Service Group"))
|
||||
Expect(infoMap).To(HaveKeyWithValue("link", "https://example.com/docs"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("with filter query parameter", func() {
|
||||
@@ -663,11 +726,19 @@ var _ = Describe("Status/Route", func() {
|
||||
Name: "group-a",
|
||||
Mode: stsctr.Must,
|
||||
Keys: []string{"service-a"},
|
||||
Info: map[string]interface{}{
|
||||
"description": "Critical Service Group A",
|
||||
"link": "https://example.com/docs/a",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "group-b",
|
||||
Mode: stsctr.Should,
|
||||
Keys: []string{"service-b"},
|
||||
Info: map[string]interface{}{
|
||||
"description": "Critical Service Group B",
|
||||
"link": "https://example.com/docs/b",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -733,6 +804,15 @@ var _ = Describe("Status/Route", func() {
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(group).To(HaveKeyWithValue("name", "group-a"))
|
||||
|
||||
// Verify the info field exists and contains correct data
|
||||
infoField, ok := group["info"]
|
||||
Expect(ok).To(BeTrue(), "info field should exist in map mode output")
|
||||
|
||||
infoMap, ok := infoField.(map[string]interface{})
|
||||
Expect(ok).To(BeTrue(), "info field should be a map")
|
||||
Expect(infoMap).To(HaveKeyWithValue("description", "Critical Service Group A"))
|
||||
Expect(infoMap).To(HaveKeyWithValue("link", "https://example.com/docs/a"))
|
||||
|
||||
components, ok := group["components"].(map[string]interface{})
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(components).To(HaveLen(1))
|
||||
|
||||
Executable
+179
@@ -0,0 +1,179 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2026 Nicolas JUHEL
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#set -e
|
||||
|
||||
# Default package to current directory if not provided
|
||||
PKG="${1:-.}"
|
||||
TIMEOUT="2m"
|
||||
|
||||
# Determine Output Directory
|
||||
# Strip common suffixes to find the directory part
|
||||
CLEAN_PKG="$PKG"
|
||||
CLEAN_PKG="${CLEAN_PKG%...}"
|
||||
CLEAN_PKG="${CLEAN_PKG%/}"
|
||||
|
||||
if [ -d "$CLEAN_PKG" ]; then
|
||||
LOG_DIR="$CLEAN_PKG"
|
||||
else
|
||||
# If the package path isn't a directory (e.g. a go module path), default to current
|
||||
LOG_DIR="."
|
||||
fi
|
||||
|
||||
echo "Running tests for package: $PKG"
|
||||
echo "Logs and metrics will be stored in: $LOG_DIR"
|
||||
|
||||
# Define output files
|
||||
F_COV="$LOG_DIR/res_coverage.log"
|
||||
F_COV_RACE="$LOG_DIR/res_coverage_race.log"
|
||||
F_LOG_TEST="$LOG_DIR/res_test.log"
|
||||
F_LOG_RACE="$LOG_DIR/res_test_race.log"
|
||||
F_LOG_BENCH="$LOG_DIR/res_bench.log"
|
||||
F_CPULST="$LOG_DIR/res_cpu-list.log"
|
||||
F_CPUSVG="$LOG_DIR/res_cpu.svg"
|
||||
F_MEMLST="$LOG_DIR/res_mem-list.log"
|
||||
F_MEMSVG="$LOG_DIR/res_mem.svg"
|
||||
F_MEMTOP="$LOG_DIR/res_mem-top.log"
|
||||
F_REPORT="$LOG_DIR/res_report.log"
|
||||
F_LSHW="$LOG_DIR/res_lshw.log"
|
||||
F_LOG_SEC="$LOG_DIR/res_gosec.log"
|
||||
F_LOG_LINT="$LOG_DIR/res_golint.log"
|
||||
|
||||
# Clean up previous artifacts
|
||||
rm -f "$F_COV" "$F_COV.out" "$F_COV_RACE" "$F_COV_RACE.out" "$F_LOG_TEST" "$F_LOG_RACE"
|
||||
rm -f "$F_LOG_BENCH" "$F_CPULST" "$F_CPULST.out" "$F_CPUSVG" "$F_MEMLST" "$F_MEMLST.out" "$F_MEMSVG" "$F_MEMTOP"
|
||||
rm -f "$F_REPORT" "$F_LSHW" "$F_LOG_SEC" "$F_LOG_LINT"
|
||||
|
||||
# Testing sudo
|
||||
sudo echo "ok"
|
||||
|
||||
# 1. Print Material used for test
|
||||
# Capture both script messages and command output to file
|
||||
{
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Listing materials..."
|
||||
echo "----------------------------------------------------------------------"
|
||||
sudo lshw
|
||||
} > "$F_LSHW" 2>&1
|
||||
|
||||
echo "Step 1/7: Listing materials. Logs: $F_LSHW"
|
||||
|
||||
# 2. Calling Reports script
|
||||
# Capture both script messages and command output to file
|
||||
$(dirname "${0}")/coverage-report.sh -o "$(basename "$F_REPORT")" "${CLEAN_PKG#./}"
|
||||
echo "Step 2/7: Report called. Logs: $F_REPORT"
|
||||
|
||||
# 3. Normal Test Mode with Coverage
|
||||
# Capture both script messages and command output to file
|
||||
{
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Running Tests (Normal Mode) with Coverage..."
|
||||
echo "Package: $PKG"
|
||||
echo "Timeout: $TIMEOUT"
|
||||
echo "Mode: atomic"
|
||||
echo "----------------------------------------------------------------------"
|
||||
go test -v -timeout "$TIMEOUT" -covermode=atomic -coverprofile="$F_COV.out" "$PKG"
|
||||
go tool cover -func="$F_COV.out" -o="$F_COV"
|
||||
rm -f "$F_COV.out"
|
||||
} > "$F_LOG_TEST" 2>&1
|
||||
|
||||
echo "Step 3/7: Normal Tests completed. Logs: $F_LOG_TEST"
|
||||
|
||||
# 4. Benchmarks (Normal Mode)
|
||||
{
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Running Benchmarks..."
|
||||
echo "Package: $PKG"
|
||||
echo "Flags: -bench=. -benchmem"
|
||||
echo "----------------------------------------------------------------------"
|
||||
go test -v -run=^$ -bench=. -benchmem -cpuprofile="$F_CPULST.out" -memprofile="$F_MEMLST.out" "$PKG"
|
||||
go tool pprof -svg "$F_CPULST.out" > "$F_CPUSVG"
|
||||
go tool pprof -list . "$F_CPULST.out" > "$F_CPULST"
|
||||
go tool pprof -svg "$F_MEMLST.out" > "$F_MEMSVG"
|
||||
go tool pprof -list . "$F_MEMLST.out" > "$F_MEMLST"
|
||||
go tool pprof -top . "$F_MEMLST.out" > "$F_MEMTOP"
|
||||
rm -f "$F_CPULST.out" "$F_MEMLST.out"
|
||||
} > "$F_LOG_BENCH" 2>&1
|
||||
|
||||
echo "Step 4/7: Benchmarks completed. Logs: $F_LOG_BENCH"
|
||||
|
||||
# 5. Race Test Mode with Coverage
|
||||
{
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Running Tests (Race Mode) with Coverage..."
|
||||
echo "Package: $PKG"
|
||||
echo "Timeout: $TIMEOUT"
|
||||
echo "Mode: atomic + race"
|
||||
echo "----------------------------------------------------------------------"
|
||||
export CGO_ENABLED=1
|
||||
go test -v -race -timeout "$TIMEOUT" -covermode=atomic -coverprofile="$F_COV_RACE.out" "$PKG"
|
||||
export CGO_ENABLED=0
|
||||
go tool cover -func="$F_COV_RACE.out" -o="$F_COV_RACE"
|
||||
rm -f "$F_COV_RACE.out"
|
||||
} > "$F_LOG_RACE" 2>&1
|
||||
|
||||
echo "Step 5/7: Race Tests completed. Logs: $F_LOG_RACE"
|
||||
|
||||
# 6. Checking security static code
|
||||
{
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Checking static security ..."
|
||||
echo "Package: $PKG"
|
||||
echo "----------------------------------------------------------------------"
|
||||
gosec -sort "$PKG"
|
||||
} > "$F_LOG_SEC" 2>&1
|
||||
|
||||
echo "Step 6/7: Checking static security completed. Logs: $F_LOG_SEC"
|
||||
|
||||
# 7. Verify Golint
|
||||
{
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Checking / Updating format & imports..."
|
||||
echo "Package: $PKG"
|
||||
echo "----------------------------------------------------------------------"
|
||||
for ITM in $(find "$LOG_DIR" -type f -name '*.go' | grep -v '/vendor/')
|
||||
do
|
||||
gofmt -w "$ITM"
|
||||
go fmt "$ITM"
|
||||
goimports -w "$ITM"
|
||||
done
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "Checking linters..."
|
||||
echo "Package: $PKG"
|
||||
echo "----------------------------------------------------------------------"
|
||||
golangci-lint --config .golangci.yml run "$PKG"
|
||||
} > "$F_LOG_LINT" 2>&1
|
||||
|
||||
echo "Step 7/7: Checking format, imports & linter completed. Logs: $F_LOG_LINT"
|
||||
|
||||
echo "----------------------------------------------------------------------"
|
||||
echo "All operations completed successfully."
|
||||
echo "Artifacts in $LOG_DIR:"
|
||||
echo " - Logs: test.log, test_race.log, bench.log"
|
||||
echo " - Coverage: coverage.out, coverage_race.out"
|
||||
echo " - Profiles: cpu.out, mem.out"
|
||||
echo " - Quality: gosec.log golint.log"
|
||||
echo " - Reports: lshw.log, report.log"
|
||||
echo "----------------------------------------------------------------------"
|
||||
Reference in New Issue
Block a user