Skip to content

Commit

Permalink
chore: Fix flags and add tests (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsumners-nr authored Sep 17, 2024
1 parent 023ae85 commit f5dd326
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 82 deletions.
62 changes: 33 additions & 29 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,44 @@ For optional CLI args, run:
```sh
❯ ./nrversions -help

This tool is used to generate a document detailing the modules that
nrversions - This tool is used to generate a document detailing the modules that
the newrelic Node.js agent instruments and the version ranges of those
modules.

The following flags are supported:

-a, --ai-compat-json string Path to the ai-compat.json file that describes the AI Monitoring
compatibility of the agent. The default is to use the JSON file included
in the mainline agent repository.

-n, --no-externals Disable cloning and processing of external repos. An external repo is
one that provides extra functionality to the "newrelic" module. This
allows processing a single repo with --repo-dir. The default, i.e. not
supplying this flag, is to process all known external repos.

-R, --replace-in-file string Specify a target file in which the results will be written. Normally,
the result is written to stdout. When this flag is given, the result
will be written to the specified file. The generated text will replace
all text in the file between two marker lines. The markers can be defined
through environment variables: START_MARKER and END_MARKER. Default values
are "{/* begin: compat-table */}"
and "{/* end: compat-table */}".

-r, --repo-dir string Specify a local directory that contains a Node.js instrumentation repo.
If not provided, the main agent GitHub repository will be cloned to a
local temporary directory and that will be used.

-t, --test-dir string Specify the test directory to parse the package.json files.
If not provided, it will default to 'test/versioned'. This applies to
the repo provided by the --repo-dir flag.

-v, --verbose Enable verbose output. As the data is being loaded and parsed various
logs will be written to stderr that should give indicators of what
is happening.

Flags:
--version Displays the program version string.
-h --help Displays help with available flag, subcommand, and positional value parameters.
-ai-compat-json --a Path to the ai-compat.json file that describes the AI Monitoring
compatibility of the agent. The default is to use the JSON file included
in the mainline agent repository.

-no-externals --n Disable cloning and processing of external repos. An external repo is
one that provides extra functionality to the "newrelic" module. This
allows processing a single repo with --repo-dir. The default, i.e. not
supplying this flaggy, is to process all known external repos.

-replace-in-file --R Specify a target file in which the results will be written. Normally,
the result is written to stdout. When this flaggy is given, the result
will be written to the specified file. The generated text will replace
all text in the file between two marker lines. The markers can be defined
through environment variables: START_MARKER and END_MARKER. Default values
are "{/* begin: compat-table */}"
and "{/* end: compat-table */}".

-repo-dir --r Specify a local directory that contains a Node.js instrumentation repo.
If not provided, the main agent GitHub repository will be cloned to a
local temporary directory and that will be used.

-test-dir --t Specify the test directory to parse the package.json files.
If not provided, it will default to 'test/versioned'. This applies to
the repo provided by the --repo-dir flaggy.

-verbose --v Enable verbose output. As the data is being loaded and parsed various
logs will be written to stderr that should give indicators of what
is happening.
```

## Building
Expand Down
42 changes: 15 additions & 27 deletions flags.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package main

import (
"fmt"
"github.com/MakeNowJust/heredoc/v2"
flag "github.com/spf13/pflag"
"github.com/integrii/flaggy"
"os"
)

Expand All @@ -30,44 +29,41 @@ var usageText = heredoc.Doc(`
`)

func createAndParseFlags(args []string) error {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.Usage = func() {
printUsage(fs.FlagUsages())
}

fs.StringVarP(
parser := flaggy.NewParser("nrversions")
parser.ShowHelpOnUnexpected = false
parser.Description = usageText

parser.String(
&flags.aiCompatJsonFile,
"ai-compat-json",
"a",
"",
heredoc.Doc(`
Path to the ai-compat.json file that describes the AI Monitoring
compatibility of the agent. The default is to use the JSON file included
in the mainline agent repository.
`),
)

fs.BoolVarP(
parser.Bool(
&flags.noExternals,
"no-externals",
"n",
false,
heredoc.Doc(`
Disable cloning and processing of external repos. An external repo is
one that provides extra functionality to the "newrelic" module. This
allows processing a single repo with --repo-dir. The default, i.e. not
supplying this flag, is to process all known external repos.
supplying this flaggy, is to process all known external repos.
`),
)

fs.StringVarP(
parser.String(
&flags.replaceInFile,
"replace-in-file",
"R",
"",
heredoc.Doc(`
Specify a target file in which the results will be written. Normally,
the result is written to stdout. When this flag is given, the result
the result is written to stdout. When this flaggy is given, the result
will be written to the specified file. The generated text will replace
all text in the file between two marker lines. The markers can be defined
through environment variables: START_MARKER and END_MARKER. Default values
Expand All @@ -77,35 +73,32 @@ func createAndParseFlags(args []string) error {
),
)

fs.StringVarP(
parser.String(
&flags.repoDir,
"repo-dir",
"r",
"",
heredoc.Doc(`
Specify a local directory that contains a Node.js instrumentation repo.
If not provided, the main agent GitHub repository will be cloned to a
local temporary directory and that will be used.
`),
)

fs.StringVarP(
parser.String(
&flags.testDir,
"test-dir",
"t",
"",
heredoc.Doc(`
Specify the test directory to parse the package.json files.
If not provided, it will default to 'test/versioned'. This applies to
the repo provided by the --repo-dir flag.
the repo provided by the --repo-dir flaggy.
`),
)

fs.BoolVarP(
parser.Bool(
&flags.verbose,
"verbose",
"v",
false,
heredoc.Doc(`
Enable verbose output. As the data is being loaded and parsed various
logs will be written to stderr that should give indicators of what
Expand All @@ -114,7 +107,7 @@ func createAndParseFlags(args []string) error {
)

readEnvironment()
return fs.Parse(args[1:])
return parser.ParseArgs(args)
}

func readEnvironment() {
Expand All @@ -132,8 +125,3 @@ func readEnvironment() {
flags.endMarker = "{/* end: compat-table */}"
}
}

func printUsage(help string) {
fmt.Println(usageText)
fmt.Println(help)
}
6 changes: 6 additions & 0 deletions flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ func Test_createAndParseFlags(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, expected, flags)
})

t.Run("no-externals", func(t *testing.T) {
err := createAndParseFlags([]string{"--no-externals"})
assert.Nil(t, err)
assert.Equal(t, true, flags.noExternals)
})
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/dusted-go/logging v1.3.0
github.com/go-git/go-git/v5 v5.12.0
github.com/integrii/flaggy v1.5.2
github.com/jedib0t/go-pretty/v6 v6.5.9
github.com/jsumners/go-rfc3339 v1.2.0
github.com/spf13/afero v1.11.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZt
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/integrii/flaggy v1.5.2 h1:bWV20MQEngo4hWhno3i5Z9ISPxLPKj9NOGNwTWb/8IQ=
github.com/integrii/flaggy v1.5.2/go.mod h1:dO13u7SYuhk910nayCJ+s1DeAAGC1THCMj1uSFmwtQ8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU=
Expand Down Expand Up @@ -164,6 +167,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand Down
4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ var columHeaders = map[string]string{
var appFS = afero.NewOsFs()

func main() {
err := run(os.Args)
err := Run(os.Args[1:])
if err != nil {
fmt.Printf("app error: %v", err)
os.Exit(1)
}
}

func run(args []string) error {
func Run(args []string) error {
err := createAndParseFlags(args)
if err != nil {
if errors.Is(err, flag.ErrHelp) {
Expand Down
62 changes: 62 additions & 0 deletions main_int_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main_test

import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"os"
"path"
"strings"
"testing"
)
import "nrversions"

func Test_RenderCompatDoc(t *testing.T) {
outFilePath := path.Join(os.TempDir(), "compat.md")
outFile, err := os.OpenFile(outFilePath, os.O_CREATE|os.O_RDWR, os.ModePerm)
require.Nil(t, err)

t.Cleanup(func() {
os.Remove(outFilePath)
})

_, err = outFile.WriteString("{/* begin: compat-table */}\n{/* end: compat-table */}")
require.Nil(t, err)

args := []string{
"--no-externals",
"--repo-dir", ".",
"--test-dir", "testdata/versioned",
"--ai-compat-json", "testdata/ai-compat.json",
"--replace-in-file", outFilePath,
}
err = main.Run(args)
require.Nil(t, err)

fileData, err := os.ReadFile(outFilePath)
require.Nil(t, err)
err = outFile.Close()
require.Nil(t, err)

found := string(fileData)

// Verify that all of the modules are found and their minimum versions
// are listed correctly. We can't compare against a static document because
// we can't override private methods in a `_test` package. As a result, this
// test does hit npmjs.com to find the latest version of each package. So
// the result will change according to whatever versions are available each
// time the test is run.
assert.Equal(t, true, strings.Contains(found, "`@aws-sdk/client-bedrock-runtime` | 3.474.0"))
assert.Equal(t, true, strings.Contains(found, "`@aws-sdk/client-dynamodb` | 3.0.0"))
assert.Equal(t, true, strings.Contains(found, "`@aws-sdk/client-sns` | 3.0.0"))
assert.Equal(t, true, strings.Contains(found, "`@aws-sdk/client-sqs` | 3.0.0"))
assert.Equal(t, true, strings.Contains(found, "`@aws-sdk/lib-dynamodb` | 3.377.0"))
assert.Equal(t, true, strings.Contains(found, "`@aws-sdk/smithy-client` | 3.47.0"))
assert.Equal(t, true, strings.Contains(found, "`@elastic/elasticsearch` | 7.16.0"))
assert.Equal(t, true, strings.Contains(found, "`@koa/router` | 8.0.0"))
assert.Equal(t, true, strings.Contains(found, "`@langchain/core` | 0.1.17"))
assert.Equal(t, true, strings.Contains(found, "`@smithy/smithy-client` | 2.0.0"))
assert.Equal(t, true, strings.Contains(found, "`koa` | 2.0.0"))
assert.Equal(t, true, strings.Contains(found, "`koa-route` | 3.0.0"))
assert.Equal(t, true, strings.Contains(found, "`koa-router` | 7.1.0"))
assert.Equal(t, true, strings.Contains(found, "`mongodb` | 2.1.0"))
}
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func Test_processVersionedTestDirs(t *testing.T) {

releaseData := processVersionedTestDirs(testDirs, logger)
assert.Equal(t, 0, len(collector.logs))
assert.Equal(t, 7, len(releaseData))
assert.Equal(t, 14, len(releaseData))
})
}

Expand Down
6 changes: 5 additions & 1 deletion parse-package.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ func parsePackage(pkg *VersionedTestPackageJson) ([]PkgInfo, error) {
}

if lastVersion == nil {
return nil, fmt.Errorf("%s: %w", pkg.Name, ErrTargetMissing)
if target.Name != "" {
return nil, fmt.Errorf("%s (%s): %w", pkg.Name, target.Name, ErrTargetMissing)
} else {
return nil, fmt.Errorf("%s: %w", pkg.Name, ErrTargetMissing)
}
}

minVersion := lastVersion.GetLowerBoundary()
Expand Down
2 changes: 1 addition & 1 deletion parse-package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func Test_ParsePackage(t *testing.T) {
t.Run("handles aws-sdk-v3 with missing dep", func(t *testing.T) {
// This test verifies that if a target is specified, but no test descriptor
// exists which explicitly tests that target, then an error will occur.
pkg := readJsonFile(t, "testdata/versioned/aws-sdk-v3/package.json")
pkg := readJsonFile(t, "testdata/missing-test-target.json")
found, err := parsePackage(&pkg)
assert.Nil(t, found)
assert.ErrorIs(t, err, ErrTargetMissing)
Expand Down
13 changes: 13 additions & 0 deletions testdata/missing-test-target.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "missing-test-target",
"targets": [{ "name": "foo", "minAgentVersion": "1.0.0" }],
"tests": [
{
"dependencies": {
"bar": {
"versions": "latest"
}
}
}
]
}
Loading

0 comments on commit f5dd326

Please sign in to comment.