From a7e28f87e38174cf3089da9cd86d739f1cd4b2bf Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Fri, 30 May 2025 08:44:00 -0500 Subject: [PATCH 01/10] Upgrade CLI to opslevel-go 2025 --- src/cmd/account.go | 2 +- src/cmd/action.go | 2 +- src/cmd/alias.go | 2 +- src/cmd/check.go | 2 +- src/cmd/dependency.go | 2 +- src/cmd/deploy.go | 2 +- src/cmd/document.go | 2 +- src/cmd/domain.go | 2 +- src/cmd/example.go | 2 +- src/cmd/filter.go | 2 +- src/cmd/graphql.go | 2 +- src/cmd/infra.go | 2 +- src/cmd/integration.go | 2 +- src/cmd/maturity.go | 2 +- src/cmd/policy.go | 2 +- src/cmd/property.go | 2 +- src/cmd/repository.go | 2 +- src/cmd/root.go | 2 +- src/cmd/rubric.go | 2 +- src/cmd/scorecard.go | 2 +- src/cmd/secret.go | 2 +- src/cmd/service.go | 2 +- src/cmd/system.go | 2 +- src/cmd/tag.go | 2 +- src/cmd/team.go | 2 +- src/cmd/team_test.go | 2 +- src/cmd/terraform.go | 2 +- src/cmd/tools.go | 2 +- src/cmd/trigger_definition.go | 2 +- src/cmd/user.go | 2 +- src/cmd/user_test.go | 2 +- src/common/client.go | 2 +- src/common/prompts.go | 2 +- src/go.mod | 10 +++++----- src/go.sum | 10 ++++++---- src/submodules/opslevel-go | 2 +- 36 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/cmd/account.go b/src/cmd/account.go index 9fa23831..166ff48a 100644 --- a/src/cmd/account.go +++ b/src/cmd/account.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" diff --git a/src/cmd/action.go b/src/cmd/action.go index 3af479e8..ec44315b 100644 --- a/src/cmd/action.go +++ b/src/cmd/action.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/alias.go b/src/cmd/alias.go index 4ceb50df..b26c1270 100644 --- a/src/cmd/alias.go +++ b/src/cmd/alias.go @@ -6,7 +6,7 @@ import ( "slices" "strings" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) diff --git a/src/cmd/check.go b/src/cmd/check.go index 937cfa71..ab058f7b 100644 --- a/src/cmd/check.go +++ b/src/cmd/check.go @@ -5,7 +5,7 @@ import ( "fmt" "slices" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/rs/zerolog/log" diff --git a/src/cmd/dependency.go b/src/cmd/dependency.go index c44c5c66..3fe55c91 100644 --- a/src/cmd/dependency.go +++ b/src/cmd/dependency.go @@ -3,7 +3,7 @@ package cmd import ( "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/deploy.go b/src/cmd/deploy.go index 753b051d..3e1bfcce 100644 --- a/src/cmd/deploy.go +++ b/src/cmd/deploy.go @@ -5,7 +5,7 @@ import ( "os" "time" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/creasty/defaults" "github.com/go-git/go-git/v5" diff --git a/src/cmd/document.go b/src/cmd/document.go index 15031092..1fef674c 100644 --- a/src/cmd/document.go +++ b/src/cmd/document.go @@ -5,7 +5,7 @@ import ( "os" "strings" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/rs/zerolog/log" "github.com/spf13/cobra" diff --git a/src/cmd/domain.go b/src/cmd/domain.go index 19341292..1b64e48e 100644 --- a/src/cmd/domain.go +++ b/src/cmd/domain.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/example.go b/src/cmd/example.go index 80ea4f4b..92fd8d15 100644 --- a/src/cmd/example.go +++ b/src/cmd/example.go @@ -3,7 +3,7 @@ package cmd import ( "encoding/json" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" "github.com/spf13/viper" "gopkg.in/yaml.v2" diff --git a/src/cmd/filter.go b/src/cmd/filter.go index 1ecb5698..2e445a3c 100644 --- a/src/cmd/filter.go +++ b/src/cmd/filter.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/graphql.go b/src/cmd/graphql.go index c7dba22c..fae05a36 100644 --- a/src/cmd/graphql.go +++ b/src/cmd/graphql.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/itchyny/gojq" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/infra.go b/src/cmd/infra.go index 64e4d8b5..d4165f48 100644 --- a/src/cmd/infra.go +++ b/src/cmd/infra.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "gopkg.in/yaml.v3" diff --git a/src/cmd/integration.go b/src/cmd/integration.go index 97c44d8c..93cabf6d 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -8,7 +8,7 @@ import ( "github.com/mitchellh/mapstructure" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/maturity.go b/src/cmd/maturity.go index b2796985..0eeabdb4 100644 --- a/src/cmd/maturity.go +++ b/src/cmd/maturity.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 4f9eadd5..073c8407 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -14,7 +14,7 @@ import ( "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/rego" "github.com/open-policy-agent/opa/types" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/relvacode/iso8601" "github.com/rs/zerolog/log" "github.com/spf13/cobra" diff --git a/src/cmd/property.go b/src/cmd/property.go index bab6ade3..1de500db 100644 --- a/src/cmd/property.go +++ b/src/cmd/property.go @@ -7,7 +7,7 @@ import ( "os" "strings" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" diff --git a/src/cmd/repository.go b/src/cmd/repository.go index 4ff2b918..557546fd 100644 --- a/src/cmd/repository.go +++ b/src/cmd/repository.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/root.go b/src/cmd/root.go index 39877288..52eb8beb 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/go-resty/resty/v2" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/rubric.go b/src/cmd/rubric.go index ebb453e7..90ea7f7c 100644 --- a/src/cmd/rubric.go +++ b/src/cmd/rubric.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/scorecard.go b/src/cmd/scorecard.go index d0a3aa9d..de0577f1 100644 --- a/src/cmd/scorecard.go +++ b/src/cmd/scorecard.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/secret.go b/src/cmd/secret.go index e3fdca43..7807a402 100644 --- a/src/cmd/secret.go +++ b/src/cmd/secret.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" diff --git a/src/cmd/service.go b/src/cmd/service.go index 4b4945fb..dea67c54 100644 --- a/src/cmd/service.go +++ b/src/cmd/service.go @@ -7,7 +7,7 @@ import ( "os" "strings" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/rs/zerolog/log" diff --git a/src/cmd/system.go b/src/cmd/system.go index 367e6b88..fd06fcb2 100644 --- a/src/cmd/system.go +++ b/src/cmd/system.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/tag.go b/src/cmd/tag.go index 9b099e61..a54e09bf 100644 --- a/src/cmd/tag.go +++ b/src/cmd/tag.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "golang.org/x/exp/slices" "github.com/spf13/cobra" diff --git a/src/cmd/team.go b/src/cmd/team.go index 72431f40..8141e772 100644 --- a/src/cmd/team.go +++ b/src/cmd/team.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/rs/zerolog/log" "github.com/opslevel/cli/common" diff --git a/src/cmd/team_test.go b/src/cmd/team_test.go index 1a0fe2b3..9b0522de 100644 --- a/src/cmd/team_test.go +++ b/src/cmd/team_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/opslevel/cli/cmd" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" ) const ( diff --git a/src/cmd/terraform.go b/src/cmd/terraform.go index fbb9693d..13493358 100644 --- a/src/cmd/terraform.go +++ b/src/cmd/terraform.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/gosimple/slug" "github.com/spf13/cobra" diff --git a/src/cmd/tools.go b/src/cmd/tools.go index 8920f0ea..a0f2c249 100644 --- a/src/cmd/tools.go +++ b/src/cmd/tools.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" ) diff --git a/src/cmd/trigger_definition.go b/src/cmd/trigger_definition.go index a82640aa..8ba3ba60 100644 --- a/src/cmd/trigger_definition.go +++ b/src/cmd/trigger_definition.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/opslevel/cli/common" "github.com/spf13/cobra" diff --git a/src/cmd/user.go b/src/cmd/user.go index 811a9f24..9199d545 100644 --- a/src/cmd/user.go +++ b/src/cmd/user.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/opslevel/cli/common" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) diff --git a/src/cmd/user_test.go b/src/cmd/user_test.go index 189e716c..00a21ef8 100644 --- a/src/cmd/user_test.go +++ b/src/cmd/user_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/opslevel/cli/cmd" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" ) const ( diff --git a/src/common/client.go b/src/common/client.go index 68b73b3d..4290d884 100644 --- a/src/common/client.go +++ b/src/common/client.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" "github.com/spf13/viper" ) diff --git a/src/common/prompts.go b/src/common/prompts.go index 16a76d75..3ab83262 100644 --- a/src/common/prompts.go +++ b/src/common/prompts.go @@ -4,7 +4,7 @@ import ( "fmt" "sort" - "github.com/opslevel/opslevel-go/v2024" + "github.com/opslevel/opslevel-go/v2025" "github.com/manifoldco/promptui" ) diff --git a/src/go.mod b/src/go.mod index adb35199..59288fa7 100644 --- a/src/go.mod +++ b/src/go.mod @@ -1,8 +1,8 @@ module github.com/opslevel/cli -go 1.23.0 +go 1.24 -toolchain go1.23.4 +toolchain go1.24.2 require ( github.com/creasty/defaults v1.8.0 @@ -13,7 +13,7 @@ require ( github.com/manifoldco/promptui v0.9.0 github.com/mitchellh/mapstructure v1.5.0 github.com/open-policy-agent/opa v0.67.1 - github.com/opslevel/opslevel-go/v2024 v2024.12.24 + github.com/opslevel/opslevel-go/v2025 v2025.5.28 github.com/relvacode/iso8601 v1.6.0 github.com/rocktavious/autopilot v0.1.5 github.com/rs/zerolog v1.34.0 @@ -47,7 +47,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.25.0 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect @@ -56,7 +56,7 @@ require ( github.com/gosimple/unidecode v1.0.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect - github.com/hasura/go-graphql-client v0.13.1 // indirect + github.com/hasura/go-graphql-client v0.14.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect diff --git a/src/go.sum b/src/go.sum index 548a9495..0ae67af3 100644 --- a/src/go.sum +++ b/src/go.sum @@ -103,8 +103,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= -github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM= github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= @@ -143,8 +143,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1 github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hasura/go-graphql-client v0.13.1 h1:kKbjhxhpwz58usVl+Xvgah/TDha5K2akNTRQdsEHN6U= -github.com/hasura/go-graphql-client v0.13.1/go.mod h1:k7FF7h53C+hSNFRG3++DdVZWIuHdCaTbI7siTJ//zGQ= +github.com/hasura/go-graphql-client v0.14.3 h1:7La92TuA/FRkVmFd1IN8E+WGW8Lxyn6NKOXAgWcoBDA= +github.com/hasura/go-graphql-client v0.14.3/go.mod h1:jfSZtBER3or+88Q9vFhWHiFMPppfYILRyl+0zsgPIIw= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -193,6 +193,8 @@ github.com/open-policy-agent/opa v0.67.1 h1:rzy26J6g1X+CKknAcx0Vfbt41KqjuSzx4E0A github.com/open-policy-agent/opa v0.67.1/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk= github.com/opslevel/moredefaults v0.0.0-20240529152742-17d1318a3c12 h1:OQZ3W8kbyCcdS8QUWFTnZd6xtdkfhdckc7Paro7nXio= github.com/opslevel/moredefaults v0.0.0-20240529152742-17d1318a3c12/go.mod h1:g2GSXVP6LO+5+AIsnMRPN+BeV86OXuFRTX7HXCDtYeI= +github.com/opslevel/opslevel-go/v2025 v2025.5.28 h1:LCkgLakF0MWIHMmgQHr3ldNjcO8CB4fLcs/LnRZXnHU= +github.com/opslevel/opslevel-go/v2025 v2025.5.28/go.mod h1:QiYGhFPwJj3V4efdiY3gqWlU0ZFMcJDiWPnQkPYKSYA= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= diff --git a/src/submodules/opslevel-go b/src/submodules/opslevel-go index 9a9d9617..ae98dc11 160000 --- a/src/submodules/opslevel-go +++ b/src/submodules/opslevel-go @@ -1 +1 @@ -Subproject commit 9a9d9617088b51312c14ae9dd05bab36032f4544 +Subproject commit ae98dc11b4d1ae3c0b8f5eb5af18144e7365e1bf From f7b8172c0036857e03fd3a645a7d7eb70a8567e0 Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Fri, 30 May 2025 11:34:45 -0500 Subject: [PATCH 02/10] =?UTF-8?q?Cursor=E2=80=99s=20changed=20to=20upgrade?= =?UTF-8?q?=20opslevel-go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/cmd/action.go | 4 ++-- src/cmd/filter.go | 2 +- src/cmd/infra.go | 4 ++-- src/cmd/integration.go | 2 +- src/cmd/property.go | 9 +++------ src/cmd/rubric.go | 6 +++--- src/cmd/scorecard.go | 2 +- src/cmd/secret.go | 10 +++++----- src/cmd/service.go | 37 ++++++------------------------------- src/cmd/tag.go | 14 ++++++++------ src/cmd/team.go | 6 +++--- src/cmd/team_test.go | 2 +- src/cmd/terraform.go | 4 ++-- src/cmd/user.go | 12 +++++++----- src/cmd/user_test.go | 8 +++----- src/common/prompts.go | 4 ++-- src/go.mod | 2 +- src/submodules/opslevel-go | 2 +- 18 files changed, 52 insertions(+), 78 deletions(-) diff --git a/src/cmd/action.go b/src/cmd/action.go index ec44315b..f26e48aa 100644 --- a/src/cmd/action.go +++ b/src/cmd/action.go @@ -58,7 +58,7 @@ EOF`, cobra.CheckErr(err) result, err := getClientGQL().CreateWebhookAction(*input) cobra.CheckErr(err) - fmt.Printf("created webhook action: %s\n", result.Id) + fmt.Printf("created webhook action: %s\n", string(result.CustomActionsId.Id)) default: err := fmt.Errorf("unknown action type: '%s'", actionType) cobra.CheckErr(err) @@ -94,7 +94,7 @@ var listActionCmd = &cobra.Command{ } else { w := common.NewTabWriter("ID", "NAME", "HTTP_METHOD", "WEBHOOK_URL") for _, item := range list { - fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", item.Id, item.Name, item.HTTPMethod, item.WebhookURL) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", string(item.CustomActionsId.Id), item.Name, item.HttpMethod, item.WebhookUrl) } w.Flush() } diff --git a/src/cmd/filter.go b/src/cmd/filter.go index 2e445a3c..a38f0566 100644 --- a/src/cmd/filter.go +++ b/src/cmd/filter.go @@ -108,7 +108,7 @@ EOF`, // by adding in the first argument. updateInput := &opslevel.FilterUpdateInput{ Id: *opslevel.NewID(args[0]), - Name: &input.Name, + Name: opslevel.NewNullableFrom(input.Name), Predicates: input.Predicates, Connective: input.Connective, } diff --git a/src/cmd/infra.go b/src/cmd/infra.go index d4165f48..588e0d96 100644 --- a/src/cmd/infra.go +++ b/src/cmd/infra.go @@ -173,7 +173,7 @@ opslevel list infra -o json | jq 'map(select(.type == "Database") | .data | from w := csv.NewWriter(os.Stdout) w.Write([]string{"NAME", "ID", "ALIASES"}) for _, item := range list { - w.Write([]string{item.Name, item.Id, strings.Join(item.Aliases, "/")}) + w.Write([]string{item.Name, string(item.Id), strings.Join(item.Aliases, "/")}) } w.Flush() } else { @@ -216,7 +216,7 @@ EOF`, cobra.CheckErr(err) result, err := getClientGQL().UpdateInfrastructure(key, *input) cobra.CheckErr(err) - fmt.Println(result.Id) + fmt.Println(string(result.Id)) }, } diff --git a/src/cmd/integration.go b/src/cmd/integration.go index 93cabf6d..c47196d2 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -248,7 +248,7 @@ EOF cobra.CheckErr(err) result, err = getClientGQL().UpdateEventIntegration(opslevel.EventIntegrationUpdateInput{ Id: opslevel.ID(args[0]), - Name: *eventIntegrationInput.Name, + Name: eventIntegrationInput.Name.Value, }) cobra.CheckErr(err) } else { diff --git a/src/cmd/property.go b/src/cmd/property.go index 1de500db..9735e9f0 100644 --- a/src/cmd/property.go +++ b/src/cmd/property.go @@ -61,11 +61,7 @@ var listPropertyCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { var service *opslevel.Service var err error - if opslevel.IsID(args[0]) { - service, err = getClientGQL().GetService(*opslevel.NewID(args[0])) - } else { - service, err = getClientGQL().GetServiceWithAlias(args[0]) - } + service, err = getClientGQL().GetService(args[0]) cobra.CheckErr(err) properties, err := service.GetProperties(getClientGQL(), nil) cobra.CheckErr(err) @@ -227,7 +223,8 @@ func readPropertyDefinitionInput() (*opslevel.PropertyDefinitionInput, error) { propDefInput.Description = opslevel.RefOf(description) } if propertyDisplayStatus, ok := data["propertyDisplayStatus"].(string); ok { - propDefInput.PropertyDisplayStatus = opslevel.RefOf(opslevel.PropertyDisplayStatusEnum(propertyDisplayStatus)) + status := opslevel.PropertyDisplayStatusEnum(propertyDisplayStatus) + propDefInput.PropertyDisplayStatus = &status } return &propDefInput, nil diff --git a/src/cmd/rubric.go b/src/cmd/rubric.go index 90ea7f7c..4db95af7 100644 --- a/src/cmd/rubric.go +++ b/src/cmd/rubric.go @@ -131,13 +131,13 @@ var listLevelCmd = &cobra.Command{ Short: "Lists rubric levels", Long: `Lists rubric levels`, Run: func(cmd *cobra.Command, args []string) { - list, err := getClientGQL().ListLevels() + resp, err := getClientGQL().ListLevels(nil) cobra.CheckErr(err) if isJsonOutput() { - common.JsonPrint(json.MarshalIndent(list, "", " ")) + common.JsonPrint(json.MarshalIndent(resp.Nodes, "", " ")) } else { w := common.NewTabWriter("NAME", "ALIAS", "ID") - for _, item := range list { + for _, item := range resp.Nodes { fmt.Fprintf(w, "%s\t%s\t%s\t\n", item.Name, item.Alias, item.Id) } w.Flush() diff --git a/src/cmd/scorecard.go b/src/cmd/scorecard.go index de0577f1..ec62b515 100644 --- a/src/cmd/scorecard.go +++ b/src/cmd/scorecard.go @@ -73,7 +73,7 @@ opslevel list scorecards -o json | jq 'map( {(.Name): (.ServiceCount)} )' } else { w := common.NewTabWriter("ID", "NAME", "PASSING_CHECKS", "CHECKS_COUNT", "SERVICE_COUNT") for _, item := range list { - fmt.Fprintf(w, "%s\t%s\t%d\t%d\t%d\n", item.Id, item.Name, item.PassingChecks, item.ChecksCount, item.ServiceCount) + fmt.Fprintf(w, "%s\t%s\t%d\t%d\t%d\n", item.Id, item.Name, item.PassingChecks, item.TotalChecks, item.ServiceCount) } w.Flush() } diff --git a/src/cmd/secret.go b/src/cmd/secret.go index 7807a402..3f8614f9 100644 --- a/src/cmd/secret.go +++ b/src/cmd/secret.go @@ -38,7 +38,7 @@ EOF`, newSecret, err := getClientGQL().CreateSecret(secretAlias, *input) cobra.CheckErr(err) - fmt.Println(newSecret.ID) + fmt.Printf(string(newSecret.Id)) }, } @@ -53,7 +53,7 @@ var getSecretCmd = &cobra.Command{ result, err := getClientGQL().GetSecret(identifier) cobra.CheckErr(err) - common.WasFound(result.ID == "", identifier) + common.WasFound(result.Id == "", identifier) if isYamlOutput() { common.YamlPrint(result) } else { @@ -77,7 +77,7 @@ var listSecretsCmd = &cobra.Command{ } else { w := common.NewTabWriter("ALIAS", "ID", "OWNER", "UPDATED_AT") for _, item := range list { - fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", item.Alias, item.ID, item.Owner.Alias, item.Timestamps.UpdatedAt.Time) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", item.Alias, item.Id, item.Owner.Alias, item.Timestamps.UpdatedAt.Time) } w.Flush() } @@ -102,7 +102,7 @@ EOF`, cobra.CheckErr(err) secret, err := getClientGQL().UpdateSecret(secretId, *input) cobra.CheckErr(err) - fmt.Println(secret.ID) + fmt.Printf(string(secret.Id)) }, } @@ -116,7 +116,7 @@ var deleteSecretCmd = &cobra.Command{ secretId := args[0] err := getClientGQL().DeleteSecret(secretId) cobra.CheckErr(err) - fmt.Printf("deleted '%s' secret\n", secretId) + fmt.Printf("deleted secret: %s\n", secretId) }, } diff --git a/src/cmd/service.go b/src/cmd/service.go index dea67c54..d9e9f61b 100644 --- a/src/cmd/service.go +++ b/src/cmd/service.go @@ -121,13 +121,13 @@ var listServiceCmd = &cobra.Command{ w := csv.NewWriter(os.Stdout) w.Write([]string{"NAME", "ID", "TYPE", "ALIASES"}) for _, item := range list { - w.Write([]string{item.Name, string(item.Id), item.Type.Alias, strings.Join(item.Aliases, "/")}) + w.Write([]string{item.Name, string(item.Id), item.Type.Aliases[0], strings.Join(item.Aliases, "/")}) } w.Flush() } else { w := common.NewTabWriter("NAME", "ID", "TYPE", "ALIASES") for _, item := range list { - fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", item.Name, item.Id, item.Type.Alias, strings.Join(item.Aliases, ",")) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", item.Name, item.Id, item.Type.Aliases[0], strings.Join(item.Aliases, ",")) } w.Flush() } @@ -159,8 +159,7 @@ EOF`, Run: func(cmd *cobra.Command, args []string) { input, err := readResourceInput[opslevel.ServiceUpdateInput]() cobra.CheckErr(err) - convertedInput := convertServiceUpdateInput(*input) - service, err := getClientGQL().UpdateService(convertedInput) + service, err := getClientGQL().UpdateService(*input) cobra.CheckErr(err) common.JsonPrint(json.MarshalIndent(service, "", " ")) }, @@ -216,13 +215,13 @@ EOF tier := reader.Text("Tier") if tier != "" { if item, ok := opslevel.Cache.Tiers[tier]; ok { - input.TierAlias = &item.Alias + input.TierAlias = opslevel.RefOf(item.Alias) } } lifecycle := reader.Text("Lifecycle") if lifecycle != "" { if item, ok := opslevel.Cache.Lifecycles[lifecycle]; ok { - input.LifecycleAlias = &item.Alias + input.LifecycleAlias = opslevel.RefOf(item.Alias) } } owner := reader.Text("Owner") @@ -257,23 +256,6 @@ func init() { importCmd.AddCommand(importServicesCmd) } -func convertServiceUpdateInput(input opslevel.ServiceUpdateInput) opslevel.ServiceUpdateInputV2 { - return opslevel.ServiceUpdateInputV2{ - Alias: NullableString(input.Alias), - Description: NullableString(input.Description), - Framework: NullableString(input.Framework), - Id: input.Id, - Language: NullableString(input.Language), - LifecycleAlias: NullableString(input.LifecycleAlias), - Name: NullableString(input.Name), - OwnerInput: input.OwnerInput, - Parent: input.Parent, - SkipAliasesValidation: input.SkipAliasesValidation, - Product: NullableString(input.Product), - TierAlias: NullableString(input.TierAlias), - } -} - func NullableString(value *string) *opslevel.Nullable[string] { if value == nil { return nil @@ -285,14 +267,7 @@ func NullableString(value *string) *opslevel.Nullable[string] { } func getService(identifier string) (*opslevel.Service, error) { - var err error - var service *opslevel.Service - - if opslevel.IsID(identifier) { - service, err = getClientGQL().GetService(opslevel.ID(identifier)) - } else { - service, err = getClientGQL().GetServiceWithAlias(identifier) - } + service, err := getClientGQL().GetService(identifier) if service == nil || !opslevel.IsID(string(service.Id)) { err = fmt.Errorf("service with identifier '%s' not found", identifier) } diff --git a/src/cmd/tag.go b/src/cmd/tag.go index a54e09bf..347cd3b9 100644 --- a/src/cmd/tag.go +++ b/src/cmd/tag.go @@ -50,10 +50,11 @@ opslevel create tag --type=Infra my-infra-alias foo bar input := opslevel.TagAssignInput{Tags: []opslevel.TagInput{tagInput}} if opslevel.IsID(resource) { - input.Id = opslevel.NewID(resource) + input.Id = opslevel.RefOf(opslevel.ID(resource)) } else { input.Alias = opslevel.RefOf(resource) - input.Type = opslevel.RefOf(opslevel.TaggableResource(resourceType)) + resourceType := opslevel.TaggableResource(resourceType) + input.Type = &resourceType } result, err := getClientGQL().AssignTag(input) @@ -67,8 +68,9 @@ opslevel create tag --type=Infra my-infra-alias foo bar if opslevel.IsID(resource) { input.Id = opslevel.NewID(resource) } else { - input.Alias = opslevel.RefOf(resource) - input.Type = opslevel.RefOf(opslevel.TaggableResource(resourceType)) + input.Alias = &resource + resourceType := opslevel.TaggableResource(resourceType) + input.Type = &resourceType } result, err := getClientGQL().CreateTag(input) @@ -155,8 +157,8 @@ opslevel update tag XXX_TAG_ID_XXX foo baz input := opslevel.TagUpdateInput{ Id: opslevel.ID(tag), - Key: opslevel.RefOf(key), - Value: opslevel.RefOf(value), + Key: &key, + Value: &value, } result, err := getClientGQL().UpdateTag(input) diff --git a/src/cmd/team.go b/src/cmd/team.go index 8141e772..f702e92a 100644 --- a/src/cmd/team.go +++ b/src/cmd/team.go @@ -117,12 +117,12 @@ opslevel create contact --type=email my-team team@example.com "Mailing List"`, } cobra.CheckErr(err) common.WasFound(team.Id == "", key) - contactInput := opslevel.CreateContactSlack(address, &displayName) + contactInput := opslevel.CreateContactSlack(displayName, opslevel.RefOf(address)) switch contactType { case string(opslevel.ContactTypeEmail): - contactInput = opslevel.CreateContactEmail(address, &displayName) + contactInput = opslevel.CreateContactEmail(displayName, opslevel.RefOf(address)) case string(opslevel.ContactTypeWeb): - contactInput = opslevel.CreateContactWeb(address, &displayName) + contactInput = opslevel.CreateContactWeb(displayName, opslevel.RefOf(address)) } contact, err := getClientGQL().AddContact(team.TeamId.Alias, contactInput) cobra.CheckErr(err) diff --git a/src/cmd/team_test.go b/src/cmd/team_test.go index 9b0522de..b39b5be0 100644 --- a/src/cmd/team_test.go +++ b/src/cmd/team_test.go @@ -30,7 +30,7 @@ func Test_TeamCRUD(t *testing.T) { t.Fatal(err) } if createdTeam.Name != teamToCreate.Name || - createdTeam.Responsibilities != *teamToCreate.Responsibilities { + createdTeam.Responsibilities != (*teamToCreate.Responsibilities).Value { t.Errorf("Create 'team' failed, expected team '%+v' but got '%+v'", teamToCreate, createdTeam) } diff --git a/src/cmd/terraform.go b/src/cmd/terraform.go index 13493358..e8b503c0 100644 --- a/src/cmd/terraform.go +++ b/src/cmd/terraform.go @@ -380,9 +380,9 @@ func exportRubric(c *opslevel.Client, config *os.File, shell *os.File) { index = %d } ` - levels, err := c.ListLevels() + levels, err := c.ListLevels(nil) cobra.CheckErr(err) - for _, level := range levels { + for _, level := range levels.Nodes { config.WriteString(templateConfig(levelConfig, level.Alias, level.Name, level.Description, level.Index)) shell.WriteString(fmt.Sprintf("terraform import opslevel_rubric_level.%s %s\n", level.Alias, level.Id)) } diff --git a/src/cmd/user.go b/src/cmd/user.go index 9199d545..4bb8ad8c 100644 --- a/src/cmd/user.go +++ b/src/cmd/user.go @@ -53,7 +53,7 @@ opslevel create user "jane@example.com" "Jane Doe" Admin --skip-send-invite --sk userInput := opslevel.UserInput{ Name: opslevel.RefOf(name), - Role: opslevel.RefOf(role), + Role: &role, SkipWelcomeEmail: opslevel.RefOf(skipEmail), } resource, err := getClientGQL().InviteUser(email, userInput, !skipSendInvite) @@ -130,13 +130,13 @@ opslevel list user -o json | jq 'map({"key": .Name, "value": .Role}) | from_entr w := csv.NewWriter(os.Stdout) w.Write([]string{"ID", "EMAIL", "NAME", "ROLE", "URL"}) for _, item := range list { - w.Write([]string{string(item.Id), item.Email, item.Name, string(item.Role), item.HTMLUrl}) + w.Write([]string{string(item.Id), item.Email, item.Name, string(item.Role), item.HtmlUrl}) } w.Flush() } else { - w := common.NewTabWriter("NAME", "EMAIL", "ID") + w := common.NewTabWriter("NAME", "EMAIL", "ROLE", "ID") for _, item := range list { - fmt.Fprintf(w, "%s\t%s\t%s\t\n", item.Name, item.Email, item.Id) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", item.Name, item.Email, string(item.Role), item.Id) } w.Flush() } @@ -191,10 +191,12 @@ EOF userRole := opslevel.UserRoleUser if slices.Contains(opslevel.AllUserRole, role) { userRole = opslevel.UserRole(role) + } else { + log.Warn().Msgf("user '%s' has invalid role '%s' defaulting role to 'User'", name, role) } input := opslevel.UserInput{ Name: opslevel.RefOf(name), - Role: opslevel.RefOf(userRole), + Role: &userRole, SkipWelcomeEmail: opslevel.RefOf(skipWelcomeEmail), } user, err := getClientGQL().InviteUser(email, input, !skipSendInvite) diff --git a/src/cmd/user_test.go b/src/cmd/user_test.go index 00a21ef8..b473481e 100644 --- a/src/cmd/user_test.go +++ b/src/cmd/user_test.go @@ -9,7 +9,7 @@ import ( "github.com/opslevel/opslevel-go/v2025" ) -const ( +var ( defaultUserRole = opslevel.UserRoleUser userFileName = "test_user.yaml" userName = "CLI Test User" @@ -17,8 +17,7 @@ const ( func Test_UserCRUD(t *testing.T) { expectedUser := opslevel.User{ - UserId: opslevel.UserId{Email: "testcli+pat@opslevel.com"}, - Name: userName, + UserId: opslevel.UserId{Email: "testcli+pat@opslevel.com", Name: userName}, } // Create User userId, err := createUser(expectedUser) @@ -34,14 +33,13 @@ func Test_UserCRUD(t *testing.T) { if createdUser.Name != expectedUser.Name || createdUser.Email != expectedUser.Email || string(createdUser.Role) != string(defaultUserRole) || - !strings.HasPrefix(createdUser.HTMLUrl, "https://app.opslevel.com/users/") { + !strings.HasPrefix(createdUser.HtmlUrl, "https://app.opslevel.com/users/") { t.Errorf("Create 'user' failed, expected user '%+v' but got '%+v'", expectedUser, createdUser) } // Update User expectedUpdatedUser := opslevel.User{ UserId: createdUser.UserId, - Name: createdUser.Name, Role: opslevel.UserRoleTeamMember, } updatedUserId, err := updateUser(string(createdUser.Id), expectedUpdatedUser) diff --git a/src/common/prompts.go b/src/common/prompts.go index 3ab83262..4db67b55 100644 --- a/src/common/prompts.go +++ b/src/common/prompts.go @@ -37,7 +37,7 @@ func PromptForCategories(client *opslevel.Client) (*opslevel.Category, error) { } func PromptForLevels(client *opslevel.Client) (*opslevel.Level, error) { - list, err := client.ListLevels() + resp, err := client.ListLevels(nil) if err != nil { return nil, err } @@ -53,7 +53,7 @@ func PromptForLevels(client *opslevel.Client) (*opslevel.Level, error) { } var filteredList []opslevel.Level - for _, val := range list { + for _, val := range resp.Nodes { if val.Index != 0 { filteredList = append(filteredList, val) } diff --git a/src/go.mod b/src/go.mod index 59288fa7..362e06ac 100644 --- a/src/go.mod +++ b/src/go.mod @@ -101,4 +101,4 @@ require ( sigs.k8s.io/yaml v1.4.0 // indirect ) -replace github.com/opslevel/opslevel-go/v2024 => ./submodules/opslevel-go +replace github.com/opslevel/opslevel-go/v2025 => ./submodules/opslevel-go diff --git a/src/submodules/opslevel-go b/src/submodules/opslevel-go index ae98dc11..9192710d 160000 --- a/src/submodules/opslevel-go +++ b/src/submodules/opslevel-go @@ -1 +1 @@ -Subproject commit ae98dc11b4d1ae3c0b8f5eb5af18144e7365e1bf +Subproject commit 9192710ddc40382025d52397711ec916dcdc7c0c From b5bdbb7dde20d9898233a3924b87818affd9de31 Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Fri, 30 May 2025 13:25:21 -0500 Subject: [PATCH 03/10] copilot review feedback --- src/cmd/integration.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/cmd/integration.go b/src/cmd/integration.go index c47196d2..854727ad 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -3,6 +3,7 @@ package cmd import ( "encoding/json" "fmt" + "github.com/rs/zerolog/log" "slices" "github.com/mitchellh/mapstructure" @@ -32,9 +33,9 @@ type IntegrationInputType struct { type IntegrationInput interface { opslevel.AWSIntegrationInput | - opslevel.AzureResourcesIntegrationInput | - opslevel.EventIntegrationInput | - opslevel.GoogleCloudIntegrationInput + opslevel.AzureResourcesIntegrationInput | + opslevel.EventIntegrationInput | + opslevel.GoogleCloudIntegrationInput } func validateIntegrationInput() (*IntegrationInputType, error) { @@ -246,11 +247,17 @@ EOF input.Spec["type"] = input.Kind eventIntegrationInput, err := readIntegrationInput[opslevel.EventIntegrationInput](input) cobra.CheckErr(err) - result, err = getClientGQL().UpdateEventIntegration(opslevel.EventIntegrationUpdateInput{ - Id: opslevel.ID(args[0]), - Name: eventIntegrationInput.Name.Value, - }) - cobra.CheckErr(err) + if eventIntegrationInput.Name == nil { + apiInput := opslevel.EventIntegrationUpdateInput{ + Id: opslevel.ID(args[0]), + Name: eventIntegrationInput.Name.Value, + } + result, err = getClientGQL().UpdateEventIntegration(apiInput) + cobra.CheckErr(err) + } else { + log.Warn().Msgf("event integration 'name' cannot be updated as no name field was provided") + return + } } else { switch input.Kind { case IntegrationTypeAWS: From 054a4ee5f8f80413951367b5a78e0cf8ca2dd7d1 Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Fri, 30 May 2025 13:50:14 -0500 Subject: [PATCH 04/10] run task fix --- src/cmd/integration.go | 9 +++++---- src/cmd/secret.go | 4 ++-- src/go.mod | 10 +++++----- src/go.sum | 30 ++++++++++++++---------------- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/cmd/integration.go b/src/cmd/integration.go index 854727ad..38aae1ec 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -3,9 +3,10 @@ package cmd import ( "encoding/json" "fmt" - "github.com/rs/zerolog/log" "slices" + "github.com/rs/zerolog/log" + "github.com/mitchellh/mapstructure" "github.com/opslevel/cli/common" @@ -33,9 +34,9 @@ type IntegrationInputType struct { type IntegrationInput interface { opslevel.AWSIntegrationInput | - opslevel.AzureResourcesIntegrationInput | - opslevel.EventIntegrationInput | - opslevel.GoogleCloudIntegrationInput + opslevel.AzureResourcesIntegrationInput | + opslevel.EventIntegrationInput | + opslevel.GoogleCloudIntegrationInput } func validateIntegrationInput() (*IntegrationInputType, error) { diff --git a/src/cmd/secret.go b/src/cmd/secret.go index 3f8614f9..57138702 100644 --- a/src/cmd/secret.go +++ b/src/cmd/secret.go @@ -38,7 +38,7 @@ EOF`, newSecret, err := getClientGQL().CreateSecret(secretAlias, *input) cobra.CheckErr(err) - fmt.Printf(string(newSecret.Id)) + fmt.Print("%s", string(newSecret.Id)) }, } @@ -102,7 +102,7 @@ EOF`, cobra.CheckErr(err) secret, err := getClientGQL().UpdateSecret(secretId, *input) cobra.CheckErr(err) - fmt.Printf(string(secret.Id)) + fmt.Print("%s", string(secret.Id)) }, } diff --git a/src/go.mod b/src/go.mod index 362e06ac..7c73e9a4 100644 --- a/src/go.mod +++ b/src/go.mod @@ -39,7 +39,7 @@ require ( github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect github.com/go-ini/ini v1.67.0 // indirect @@ -92,10 +92,10 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.37.0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.24.0 // indirect + golang.org/x/crypto v0.38.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/src/go.sum b/src/go.sum index 0ae67af3..27b79c9a 100644 --- a/src/go.sum +++ b/src/go.sum @@ -78,8 +78,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -193,8 +193,6 @@ github.com/open-policy-agent/opa v0.67.1 h1:rzy26J6g1X+CKknAcx0Vfbt41KqjuSzx4E0A github.com/open-policy-agent/opa v0.67.1/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk= github.com/opslevel/moredefaults v0.0.0-20240529152742-17d1318a3c12 h1:OQZ3W8kbyCcdS8QUWFTnZd6xtdkfhdckc7Paro7nXio= github.com/opslevel/moredefaults v0.0.0-20240529152742-17d1318a3c12/go.mod h1:g2GSXVP6LO+5+AIsnMRPN+BeV86OXuFRTX7HXCDtYeI= -github.com/opslevel/opslevel-go/v2025 v2025.5.28 h1:LCkgLakF0MWIHMmgQHr3ldNjcO8CB4fLcs/LnRZXnHU= -github.com/opslevel/opslevel-go/v2025 v2025.5.28/go.mod h1:QiYGhFPwJj3V4efdiY3gqWlU0ZFMcJDiWPnQkPYKSYA= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= @@ -287,17 +285,17 @@ go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -309,14 +307,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From b78dcccc6de314893e527e2a397291e36c1019da Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 2 Jun 2025 13:49:07 -0500 Subject: [PATCH 05/10] Apply suggestions from code review --- src/cmd/integration.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/integration.go b/src/cmd/integration.go index 38aae1ec..8ab41567 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -248,7 +248,7 @@ EOF input.Spec["type"] = input.Kind eventIntegrationInput, err := readIntegrationInput[opslevel.EventIntegrationInput](input) cobra.CheckErr(err) - if eventIntegrationInput.Name == nil { + if eventIntegrationInput.Name != nil { apiInput := opslevel.EventIntegrationUpdateInput{ Id: opslevel.ID(args[0]), Name: eventIntegrationInput.Name.Value, From 724265c05eb67204e827f7724a46091f838623a8 Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Tue, 3 Jun 2025 11:46:54 -0500 Subject: [PATCH 06/10] update submodule of opslevel-go --- src/submodules/opslevel-go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/submodules/opslevel-go b/src/submodules/opslevel-go index 9192710d..095e4b04 160000 --- a/src/submodules/opslevel-go +++ b/src/submodules/opslevel-go @@ -1 +1 @@ -Subproject commit 9192710ddc40382025d52397711ec916dcdc7c0c +Subproject commit 095e4b041e53c38dff17aa0a23501e0a52c79d07 From e8ad73f44e65039bb8f3cd4c6cbe5fd544d297ff Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Wed, 4 Jun 2025 15:52:13 -0500 Subject: [PATCH 07/10] Fix lint --- src/cmd/secret.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/secret.go b/src/cmd/secret.go index 57138702..231a6eb9 100644 --- a/src/cmd/secret.go +++ b/src/cmd/secret.go @@ -38,7 +38,7 @@ EOF`, newSecret, err := getClientGQL().CreateSecret(secretAlias, *input) cobra.CheckErr(err) - fmt.Print("%s", string(newSecret.Id)) + fmt.Printf("%s", string(newSecret.Id)) }, } @@ -102,7 +102,7 @@ EOF`, cobra.CheckErr(err) secret, err := getClientGQL().UpdateSecret(secretId, *input) cobra.CheckErr(err) - fmt.Print("%s", string(secret.Id)) + fmt.Printf("%s", string(secret.Id)) }, } From d9f90fc89248d660407280cf8a8a39436ede9ac3 Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Wed, 4 Jun 2025 15:52:19 -0500 Subject: [PATCH 08/10] Fix Filters --- src/cmd/filter.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/cmd/filter.go b/src/cmd/filter.go index a38f0566..840e3bda 100644 --- a/src/cmd/filter.go +++ b/src/cmd/filter.go @@ -100,19 +100,11 @@ EOF`, Args: cobra.ExactArgs(1), ArgAliases: []string{"ID"}, Run: func(cmd *cobra.Command, args []string) { - input, err := readResourceInput[opslevel.FilterCreateInput]() + input, err := readResourceInput[opslevel.FilterUpdateInput]() cobra.CheckErr(err) + input.Id = *opslevel.NewID(args[0]) - // hack: in the future all ObjectUpdateInput and ObjectCreateInput - // will be merged into ObjectInput. for now, create an update input - // by adding in the first argument. - updateInput := &opslevel.FilterUpdateInput{ - Id: *opslevel.NewID(args[0]), - Name: opslevel.NewNullableFrom(input.Name), - Predicates: input.Predicates, - Connective: input.Connective, - } - filter, err := getClientGQL().UpdateFilter(*updateInput) + filter, err := getClientGQL().UpdateFilter(*input) cobra.CheckErr(err) common.JsonPrint(json.MarshalIndent(filter, "", " ")) }, From 32c5b15e3fd4dc5a57ca2fa67f9cb446e0b13fcd Mon Sep 17 00:00:00 2001 From: Kyle Rockman Date: Wed, 4 Jun 2025 15:52:42 -0500 Subject: [PATCH 09/10] Fix Mapstructure problem on event integrations --- src/cmd/integration.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/cmd/integration.go b/src/cmd/integration.go index 8ab41567..84e89c52 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -26,6 +26,11 @@ var AllIntegrationType = []IntegrationType{IntegrationTypeAWS, IntegrationTypeAz var IntegrationConfigCurrentVersion = "1" +type EventIntegrationInputDTO struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Type opslevel.EventIntegrationEnum `json:"type" yaml:"type" example:"apiDoc"` +} + type IntegrationInputType struct { Version string `yaml:"version"` Kind IntegrationType @@ -34,9 +39,9 @@ type IntegrationInputType struct { type IntegrationInput interface { opslevel.AWSIntegrationInput | - opslevel.AzureResourcesIntegrationInput | - opslevel.EventIntegrationInput | - opslevel.GoogleCloudIntegrationInput + opslevel.AzureResourcesIntegrationInput | + EventIntegrationInputDTO | + opslevel.GoogleCloudIntegrationInput } func validateIntegrationInput() (*IntegrationInputType, error) { @@ -124,12 +129,11 @@ EOF var result *opslevel.Integration if slices.Contains(opslevel.AllEventIntegrationEnum, string(input.Kind)) { input.Spec["type"] = input.Kind - eventIntegrationInput, err := readIntegrationInput[opslevel.EventIntegrationInput](input) - integrationTypeEnum := opslevel.EventIntegrationEnum(eventIntegrationInput.Type) + eventIntegrationInput, err := readIntegrationInput[EventIntegrationInputDTO](input) cobra.CheckErr(err) result, err = getClientGQL().CreateEventIntegration(opslevel.EventIntegrationInput{ - Name: eventIntegrationInput.Name, - Type: integrationTypeEnum, + Name: opslevel.NewNullableFrom(eventIntegrationInput.Name), + Type: eventIntegrationInput.Type, }) cobra.CheckErr(err) } else { @@ -246,15 +250,17 @@ EOF var result *opslevel.Integration if slices.Contains(opslevel.AllEventIntegrationEnum, string(input.Kind)) { input.Spec["type"] = input.Kind - eventIntegrationInput, err := readIntegrationInput[opslevel.EventIntegrationInput](input) + eventIntegrationInput, err := readIntegrationInput[EventIntegrationInputDTO](input) cobra.CheckErr(err) - if eventIntegrationInput.Name != nil { + if eventIntegrationInput.Name != "" { apiInput := opslevel.EventIntegrationUpdateInput{ Id: opslevel.ID(args[0]), - Name: eventIntegrationInput.Name.Value, + Name: eventIntegrationInput.Name, } result, err = getClientGQL().UpdateEventIntegration(apiInput) + cobra.CheckErr(err) + } else { log.Warn().Msgf("event integration 'name' cannot be updated as no name field was provided") return From 23f596846c3cd54965e1c0560c19d35db2bb9656 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 24 Jun 2025 11:31:12 -0500 Subject: [PATCH 10/10] Setup e2e tests for some resources (#404) * Setup e2e tests for domain * PR feedback * Checkpoint * Expand test coverage * Add system test * First pass at fixing example command * more tweaks * Fix CI * Fix up all example commands * More fixes * fixes * more fixes for removal of old code * Update Taskfile.yml * fix e2e integration tests * few more tweaks after testing manually --- Taskfile.yml | 6 + src/cmd/action.go | 11 +- src/cmd/alias.go | 5 +- src/cmd/dependency.go | 8 +- src/cmd/domain.go | 7 +- src/cmd/example.go | 34 ++---- src/cmd/filter.go | 12 +- src/cmd/infra.go | 17 ++- src/cmd/integration.go | 6 +- src/cmd/property.go | 28 ++++- src/cmd/rubric.go | 8 +- src/cmd/scorecard.go | 7 +- src/cmd/secret.go | 5 +- src/cmd/service.go | 21 +++- src/cmd/system.go | 8 +- src/cmd/tag.go | 5 +- src/cmd/team.go | 26 ++++- src/cmd/trigger_definition.go | 5 +- src/cmd/user.go | 4 +- src/e2e/domain_test.go | 83 ++++++++++++++ src/e2e/helpers.go | 194 +++++++++++++++++++++++++++++++++ src/e2e/infrastructure_test.go | 85 +++++++++++++++ src/e2e/service_test.go | 91 ++++++++++++++++ src/e2e/system_test.go | 85 +++++++++++++++ src/e2e/team_test.go | 86 +++++++++++++++ src/go.mod | 10 +- src/go.sum | 32 +++--- src/submodules/opslevel-go | 2 +- 28 files changed, 813 insertions(+), 78 deletions(-) create mode 100644 src/e2e/domain_test.go create mode 100644 src/e2e/helpers.go create mode 100644 src/e2e/infrastructure_test.go create mode 100644 src/e2e/service_test.go create mode 100644 src/e2e/system_test.go create mode 100644 src/e2e/team_test.go diff --git a/Taskfile.yml b/Taskfile.yml index 7c1ac434..16116292 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -56,6 +56,12 @@ tasks: cmds: - go test -race -coverprofile=coverage.txt -covermode=atomic -v ./cmd/... {{ .CLI_ARGS }} + test-e2e: + desc: Run end to end Integration tests + dir: "{{.SRC_DIR}}" + cmds: + - go test -v ./e2e/... {{ .CLI_ARGS }} + update-opslevel-go: desc: Update opslevel-go version to latest release dir: "{{.SRC_DIR}}" diff --git a/src/cmd/action.go b/src/cmd/action.go index f26e48aa..a0f610e7 100644 --- a/src/cmd/action.go +++ b/src/cmd/action.go @@ -17,7 +17,16 @@ var exampleActionCmd = &cobra.Command{ Short: "Example action", Long: `Example action`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.CustomActionsWebhookActionCreateInput]()) + fmt.Println(getExample(opslevel.CustomActionsWebhookActionCreateInput{ + Name: "example_name", + Description: opslevel.RefOf("example_description"), + WebhookUrl: "example_webhook_url", + HttpMethod: opslevel.CustomActionsHttpMethodEnumPost, + Headers: &opslevel.JSON{ + "example_header": "example_value", + }, + LiquidTemplate: opslevel.RefOf("example_liquid_template"), + })) }, } diff --git a/src/cmd/alias.go b/src/cmd/alias.go index b26c1270..cd3c530f 100644 --- a/src/cmd/alias.go +++ b/src/cmd/alias.go @@ -16,7 +16,10 @@ var exampleAliasCmd = &cobra.Command{ Short: "Example alias", Long: `Example alias`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.AliasCreateInput]()) + fmt.Println(getExample(opslevel.AliasCreateInput{ + OwnerId: opslevel.ID("Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk"), + Alias: "example_alias", + })) }, } diff --git a/src/cmd/dependency.go b/src/cmd/dependency.go index 3fe55c91..b7c6a715 100644 --- a/src/cmd/dependency.go +++ b/src/cmd/dependency.go @@ -20,7 +20,13 @@ var exampleServiceDependencyCmd = &cobra.Command{ Short: "Example service dependency", Long: `Example service dependency`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.ServiceDependencyCreateInput]()) + fmt.Println(getExample(opslevel.ServiceDependencyCreateInput{ + DependencyKey: opslevel.ServiceDependencyKey{ + SourceIdentifier: opslevel.NewIdentifier("example_source"), + DestinationIdentifier: opslevel.NewIdentifier("example_destination"), + }, + Notes: opslevel.RefOf("example_notes"), + })) }, } diff --git a/src/cmd/domain.go b/src/cmd/domain.go index 1b64e48e..277a75a2 100644 --- a/src/cmd/domain.go +++ b/src/cmd/domain.go @@ -17,7 +17,12 @@ var exampleDomainCmd = &cobra.Command{ Short: "Example Domain", Long: `Example Domain`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.DomainInput]()) + fmt.Println(getExample(opslevel.DomainInput{ + Name: opslevel.RefOf("example_name"), + Description: opslevel.RefOf("example_description"), + OwnerId: opslevel.RefOf(opslevel.ID("Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk")), + Note: opslevel.RefOf("example_note"), + })) }, } diff --git a/src/cmd/example.go b/src/cmd/example.go index 92fd8d15..9effd75e 100644 --- a/src/cmd/example.go +++ b/src/cmd/example.go @@ -3,7 +3,6 @@ package cmd import ( "encoding/json" - "github.com/opslevel/opslevel-go/v2025" "github.com/spf13/cobra" "github.com/spf13/viper" "gopkg.in/yaml.v2" @@ -17,35 +16,16 @@ var exampleCmd = &cobra.Command{ Long: "Examples of OpsLevel resources in different formats", } -func getExample[T any]() string { +func getExample[T any](v T) string { + var out []byte + var err error if exampleIsJson { - return getJson[T]() + out, err = json.Marshal(v) + } else { + out, err = yaml.Marshal(v) } - return getYaml[T]() -} - -func getJson[T any]() string { - var ( - out []byte - err error - ) - t := opslevel.NewExampleOf[T]() - out, err = json.Marshal(t) - if err != nil { - panic("unexpected error getting example json") - } - return string(out) -} - -func getYaml[T any]() string { - var ( - out []byte - err error - ) - t := opslevel.NewExampleOf[T]() - out, err = yaml.Marshal(t) if err != nil { - panic("unexpected error getting example yaml") + panic("unexpected error getting example") } return string(out) } diff --git a/src/cmd/filter.go b/src/cmd/filter.go index 840e3bda..2c3c91dd 100644 --- a/src/cmd/filter.go +++ b/src/cmd/filter.go @@ -15,7 +15,17 @@ var exampleFilterCmd = &cobra.Command{ Short: "Example filter", Long: `Example filter`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.FilterCreateInput]()) + fmt.Println(getExample(opslevel.FilterCreateInput{ + Name: "example_name", + Predicates: &[]opslevel.FilterPredicateInput{ + { + Key: opslevel.PredicateKeyEnumAliases, + Type: opslevel.PredicateTypeEnumEquals, + Value: opslevel.RefOf("example_value"), + CaseSensitive: opslevel.RefOf(false), + }, + }, + })) }, } diff --git a/src/cmd/infra.go b/src/cmd/infra.go index 588e0d96..21547737 100644 --- a/src/cmd/infra.go +++ b/src/cmd/infra.go @@ -20,7 +20,22 @@ var exampleInfraCmd = &cobra.Command{ Short: "Example infrastructure resource", Long: `Example infrastructure resource`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.InfrastructureResourceInput]()) + fmt.Println(getExample(opslevel.InfraInput{ + Schema: "example_schema", + Owner: opslevel.NewID("Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk"), + Provider: &opslevel.InfraProviderInput{ + Account: "example_account", + Name: "example_provider_name", + Type: "example_provider_type", + URL: "example_external_url", + }, + Data: &opslevel.JSON{ + "name": "my-big-query", + "endpoint": "https://google.com", + "engine": "BigQuery", + "replica": false, + }, + })) }, } diff --git a/src/cmd/integration.go b/src/cmd/integration.go index 84e89c52..e36d243b 100644 --- a/src/cmd/integration.go +++ b/src/cmd/integration.go @@ -39,9 +39,9 @@ type IntegrationInputType struct { type IntegrationInput interface { opslevel.AWSIntegrationInput | - opslevel.AzureResourcesIntegrationInput | - EventIntegrationInputDTO | - opslevel.GoogleCloudIntegrationInput + opslevel.AzureResourcesIntegrationInput | + EventIntegrationInputDTO | + opslevel.GoogleCloudIntegrationInput } func validateIntegrationInput() (*IntegrationInputType, error) { diff --git a/src/cmd/property.go b/src/cmd/property.go index 9735e9f0..f37f72fc 100644 --- a/src/cmd/property.go +++ b/src/cmd/property.go @@ -14,13 +14,31 @@ import ( "github.com/spf13/cobra" ) +func buildExamplePropertyInput() string { + return getExample(opslevel.PropertyInput{ + Definition: *opslevel.NewIdentifier("example_definition"), + Owner: *opslevel.NewIdentifier("example_owner"), + Value: opslevel.JsonString("example_value"), + }) +} + +func buildExamplePropertyDefinitionInput() string { + return getExample(opslevel.PropertyDefinitionInput{ + Name: opslevel.RefOf("example_name"), + Description: opslevel.RefOf("example_description"), + Schema: &opslevel.JSONSchema{ + "type": "string", + }, + }) +} + var examplePropertyCmd = &cobra.Command{ Use: "property", Aliases: []string{"prop"}, Short: "Example Property", Long: `Example Property`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.PropertyInput]()) + fmt.Println(buildExamplePropertyInput()) }, } @@ -104,7 +122,7 @@ EOF cat << EOF | opslevel assign property -f - %s -EOF`, getYaml[opslevel.PropertyInput]()), +EOF`, buildExamplePropertyInput()), Run: func(cmd *cobra.Command, args []string) { input, err := readResourceInput[opslevel.PropertyInput]() cobra.CheckErr(err) @@ -149,7 +167,7 @@ var examplePropertyDefinitionCmd = &cobra.Command{ Short: "Example Property Definition", Long: `Example Property Definition`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.PropertyDefinitionInput]()) + fmt.Println(buildExamplePropertyDefinitionInput()) }, } @@ -161,7 +179,7 @@ var createPropertyDefinitionCmd = &cobra.Command{ Example: fmt.Sprintf(` cat << EOF | opslevel create property-definition -f - %s -EOF`, getYaml[opslevel.PropertyDefinitionInput]()), +EOF`, buildExamplePropertyDefinitionInput()), Run: func(cmd *cobra.Command, args []string) { input, err := readPropertyDefinitionInput() cobra.CheckErr(err) @@ -180,7 +198,7 @@ var updatePropertyDefinitionCmd = &cobra.Command{ Example: fmt.Sprintf(` cat << EOF | opslevel update property-definition propdef3 -f - %s -EOF`, getYaml[opslevel.PropertyDefinitionInput]()), +EOF`, buildExamplePropertyDefinitionInput()), Args: cobra.ExactArgs(1), ArgAliases: []string{"ID", "ALIAS"}, Run: func(cmd *cobra.Command, args []string) { diff --git a/src/cmd/rubric.go b/src/cmd/rubric.go index 4db95af7..7cf16763 100644 --- a/src/cmd/rubric.go +++ b/src/cmd/rubric.go @@ -16,7 +16,9 @@ var exampleCategoryCmd = &cobra.Command{ Short: "Example rubric category", Long: `Example rubric category`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.CategoryCreateInput]()) + fmt.Println(getExample(opslevel.CategoryCreateInput{ + Name: "example_name", + })) }, } @@ -92,7 +94,9 @@ var exampleLevelCmd = &cobra.Command{ Short: "Example rubric level", Long: `Example rubric level`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.LevelCreateInput]()) + fmt.Println(getExample(opslevel.LevelCreateInput{ + Name: "example_name", + })) }, } diff --git a/src/cmd/scorecard.go b/src/cmd/scorecard.go index ec62b515..0742cb5d 100644 --- a/src/cmd/scorecard.go +++ b/src/cmd/scorecard.go @@ -16,7 +16,12 @@ var exampleScorecardCmd = &cobra.Command{ Short: "Example Scorecard", Long: `Example Scorecard`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.ScorecardInput]()) + fmt.Println(getExample(opslevel.ScorecardInput{ + Name: "example_name", + Description: opslevel.RefOf("example_description"), + OwnerId: opslevel.ID("Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk"), + AffectsOverallServiceLevels: opslevel.RefOf(false), + })) }, } diff --git a/src/cmd/secret.go b/src/cmd/secret.go index 231a6eb9..98d15e0d 100644 --- a/src/cmd/secret.go +++ b/src/cmd/secret.go @@ -18,7 +18,10 @@ var exampleSecretCmd = &cobra.Command{ Short: "Example Secret", Long: `Example Secret`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.SecretInput]()) + fmt.Println(getExample(opslevel.SecretInput{ + Owner: opslevel.NewIdentifier("example_owner"), + Value: opslevel.RefOf("example_value"), + })) }, } diff --git a/src/cmd/service.go b/src/cmd/service.go index d9e9f61b..bbbf8c42 100644 --- a/src/cmd/service.go +++ b/src/cmd/service.go @@ -21,7 +21,18 @@ var exampleServiceCmd = &cobra.Command{ Short: "Example service", Long: `Example service`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.ServiceCreateInput]()) + fmt.Println(getExample(opslevel.ServiceCreateInput{ + Name: "example_name", + Description: opslevel.RefOf("example_description"), + Framework: opslevel.RefOf("example_framework"), + Language: opslevel.RefOf("example_language"), + LifecycleAlias: opslevel.RefOf("example_lifecycle"), + OwnerAlias: opslevel.RefOf("example_owner"), + Parent: opslevel.NewIdentifier("example_parent"), + Product: opslevel.RefOf("example_product"), + TierAlias: opslevel.RefOf("example_tier"), + Type: opslevel.NewIdentifier("example_type"), + })) }, } @@ -158,6 +169,14 @@ type: EOF`, Run: func(cmd *cobra.Command, args []string) { input, err := readResourceInput[opslevel.ServiceUpdateInput]() + if len(args) == 1 { + key := args[0] + if opslevel.IsID(key) { + input.Id = opslevel.RefOf(opslevel.ID(key)) + } else { + input.Alias = opslevel.RefOf(key) + } + } cobra.CheckErr(err) service, err := getClientGQL().UpdateService(*input) cobra.CheckErr(err) diff --git a/src/cmd/system.go b/src/cmd/system.go index fd06fcb2..88bd581e 100644 --- a/src/cmd/system.go +++ b/src/cmd/system.go @@ -18,7 +18,13 @@ var exampleSystemCmd = &cobra.Command{ Short: "Example system", Long: `Example system`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.SystemInput]()) + fmt.Println(getExample(opslevel.SystemInput{ + Name: opslevel.RefOf("example_name"), + Description: opslevel.RefOf("example_description"), + OwnerId: opslevel.RefOf(opslevel.ID("Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk")), + Parent: opslevel.NewIdentifier("domain-alias"), + Note: opslevel.RefOf("example_note"), + })) }, } diff --git a/src/cmd/tag.go b/src/cmd/tag.go index 347cd3b9..dd7eb300 100644 --- a/src/cmd/tag.go +++ b/src/cmd/tag.go @@ -19,7 +19,10 @@ var exampleTagCmd = &cobra.Command{ Short: "Example tag to assign to a resource", Long: `Example tag to assign to a resource`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.TagInput]()) + fmt.Println(getExample(opslevel.TagInput{ + Key: "example_key", + Value: "example_value", + })) }, } diff --git a/src/cmd/team.go b/src/cmd/team.go index f702e92a..1ca6faff 100644 --- a/src/cmd/team.go +++ b/src/cmd/team.go @@ -16,7 +16,14 @@ var exampleTeamCmd = &cobra.Command{ Short: "Example team", Long: `Example team`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.TeamCreateInput]()) + fmt.Println(getExample(opslevel.TeamCreateInput{ + Contacts: &[]opslevel.ContactInput{}, + ManagerEmail: opslevel.RefOf("example_manager_email"), + Members: &[]opslevel.TeamMembershipUserInput{}, + Name: "example_name", + ParentTeam: opslevel.NewIdentifier("example_parent_team"), + Responsibilities: opslevel.RefOf("example_responsibilities"), + })) }, } @@ -31,12 +38,12 @@ parentTeam: alias: "parent-team" responsibilities: "all the things" EOF`, - Args: cobra.ExactArgs(1), ArgAliases: []string{"NAME"}, Run: func(cmd *cobra.Command, args []string) { - key := args[0] input, err := readResourceInput[opslevel.TeamCreateInput]() - input.Name = key + if len(args) == 1 { + input.Name = args[0] + } cobra.CheckErr(err) team, err := getClientGQL().CreateTeam(*input) cobra.CheckErr(err) @@ -49,7 +56,11 @@ var exampleMemberCmd = &cobra.Command{ Short: "Example member", Long: `Example member`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.TeamMembershipUserInput]()) + fmt.Println(getExample(opslevel.TeamMembershipUserInput{ + Email: opslevel.RefOf("example_email"), + Role: opslevel.RefOf("example_role"), + User: opslevel.NewUserIdentifier("example_user"), + })) }, } @@ -92,7 +103,10 @@ var exampleContactCmd = &cobra.Command{ Short: "Example contact to a team", Long: `Example contact to a team`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.ContactInput]()) + fmt.Println(getExample(opslevel.ContactInput{ + DisplayName: opslevel.RefOf("example_display_name"), + Address: "example_address", + })) }, } diff --git a/src/cmd/trigger_definition.go b/src/cmd/trigger_definition.go index 8ba3ba60..d346cd3f 100644 --- a/src/cmd/trigger_definition.go +++ b/src/cmd/trigger_definition.go @@ -16,7 +16,10 @@ var exampleTriggerDefinitionCmd = &cobra.Command{ Short: "Example Scorecard", Long: `Example Scorecard`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.CustomActionsTriggerDefinitionCreateInput]()) + fmt.Println(getExample(opslevel.CustomActionsTriggerDefinitionCreateInput{ + Name: "example_name", + OwnerId: opslevel.ID("Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk"), + })) }, } diff --git a/src/cmd/user.go b/src/cmd/user.go index 4bb8ad8c..df0c4c48 100644 --- a/src/cmd/user.go +++ b/src/cmd/user.go @@ -20,7 +20,9 @@ var exampleUserCmd = &cobra.Command{ Short: "Example User", Long: `Example User`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println(getExample[opslevel.UserInput]()) + fmt.Println(getExample(opslevel.UserInput{ + Name: opslevel.RefOf("example_name"), + })) }, } diff --git a/src/e2e/domain_test.go b/src/e2e/domain_test.go new file mode 100644 index 00000000..05b98455 --- /dev/null +++ b/src/e2e/domain_test.go @@ -0,0 +1,83 @@ +package e2e + +import ( + "strings" + "testing" +) + +func TestDomainHappyPath(t *testing.T) { + tc := CLITest{ + Steps: []Step{ + Example{ + Cmd: "example domain", + Yaml: ` +description: example_description +name: example_name +note: example_note +ownerId: Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk +`, + }, + Create{ + Cmd: "create domain", + Input: ` +name: "Integration Test Domain" +description: "Created by integration test" +`, + }, + Get{ + Cmd: "get domain", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "Integration Test Domain") { + u.Fatalf("get after create failed: %s", out) + } + }, + }, + List{ + Cmd: "list domain", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "Integration Test Domain") { + u.Fatalf("list missing domain: %s", out) + } + }, + }, + Update{ + Cmd: "update domain", + Input: ` +name: "Integration Test Domain Updated" +description: "Updated by integration test" +`, + }, + Get{ + Cmd: "get domain", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "Integration Test Domain Updated") || !strings.Contains(out, "Updated by integration test") { + u.Fatalf("update1 failed\nout: %s", out) + } + }, + }, + // TODO: description cannot be unset yest + // Update{ + // Cmd: "update domain", + // Input: ` + //name: "Integration Test Domain Updated Again" + //description: null + //`, + // }, + // Get{ + // Cmd: "get domain", + // Validate: func(u *Utility, out string) { + // if !strings.Contains(out, "Integration Test Domain Updated Again") || strings.Contains(out, "Updated by integration test") { + // u.Fatalf("update2 failed (description should be unset)\nout: %s", out) + // } + // }, + // }, + Delete{ + Cmd: "delete domain", + }, + Missing{ + Cmd: "get domain", + }, + }, + } + tc.Run(t) +} diff --git a/src/e2e/helpers.go b/src/e2e/helpers.go new file mode 100644 index 00000000..fa1e54e5 --- /dev/null +++ b/src/e2e/helpers.go @@ -0,0 +1,194 @@ +package e2e + +import ( + "bytes" + "os" + "os/exec" + "strconv" + "strings" + "testing" +) + +type Utility struct { + *testing.T + ID string // The resource ID created by a step, if needed +} + +type Step interface { + Run(u *Utility) + Name() string + Deferred() bool +} + +// CLITest uses []Step interface now +type CLITest struct { + Steps []Step +} + +func (tc *CLITest) Run(t *testing.T) { + util := &Utility{T: t} + // Run non-deferred steps + for i, step := range tc.Steps { + if step.Deferred() { + continue + } + t.Run(step.Name()+"_"+strconv.Itoa(i), func(t *testing.T) { + util.T = t + step.Run(util) + }) + } + // Run deferred steps + for i, step := range tc.Steps { + if !step.Deferred() { + continue + } + t.Run(step.Name()+"_"+strconv.Itoa(i), func(t *testing.T) { + util.T = t + step.Run(util) + }) + } +} + +// Run executes the CLI using 'go run main.go' from the ./src directory with the given arguments and optional stdin, returning combined output and error. +func (u *Utility) Run(args string, stdin ...string) (string, error) { + // TODO: need to allow using the pre-built binary + // cmd := exec.Command("opslevel", strings.Split(args, " ")...) + + cmd := exec.Command("go", append([]string{"run", "main.go"}, strings.Split(args, " ")...)...) + cmd.Dir = ".." + cmd.Env = os.Environ() + var out bytes.Buffer + var errBuf bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &errBuf + if len(stdin) > 0 { + cmd.Stdin = strings.NewReader(stdin[0]) + } + err := cmd.Run() + return out.String() + errBuf.String(), err +} + +// Create step +type Create struct { + Cmd string + Input string +} + +func (s Create) Run(u *Utility) { + out, err := u.Run(s.Cmd+" -f -", s.Input) + if err != nil { + panic("create failed: " + err.Error() + "\nout: " + out) + } + u.ID = strings.TrimRight(strings.TrimLeft(strings.TrimSpace(out), "\""), "\"") + if u.ID == "" { + panic("expected ID, got: " + out) + } +} + +func (s Create) Name() string { return "Create" } +func (s Create) Deferred() bool { return false } + +// Get step +type Get struct { + Cmd string + Validate func(u *Utility, out string) +} + +func (s Get) Run(u *Utility) { + out, err := u.Run(s.Cmd + " " + u.ID) + if err != nil { + u.Fatalf("get failed: %v\nout: %s", err, out) + } + s.Validate(u, out) +} + +func (s Get) Name() string { return "Get" } +func (s Get) Deferred() bool { return false } + +// List step +type List struct { + Cmd string + Validate func(u *Utility, out string) +} + +func (s List) Run(u *Utility) { + out, err := u.Run(s.Cmd) + if err != nil { + u.Fatalf("list failed: %v\nout: %s", err, out) + } + if s.Validate != nil { + s.Validate(u, out) + } +} + +func (s List) Name() string { return "List" } +func (s List) Deferred() bool { return false } + +// Update step +type Update struct { + Cmd string + Input string + Validate func(u *Utility, out string) +} + +func (s Update) Run(u *Utility) { + out, err := u.Run(s.Cmd+" -f - "+u.ID, s.Input) + if err != nil { + u.Fatalf("update failed: %v\nout: %s", err, out) + } + if s.Validate != nil { + s.Validate(u, out) + } +} + +func (s Update) Name() string { return "Update" } +func (s Update) Deferred() bool { return false } + +type Delete struct { + Cmd string +} + +func (s Delete) Run(u *Utility) { + out, err := u.Run(s.Cmd + " " + u.ID) + if err != nil { + u.Fatalf("delete failed: %v\nout: %s", err, out) + } +} + +func (s Delete) Name() string { return "Delete" } +func (s Delete) Deferred() bool { return true } + +type Missing struct { + Cmd string +} + +func (s Missing) Run(u *Utility) { + out, err := u.Run(s.Cmd + " " + u.ID) + lower := strings.ToLower(out) + if err == nil || !(strings.Contains(lower, "not found") || strings.Contains(lower, "missing") || strings.Contains(lower, "does not exist on this account")) { + u.Fatalf("expected get after delete to fail with not found, got: %v\nout: %s", err, out) + } +} + +func (s Missing) Name() string { return "Missing" } +func (s Missing) Deferred() bool { return true } + +type Example struct { + Cmd string + Yaml string +} + +func (s Example) Run(u *Utility) { + out, err := u.Run(s.Cmd + " --yaml") + if err != nil { + panic("example failed: " + err.Error() + "\nout: " + out) + } + wip := strings.TrimSpace(out) + expected := strings.TrimSpace(s.Yaml) + if wip != expected { + u.Fatalf("example mismatch for '%s'\nExpected:\n%s\nGot:\n%s", s.Cmd, expected, wip) + } +} + +func (s Example) Name() string { return "Example" } +func (s Example) Deferred() bool { return false } diff --git a/src/e2e/infrastructure_test.go b/src/e2e/infrastructure_test.go new file mode 100644 index 00000000..ee935844 --- /dev/null +++ b/src/e2e/infrastructure_test.go @@ -0,0 +1,85 @@ +package e2e + +import ( + "strings" + "testing" +) + +func TestInfrastructureHappyPath(t *testing.T) { + tc := CLITest{ + Steps: []Step{ + Example{ + Cmd: "example infra", + Yaml: ` +schema: example_schema +owner: Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk +provider: + account: example_account + name: example_provider_name + type: example_provider_type + url: example_external_url +data: + endpoint: https://google.com + engine: BigQuery + name: my-big-query + replica: false +`, + }, + Create{ + Cmd: "create infra", + Input: ` +schema: "Database" +provider: + account: "Dev - 123456789" + name: "GCP" + type: "BigQuery" + url: "https://google.com" +data: + name: "my-big-query" + endpoint: "https://google.com" + engine: "BigQuery" + replica: false +`, + }, + Get{ + Cmd: "get infra", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "my-big-query") { + u.Fatalf("get after create failed: %s", out) + } + }, + }, + List{ + Cmd: "list infra", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "my-big-query") { + u.Fatalf("list missing infra: %s", out) + } + }, + }, + Update{ + Cmd: "update infra", + Input: ` +schema: "Database" +data: + name: "my-big-query-updated" +`, + }, + Get{ + Cmd: "get infra", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "my-big-query-updated") { + u.Fatalf("update1 failed\nout: %s", out) + } + }, + }, + Delete{ + Cmd: "delete infra", + }, + Missing{ + Cmd: "get infra", + }, + }, + } + tc.Run(t) +} diff --git a/src/e2e/service_test.go b/src/e2e/service_test.go new file mode 100644 index 00000000..6e73789f --- /dev/null +++ b/src/e2e/service_test.go @@ -0,0 +1,91 @@ +package e2e + +import ( + "strings" + "testing" +) + +func TestServiceHappyPath(t *testing.T) { + tc := CLITest{ + Steps: []Step{ + Example{ + Cmd: "example service", + Yaml: ` +description: example_description +framework: example_framework +language: example_language +lifecycleAlias: example_lifecycle +name: example_name +ownerAlias: example_owner +parent: + alias: example_parent +product: example_product +tierAlias: example_tier +type: + alias: example_type +`, + }, + Create{ + Cmd: "create service", + Input: ` +name: "TestService" +description: "Created by integration test" +`, + }, + Get{ + Cmd: "get service", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "TestService") { + u.Fatalf("get after create failed: %s", out) + } + }, + }, + List{ + Cmd: "list service", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "TestService") { + u.Fatalf("list missing service: %s", out) + } + }, + }, + Update{ + Cmd: "update service", + Input: ` +name: "TestServiceUpdated" +description: "Updated by integration test" +`, + }, + Get{ + Cmd: "get service", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "TestServiceUpdated") || !strings.Contains(out, "Updated by integration test") { + u.Fatalf("update1 failed\nout: %s", out) + } + }, + }, + // TODO: description cannot be unset yet + // Update{ + // Cmd: "update service", + // Input: ` + //name: "TestServiceUpdatedAgain" + //description: null + //`, + // }, + // Get{ + // Cmd: "get service", + // Validate: func(u *Utility, out string) { + // if !strings.Contains(out, "TestServiceUpdatedAgain") || strings.Contains(out, "Updated by integration test") { + // u.Fatalf("update2 failed (description should be unset)\nout: %s", out) + // } + // }, + // }, + Delete{ + Cmd: "delete service", + }, + Missing{ + Cmd: "get service", + }, + }, + } + tc.Run(t) +} diff --git a/src/e2e/system_test.go b/src/e2e/system_test.go new file mode 100644 index 00000000..0b4b02be --- /dev/null +++ b/src/e2e/system_test.go @@ -0,0 +1,85 @@ +package e2e + +import ( + "strings" + "testing" +) + +func TestSystemHappyPath(t *testing.T) { + tc := CLITest{ + Steps: []Step{ + Example{ + Cmd: "example system", + Yaml: ` +description: example_description +name: example_name +note: example_note +ownerId: Z2lkOi8vc2VydmljZS8xMjM0NTY3ODk +parent: + alias: domain-alias +`, + }, + Create{ + Cmd: "create system", + Input: ` +name: "Integration Test System" +description: "Created by integration test" +`, + }, + Get{ + Cmd: "get system", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "Integration Test System") { + u.Fatalf("get after create failed: %s", out) + } + }, + }, + List{ + Cmd: "list system", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "Integration Test System") { + u.Fatalf("list missing system: %s", out) + } + }, + }, + Update{ + Cmd: "update system", + Input: ` +name: "Integration Test System Updated" +description: "Updated by integration test" +`, + }, + Get{ + Cmd: "get system", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "Integration Test System Updated") || !strings.Contains(out, "Updated by integration test") { + u.Fatalf("update1 failed\nout: %s", out) + } + }, + }, + // TODO: description cannot be unset yet + // Update{ + // Cmd: "update system", + // Input: ` + //name: "Integration Test System Updated Again" + //description: null + //`, + // }, + // Get{ + // Cmd: "get system", + // Validate: func(u *Utility, out string) { + // if !strings.Contains(out, "Integration Test System Updated Again") || strings.Contains(out, "Updated by integration test") { + // u.Fatalf("update2 failed (description should be unset)\nout: %s", out) + // } + // }, + // }, + Delete{ + Cmd: "delete system", + }, + Missing{ + Cmd: "get system", + }, + }, + } + tc.Run(t) +} diff --git a/src/e2e/team_test.go b/src/e2e/team_test.go new file mode 100644 index 00000000..b5910189 --- /dev/null +++ b/src/e2e/team_test.go @@ -0,0 +1,86 @@ +package e2e + +import ( + "strings" + "testing" +) + +func TestTeamHappyPath(t *testing.T) { + tc := CLITest{ + Steps: []Step{ + Example{ + Cmd: "example team", + Yaml: ` +contacts: [] +managerEmail: example_manager_email +members: [] +name: example_name +parentTeam: + alias: example_parent_team +responsibilities: example_responsibilities +`, + }, + Create{ + Cmd: "create team", + Input: ` +name: "TestTeam" +responsibilities: "Created by integration test" +`, + }, + Get{ + Cmd: "get team", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "TestTeam") { + u.Fatalf("get after create failed: %s", out) + } + }, + }, + List{ + Cmd: "list team", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "TestTeam") { + u.Fatalf("list missing team: %s", out) + } + }, + }, + Update{ + Cmd: "update team", + Input: ` +name: "TestTeam Updated" +responsibilities: "Updated by integration test" +`, + }, + Get{ + Cmd: "get team", + Validate: func(u *Utility, out string) { + if !strings.Contains(out, "TestTeam Updated") || !strings.Contains(out, "Updated by integration test") { + u.Fatalf("update1 failed\nout: %s", out) + } + }, + }, + // TODO: responsibilities cannot be unset yet + // Update{ + // Cmd: "update team", + // Input: ` + //name: "Integration Test Team Updated Again" + //responsibilities: null + //`, + // }, + // Get{ + // Cmd: "get team", + // Validate: func(u *Utility, out string) { + // if !strings.Contains(out, "Integration Test Team Updated Again") || strings.Contains(out, "Updated by integration test") { + // u.Fatalf("update2 failed (responsibilities should be unset)\nout: %s", out) + // } + // }, + // }, + Delete{ + Cmd: "delete team", + }, + Missing{ + Cmd: "get team", + }, + }, + } + tc.Run(t) +} diff --git a/src/go.mod b/src/go.mod index 7c73e9a4..c55ce7d1 100644 --- a/src/go.mod +++ b/src/go.mod @@ -55,8 +55,8 @@ require ( github.com/gorilla/mux v1.8.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect - github.com/hasura/go-graphql-client v0.14.3 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect + github.com/hasura/go-graphql-client v0.14.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect @@ -92,10 +92,10 @@ require ( go.opentelemetry.io/otel/sdk v1.29.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.38.0 // indirect - golang.org/x/net v0.40.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/text v0.25.0 // indirect + golang.org/x/text v0.26.0 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/src/go.sum b/src/go.sum index 27b79c9a..09abc552 100644 --- a/src/go.sum +++ b/src/go.sum @@ -141,10 +141,10 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hasura/go-graphql-client v0.14.3 h1:7La92TuA/FRkVmFd1IN8E+WGW8Lxyn6NKOXAgWcoBDA= -github.com/hasura/go-graphql-client v0.14.3/go.mod h1:jfSZtBER3or+88Q9vFhWHiFMPppfYILRyl+0zsgPIIw= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= +github.com/hasura/go-graphql-client v0.14.4 h1:bYU7/+V50T2YBGdNQXt6l4f2cMZPECPUd8cyCR+ixtw= +github.com/hasura/go-graphql-client v0.14.4/go.mod h1:jfSZtBER3or+88Q9vFhWHiFMPppfYILRyl+0zsgPIIw= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -285,17 +285,17 @@ go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -313,13 +313,13 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= diff --git a/src/submodules/opslevel-go b/src/submodules/opslevel-go index 095e4b04..fc57f4af 160000 --- a/src/submodules/opslevel-go +++ b/src/submodules/opslevel-go @@ -1 +1 @@ -Subproject commit 095e4b041e53c38dff17aa0a23501e0a52c79d07 +Subproject commit fc57f4af07fd26bff92998437fff6ecfc2bb8e23