Skip to content

Commit

Permalink
semconvgen: Add a flag for a path to a custom capitalizations file (#529
Browse files Browse the repository at this point in the history
)
  • Loading branch information
carrbs authored Apr 19, 2024
1 parent dbdb565 commit a8785aa
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 19 deletions.
16 changes: 16 additions & 0 deletions .chloggen/528-semconvgen-flag-for-custom-capitalizations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. crosslink)
component: semconvgen

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Add `--capitalizations-path` to allow users to add additional strings to the static capitalizations slice in generator.go"

# One or more tracking issues related to the change
issues: [528]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
21 changes: 11 additions & 10 deletions semconvgen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ semconvgen -i <path to spec YAML> -t <path to template> -o <path to output>

A full list of available options:

```txt
-c, --container string Container image ID (default "otel/semconvgen")
-f, --filename string Filename for templated output. If not specified 'basename(inputPath).go' will be used.
-i, --input string Path to semantic convention definition YAML. Should be a directory in the specification git repository.
--only string Process only semantic conventions of the specified type. {span, resource, event, metric_group, metric, units, scope, attribute_group}
-o, --output string Path to output target. Must be either an absolute path or relative to the repository root. If unspecified will output to a sub-directory with the name matching the version number specified via --specver flag.
-p, --parameters string List of key=value pairs separated by comma. These values are fed into the template as-is.
-s, --specver string Version of semantic convention to generate. Must be an existing version tag in the specification git repository.
-t, --template string Template filename (default "template.j2")
```
````txt
-z, --capitalizations-path string Path to a file containing additional newline-separated capitalization strings.
-c, --container string Container image ID (default "otel/semconvgen")
-f, --filename string Filename for templated output. If not specified 'basename(inputPath).go' will be used.
-i, --input string Path to semantic convention definition YAML. Should be a directory in the specification git repository.
--only string Process only semantic conventions of the specified type. {span, resource, event, metric_group, metric, units, scope, attribute_group}
-o, --output string Path to output target. Must be either an absolute path or relative to the repository root. If unspecified will output to a sub-directory with the name matching the version number specified via --specver flag.
-p, --parameters string List of key=value pairs separated by comma. These values are fed into the template as-is.
-s, --specver string Version of semantic convention to generate. Must be an existing version tag in the specification git repository.
-t, --template string Template filename (default "template.j2")```
````
59 changes: 50 additions & 9 deletions semconvgen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package main

import (
"bufio"
"bytes"
"errors"
"fmt"
Expand Down Expand Up @@ -48,6 +49,7 @@ func main() {
flag.StringVarP(&cfg.outputFilename, "filename", "f", "", "Filename for templated output. If not specified 'basename(inputPath).go' will be used.")
flag.StringVarP(&cfg.templateFilename, "template", "t", "template.j2", "Template filename")
flag.StringVarP(&cfg.templateParameters, "parameters", "p", "", "List of key=value pairs separated by comma. These values are fed into the template as-is.")
flag.StringVarP(&cfg.capitalizationsPath, "capitalizations-path", "z", "", "Path to a file containing additional newline-separated capitalization strings.")
flag.Parse()

cfg, err := validateConfig(cfg)
Expand All @@ -74,14 +76,15 @@ func main() {
}

type config struct {
inputPath string
outputPath string
outputFilename string
templateFilename string
templateParameters string
onlyType string
containerImage string
specVersion string
inputPath string
outputPath string
outputFilename string
templateFilename string
templateParameters string
onlyType string
containerImage string
specVersion string
capitalizationsPath string
}

func validateConfig(cfg config) (config, error) {
Expand Down Expand Up @@ -126,6 +129,12 @@ func validateConfig(cfg config) (config, error) {
cfg.templateFilename = path.Join(pwd, cfg.templateFilename)
}

if cfg.capitalizationsPath != "" {
if _, err := os.Stat(cfg.capitalizationsPath); os.IsNotExist(err) {
return config{}, fmt.Errorf("capitalizations file does not exist: %w", err)
}
}

return cfg, nil
}

Expand Down Expand Up @@ -282,7 +291,7 @@ func checkoutSpecToDir(cfg config, toDir string) (doneFunc func(), err error) {
return doneFunc, nil
}

var capitalizations = []string{
var staticCapitalizations = []string{
"ACL",
"AIX",
"AKS",
Expand Down Expand Up @@ -379,6 +388,34 @@ var capitalizations = []string{
"OTel",
}

func capitalizations(capitalizationsPath string) ([]string, error) {
c := append([]string(nil), staticCapitalizations...)

if capitalizationsPath != "" {
// #nosec G304 -- We expect the file path to be provided by the user.
file, err := os.Open(capitalizationsPath)
if err != nil {
return nil, fmt.Errorf("unable to open capitalizations file: %w", err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
capitalization := strings.TrimSpace(scanner.Text())
if capitalization == "" {
continue
}
c = append(c, capitalization)
}

if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("unable to read capitalizations file: %w", err)
}
}

return c, nil
}

// These are not simple capitalization fixes, but require string replacement.
// All occurrences of the key will be replaced with the corresponding value.
var replacements = map[string]string{
Expand All @@ -394,6 +431,10 @@ func fixIdentifiers(cfg config) error {
return fmt.Errorf("unable to read file: %w", err)
}

capitalizations, err := capitalizations(cfg.capitalizationsPath)
if err != nil {
return fmt.Errorf("unable to combine custom and static capitalizations: %w", err)
}
caser := cases.Title(language.Und)
for _, init := range capitalizations {
// Match the title-cased capitalization target, asserting that its followed by
Expand Down
83 changes: 83 additions & 0 deletions semconvgen/generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"os"
"reflect"
"testing"
)

func TestCapitalizations(t *testing.T) {
tests := []struct {
name string
capitalizations string
want []string
}{
{
name: "No additional capitalizations",
capitalizations: "",
want: staticCapitalizations,
},
{
name: "Some additional capitalizations",
capitalizations: "ASPNETCore\nJVM",
want: append(staticCapitalizations, "ASPNETCore", "JVM"),
},
{
name: "Wrong separator for capitalizations",
capitalizations: "ASPNETCore,JVM",
want: append(staticCapitalizations, "ASPNETCore,JVM"),
},
{
name: "Copius amounts of whitespace",
capitalizations: `
ASPNETCore
JVM
`,
want: append(staticCapitalizations, "ASPNETCore", "JVM"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpfile, err := os.CreateTemp("", "test")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpfile.Name())

if _, err = tmpfile.Write([]byte(tt.capitalizations)); err != nil {
t.Fatal(err)
}
if err = tmpfile.Close(); err != nil {
t.Fatal(err)
}

customCapitalizations, err := capitalizations(tmpfile.Name())
if err != nil {
t.Fatal(err)
}

if !reflect.DeepEqual(customCapitalizations, tt.want) {
t.Errorf("capitalizations() = %v, want %v", customCapitalizations, tt.want)
}
})
}
}

0 comments on commit a8785aa

Please sign in to comment.