Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ run-name: "CI (${{ github.event_name }}) on ${{ github.ref_name }} by @${{ githu
on:
push:
branches: ["**"]
paths-ignore: ['**/*.md']
pull_request:
branches: ["**"]
paths-ignore: ['**/*.md']

permissions:
contents: read
Expand All @@ -16,6 +18,7 @@ jobs:
uses: otfabric/.github/.github/workflows/go-ci.yml@v3.3.1
with:
run-govulncheck: true
policy-version: v1.4.1
fuzz-time: 10s
coverage-min: "90"
codecov-name: profinetctl
Expand Down
19 changes: 19 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Documents against the code (DOC-008, standards/documentation.md#doc-sync).
# No path filter: this is the check that runs when ci.yml skips a
# Markdown-only change, so branch protection can require it.
name: Docs
on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
docs:
uses: otfabric/.github/.github/workflows/docs-check.yml@v3.5.0
with:
docsync-version: v0.2.0
policy-version: v1.4.1
secrets: inherit
9 changes: 9 additions & 0 deletions .otfabric/docsync.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"clis": [
{
"name": "profinetctl",
"manifest": "./cmd",
"exit_codes": "internal/errs"
}
]
}
2 changes: 1 addition & 1 deletion .otfabric/policy.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# OT Fabric engineering policy adoption (otfabric/engineering standards/README.md#adoption).
policy: "1.2"
policy: "1.4"
profile: cli
mode: enforce
owner: bartvanbos
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Command-line tool for PROFINET IO built on [go-profinet](https://github.com/otfa

## Organisation standards

This repository follows **otfabric/engineering policy 1.2**, profile **cli** (`.otfabric/policy.yaml`, mode `enforce`). Where this file and the organisation standards disagree, this file wins here — say so in your report.
This repository follows **otfabric/engineering policy 1.4**, profile **cli** (`.otfabric/policy.yaml`, mode `enforce`). Where this file and the organisation standards disagree, this file wins here — say so in your report.

## Where the truth lives

Expand Down
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help all run test coverage cover compile cross lint lint-ci fmt fmt-check vet vuln build build-nocheck build-all release-all install clean pnet-smoke examples-doc release-notes-check e2e coverage-pkg-check fuzz
.PHONY: help all run test coverage cover compile cross lint lint-ci fmt fmt-check vet vuln build build-nocheck build-all release-all install clean pnet-smoke examples-doc release-notes-check e2e coverage-pkg-check fuzz docs-check

help: ## This help
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
Expand Down Expand Up @@ -35,14 +35,16 @@ COVERAGE_MIN ?= 90
# Per-package floor (TEST-012), from the coverage.out of `make coverage`.
COVER_PKG_MIN := 85
FUZZTIME ?= 10s
# docsync release of docs-check (DOC-008).
DOCSYNC_VERSION := v0.2.0

all: test build build-all ## Test and build the application

run: ## Run the application
@echo "Running $(APP_NAME)"
@go run $(APP_SRC)

check: release-notes-check fmt fmt-check lint lint-ci vet cross vuln test coverage coverage-pkg-check ## Run all checks (format, lint, vet, 32-bit build, vulnerability scan, test, coverage)
check: release-notes-check fmt fmt-check lint lint-ci vet cross vuln test coverage coverage-pkg-check docs-check ## Run all checks (format, lint, vet, 32-bit build, vulnerability scan, test, coverage)

test: ## Run unit tests with race detector
@echo "Running unit tests (race detector)"
Expand Down Expand Up @@ -186,5 +188,9 @@ clean: ## Clean the build artifacts
@rm -rf $(BIN_DIR) coverage.out
@rm -f $(RELEASE_DIR)/*

# The documents against the code (DOC-008): docsync, as docs-check.yml runs it.
docs-check: ## Check that the documents agree with the code (docsync)
@go run github.com/otfabric/docsync@$(DOCSYNC_VERSION) check .

release-notes-check: ## Fail when RELEASE.md is not in the otfabric release-notes format (## vX.Y.Z sections ending with ---)
@scripts/release-notes.sh --check
81 changes: 81 additions & 0 deletions cmd/docsync_manifest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: MIT

// docsync manifest v1 (template from github.com/otfabric/docsync; keep it as
// it is apart from the package clause and the line marked docsync:root).

package cmd

import (
"encoding/json"
"os"
"strings"
"testing"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

// TestDocsyncManifest writes the command tree to $DOCSYNC_MANIFEST for
// docsync, which checks it against the documents. Without the variable the
// test does nothing.
func TestDocsyncManifest(t *testing.T) {
out := os.Getenv("DOCSYNC_MANIFEST")
if out == "" {
t.Skip("DOCSYNC_MANIFEST is not set")
}
root := NewRootCmd(nil) // docsync:root
root.InitDefaultHelpCmd()
root.InitDefaultCompletionCmd()
type flag struct {
Name string `json:"name"`
Shorthand string `json:"shorthand,omitempty"`
Bool bool `json:"bool,omitempty"`
Required bool `json:"required,omitempty"`
Hidden bool `json:"hidden,omitempty"`
Local bool `json:"local,omitempty"`
}
type command struct {
Path string `json:"path"`
Aliases []string `json:"aliases,omitempty"`
Hidden bool `json:"hidden,omitempty"`
Runnable bool `json:"runnable"`
Subcommands []string `json:"subcommands,omitempty"`
Flags []flag `json:"flags,omitempty"`
}
var cmds []command
var walk func(c *cobra.Command)
walk = func(c *cobra.Command) {
c.InitDefaultHelpFlag()
c.InitDefaultVersionFlag()
path := strings.TrimSpace(strings.TrimPrefix(c.CommandPath(), root.Name()))
cmd := command{Path: path, Aliases: c.Aliases, Hidden: c.Hidden, Runnable: c.Runnable()}
local := map[string]bool{}
c.LocalNonPersistentFlags().VisitAll(func(f *pflag.Flag) { local[f.Name] = true })
c.PersistentFlags().VisitAll(func(f *pflag.Flag) { local[f.Name] = true })
add := func(f *pflag.Flag) {
req := false
if v, ok := f.Annotations[cobra.BashCompOneRequiredFlag]; ok && len(v) > 0 && v[0] == "true" {
req = true
}
cmd.Flags = append(cmd.Flags, flag{Name: f.Name, Shorthand: f.Shorthand, Bool: f.NoOptDefVal != "",
Required: req, Hidden: f.Hidden, Local: local[f.Name]})
}
c.LocalFlags().VisitAll(add)
c.InheritedFlags().VisitAll(add)
for _, s := range c.Commands() {
cmd.Subcommands = append(cmd.Subcommands, s.Name())
}
cmds = append(cmds, cmd)
for _, s := range c.Commands() {
walk(s)
}
}
walk(root)
data, err := json.Marshal(map[string]any{"version": 1, "name": root.Name(), "commands": cmds})
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(out, data, 0o600); err != nil {
t.Fatal(err)
}
}
Loading