From 60e53e3f39dd53a94c558903ed155802f837ebd5 Mon Sep 17 00:00:00 2001 From: Mark McDonnell Date: Wed, 15 Nov 2023 12:16:35 +0000 Subject: [PATCH] feat: support SSO (Single Sign-On) (#1010) * feat(authenticate): support pkce * refactor: authentication * fix: acquire session token from api endpoint * feat(undocumented): support debug output * fix(app): avoid auth for config command * fix: acquire api token * feat(auth): implement refresh behaviour * refactor: move FastlyAPIClient out of app package * refactor: variable naming * refactor: display profile name * refactor: clarify tokenless commands * doc(testing): explain delve debugging * tests: fix * refactor(app): move kingpin config * refactor(app): small doc clean-ups * refactor: support flag/env-var override for accounts endpoint * refactor: move token exchange to separate function * refactor: move auth logic to separate functions * fix(config): update config version * refactor(app): make prompt less scary * test: fix whoami test * fix: support skipping OAuth * refactor(app): move more logic from Run function * refactor(app): move more logic to separate functions + support new env var * fix(profile/create): support OAuth token flow * refactor(authenticate): move new default logic to separate function * fix: allow profile override for authenticate command + skip auth prompt * fix: allow profile override for profile update command * refactor(profile/update): move static token flow to separate function * fix(profile/update): support OAuth flow * fix(app): move endpoint display before token validation * fix: avoid breaking change by switching SSO to be opt-in * refactor(app): group token processing logic * refactor(profile/create): update prompt description * fix: profile logic * fix: resolve semgrep concern for modified variable * refactor(authenticate): move profile logic to separate function * fix(app): wrap prompt in flag checks * doc(authenticate): explain prompt skip * doc(authenticate): explain processProfiles logic * refactor(authenticate): move case conditionals to separate functions * doc(profile/update): clarify else if conditional * fix: set Default correctly when invoking authenticate command directly * refactor: clean-up profile.Get interface * fix: refactor profile.Default interface * refactor: rename OAuth to SSO * refactor: inject browser opener behaviour * refactor: inject auth server * test(authenticate): add validation for authenticate command * doc(app): clarify env var usage * fix: vcl/conditions test after rebase from main * refactor(app): hide token message with --quiet * feat: add Important text header * feat(profile): add SetADefault * test(authenticate): add more test assertions * refactor: support profile arg to authenticate command * refactor: rename authenticate command to sso * doc: rename DEVELOP to DEVELOPMENT * fix: split command name to avoid arguments being included * fix: use correct profile name after authentication * refactor: rename all instances of authenticate to sso * refactor(app): reword instructions for SSO opt-in * refactor(profile/update): avoid excessive config writes * refactor(sso): change text function depending on how command is invoked * feat(sso): validate azp/aud claims * fix: resolve linter feedback * refactor: rename testcase field * test: add more tests to validate pre-command token processing * refactor: move INFO output related to expired tokens to verbose mode * fix: set Authorization header alongside Fastly-Key * doc: warn callers of memory concern with undocumented.Call() * refactor(whoami): replace manual request with existing abstraction * feat: FASTLY_DEBUG_MODE * refactor: remove unnecessary profile check * fix(undocumented): print correct output * refactor: deduplicate JWT validation and token logic * fix(profile/update): ensure SetDefault() is called * fix: avoid breaking flow in profile commands * fix(profile/update): put back the flow to how it was prior to sso * fix(testutil): correct annotations * fix(undocumented): move response output to before error check * style(profile/update): add line breaks to info output * fix(config): remove duplicate key * fix(app): move verbose flag out of signature * fix(app): add compute metadata to the no token switch * fix(tests): remove extra line break * fix(undocumented): remove unnecessary Authorization header * fix(config): bump config_version * refactor: rename Endpoint to APIEndpoint for clarity * style(app): add line breaks * doc(auth): add well-known path * style: tweak line breaks * fix(sso): hide command until GA * remove: SSO messaging until GA * refactor(global): rename constants * refactor(profile): hide sso flag until GA * fix(auth): check type assert * refactor(main): rename s to authServer * feat: store .well-known inside of auth.Server * refactor: store well-known as struct not bytes * refactor: rename Account to AccountEndpoint * refactor: move main logic to custom init * refactor: correct some linter items * refactor: all the things * fix: move functions inside auth server + set api endpoint * remove(testutil): SetAccountEndpoint mock method * fix: stop processing if user doesn't want to continue * test: add DontWantOutput for TestSSO * feat: add --enable-sso flag * fix: don't os.Exit(1) for Yes/No * style(app): remove line break * fix(app): don't auto SSO if no profiles * refactor: auth flow * refactor: naming of variables * feat: support account endpoint override --- .fastly/config.toml | 3 +- .tmpl/create.go | 5 - .tmpl/delete.go | 5 - .tmpl/describe.go | 5 - .tmpl/list.go | 5 - .tmpl/update.go | 5 - DEVELOP.md => DEVELOPMENT.md | 0 README.md | 7 +- TESTING.md | 18 + cmd/fastly/main.go | 134 +--- go.mod | 13 + go.sum | 74 ++ pkg/api/undocumented/undocumented.go | 22 +- pkg/app/run.go | 731 +++++++++++++---- pkg/app/run_test.go | 9 +- pkg/app/usage.go | 61 +- pkg/auth/auth.go | 413 ++++++++++ pkg/auth/doc.go | 2 + pkg/cmd/cmd.go | 8 +- pkg/commands/acl/acl_test.go | 50 +- pkg/commands/acl/create.go | 9 +- pkg/commands/acl/delete.go | 9 +- pkg/commands/acl/describe.go | 12 +- pkg/commands/acl/list.go | 12 +- pkg/commands/acl/update.go | 12 +- pkg/commands/aclentry/aclentry_test.go | 51 +- pkg/commands/aclentry/create.go | 12 +- pkg/commands/aclentry/delete.go | 9 +- pkg/commands/aclentry/describe.go | 12 +- pkg/commands/aclentry/list.go | 12 +- pkg/commands/aclentry/update.go | 9 +- pkg/commands/authtoken/authtoken_test.go | 77 +- pkg/commands/authtoken/create.go | 17 +- pkg/commands/authtoken/delete.go | 18 +- pkg/commands/authtoken/describe.go | 14 +- pkg/commands/authtoken/list.go | 10 +- pkg/commands/backend/backend_test.go | 49 +- pkg/commands/backend/create.go | 9 +- pkg/commands/backend/delete.go | 12 +- pkg/commands/backend/describe.go | 12 +- pkg/commands/backend/list.go | 12 +- pkg/commands/backend/update.go | 9 +- pkg/{app => commands}/commands.go | 749 +++++++++--------- pkg/commands/compute/build.go | 7 +- pkg/commands/compute/build_test.go | 153 ++-- pkg/commands/compute/compute_test.go | 18 +- pkg/commands/compute/deploy.go | 13 +- pkg/commands/compute/deploy_test.go | 24 +- pkg/commands/compute/init.go | 17 +- pkg/commands/compute/init_test.go | 20 +- pkg/commands/compute/metadata_test.go | 25 +- pkg/commands/compute/pack.go | 7 +- pkg/commands/compute/pack_test.go | 8 +- pkg/commands/compute/serve.go | 6 +- pkg/commands/compute/update.go | 16 +- pkg/commands/compute/update_test.go | 15 +- pkg/commands/compute/validate_test.go | 8 +- pkg/commands/config/config_test.go | 13 +- pkg/commands/configstore/configstore_test.go | 74 +- pkg/commands/configstore/create.go | 8 +- pkg/commands/configstore/delete.go | 8 +- pkg/commands/configstore/describe.go | 9 +- pkg/commands/configstore/list.go | 6 +- pkg/commands/configstore/list_services.go | 11 +- pkg/commands/configstore/update.go | 8 +- .../configstoreentry/configstoreentry_test.go | 63 +- pkg/commands/configstoreentry/create.go | 10 +- pkg/commands/configstoreentry/delete.go | 7 +- pkg/commands/configstoreentry/describe.go | 11 +- pkg/commands/configstoreentry/list.go | 11 +- pkg/commands/configstoreentry/update.go | 10 +- pkg/commands/dictionary/create.go | 9 +- pkg/commands/dictionary/delete.go | 9 +- pkg/commands/dictionary/describe.go | 12 +- pkg/commands/dictionary/dictionary_test.go | 51 +- pkg/commands/dictionary/list.go | 9 +- pkg/commands/dictionary/update.go | 10 +- pkg/commands/dictionaryentry/create.go | 9 +- pkg/commands/dictionaryentry/delete.go | 9 +- pkg/commands/dictionaryentry/describe.go | 12 +- .../dictionaryentry/dictionaryitem_test.go | 47 +- pkg/commands/dictionaryentry/list.go | 12 +- pkg/commands/dictionaryentry/update.go | 9 +- pkg/commands/doc.go | 2 + pkg/commands/domain/create.go | 12 +- pkg/commands/domain/delete.go | 12 +- pkg/commands/domain/describe.go | 12 +- pkg/commands/domain/domain_test.go | 78 +- pkg/commands/domain/list.go | 12 +- pkg/commands/domain/update.go | 12 +- pkg/commands/domain/validate.go | 18 +- pkg/commands/healthcheck/create.go | 12 +- pkg/commands/healthcheck/delete.go | 12 +- pkg/commands/healthcheck/describe.go | 12 +- pkg/commands/healthcheck/healthcheck_test.go | 49 +- pkg/commands/healthcheck/list.go | 12 +- pkg/commands/healthcheck/update.go | 12 +- pkg/commands/ip/ip_test.go | 13 +- pkg/commands/ip/root.go | 7 - pkg/commands/kvstore/create.go | 7 +- pkg/commands/kvstore/delete.go | 7 +- pkg/commands/kvstore/describe.go | 7 +- pkg/commands/kvstore/kvstore_test.go | 50 +- pkg/commands/kvstore/list.go | 8 +- pkg/commands/kvstoreentry/create.go | 5 +- pkg/commands/kvstoreentry/delete.go | 7 +- pkg/commands/kvstoreentry/describe.go | 7 +- .../kvstoreentry/kvstoreentry_test.go | 53 +- pkg/commands/kvstoreentry/list.go | 5 +- .../azureblob/azureblob_integration_test.go | 49 +- pkg/commands/logging/azureblob/create.go | 10 +- pkg/commands/logging/azureblob/delete.go | 12 +- pkg/commands/logging/azureblob/describe.go | 12 +- pkg/commands/logging/azureblob/list.go | 12 +- pkg/commands/logging/azureblob/update.go | 10 +- .../bigquery/bigquery_integration_test.go | 49 +- pkg/commands/logging/bigquery/create.go | 7 +- pkg/commands/logging/bigquery/delete.go | 12 +- pkg/commands/logging/bigquery/describe.go | 12 +- pkg/commands/logging/bigquery/list.go | 12 +- pkg/commands/logging/bigquery/update.go | 7 +- .../cloudfiles/cloudfiles_integration_test.go | 52 +- pkg/commands/logging/cloudfiles/create.go | 7 +- pkg/commands/logging/cloudfiles/delete.go | 12 +- pkg/commands/logging/cloudfiles/describe.go | 12 +- pkg/commands/logging/cloudfiles/list.go | 12 +- pkg/commands/logging/cloudfiles/update.go | 7 +- pkg/commands/logging/datadog/create.go | 10 +- .../datadog/datadog_integration_test.go | 49 +- pkg/commands/logging/datadog/delete.go | 12 +- pkg/commands/logging/datadog/describe.go | 12 +- pkg/commands/logging/datadog/list.go | 12 +- pkg/commands/logging/datadog/update.go | 10 +- pkg/commands/logging/digitalocean/create.go | 10 +- pkg/commands/logging/digitalocean/delete.go | 12 +- pkg/commands/logging/digitalocean/describe.go | 12 +- .../digitalocean_integration_test.go | 49 +- pkg/commands/logging/digitalocean/list.go | 12 +- pkg/commands/logging/digitalocean/update.go | 10 +- pkg/commands/logging/elasticsearch/create.go | 10 +- pkg/commands/logging/elasticsearch/delete.go | 12 +- .../logging/elasticsearch/describe.go | 12 +- .../elasticsearch_integration_test.go | 49 +- pkg/commands/logging/elasticsearch/list.go | 12 +- pkg/commands/logging/elasticsearch/update.go | 10 +- pkg/commands/logging/ftp/create.go | 10 +- pkg/commands/logging/ftp/delete.go | 12 +- pkg/commands/logging/ftp/describe.go | 12 +- .../logging/ftp/ftp_integration_test.go | 49 +- pkg/commands/logging/ftp/list.go | 12 +- pkg/commands/logging/ftp/update.go | 10 +- pkg/commands/logging/gcs/create.go | 10 +- pkg/commands/logging/gcs/delete.go | 12 +- pkg/commands/logging/gcs/describe.go | 12 +- .../logging/gcs/gcs_integration_test.go | 49 +- pkg/commands/logging/gcs/list.go | 12 +- pkg/commands/logging/gcs/update.go | 10 +- pkg/commands/logging/googlepubsub/create.go | 10 +- pkg/commands/logging/googlepubsub/delete.go | 12 +- pkg/commands/logging/googlepubsub/describe.go | 12 +- .../googlepubsub_integration_test.go | 49 +- pkg/commands/logging/googlepubsub/list.go | 12 +- pkg/commands/logging/googlepubsub/update.go | 10 +- pkg/commands/logging/heroku/create.go | 10 +- pkg/commands/logging/heroku/delete.go | 12 +- pkg/commands/logging/heroku/describe.go | 12 +- .../logging/heroku/heroku_integration_test.go | 52 +- pkg/commands/logging/heroku/list.go | 12 +- pkg/commands/logging/heroku/update.go | 10 +- pkg/commands/logging/honeycomb/create.go | 10 +- pkg/commands/logging/honeycomb/delete.go | 12 +- pkg/commands/logging/honeycomb/describe.go | 12 +- .../honeycomb/honeycomb_integration_test.go | 49 +- pkg/commands/logging/honeycomb/list.go | 12 +- pkg/commands/logging/honeycomb/update.go | 10 +- pkg/commands/logging/https/create.go | 10 +- pkg/commands/logging/https/delete.go | 12 +- pkg/commands/logging/https/describe.go | 12 +- .../logging/https/https_integration_test.go | 49 +- pkg/commands/logging/https/list.go | 12 +- pkg/commands/logging/https/update.go | 10 +- pkg/commands/logging/kafka/create.go | 10 +- pkg/commands/logging/kafka/delete.go | 12 +- pkg/commands/logging/kafka/describe.go | 12 +- .../logging/kafka/kafka_integration_test.go | 78 +- pkg/commands/logging/kafka/list.go | 12 +- pkg/commands/logging/kafka/update.go | 10 +- pkg/commands/logging/kinesis/create.go | 7 +- pkg/commands/logging/kinesis/delete.go | 12 +- pkg/commands/logging/kinesis/describe.go | 12 +- .../kinesis/kinesis_integration_test.go | 64 +- pkg/commands/logging/kinesis/list.go | 12 +- pkg/commands/logging/kinesis/update.go | 10 +- pkg/commands/logging/loggly/create.go | 10 +- pkg/commands/logging/loggly/delete.go | 12 +- pkg/commands/logging/loggly/describe.go | 12 +- pkg/commands/logging/loggly/list.go | 12 +- .../logging/loggly/loggly_integration_test.go | 49 +- pkg/commands/logging/loggly/update.go | 10 +- pkg/commands/logging/logshuttle/create.go | 10 +- pkg/commands/logging/logshuttle/delete.go | 12 +- pkg/commands/logging/logshuttle/describe.go | 12 +- pkg/commands/logging/logshuttle/list.go | 12 +- .../logshuttle/logshuttle_integration_test.go | 49 +- pkg/commands/logging/logshuttle/update.go | 10 +- pkg/commands/logging/newrelic/create.go | 12 +- pkg/commands/logging/newrelic/delete.go | 12 +- pkg/commands/logging/newrelic/describe.go | 12 +- pkg/commands/logging/newrelic/list.go | 12 +- .../logging/newrelic/newrelic_test.go | 52 +- pkg/commands/logging/newrelic/update.go | 12 +- pkg/commands/logging/newrelicotlp/create.go | 12 +- pkg/commands/logging/newrelicotlp/delete.go | 12 +- pkg/commands/logging/newrelicotlp/describe.go | 12 +- pkg/commands/logging/newrelicotlp/list.go | 12 +- .../logging/newrelicotlp/newrelicotlp_test.go | 52 +- pkg/commands/logging/newrelicotlp/update.go | 12 +- pkg/commands/logging/openstack/create.go | 10 +- pkg/commands/logging/openstack/delete.go | 12 +- pkg/commands/logging/openstack/describe.go | 12 +- pkg/commands/logging/openstack/list.go | 12 +- .../openstack/openstack_integration_test.go | 49 +- pkg/commands/logging/openstack/update.go | 10 +- pkg/commands/logging/papertrail/create.go | 10 +- pkg/commands/logging/papertrail/delete.go | 12 +- pkg/commands/logging/papertrail/describe.go | 12 +- pkg/commands/logging/papertrail/list.go | 12 +- .../papertrail/papertrail_integration_test.go | 49 +- pkg/commands/logging/papertrail/update.go | 10 +- pkg/commands/logging/s3/create.go | 7 +- pkg/commands/logging/s3/delete.go | 12 +- pkg/commands/logging/s3/describe.go | 12 +- pkg/commands/logging/s3/list.go | 12 +- .../logging/s3/s3_integration_test.go | 49 +- pkg/commands/logging/s3/update.go | 10 +- pkg/commands/logging/scalyr/create.go | 10 +- pkg/commands/logging/scalyr/delete.go | 12 +- pkg/commands/logging/scalyr/describe.go | 12 +- pkg/commands/logging/scalyr/list.go | 12 +- .../logging/scalyr/scalyr_integration_test.go | 49 +- pkg/commands/logging/scalyr/update.go | 10 +- pkg/commands/logging/sftp/create.go | 10 +- pkg/commands/logging/sftp/delete.go | 12 +- pkg/commands/logging/sftp/describe.go | 12 +- pkg/commands/logging/sftp/list.go | 12 +- .../logging/sftp/sftp_integration_test.go | 49 +- pkg/commands/logging/sftp/update.go | 10 +- pkg/commands/logging/splunk/create.go | 10 +- pkg/commands/logging/splunk/delete.go | 12 +- pkg/commands/logging/splunk/describe.go | 12 +- pkg/commands/logging/splunk/list.go | 12 +- .../logging/splunk/splunk_integration_test.go | 64 +- pkg/commands/logging/splunk/update.go | 10 +- pkg/commands/logging/sumologic/create.go | 10 +- pkg/commands/logging/sumologic/delete.go | 12 +- pkg/commands/logging/sumologic/describe.go | 12 +- pkg/commands/logging/sumologic/list.go | 12 +- .../sumologic/sumologic_integration_test.go | 49 +- pkg/commands/logging/sumologic/update.go | 10 +- pkg/commands/logging/syslog/create.go | 10 +- pkg/commands/logging/syslog/delete.go | 12 +- pkg/commands/logging/syslog/describe.go | 12 +- pkg/commands/logging/syslog/list.go | 12 +- .../logging/syslog/syslog_integration_test.go | 57 +- pkg/commands/logging/syslog/update.go | 10 +- pkg/commands/logtail/root.go | 11 +- pkg/commands/pop/pop_test.go | 16 +- pkg/commands/pop/root.go | 7 - pkg/commands/products/products_test.go | 11 +- pkg/commands/products/root.go | 9 +- pkg/commands/profile/create.go | 69 +- pkg/commands/profile/delete.go | 2 +- pkg/commands/profile/list.go | 2 +- pkg/commands/profile/profile_test.go | 98 ++- pkg/commands/profile/token.go | 4 +- pkg/commands/profile/update.go | 238 ++++-- pkg/commands/purge/purge_test.go | 90 +-- pkg/commands/purge/root.go | 14 +- pkg/commands/ratelimit/create.go | 18 +- pkg/commands/ratelimit/delete.go | 14 +- pkg/commands/ratelimit/describe.go | 13 +- pkg/commands/ratelimit/list.go | 18 +- pkg/commands/ratelimit/ratelimit_test.go | 67 +- pkg/commands/ratelimit/update.go | 10 +- pkg/commands/resourcelink/create.go | 14 +- pkg/commands/resourcelink/delete.go | 14 +- pkg/commands/resourcelink/describe.go | 12 +- pkg/commands/resourcelink/list.go | 9 +- .../resourcelink/resourcelink_test.go | 60 +- pkg/commands/resourcelink/update.go | 14 +- pkg/commands/secretstore/create.go | 7 +- pkg/commands/secretstore/delete.go | 7 +- pkg/commands/secretstore/describe.go | 10 +- pkg/commands/secretstore/list.go | 9 +- pkg/commands/secretstore/secretstore_test.go | 46 +- pkg/commands/secretstoreentry/create.go | 5 +- pkg/commands/secretstoreentry/delete.go | 7 +- pkg/commands/secretstoreentry/describe.go | 10 +- pkg/commands/secretstoreentry/list.go | 12 +- .../secretstoreentry/secretstoreentry_test.go | 48 +- pkg/commands/service/create.go | 3 +- pkg/commands/service/delete.go | 17 +- pkg/commands/service/describe.go | 11 +- pkg/commands/service/search.go | 10 +- pkg/commands/service/service_test.go | 62 +- pkg/commands/service/update.go | 12 +- pkg/commands/serviceauth/create.go | 11 +- pkg/commands/serviceauth/delete.go | 10 +- pkg/commands/serviceauth/describe.go | 10 +- pkg/commands/serviceauth/service_test.go | 49 +- pkg/commands/serviceauth/update.go | 10 +- pkg/commands/serviceversion/activate.go | 12 +- pkg/commands/serviceversion/clone.go | 12 +- pkg/commands/serviceversion/deactivate.go | 12 +- pkg/commands/serviceversion/list.go | 12 +- pkg/commands/serviceversion/lock.go | 12 +- .../serviceversion/serviceversion_test.go | 58 +- pkg/commands/serviceversion/update.go | 9 +- pkg/commands/sso/doc.go | 3 + pkg/commands/sso/root.go | 285 +++++++ pkg/commands/sso/sso_test.go | 333 ++++++++ pkg/commands/stats/historical.go | 9 +- pkg/commands/stats/historical_test.go | 11 +- pkg/commands/stats/realtime.go | 12 +- pkg/commands/stats/regions_test.go | 14 +- pkg/commands/tls/config/config_test.go | 32 +- pkg/commands/tls/config/describe.go | 12 +- pkg/commands/tls/config/list.go | 8 +- pkg/commands/tls/config/update.go | 12 +- .../tls/custom/activation/activation_test.go | 50 +- pkg/commands/tls/custom/activation/create.go | 12 +- pkg/commands/tls/custom/activation/delete.go | 10 +- .../tls/custom/activation/describe.go | 12 +- pkg/commands/tls/custom/activation/list.go | 8 +- pkg/commands/tls/custom/activation/update.go | 12 +- .../custom/certificate/certificate_test.go | 52 +- pkg/commands/tls/custom/certificate/create.go | 8 +- pkg/commands/tls/custom/certificate/delete.go | 10 +- .../tls/custom/certificate/describe.go | 10 +- pkg/commands/tls/custom/certificate/list.go | 8 +- pkg/commands/tls/custom/certificate/update.go | 8 +- pkg/commands/tls/custom/domain/domain_test.go | 14 +- pkg/commands/tls/custom/domain/list.go | 8 +- pkg/commands/tls/custom/privatekey/create.go | 12 +- pkg/commands/tls/custom/privatekey/delete.go | 10 +- .../tls/custom/privatekey/describe.go | 10 +- pkg/commands/tls/custom/privatekey/list.go | 8 +- .../tls/custom/privatekey/privatekey_test.go | 41 +- pkg/commands/tls/platform/create.go | 8 +- pkg/commands/tls/platform/delete.go | 10 +- pkg/commands/tls/platform/describe.go | 10 +- pkg/commands/tls/platform/list.go | 8 +- pkg/commands/tls/platform/platform_test.go | 50 +- pkg/commands/tls/platform/update.go | 10 +- pkg/commands/tls/subscription/create.go | 8 +- pkg/commands/tls/subscription/delete.go | 12 +- pkg/commands/tls/subscription/describe.go | 12 +- pkg/commands/tls/subscription/list.go | 8 +- .../tls/subscription/subscription_test.go | 50 +- pkg/commands/tls/subscription/update.go | 8 +- pkg/commands/update/root.go | 11 +- pkg/commands/user/create.go | 15 +- pkg/commands/user/delete.go | 17 +- pkg/commands/user/describe.go | 18 +- pkg/commands/user/list.go | 13 +- pkg/commands/user/update.go | 25 +- pkg/commands/user/user_test.go | 114 ++- pkg/commands/vcl/condition/condition_test.go | 49 +- pkg/commands/vcl/condition/create.go | 9 +- pkg/commands/vcl/condition/delete.go | 12 +- pkg/commands/vcl/condition/describe.go | 9 +- pkg/commands/vcl/condition/list.go | 12 +- pkg/commands/vcl/condition/update.go | 11 +- pkg/commands/vcl/custom/create.go | 12 +- pkg/commands/vcl/custom/custom_test.go | 52 +- pkg/commands/vcl/custom/delete.go | 12 +- pkg/commands/vcl/custom/describe.go | 12 +- pkg/commands/vcl/custom/list.go | 12 +- pkg/commands/vcl/custom/update.go | 9 +- pkg/commands/vcl/snippet/create.go | 12 +- pkg/commands/vcl/snippet/delete.go | 12 +- pkg/commands/vcl/snippet/describe.go | 9 +- pkg/commands/vcl/snippet/list.go | 12 +- pkg/commands/vcl/snippet/snippet_test.go | 49 +- pkg/commands/vcl/snippet/update.go | 9 +- pkg/commands/version/root.go | 13 +- pkg/commands/version/version_test.go | 11 +- pkg/commands/whoami/root.go | 49 +- pkg/commands/whoami/whoami_test.go | 83 +- pkg/config/config.go | 48 +- pkg/config/config_test.go | 13 +- pkg/env/env.go | 29 +- pkg/errors/errors.go | 10 + pkg/errors/remediation_error.go | 2 +- pkg/global/doc.go | 3 +- pkg/global/global.go | 136 +++- pkg/profile/profile.go | 105 +-- pkg/testutil/api.go | 39 + pkg/testutil/args.go | 72 +- pkg/testutil/scenarios.go | 14 +- 400 files changed, 6234 insertions(+), 4218 deletions(-) rename DEVELOP.md => DEVELOPMENT.md (100%) create mode 100644 pkg/auth/auth.go create mode 100644 pkg/auth/doc.go rename pkg/{app => commands}/commands.go (74%) create mode 100644 pkg/commands/doc.go create mode 100644 pkg/commands/sso/doc.go create mode 100644 pkg/commands/sso/root.go create mode 100644 pkg/commands/sso/sso_test.go diff --git a/.fastly/config.toml b/.fastly/config.toml index 5d5de4c7a..f78d8bd7e 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -1,6 +1,7 @@ -config_version = 4 +config_version = 5 [fastly] +account_endpoint = "https://accounts.fastly.com" api_endpoint = "https://api.fastly.com" [wasm-metadata] diff --git a/.tmpl/create.go b/.tmpl/create.go index 6f44261e6..c91d5baf1 100644 --- a/.tmpl/create.go +++ b/.tmpl/create.go @@ -61,11 +61,6 @@ type CreateCommand struct { // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(in io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == config.SourceUndefined { - return errors.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, Client: c.Globals.Client, diff --git a/.tmpl/delete.go b/.tmpl/delete.go index 2cd91ec05..cbb391817 100644 --- a/.tmpl/delete.go +++ b/.tmpl/delete.go @@ -61,11 +61,6 @@ type DeleteCommand struct { // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(in io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == config.SourceUndefined { - return errors.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, Client: c.Globals.Client, diff --git a/.tmpl/describe.go b/.tmpl/describe.go index 07abd0d72..9c43299c9 100644 --- a/.tmpl/describe.go +++ b/.tmpl/describe.go @@ -56,11 +56,6 @@ type DescribeCommand struct { // Exec invokes the application logic for the command. func (c *DescribeCommand) Exec(in io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == config.SourceUndefined { - return errors.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, Client: c.Globals.Client, diff --git a/.tmpl/list.go b/.tmpl/list.go index fbaf51f1d..8753205c7 100644 --- a/.tmpl/list.go +++ b/.tmpl/list.go @@ -57,11 +57,6 @@ type ListCommand struct { // Exec invokes the application logic for the command. func (c *ListCommand) Exec(in io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == config.SourceUndefined { - return errors.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, Client: c.Globals.Client, diff --git a/.tmpl/update.go b/.tmpl/update.go index 2bfed0ea9..6f713f03a 100644 --- a/.tmpl/update.go +++ b/.tmpl/update.go @@ -65,11 +65,6 @@ type UpdateCommand struct { // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(in io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == config.SourceUndefined { - return errors.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, Client: c.Globals.Client, diff --git a/DEVELOP.md b/DEVELOPMENT.md similarity index 100% rename from DEVELOP.md rename to DEVELOPMENT.md diff --git a/README.md b/README.md index d97221007..34bc7f7ae 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,12 @@ ## Quick links + - [Installation](https://developer.fastly.com/learning/tools/cli#installing) - [Shell auto-completion](https://developer.fastly.com/learning/tools/cli#shell-auto-completion) - [Configuring](https://developer.fastly.com/learning/tools/cli#configuring) - [Commands](https://developer.fastly.com/reference/cli/#command-groups) -- [Development](DEVELOP.md) +- [Development](DEVELOPMENT.md) - [Testing](TESTING.md) - [Documentation](DOCUMENTATION.md) @@ -27,8 +28,6 @@ Refer to [CONTRIBUTING.md](./CONTRIBUTING.md) If you encounter any non-security-related bug or unexpected behavior, please [file an issue][bug] using the bug report template. -[bug]: https://github.com/fastly/cli/issues/new?labels=bug&template=bug_report.md - Please also check the [CHANGELOG](./CHANGELOG.md) for any breaking-changes or migration guidance. ### Security issues @@ -38,3 +37,5 @@ Please see our [SECURITY.md](SECURITY.md) for guidance on reporting security-rel ## License [Apache 2.0](LICENSE). + +[bug]: https://github.com/fastly/cli/issues/new?labels=bug&template=bug_report.md diff --git a/TESTING.md b/TESTING.md index 37f92fad8..907707432 100644 --- a/TESTING.md +++ b/TESTING.md @@ -52,3 +52,21 @@ TEST_COMPUTE_INIT=1 TEST_COMPUTE_BUILD=1 TEST_COMPUTE_DEPLOY=1 TEST_COMMAND=gote ``` > **NOTE**: `TEST_COMMAND` is optional and allows the use of https://github.com/rakyll/gotest to improve test output. + +### Debugging + +To debug failing tests you can use [Delve](<>). + +Essentially, `cd` into a package directory (where the `_test.go` file is you want to run) and then execute... + +``` +TEST_COMPUTE_BUILD=1 dlv test -- -test.v -test.run TestNameGoesHere +``` + +Once that is done, you can set breakpoints. For example: + +``` +break ../../app/run.go:152 +``` + +> **NOTE:** The path is relative to the package directory you're running the test file. diff --git a/cmd/fastly/main.go b/cmd/fastly/main.go index 6b8c62cb6..3b3c5c8ff 100644 --- a/cmd/fastly/main.go +++ b/cmd/fastly/main.go @@ -3,148 +3,38 @@ package main import ( "errors" - "io" - "net/http" "os" - "time" - "github.com/fastly/go-fastly/v8/fastly" "github.com/fatih/color" - "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/app" - "github.com/fastly/cli/pkg/commands/compute" - "github.com/fastly/cli/pkg/config" - "github.com/fastly/cli/pkg/env" fsterr "github.com/fastly/cli/pkg/errors" - "github.com/fastly/cli/pkg/github" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/cli/pkg/sync" - "github.com/fastly/cli/pkg/text" ) func main() { - // Parse the arguments provided by the user via the command-line interface. - args := os.Args[1:] - - // Define a HTTP client that will be used for making arbitrary HTTP requests. - httpClient := &http.Client{Timeout: time.Minute * 2} - - // Define the standard input/output streams. - var ( - in io.Reader = os.Stdin - out io.Writer = sync.NewWriter(color.Output) - ) - - // Read relevant configuration options from the user's environment. - var e config.Environment - e.Read(env.Parse(os.Environ())) - - // Identify verbose flag early (before Kingpin parser has executed) so we can - // print additional output related to the CLI configuration. - var verboseOutput bool - for _, seg := range args { - if seg == "-v" || seg == "--verbose" { - verboseOutput = true - } - } - - // Identify auto-yes/non-interactive flag early (before Kingpin parser has - // executed) so we can handle the interactive prompts appropriately with - // regards to processing the CLI configuration. - var autoYes, nonInteractive bool - for _, seg := range args { - if seg == "-y" || seg == "--auto-yes" { - autoYes = true - } - if seg == "-i" || seg == "--non-interactive" { - nonInteractive = true + if err := app.Run(os.Args, os.Stdin); err != nil { + if skipExit := processErr(err, os.Args); skipExit { + return } - } - - // Extract a subset of configuration options from the local app directory. - var cfg config.File - cfg.SetAutoYes(autoYes) - cfg.SetNonInteractive(nonInteractive) - // The CLI relies on a valid configuration, otherwise we can't continue. - err := cfg.Read(config.FilePath, in, out, fsterr.Log, verboseOutput) - if err != nil { - fsterr.Deduce(err).Print(color.Error) - // WARNING: os.Exit will exit, and any `defer` calls will not be run. os.Exit(1) } +} - // Extract user's project configuration from the fastly.toml manifest. - var md manifest.Data - md.File.Args = args - md.File.SetErrLog(fsterr.Log) - md.File.SetOutput(out) - - // NOTE: We skip handling the error because not all commands relate to Compute. - _ = md.File.Read(manifest.Filename) - - // The `main` function is a shim for calling `app.Run()`. - err = app.Run(app.RunOpts{ - APIClient: func(token, endpoint string, debugMode bool) (api.Interface, error) { - client, err := fastly.NewClientForEndpoint(token, endpoint) - if debugMode { - client.DebugMode = true - } - return client, err - }, - Args: args, - ConfigFile: cfg, - ConfigPath: config.FilePath, - Env: e, - ErrLog: fsterr.Log, - ExecuteWasmTools: compute.ExecuteWasmTools, - HTTPClient: httpClient, - Manifest: &md, - Stdin: in, - Stdout: out, - Versioners: app.Versioners{ - CLI: github.New(github.Opts{ - HTTPClient: httpClient, - Org: "fastly", - Repo: "cli", - Binary: "fastly", - }), - Viceroy: github.New(github.Opts{ - HTTPClient: httpClient, - Org: "fastly", - Repo: "viceroy", - Binary: "viceroy", - Version: md.File.LocalServer.ViceroyVersion, - }), - WasmTools: github.New(github.Opts{ - HTTPClient: httpClient, - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", - External: true, - Nested: true, - }), - }, - }) - +// processErr persists the error log to disk and deduces the error type. +func processErr(err error, args []string) (skipExit bool) { // NOTE: We persist any error log entries to disk before attempting to handle // a possible error response from app.Run as there could be errors recorded // during the execution flow but were otherwise handled without bubbling an // error back the call stack, and so if the user still experiences something // unexpected we will have a record of any errors that happened along the way. - logErr := fsterr.Log.Persist(fsterr.LogPath, args) + logErr := fsterr.Log.Persist(fsterr.LogPath, args[1:]) if logErr != nil { fsterr.Deduce(logErr).Print(color.Error) } - if err != nil { - text.Break(out) - fsterr.Deduce(err).Print(color.Error) - exitError := fsterr.SkipExitError{} - if errors.As(err, &exitError) { - if exitError.Skip { - return // skip returning an error for 'help' output - } - } - os.Exit(1) + exitError := fsterr.SkipExitError{} + if errors.As(err, &exitError) { + return exitError.Skip } + fsterr.Deduce(err).Print(color.Error) + return false } diff --git a/go.mod b/go.mod index 034f807e5..cacbf7f9c 100644 --- a/go.mod +++ b/go.mod @@ -28,10 +28,12 @@ require ( require ( github.com/fastly/go-fastly/v8 v8.6.4 + github.com/hashicorp/cap v0.3.4 github.com/kennygrant/sanitize v1.2.4 github.com/mholt/archiver v3.1.1+incompatible github.com/otiai10/copy v1.14.0 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/theckman/yacspin v0.13.12 golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d @@ -47,11 +49,17 @@ require ( require ( github.com/andybalholm/brotli v1.0.5 // indirect + github.com/coreos/go-oidc/v3 v3.5.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/jsonapi v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.4.0 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/klauspost/compress v1.16.6 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -59,11 +67,16 @@ require ( github.com/nwaples/rardecode v1.1.2 // indirect github.com/peterhellberg/link v1.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.2 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect golang.org/x/net v0.17.0 // indirect + golang.org/x/oauth2 v0.5.0 // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/text v0.14.0 + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6ab0aaa4e..64ea3a984 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= @@ -9,6 +10,8 @@ github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw= +github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -24,26 +27,41 @@ github.com/fastly/go-fastly/v8 v8.6.4 h1:/jf1j8VwpXDR+b7PA6RBhBcRo3OoEWFwFHFeOba github.com/fastly/go-fastly/v8 v8.6.4/go.mod h1:sC3WMOjQxwXk+gRI68ooTJJsI+/6AMA/4JLvrhNgpVk= github.com/fastly/kingpin v2.1.12-0.20191105091915-95d230a53780+incompatible h1:FhrXlfhgGCS+uc6YwyiFUt04alnjpoX7vgDKJxS6Qbk= github.com/fastly/kingpin v2.1.12-0.20191105091915-95d230a53780+incompatible/go.mod h1:U8UynVoU1SQaqD2I4ZqgYd5lx3A1ipQYn4aSt2Y5h6c= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/frankban/quicktest v1.13.1 h1:xVm/f9seEhZFL9+n5kv5XLrGwy6elc4V9v/XFY2vmd8= github.com/frankban/quicktest v1.13.1/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/jsonapi v1.0.0 h1:qIGgO5Smu3yJmSs+QlvhQnrscdZfFhiV6S8ryJAglqU= github.com/google/jsonapi v1.0.0/go.mod h1:YYHiRPJT8ARXGER8In9VuLv4qvLfDmA9ULQqptbLE4s= +github.com/hashicorp/cap v0.3.4 h1:RoqWYqr6LaDLuvnBCpod1sZtvuEhehIhu0GncmoHW40= +github.com/hashicorp/cap v0.3.4/go.mod h1:dHTmyMIVbzT981XxRoci5G//dfWmd/HhuNiCH6J5+IA= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I= +github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o= github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -62,8 +80,12 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -110,9 +132,13 @@ github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDj github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= github.com/segmentio/textio v1.2.0 h1:Ug4IkV3kh72juJbG8azoSBlgebIbUUxVNrfFcKHfTSQ= github.com/segmentio/textio v1.2.0/go.mod h1:+Rb7v0YVODP+tK5F7FD9TCkV7gOYx9IgLHWiqtvY8ag= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4= @@ -125,25 +151,73 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= +golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/pkg/api/undocumented/undocumented.go b/pkg/api/undocumented/undocumented.go index da782bc09..e224cd219 100644 --- a/pkg/api/undocumented/undocumented.go +++ b/pkg/api/undocumented/undocumented.go @@ -3,9 +3,11 @@ package undocumented import ( + "context" "fmt" "io" "net/http" + "net/http/httputil" "net/url" "strings" "time" @@ -50,6 +52,7 @@ type HTTPHeader struct { type CallOptions struct { APIEndpoint string Body io.Reader + Debug bool HTTPClient api.HTTPClient HTTPHeaders []HTTPHeader Method string @@ -58,6 +61,8 @@ type CallOptions struct { } // Call calls the given API endpoint and returns its response data. +// +// WARNING: Loads entire response body into memory. func Call(opts CallOptions) (data []byte, err error) { host := strings.TrimSuffix(opts.APIEndpoint, "/") endpoint := fmt.Sprintf("%s%s", host, opts.Path) @@ -67,13 +72,28 @@ func Call(opts CallOptions) (data []byte, err error) { return data, NewError(err, 0) } - req.Header.Set("Fastly-Key", opts.Token) + if opts.Token != "" { + req.Header.Set("Fastly-Key", opts.Token) + } req.Header.Set("User-Agent", useragent.Name) for _, header := range opts.HTTPHeaders { req.Header.Set(header.Key, header.Value) } + if opts.Debug { + rc := req.Clone(context.Background()) + rc.Header.Set("Fastly-Key", "REDACTED") + dump, _ := httputil.DumpRequest(rc, true) + fmt.Printf("undocumented.Call request dump:\n\n%#v\n\n", string(dump)) + } + res, err := opts.HTTPClient.Do(req) + + if opts.Debug && res != nil { + dump, _ := httputil.DumpResponse(res, true) + fmt.Printf("undocumented.Call response dump:\n\n%#v\n\n", string(dump)) + } + if err != nil { if urlErr, ok := err.(*url.Error); ok && urlErr.Timeout() { return data, fsterr.RemediationError{ diff --git a/pkg/app/run.go b/pkg/app/run.go index ec0e60403..16dda60e2 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -1,8 +1,11 @@ package app import ( + "encoding/json" + "errors" "fmt" "io" + "net/http" "os" "slices" "strconv" @@ -11,8 +14,15 @@ import ( "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/kingpin" + "github.com/fatih/color" + "github.com/hashicorp/cap/oidc" + "github.com/skratchdot/open-golang/open" "github.com/fastly/cli/pkg/api" + "github.com/fastly/cli/pkg/auth" + "github.com/fastly/cli/pkg/cmd" + "github.com/fastly/cli/pkg/commands" + "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/commands/update" "github.com/fastly/cli/pkg/commands/version" "github.com/fastly/cli/pkg/config" @@ -24,85 +34,199 @@ import ( "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/profile" "github.com/fastly/cli/pkg/revision" + "github.com/fastly/cli/pkg/sync" "github.com/fastly/cli/pkg/text" ) -// FastlyAPIClient is a ClientFactory that returns a real Fastly API client -// using the provided token and endpoint. -func FastlyAPIClient(token, endpoint string, debugMode bool) (api.Interface, error) { - client, err := fastly.NewClientForEndpoint(token, endpoint) - if debugMode { - client.DebugMode = true +// Run kick starts the CLI application. +func Run(args []string, stdin io.Reader) error { + data, err := Init(args, stdin) + if err != nil { + return fmt.Errorf("failed to initialise application: %w", err) + } + return Exec(data) +} + +// Init constructs all the required objects and data for Exec(). +// +// NOTE: We define as a package level variable so we can mock output for tests. +var Init = func(args []string, stdin io.Reader) (*global.Data, error) { + // Parse the arguments provided by the user via the command-line interface. + args = args[1:] + + // Define a HTTP client that will be used for making arbitrary HTTP requests. + httpClient := &http.Client{Timeout: time.Minute * 2} + + // Define the standard input/output streams. + var ( + in io.Reader = stdin + out io.Writer = sync.NewWriter(color.Output) + ) + + // Read relevant configuration options from the user's environment. + var e config.Environment + e.Read(env.Parse(os.Environ())) + + // Identify verbose flag early (before Kingpin parser has executed) so we can + // print additional output related to the CLI configuration. + var verboseOutput bool + for _, seg := range args { + if seg == "-v" || seg == "--verbose" { + verboseOutput = true + } + } + + // Identify auto-yes/non-interactive flag early (before Kingpin parser has + // executed) so we can handle the interactive prompts appropriately with + // regards to processing the CLI configuration. + var autoYes, nonInteractive bool + for _, seg := range args { + if seg == "-y" || seg == "--auto-yes" { + autoYes = true + } + if seg == "-i" || seg == "--non-interactive" { + nonInteractive = true + } + } + + // Extract a subset of configuration options from the local app directory. + var cfg config.File + cfg.SetAutoYes(autoYes) + cfg.SetNonInteractive(nonInteractive) + if err := cfg.Read(config.FilePath, in, out, fsterr.Log, verboseOutput); err != nil { + return nil, err + } + + // Extract user's project configuration from the fastly.toml manifest. + var md manifest.Data + md.File.Args = args + md.File.SetErrLog(fsterr.Log) + md.File.SetOutput(out) + + // NOTE: We skip handling the error because not all commands relate to Compute. + _ = md.File.Read(manifest.Filename) + + // Configure authentication inputs. + metadataEndpoint := fmt.Sprintf(auth.OIDCMetadata, accountEndpoint(args, e)) + req, err := http.NewRequest(http.MethodGet, metadataEndpoint, nil) + if err != nil { + return nil, fmt.Errorf("failed to construct request object for OpenID Connect .well-known metadata: %w", err) + } + resp, err := httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("failed to request OpenID Connect .well-known metadata: %w", err) + } + openIDConfig, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read OpenID Connect .well-known metadata: %w", err) + } + _ = resp.Body.Close() + var wellknown auth.WellKnownEndpoints + err = json.Unmarshal(openIDConfig, &wellknown) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal OpenID Connect .well-known metadata: %w", err) + } + result := make(chan auth.AuthorizationResult) + router := http.NewServeMux() + verifier, err := oidc.NewCodeVerifier() + if err != nil { + return nil, fsterr.RemediationError{ + Inner: fmt.Errorf("failed to generate a code verifier for SSO authentication server: %w", err), + Remediation: auth.Remediation, + } + } + authServer := &auth.Server{ + DebugMode: e.DebugMode, + HTTPClient: httpClient, + Result: result, + Router: router, + Verifier: verifier, + WellKnownEndpoints: wellknown, + } + router.HandleFunc("/callback", authServer.HandleCallback()) + + factory := func(token, endpoint string, debugMode bool) (api.Interface, error) { + client, err := fastly.NewClientForEndpoint(token, endpoint) + if debugMode { + client.DebugMode = true + } + return client, err + } + + versioners := global.Versioners{ + CLI: github.New(github.Opts{ + HTTPClient: httpClient, + Org: "fastly", + Repo: "cli", + Binary: "fastly", + }), + Viceroy: github.New(github.Opts{ + HTTPClient: httpClient, + Org: "fastly", + Repo: "viceroy", + Binary: "viceroy", + Version: md.File.LocalServer.ViceroyVersion, + }), + WasmTools: github.New(github.Opts{ + HTTPClient: httpClient, + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + External: true, + Nested: true, + }), } - return client, err + + return &global.Data{ + APIClientFactory: factory, + Args: args, + AuthServer: authServer, + Config: cfg, + ConfigPath: config.FilePath, + Env: e, + ErrLog: fsterr.Log, + ExecuteWasmTools: compute.ExecuteWasmTools, + HTTPClient: httpClient, + Manifest: &md, + Opener: open.Run, + Output: out, + Versioners: versioners, + Input: in, + }, nil +} + +// accountEndpoint parses the account endpoint from either the environment or +// the input arguments otherwise returns the default. +func accountEndpoint(args []string, e config.Environment) string { + if e.AccountEndpoint != "" { + return e.AccountEndpoint + } + for i, a := range args { + if a == "--account" && i+1 < len(args) { + return args[i+1] + } + } + return global.DefaultAccountEndpoint } -// Run constructs the application including all of the subcommands, parses the +// Exec constructs the application including all of the subcommands, parses the // args, invokes the client factory with the token to create a Fastly API // client, and executes the chosen command, using the provided io.Reader and // io.Writer for input and output, respectively. In the real CLI, func main is // just a simple shim to this function; it exists to make end-to-end testing of // commands easier/possible. // -// The Run helper should NOT output any error-related information to the out +// The Exec helper should NOT output any error-related information to the out // io.Writer. All error-related information should be encoded into an error type // and returned to the caller. This includes usage text. -func Run(opts RunOpts) error { - // The g will hold generally-applicable configuration parameters - // from a variety of sources, and is provided to each concrete command. - g := global.Data{ - Config: opts.ConfigFile, - ConfigPath: opts.ConfigPath, - Env: opts.Env, - ErrLog: opts.ErrLog, - ExecuteWasmTools: opts.ExecuteWasmTools, - HTTPClient: opts.HTTPClient, - Manifest: *opts.Manifest, - Output: opts.Stdout, - } - - // Set up the main application root, including global flags, and then each - // of the subcommands. Note that we deliberately don't use some of the more - // advanced features of the kingpin.Application flags, like env var - // bindings, because we need to do things like track where a config - // parameter came from. - app := kingpin.New("fastly", "A tool to interact with the Fastly API") - app.Writers(opts.Stdout, io.Discard) // don't let kingpin write error output - app.UsageContext(&kingpin.UsageContext{ - Template: VerboseUsageTemplate, - Funcs: UsageTemplateFuncs, - }) - - // Prevent kingpin from calling os.Exit, this gives us greater control over - // error states and output control flow. - app.Terminate(nil) - - // WARNING: kingpin has no way of decorating flags as being "global" - // therefore if you add/remove a global flag you will also need to update - // the globalFlags map in pkg/app/usage.go which is used for usage rendering. - // You should also update `IsGlobalFlagsOnly` in ../cmd/cmd.go - // - // NOTE: Global flags (long and short) MUST be unique. - // A subcommand can't define a flag that is already global. - // Kingpin will otherwise trigger a runtime panic 🎉 - // Interestingly, short flags can be reused but only across subcommands. - tokenHelp := fmt.Sprintf("Fastly API token (or via %s)", env.Token) - app.Flag("accept-defaults", "Accept default options for all interactive prompts apart from Yes/No confirmations").Short('d').BoolVar(&g.Flags.AcceptDefaults) - app.Flag("auto-yes", "Answer yes automatically to all Yes/No confirmations. This may suppress security warnings").Short('y').BoolVar(&g.Flags.AutoYes) - // IMPORTANT: `--debug` is a built-in Kingpin flag so we can't use that. - app.Flag("debug-mode", "Print API request and response details (NOTE: can disrupt the normal CLI flow output formatting)").BoolVar(&g.Flags.Debug) - app.Flag("endpoint", "Fastly API endpoint").Hidden().StringVar(&g.Flags.Endpoint) - app.Flag("non-interactive", "Do not prompt for user input - suitable for CI processes. Equivalent to --accept-defaults and --auto-yes").Short('i').BoolVar(&g.Flags.NonInteractive) - app.Flag("profile", "Switch account profile for single command execution (see also: 'fastly profile switch')").Short('o').StringVar(&g.Flags.Profile) - app.Flag("quiet", "Silence all output except direct command output. This won't prevent interactive prompts (see: --accept-defaults, --auto-yes, --non-interactive)").Short('q').BoolVar(&g.Flags.Quiet) - app.Flag("token", tokenHelp).HintAction(env.Vars).Short('t').StringVar(&g.Flags.Token) - app.Flag("verbose", "Verbose logging").Short('v').BoolVar(&g.Flags.Verbose) - - commands := defineCommands(app, &g, *opts.Manifest, opts) - command, commandName, err := processCommandInput(opts, app, &g, commands) +func Exec(data *global.Data) error { + app := configureKingpin(data) + cmds := commands.Define(app, data) + command, commandName, err := processCommandInput(data, app, cmds) if err != nil { return err } + // We short-circuit the execution for specific cases: // // - cmd.ArgsIsHelpJSON() == true @@ -118,141 +242,412 @@ func Run(opts RunOpts) error { // FIXME: Tweak messaging before for 10.7.0 // To learn more about what data is being collected, why, and how to disable it: https://developer.fastly.com/reference/cli/ - metadataDisable, _ := strconv.ParseBool(g.Env.WasmMetadataDisable) - if slices.Contains(opts.Args, "--metadata-enable") && !metadataDisable && !g.Config.CLI.MetadataNoticeDisplayed && commandCollectsData(commandName) { - text.Important(g.Output, "The Fastly CLI is configured to collect data related to Wasm builds (e.g. compilation times, resource usage, and other non-identifying data). To learn more about our data & privacy policies visit https://www.fastly.com/trust. Join the conversation https://bit.ly/wasm-metadata") - text.Break(g.Output) - g.Config.CLI.MetadataNoticeDisplayed = true - err := g.Config.Write(g.ConfigPath) + metadataDisable, _ := strconv.ParseBool(data.Env.WasmMetadataDisable) + if slices.Contains(data.Args, "--metadata-enable") && !metadataDisable && !data.Config.CLI.MetadataNoticeDisplayed && commandCollectsData(commandName) { + text.Important(data.Output, "The Fastly CLI is configured to collect data related to Wasm builds (e.g. compilation times, resource usage, and other non-identifying data). To learn more about our data & privacy policies visit https://www.fastly.com/trust. Join the conversation https://bit.ly/wasm-metadata") + text.Break(data.Output) + data.Config.CLI.MetadataNoticeDisplayed = true + err := data.Config.Write(data.ConfigPath) if err != nil { return fmt.Errorf("failed to persist change to metadata notice: %w", err) } time.Sleep(5 * time.Second) // this message is only displayed once so give the user a chance to see it before it possibly scrolls off screen } - if g.Flags.Quiet { - opts.Manifest.File.SetQuiet(true) + if data.Flags.Quiet { + data.Manifest.File.SetQuiet(true) + } + + apiEndpoint, endpointSource := data.APIEndpoint() + if data.Verbose() { + displayAPIEndpoint(apiEndpoint, endpointSource, data.Output) } - token, source := g.Token() + // NOTE: We need the AuthServer setter method due to assignment data races. + // i.e. app.Init() doesn't have access to Kingpin flag values yet. + // The flags are only parsed/assigned via configureKingpin(). + data.AuthServer.SetAPIEndpoint(apiEndpoint) + + if commandRequiresToken(commandName) { + token, tokenSource, err := processToken(cmds, data) + if err != nil { + if errors.Is(err, fsterr.ErrDontContinue) { + return nil // we shouldn't exit 1 if user chooses to stop + } + return fmt.Errorf("failed to process token: %w", err) + } + + if data.Verbose() { + displayToken(tokenSource, data) + } + if !data.Flags.Quiet { + checkConfigPermissions(commandName, tokenSource, data.Output) + } - if g.Verbose() { - displayTokenSource( - source, - opts.Stdout, - env.Token, - determineProfile(opts.Manifest.File.Profile, g.Flags.Profile, g.Config.Profiles), - ) + data.APIClient, data.RTSClient, err = configureClients(token, apiEndpoint, data.APIClientFactory, data.Flags.Debug) + if err != nil { + data.ErrLog.Add(err) + return fmt.Errorf("error constructing client: %w", err) + } } - token, err = profile.Init(token, opts.Manifest, &g, opts.Stdin, opts.Stdout) - if err != nil { - return err + f := checkForUpdates(data.Versioners.CLI, commandName, data.Flags.Quiet) + defer f(data.Output) + + return command.Exec(data.Input, data.Output) +} + +func configureKingpin(data *global.Data) *kingpin.Application { + // Set up the main application root, including global flags, and then each + // of the subcommands. Note that we deliberately don't use some of the more + // advanced features of the kingpin.Application flags, like env var + // bindings, because we need to do things like track where a config + // parameter came from. + app := kingpin.New("fastly", "A tool to interact with the Fastly API") + app.Writers(data.Output, io.Discard) // don't let kingpin write error output + app.UsageContext(&kingpin.UsageContext{ + Template: VerboseUsageTemplate, + Funcs: UsageTemplateFuncs, + }) + + // Prevent kingpin from calling os.Exit, this gives us greater control over + // error states and output control flow. + app.Terminate(nil) + + // IMPORTANT: Kingpin doesn't support global flags. + // Any flags defined below must also be added to two other places: + // 1. ./usage.go (`globalFlags` map). + // 2. ../cmd/cmd.go (`IsGlobalFlagsOnly` function). + // + // NOTE: Global flags (long and short) MUST be unique. + // A subcommand can't define a flag that is already global. + // Kingpin will otherwise trigger a runtime panic 🎉 + // Interestingly, short flags can be reused but only across subcommands. + tokenHelp := fmt.Sprintf("Fastly API token (or via %s)", env.APIToken) + app.Flag("accept-defaults", "Accept default options for all interactive prompts apart from Yes/No confirmations").Short('d').BoolVar(&data.Flags.AcceptDefaults) + app.Flag("account", "Fastly Accounts endpoint").Hidden().StringVar(&data.Flags.AccountEndpoint) + app.Flag("api", "Fastly API endpoint").Hidden().StringVar(&data.Flags.APIEndpoint) + app.Flag("auto-yes", "Answer yes automatically to all Yes/No confirmations. This may suppress security warnings").Short('y').BoolVar(&data.Flags.AutoYes) + // IMPORTANT: `--debug` is a built-in Kingpin flag so we must use `debug-mode`. + app.Flag("debug-mode", "Print API request and response details (NOTE: can disrupt the normal CLI flow output formatting)").BoolVar(&data.Flags.Debug) + // IMPORTANT: `--sso` causes a Kingpin runtime panic 🤦 so we use `enable-sso`. + app.Flag("enable-sso", "Enable Single-Sign On (SSO) for current profile execution (see also: 'fastly sso')").Hidden().BoolVar(&data.Flags.SSO) + app.Flag("non-interactive", "Do not prompt for user input - suitable for CI processes. Equivalent to --accept-defaults and --auto-yes").Short('i').BoolVar(&data.Flags.NonInteractive) + app.Flag("profile", "Switch account profile for single command execution (see also: 'fastly profile switch')").Short('o').StringVar(&data.Flags.Profile) + app.Flag("quiet", "Silence all output except direct command output. This won't prevent interactive prompts (see: --accept-defaults, --auto-yes, --non-interactive)").Short('q').BoolVar(&data.Flags.Quiet) + app.Flag("token", tokenHelp).HintAction(env.Vars).Short('t').StringVar(&data.Flags.Token) + app.Flag("verbose", "Verbose logging").Short('v').BoolVar(&data.Flags.Verbose) + + return app +} + +// processToken handles all aspects related to the required API token. +// +// First we check if a profile token is defined in config and if so, we will +// validate if it has expired, and if it has we will attempt to refresh it. +// +// If both the access token and the refresh token has expired we will trigger +// the `fastly sso` command to execute. +// +// Either way, the CLI config is updated to reflect the token that was either +// refreshed or regenerated from the authentication process. +// +// Next, we check the config file's permissions. +// +// Finally, we check if there is a profile override in place (e.g. set via the +// --profile flag or using the `profile` field in the fastly.toml manifest). +func processToken(cmds []cmd.Command, data *global.Data) (token string, tokenSource lookup.Source, err error) { + token, tokenSource = data.Token() + + // Check if token is from a profile. + // e.g. --profile, fastly.toml override, or config default profile. + // If it is, then we'll check if it is expired. + // + // NOTE: tokens via FASTLY_API_TOKEN or --token aren't checked for a TTL. + // This is because we don't have them persisted to disk. + // Meaning we can't check for a TTL or access an access/refresh token. + // So we have to presume those overrides are using a long-lived token. + switch tokenSource { + case lookup.SourceFile: + profileName, profileData, err := getProfile(data) + if err != nil { + return "", tokenSource, err + } + // User with long-lived token will skip SSO if they've not enabled it. + if shouldSkipSSO(profileName, profileData, data) { + return token, tokenSource, nil + } + // User now either has an existing SSO-based token or they want to migrate. + // If a long-lived token, then trigger SSO. + if longLivedToken(profileData) { + return ssoAuthentication("You've not authenticated via OAuth before", cmds, data) + } + // Otherwise, for an existing SSO token, check its freshness. + reauth, err := checkAndRefreshSSOToken(profileData, profileName, data) + if err != nil { + return token, tokenSource, fmt.Errorf("failed to check access/refresh token: %w", err) + } + if reauth { + return ssoAuthentication("Your access token has expired and so has your refresh token", cmds, data) + } + case lookup.SourceUndefined: + // If there's no token available, then trigger SSO authentication flow. + // + // FIXME: Remove this conditional when SSO is GA. + // Once put back, it means "no token" == "automatic SSO". + // For now, a brand new CLI user will have to manually create long-lived + // tokens via the UI in order to use the Fastly CLI. + if data.Env.UseSSO != "1" && !data.Flags.SSO { + return "", tokenSource, nil + } + return ssoAuthentication("No API token could be found", cmds, data) + case lookup.SourceEnvironment, lookup.SourceFlag, lookup.SourceDefault: + // no-op } - // If we are using the token from config file, check the file's permissions - // to assert if they are not too open or have been altered outside of the - // application and warn if so. - segs := strings.Split(commandName, " ") - if source == lookup.SourceFile && (len(segs) > 0 && segs[0] != "profile") { - if fi, err := os.Stat(config.FilePath); err == nil { - if mode := fi.Mode().Perm(); mode > config.FilePermissions { - if !g.Flags.Quiet { - text.Warning(opts.Stdout, "Unprotected configuration file.\n\n") - text.Output(opts.Stdout, "Permissions for '%s' are too open\n\n", config.FilePath) - text.Output(opts.Stdout, "It is recommended that your configuration file is NOT accessible by others.\n\n") - } + return token, tokenSource, nil +} + +// getProfile identifies the profile we should extract a token from. +func getProfile(data *global.Data) (string, *config.Profile, error) { + var ( + profileData *config.Profile + found bool + name, profileName string + ) + switch { + case data.Flags.Profile != "": // --profile + profileName = data.Flags.Profile + case data.Manifest.File.Profile != "": // `profile` field in fastly.toml + profileName = data.Manifest.File.Profile + default: + profileName = "default" + } + for name, profileData = range data.Config.Profiles { + if (profileName == "default" && profileData.Default) || name == profileName { + // Once we find the default profile we can update the variable to be the + // associated profile name so later on we can use that information to + // update the specific profile. + if profileName == "default" { + profileName = name } + found = true + break } } + if !found { + return "", nil, fmt.Errorf("failed to locate '%s' profile", profileName) + } + return profileName, profileData, nil +} - endpoint, source := g.Endpoint() - if g.Verbose() { - switch source { - case lookup.SourceEnvironment: - fmt.Fprintf(opts.Stdout, "Fastly API endpoint (via %s): %s\n\n", env.Endpoint, endpoint) - case lookup.SourceFile: - fmt.Fprintf(opts.Stdout, "Fastly API endpoint (via config file): %s\n\n", endpoint) - case lookup.SourceFlag: - fmt.Fprintf(opts.Stdout, "Fastly API endpoint provided via --endpoint\n\n") - case lookup.SourceDefault, lookup.SourceUndefined: - fallthrough - default: - fmt.Fprintf(opts.Stdout, "Fastly API endpoint: %s\n\n", endpoint) +// checkAndRefreshSSOToken refreshes the access/refresh tokens if expired. +func checkAndRefreshSSOToken(profileData *config.Profile, profileName string, data *global.Data) (reauth bool, err error) { + // Access Token has expired + if auth.TokenExpired(profileData.AccessTokenTTL, profileData.AccessTokenCreated) { + // Refresh Token has expired + if auth.TokenExpired(profileData.RefreshTokenTTL, profileData.RefreshTokenCreated) { + return true, nil } - } - // NOTE: We return error immediately so there's no issue assigning to global. - // nosemgrep - g.APIClient, err = opts.APIClient(token, endpoint, g.Flags.Debug) - if err != nil { - g.ErrLog.Add(err) - return fmt.Errorf("error constructing Fastly API client: %w", err) + if data.Flags.Verbose { + text.Info(data.Output, "\nYour access token has now expired. We will attempt to refresh it") + } + + updatedJWT, err := data.AuthServer.RefreshAccessToken(profileData.RefreshToken) + if err != nil { + return false, fmt.Errorf("failed to refresh access token: %w", err) + } + + email, at, err := data.AuthServer.ValidateAndRetrieveAPIToken(updatedJWT.AccessToken) + if err != nil { + return false, fmt.Errorf("failed to validate JWT and retrieve API token: %w", err) + } + + // NOTE: The refresh token can sometimes be refreshed along with the access token. + // This happens all the time in my testing but according to what is + // spec'd this apparently is something that _might_ happen. + // So after we get the refreshed access token, we check to see if the + // refresh token that was returned by the API call has also changed when + // compared to the refresh token stored in the CLI config file. + current := profile.Get(profileName, data.Config.Profiles) + if current == nil { + return false, fmt.Errorf("failed to locate '%s' profile", profileName) + } + now := time.Now().Unix() + refreshToken := current.RefreshToken + refreshTokenCreated := current.RefreshTokenCreated + refreshTokenTTL := current.RefreshTokenTTL + if current.RefreshToken != updatedJWT.RefreshToken { + if data.Flags.Verbose { + text.Info(data.Output, "Your refresh token was also updated") + text.Break(data.Output) + } + refreshToken = updatedJWT.RefreshToken + refreshTokenCreated = now + refreshTokenTTL = updatedJWT.RefreshExpiresIn + } + + ps, ok := profile.Edit(profileName, data.Config.Profiles, func(p *config.Profile) { + p.AccessToken = updatedJWT.AccessToken + p.AccessTokenCreated = now + p.AccessTokenTTL = updatedJWT.ExpiresIn + p.Email = email + p.RefreshToken = refreshToken + p.RefreshTokenCreated = refreshTokenCreated + p.RefreshTokenTTL = refreshTokenTTL + p.Token = at.AccessToken + }) + if !ok { + return false, fsterr.RemediationError{ + Inner: fmt.Errorf("failed to update '%s' profile with new token data", profileName), + Remediation: "Run `fastly sso` to retry.", + } + } + data.Config.Profiles = ps + if err := data.Config.Write(data.ConfigPath); err != nil { + data.ErrLog.Add(err) + return false, fmt.Errorf("error saving config file: %w", err) + } } - // NOTE: We return error immediately so there's no issue assigning to global. - // nosemgrep - g.RTSClient, err = fastly.NewRealtimeStatsClientForEndpoint(token, fastly.DefaultRealtimeStatsEndpoint) - if err != nil { - g.ErrLog.Add(err) - return fmt.Errorf("error constructing Fastly realtime stats client: %w", err) + return false, nil +} + +// shouldSkipSSO identifies if a config is a pre-v5 config and, if it is, +// informs the user how they can use the SSO flow. It checks if the SSO +// environment variable (or flag) has been set and enables the SSO flow if so. +func shouldSkipSSO(profileName string, profileData *config.Profile, data *global.Data) bool { + if longLivedToken(profileData) { + // Skip SSO if user hasn't indicated they want to migrate. + return data.Env.UseSSO != "1" && !data.Flags.SSO + // FIXME: Put back messaging once SSO is GA. + // if data.Env.UseSSO == "1" || data.Flags.SSO { + // return false // don't skip SSO + // } + // if !data.Flags.Quiet { + // if data.Flags.Verbose { + // text.Break(data.Output) + // } + // text.Important(data.Output, "The Fastly API token used by the current '%s' profile is not a Fastly SSO (Single Sign-On) generated token. SSO-based tokens offer more security and convenience. To update your token, either set `FASTLY_USE_SSO=1` or pass `--enable-sso` before invoking the Fastly CLI. This will ensure the current profile is switched to using an SSO generated API token. Once the token has been switched over you no longer need to set `FASTLY_USE_SSO` for this profile (--token and FASTLY_API_TOKEN can still be used as overrides).\n\n", profileName) + // } + // return true // skip SSO } + return false // don't skip SSO +} + +func longLivedToken(pd *config.Profile) bool { + // If user has followed SSO flow before, then these will not be zero values. + return pd.AccessToken == "" && pd.RefreshToken == "" && pd.AccessTokenCreated == 0 && pd.RefreshTokenCreated == 0 +} + +// ssoAuthentication executes the `sso` command to handle authentication. +func ssoAuthentication(outputMessage string, cmds []cmd.Command, data *global.Data) (token string, tokenSource lookup.Source, err error) { + for _, command := range cmds { + commandName := strings.Split(command.Name(), " ")[0] + if commandName == "sso" { + if !data.Flags.AutoYes && !data.Flags.NonInteractive { + if data.Verbose() { + text.Break(data.Output) + } + text.Important(data.Output, "%s. We need to open your browser to authenticate you.", outputMessage) + text.Break(data.Output) + cont, err := text.AskYesNo(data.Output, text.BoldYellow("Do you want to continue? [y/N]: "), data.Input) + text.Break(data.Output) + if err != nil { + return token, tokenSource, err + } + if !cont { + return token, tokenSource, fsterr.ErrDontContinue + } + } - if opts.Versioners.CLI != nil && commandName != "update" && !version.IsPreRelease(revision.AppVersion) { - f := update.CheckAsync( - revision.AppVersion, - opts.Versioners.CLI, - g.Flags.Quiet, - ) - defer f(opts.Stdout) // ...and the printing function second, so we hit the timeout + data.SkipAuthPrompt = true // skip the same prompt in `sso` command flow + err := command.Exec(data.Input, data.Output) + if err != nil { + return token, tokenSource, fmt.Errorf("failed to authenticate: %w", err) + } + text.Break(data.Output) + break + } } - return command.Exec(opts.Stdin, opts.Stdout) + // Updated token should be persisted to disk after command.Exec() completes. + token, tokenSource = data.Token() + if tokenSource == lookup.SourceUndefined { + return token, tokenSource, fsterr.ErrNoToken + } + return token, tokenSource, nil } -// RunOpts represent arguments to Run(). -type RunOpts struct { - APIClient APIClientFactory - Args []string - ConfigFile config.File - ConfigPath string - Env config.Environment - ErrLog fsterr.LogInterface - ExecuteWasmTools func(bin string, args []string) error - HTTPClient api.HTTPClient - Manifest *manifest.Data - Stdin io.Reader - Stdout io.Writer - Versioners Versioners +func displayToken(tokenSource lookup.Source, data *global.Data) { + profileSource := determineProfile(data.Manifest.File.Profile, data.Flags.Profile, data.Config.Profiles) + + switch tokenSource { + case lookup.SourceFlag: + fmt.Fprintf(data.Output, "Fastly API token provided via --token\n\n") + case lookup.SourceEnvironment: + fmt.Fprintf(data.Output, "Fastly API token provided via %s\n\n", env.APIToken) + case lookup.SourceFile: + fmt.Fprintf(data.Output, "Fastly API token provided via config file (profile: %s)\n\n", profileSource) + case lookup.SourceUndefined, lookup.SourceDefault: + fallthrough + default: + fmt.Fprintf(data.Output, "Fastly API token not provided\n\n") + } } -// APIClientFactory creates a Fastly API client (modeled as an api.Interface) -// from a user-provided API token. It exists as a type in order to parameterize -// the Run helper with it: in the real CLI, we can use NewClient from the Fastly -// API client library via RealClient; in tests, we can provide a mock API -// interface via MockClient. -type APIClientFactory func(token, endpoint string, debugMode bool) (api.Interface, error) - -// Versioners represents all supported versioner types. -type Versioners struct { - CLI github.AssetVersioner - Viceroy github.AssetVersioner - WasmTools github.AssetVersioner +// If we are using the token from config file, check the file's permissions +// to assert if they are not too open or have been altered outside of the +// application and warn if so. +func checkConfigPermissions(commandName string, tokenSource lookup.Source, out io.Writer) { + segs := strings.Split(commandName, " ") + if tokenSource == lookup.SourceFile && (len(segs) > 0 && segs[0] != "profile") { + if fi, err := os.Stat(config.FilePath); err == nil { + if mode := fi.Mode().Perm(); mode > config.FilePermissions { + text.Warning(out, "Unprotected configuration file.\n\n") + text.Output(out, "Permissions for '%s' are too open\n\n", config.FilePath) + text.Output(out, "It is recommended that your configuration file is NOT accessible by others.\n\n") + } + } + } } -// displayTokenSource prints the token source. -func displayTokenSource(source lookup.Source, out io.Writer, token, profileSource string) { - switch source { +func displayAPIEndpoint(endpoint string, endpointSource lookup.Source, out io.Writer) { + switch endpointSource { case lookup.SourceFlag: - fmt.Fprintf(out, "Fastly API token provided via --token\n") + fmt.Fprintf(out, "Fastly API endpoint (via --api): %s\n", endpoint) case lookup.SourceEnvironment: - fmt.Fprintf(out, "Fastly API token provided via %s\n", token) + fmt.Fprintf(out, "Fastly API endpoint (via %s): %s\n", env.APIEndpoint, endpoint) case lookup.SourceFile: - fmt.Fprintf(out, "Fastly API token provided via config file (profile: %s)\n", profileSource) + fmt.Fprintf(out, "Fastly API endpoint (via config file): %s\n", endpoint) case lookup.SourceDefault, lookup.SourceUndefined: fallthrough default: - fmt.Fprintf(out, "Fastly API token not provided\n") + fmt.Fprintf(out, "Fastly API endpoint: %s\n", endpoint) + } +} + +func configureClients(token, apiEndpoint string, acf global.APIClientFactory, debugMode bool) (apiClient api.Interface, rtsClient api.RealtimeStatsInterface, err error) { + apiClient, err = acf(token, apiEndpoint, debugMode) + if err != nil { + return nil, nil, fmt.Errorf("error constructing Fastly API client: %w", err) + } + + rtsClient, err = fastly.NewRealtimeStatsClientForEndpoint(token, fastly.DefaultRealtimeStatsEndpoint) + if err != nil { + return nil, nil, fmt.Errorf("error constructing Fastly realtime stats client: %w", err) + } + + return apiClient, rtsClient, nil +} + +func checkForUpdates(av github.AssetVersioner, commandName string, quietMode bool) func(io.Writer) { + if av != nil && commandName != "update" && !version.IsPreRelease(revision.AppVersion) { + return update.CheckAsync(revision.AppVersion, av, quietMode) + } + return func(_ io.Writer) { + // no-op } } @@ -279,3 +674,19 @@ func commandCollectsData(command string) bool { } return false } + +// commandRequiresToken determines if the command to be executed is one that +// requires an API token. +func commandRequiresToken(command string) bool { + switch command { + case "compute init", "compute metadata": + // NOTE: Most `compute` commands require a token except init/metadata. + return false + } + command = strings.Split(command, " ")[0] + switch command { + case "config", "profile", "sso", "update", "version": + return false + } + return true +} diff --git a/pkg/app/run_test.go b/pkg/app/run_test.go index d82252502..89ce950ec 100644 --- a/pkg/app/run_test.go +++ b/pkg/app/run_test.go @@ -10,6 +10,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/testutil" ) @@ -53,6 +54,7 @@ _fastly_bash_autocomplete() { complete -F _fastly_bash_autocomplete fastly `, }, + // FIXME: Put back `sso` GA. { Name: "shell evaluate completion options", Args: args("--completion-bash"), @@ -121,9 +123,10 @@ whoami outC <- buf.String() }() - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return testutil.MockGlobalData(testcase.Args, &stdout), nil + } + err := app.Run(testcase.Args, nil) if err != nil { errors.Deduce(err).Print(&stderr) } diff --git a/pkg/app/usage.go b/pkg/app/usage.go index d146bef4d..75ca1fd1e 100644 --- a/pkg/app/usage.go +++ b/pkg/app/usage.go @@ -140,15 +140,17 @@ var UsageTemplateFuncs = template.FuncMap{ }, } -// WARNING: kingpin has no way of decorating flags as being "global" therefore -// if you add/remove a global flag you will also need to update the app.Flag() -// bindings in pkg/app/run.go. +// IMPORTANT: Kingpin doesn't support global flags. +// We hack a solution in ./run.go (`configureKingpin` function). // // NOTE: This map is used to help populate the CLI 'usage' template renderer. var globalFlags = map[string]bool{ "accept-defaults": true, + "account": true, "auto-yes": true, "debug-mode": true, + "enable-sso": true, + "endpoint": true, "help": true, "non-interactive": true, "profile": true, @@ -208,9 +210,8 @@ const VerboseUsageTemplate = `{{define "FormatCommands" -}} // processing the incoming command request from the user, as well as handling // the various places where help output can be displayed. func processCommandInput( - opts RunOpts, + data *global.Data, app *kingpin.Application, - g *global.Data, commands []cmd.Command, ) (command cmd.Command, cmdName string, err error) { // As the `help` command model gets privately added as a side-effect of @@ -218,18 +219,18 @@ func processCommandInput( // Therefore, we have to manually parse the args slice here to check for the // existence of `help --format json`, if present we print usage JSON and // exit early. - if cmd.ArgsIsHelpJSON(opts.Args) { + if cmd.ArgsIsHelpJSON(data.Args) { j, err := UsageJSON(app) if err != nil { - g.ErrLog.Add(err) + data.ErrLog.Add(err) return command, cmdName, err } - fmt.Fprintf(opts.Stdout, "%s", j) - return command, strings.Join(opts.Args, ""), nil + fmt.Fprintf(data.Output, "%s", j) + return command, strings.Join(data.Args, ""), nil } // Use partial application to generate help output function. - help := displayHelp(g.ErrLog, opts.Args, app, opts.Stdout, io.Discard) + help := displayHelp(data.ErrLog, data.Args, app, data.Output, io.Discard) // Handle parse errors and display contextual usage if possible. Due to bugs // and an obsession for lots of output side-effects in the kingpin.Parse @@ -250,14 +251,14 @@ func processCommandInput( // But it's useful to have it implemented so it's ready to roll when we do. var vars map[string]any - if cmd.IsVerboseAndQuiet(opts.Args) { + if cmd.IsVerboseAndQuiet(data.Args) { return command, cmdName, fsterr.RemediationError{ Inner: errors.New("--verbose and --quiet flag provided"), Remediation: "Either remove both --verbose and --quiet flags, or one of them.", } } - if cmd.IsHelpFlagOnly(opts.Args) && len(opts.Args) == 1 { + if cmd.IsHelpFlagOnly(data.Args) && len(data.Args) == 1 { return command, cmdName, fsterr.SkipExitError{ Skip: true, Err: help(vars, nil), @@ -284,17 +285,17 @@ func processCommandInput( // // ctx.SelectedCommand will be nil if only a flag like --verbose or -v is // provided but with no actual command set so we check with IsGlobalFlagsOnly. - noargs := len(opts.Args) == 0 - globalFlagsOnly := cmd.IsGlobalFlagsOnly(opts.Args) - ctx, err := app.ParseContext(opts.Args) - if err != nil && !cmd.IsCompletion(opts.Args) || noargs || globalFlagsOnly { + noargs := len(data.Args) == 0 + globalFlagsOnly := cmd.IsGlobalFlagsOnly(data.Args) + ctx, err := app.ParseContext(data.Args) + if err != nil && !cmd.IsCompletion(data.Args) || noargs || globalFlagsOnly { if noargs || globalFlagsOnly { err = fmt.Errorf("command not specified") } return command, cmdName, help(vars, err) } - if len(opts.Args) == 1 && opts.Args[0] == "--" { + if len(data.Args) == 1 && data.Args[0] == "--" { return command, cmdName, fsterr.RemediationError{ Inner: errors.New("-- is invalid input when not followed by a positional argument"), Remediation: "If looking for help output try: `fastly help` for full command list or `fastly --help` for command summary.", @@ -310,14 +311,14 @@ func processCommandInput( // completion flag, as that depends on kingpin.Parse() being called, and so // the `ctx` is otherwise empty. var found bool - if !noargs && !globalFlagsOnly && !cmd.IsHelpOnly(opts.Args) && !cmd.IsHelpFlagOnly(opts.Args) && !cmd.IsCompletion(opts.Args) && !cmd.IsCompletionScript(opts.Args) { + if !noargs && !globalFlagsOnly && !cmd.IsHelpOnly(data.Args) && !cmd.IsHelpFlagOnly(data.Args) && !cmd.IsCompletion(data.Args) && !cmd.IsCompletionScript(data.Args) { command, found = cmd.Select(ctx.SelectedCommand.FullCommand(), commands) if !found { return command, cmdName, help(vars, err) } } - if cmd.ContextHasHelpFlag(ctx) && !cmd.IsHelpFlagOnly(opts.Args) { + if cmd.ContextHasHelpFlag(ctx) && !cmd.IsHelpFlagOnly(data.Args) { return command, cmdName, fsterr.SkipExitError{ Skip: true, Err: help(vars, nil), @@ -344,21 +345,21 @@ func processCommandInput( // caller passes --completion-bash because adding a command to the arguments // list in that scenario would cause Kingpin logic to fail (as it expects the // flag to be used on its own). - if cmd.IsCompletionScript(opts.Args) { - opts.Args = append(opts.Args, "shellcomplete") + if cmd.IsCompletionScript(data.Args) { + data.Args = append(data.Args, "shellcomplete") } - cmdName, err = app.Parse(opts.Args) + cmdName, err = app.Parse(data.Args) if err != nil { return command, "", help(vars, err) } // Restore output writers - app.Writers(opts.Stdout, io.Discard) + app.Writers(data.Output, io.Discard) // Kingpin generates shell completion as a side-effect of kingpin.Parse() so // we allow it to call os.Exit, only if a completion flag is present. - if cmd.IsCompletion(opts.Args) || cmd.IsCompletionScript(opts.Args) { + if cmd.IsCompletion(data.Args) || cmd.IsCompletionScript(data.Args) { app.Terminate(os.Exit) return command, "shell-autocomplete", nil } @@ -371,14 +372,14 @@ func processCommandInput( return command, cmdName, fsterr.SkipExitError{ Skip: true, Err: fsterr.RemediationError{ - Prefix: useFullHelpOutput(app, opts).String(), + Prefix: useFullHelpOutput(app, data.Args, data.Output).String(), }, } } // Catch scenario where user wants to view help with the following format: // fastly --help - if cmd.IsHelpFlagOnly(opts.Args) { + if cmd.IsHelpFlagOnly(data.Args) { return command, cmdName, fsterr.SkipExitError{ Skip: true, Err: help(vars, nil), @@ -388,16 +389,16 @@ func processCommandInput( return command, cmdName, nil } -func useFullHelpOutput(app *kingpin.Application, opts RunOpts) *bytes.Buffer { +func useFullHelpOutput(app *kingpin.Application, args []string, out io.Writer) *bytes.Buffer { var buf bytes.Buffer app.Writers(&buf, io.Discard) - _, _ = app.Parse(opts.Args) - app.Writers(opts.Stdout, io.Discard) + _, _ = app.Parse(args) + app.Writers(out, io.Discard) // The full-fat output of `fastly help` should have a hint at the bottom // for more specific help. Unfortunately I don't know of a better way to // distinguish `fastly help` from e.g. `fastly help pops` than this check. - if len(opts.Args) > 0 && opts.Args[len(opts.Args)-1] == "help" { + if len(args) > 0 && args[len(args)-1] == "help" { fmt.Fprintln(&buf, "\nFor help on a specific command, try e.g.") fmt.Fprintln(&buf, "") fmt.Fprintln(&buf, "\tfastly help profile") diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go new file mode 100644 index 000000000..3f6cafd55 --- /dev/null +++ b/pkg/auth/auth.go @@ -0,0 +1,413 @@ +package auth + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/hashicorp/cap/jwt" + "github.com/hashicorp/cap/oidc" + + "github.com/fastly/cli/pkg/api" + "github.com/fastly/cli/pkg/api/undocumented" + fsterr "github.com/fastly/cli/pkg/errors" +) + +// Remediation is a generic remediation message for an error authorizing. +const Remediation = "Please re-run the command. If the problem persists, please file an issue: https://github.com/fastly/cli/issues/new?labels=bug&template=bug_report.md" + +// ClientID is the auth provider's Client ID. +const ClientID = "fastly-cli" + +// RedirectURL is the endpoint the auth provider will pass an authorization code to. +const RedirectURL = "http://localhost:8080/callback" + +// OIDCMetadata is OpenID Connect's metadata discovery mechanism. +// https://swagger.io/docs/specification/authentication/openid-connect-discovery/ +const OIDCMetadata = "%s/realms/fastly/.well-known/openid-configuration" + +// WellKnownEndpoints represents the OpenID Connect metadata. +type WellKnownEndpoints struct { + // Auth is the authorization_endpoint. + Auth string `json:"authorization_endpoint"` + // Certs is the jwks_uri. + Certs string `json:"jwks_uri"` + // Token is the token_endpoint. + Token string `json:"token_endpoint"` +} + +// Runner defines the behaviour for the authentication server. +type Runner interface { + // AuthURL returns a fully qualified authorization_endpoint. + // i.e. path + audience + scope + code_challenge etc. + AuthURL() (string, error) + // GetResult returns the results channel + GetResult() chan AuthorizationResult + // RefreshAccessToken constructs and calls the token_endpoint with the + // refresh token so we can refresh and return the access token. + RefreshAccessToken(refreshToken string) (JWT, error) + // SetEndpoint sets the API endpoint. + SetAPIEndpoint(endpoint string) + // Start starts a local server for handling authentication processing. + Start() error + // ValidateAndRetrieveAPIToken verifies the signature and the claims and + // exchanges the access token for an API token. + ValidateAndRetrieveAPIToken(accessToken string) (string, *APIToken, error) +} + +// Server is a local server responsible for authentication processing. +type Server struct { + // APIEndpoint is the API endpoint. + APIEndpoint string + // AccountEndpoint is the accounts endpoint. + AccountEndpoint string + // DebugMode indicates to the CLI it can display debug information. + DebugMode string + // HTTPClient is a HTTP client used to call the API to exchange the access token for a session token. + HTTPClient api.HTTPClient + // Result is a channel that reports the result of authorization. + Result chan AuthorizationResult + // Router is an HTTP request multiplexer. + Router *http.ServeMux + // Verifier represents an OAuth PKCE code verifier that uses the S256 challenge method. + Verifier *oidc.S256Verifier + // WellKnownEndpoints is the .well-known metadata. + WellKnownEndpoints WellKnownEndpoints +} + +// AuthURL returns a fully qualified authorization_endpoint. +// i.e. path + audience + scope + code_challenge etc. +func (s Server) AuthURL() (string, error) { + challenge, err := oidc.CreateCodeChallenge(s.Verifier) + if err != nil { + return "", err + } + + authorizationURL := fmt.Sprintf( + "%s?audience=%s"+ + "&scope=openid"+ + "&response_type=code&client_id=%s"+ + "&code_challenge=%s"+ + "&code_challenge_method=S256&redirect_uri=%s", + s.WellKnownEndpoints.Auth, s.APIEndpoint, ClientID, challenge, RedirectURL) + + return authorizationURL, nil +} + +// GetResult returns the result channel. +func (s Server) GetResult() chan AuthorizationResult { + return s.Result +} + +// GetJWT constructs and calls the token_endpoint path, returning a JWT +// containing the access and refresh tokens and associated TTLs. +func (s Server) GetJWT(authorizationCode string) (JWT, error) { + payload := fmt.Sprintf( + "grant_type=authorization_code&client_id=%s&code_verifier=%s&code=%s&redirect_uri=%s", + ClientID, + s.Verifier.Verifier(), + authorizationCode, + "http://localhost:8080/callback", // NOTE: not redirected to, just a security check. + ) + + req, err := http.NewRequest("POST", s.WellKnownEndpoints.Token, strings.NewReader(payload)) + if err != nil { + return JWT{}, err + } + + req.Header.Add("content-type", "application/x-www-form-urlencoded") + + res, err := http.DefaultClient.Do(req) + if err != nil { + return JWT{}, err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return JWT{}, fmt.Errorf("failed to exchange code for jwt (status: %s)", res.Status) + } + + body, err := io.ReadAll(res.Body) + if err != nil { + return JWT{}, err + } + + var j JWT + err = json.Unmarshal(body, &j) + if err != nil { + return JWT{}, err + } + + return j, nil +} + +// SetAPIEndpoint sets the API endpoint. +func (s *Server) SetAPIEndpoint(endpoint string) { + s.APIEndpoint = endpoint +} + +// SetVerifier sets the code verifier endpoint. +func (s *Server) SetVerifier(verifier *oidc.S256Verifier) { + s.Verifier = verifier +} + +// Start starts a local server for handling authentication processing. +func (s *Server) Start() error { + server := &http.Server{ + Addr: ":8080", + Handler: s.Router, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + } + + err := server.ListenAndServe() + if err != nil { + return fsterr.RemediationError{ + Inner: fmt.Errorf("failed to start local server: %w", err), + Remediation: Remediation, + } + } + return nil +} + +// HandleCallback processes the callback from the authentication service. +func (s *Server) HandleCallback() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + authorizationCode := r.URL.Query().Get("code") + if authorizationCode == "" { + fmt.Fprint(w, "ERROR: no authorization code returned\n") + s.Result <- AuthorizationResult{ + Err: fmt.Errorf("no authorization code returned"), + } + return + } + + // Exchange the authorization code and the code verifier for a JWT. + // NOTE: I use the identifier `j` to avoid overlap with the `jwt` package. + j, err := s.GetJWT(authorizationCode) + if err != nil || j.AccessToken == "" || j.IDToken == "" { + fmt.Fprint(w, "ERROR: failed to exchange code for JWT\n") + s.Result <- AuthorizationResult{ + Err: fmt.Errorf("failed to exchange code for JWT"), + } + return + } + + email, at, err := s.ValidateAndRetrieveAPIToken(j.AccessToken) + if err != nil { + s.Result <- AuthorizationResult{ + Err: err, + } + return + } + + fmt.Fprint(w, "Authenticated successfully. Please close this page and return to the Fastly CLI in your terminal.") + s.Result <- AuthorizationResult{ + Email: email, + Jwt: j, + SessionToken: at.AccessToken, + } + } +} + +// ValidateAndRetrieveAPIToken verifies the signature and the claims and +// exchanges the access token for an API token. +// +// NOTE: This function exists as it's called by this package + app.Run(). +func (s *Server) ValidateAndRetrieveAPIToken(accessToken string) (string, *APIToken, error) { + claims, err := s.VerifyJWTSignature(accessToken) + if err != nil { + return "", nil, err + } + + azp, ok := claims["azp"] + if !ok { + return "", nil, errors.New("failed to extract azp from JWT claims") + } + if azp != ClientID { + if !ok { + return "", nil, fmt.Errorf("failed to match expected azp: %s", azp) + } + } + + aud, ok := claims["aud"] + if !ok { + return "", nil, errors.New("failed to extract aud from JWT claims") + } + + if aud != s.APIEndpoint { + if !ok { + return "", nil, fmt.Errorf("failed to match expected aud: %s", s.APIEndpoint) + } + } + + email, ok := claims["email"] + if !ok { + return "", nil, errors.New("failed to extract email from JWT claims") + } + + // Exchange the access token for a Fastly API token. + at, err := s.ExchangeAccessToken(accessToken) + if err != nil { + return "", nil, fmt.Errorf("failed to exchange access token for an API token: %w", err) + } + + e, ok := email.(string) + if !ok { + return "", nil, fmt.Errorf("failed to type assert 'email' (%#v) to a string", email) + } + return e, at, nil +} + +// VerifyJWTSignature calls the jwks_uri endpoint and extracts its claims. +func (s *Server) VerifyJWTSignature(accessToken string) (claims map[string]any, err error) { + ctx := context.Background() + + // NOTE: The last argument is optional and is for validating the JWKs endpoint + // (which we don't need to do, so we pass an empty string) + keySet, err := jwt.NewJSONWebKeySet(ctx, s.WellKnownEndpoints.Certs, "") + if err != nil { + return claims, fmt.Errorf("failed to verify signature of access token: %w", err) + } + + claims, err = keySet.VerifySignature(ctx, accessToken) + if err != nil { + return nil, fmt.Errorf("failed to verify signature of access token: %w", err) + } + + return claims, nil +} + +// ExchangeAccessToken exchanges `accessToken` for a Fastly API token. +func (s *Server) ExchangeAccessToken(accessToken string) (*APIToken, error) { + debug, _ := strconv.ParseBool(s.DebugMode) + resp, err := undocumented.Call(undocumented.CallOptions{ + APIEndpoint: s.APIEndpoint, + HTTPClient: s.HTTPClient, + HTTPHeaders: []undocumented.HTTPHeader{ + { + Key: "Authorization", + Value: fmt.Sprintf("Bearer %s", accessToken), + }, + }, + Method: http.MethodPost, + Path: "/login-enhanced", + Debug: debug, + }) + if err != nil { + if apiErr, ok := err.(undocumented.APIError); ok { + if apiErr.StatusCode != http.StatusConflict { + err = fmt.Errorf("%w: %d %s", err, apiErr.StatusCode, http.StatusText(apiErr.StatusCode)) + } + } + return nil, err + } + + at := &APIToken{} + err = json.Unmarshal(resp, at) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal json containing API token: %w", err) + } + + return at, nil +} + +// RefreshAccessToken constructs and calls the token_endpoint with the +// refresh token so we can refresh and return the access token. +func (s *Server) RefreshAccessToken(refreshToken string) (JWT, error) { + payload := fmt.Sprintf( + "grant_type=refresh_token&client_id=%s&refresh_token=%s", + ClientID, + refreshToken, + ) + + req, err := http.NewRequest("POST", s.WellKnownEndpoints.Token, strings.NewReader(payload)) + if err != nil { + return JWT{}, err + } + + req.Header.Add("content-type", "application/x-www-form-urlencoded") + + res, err := http.DefaultClient.Do(req) + if err != nil { + return JWT{}, err + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return JWT{}, err + } + + if res.StatusCode != http.StatusOK { + return JWT{}, fmt.Errorf("failed to refresh the access token (status: %s)", res.Status) + } + + var j JWT + err = json.Unmarshal(body, &j) + if err != nil { + return JWT{}, err + } + + return j, nil +} + +// APIToken is returned from the /login-enhanced endpoint. +type APIToken struct { + // AccessToken is used to access the Fastly API. + AccessToken string `json:"access_token"` + // CustomerID is the customer ID. + CustomerID string `json:"customer_id"` + // ExpiresAt is when the access token will expire. + ExpiresAt string `json:"expires_at"` + // ID is a unique ID. + ID string `json:"id"` + // Name is a description of the token. + Name string `json:"name"` + // UserID is the user's ID. + UserID string `json:"user_id"` +} + +// AuthorizationResult represents the result of the authorization process. +type AuthorizationResult struct { + // Email address extracted from JWT claims. + Email string + // Err is any error received during authentication. + Err error + // Jwt is the JWT token returned by the authorization server. + Jwt JWT + // SessionToken is a temporary API token. + SessionToken string +} + +// JWT is the API response for a Token request. +// +// Access Token typically has a TTL of 5mins. +// Refresh Token typically has a TTL of 30mins. +type JWT struct { + // AccessToken can be exchanged for a Fastly API token. + AccessToken string `json:"access_token"` + // ExpiresIn indicates the lifetime (in seconds) of the access token. + ExpiresIn int `json:"expires_in"` + // IDToken contains user information that must be decoded and extracted. + IDToken string `json:"id_token"` + // RefreshExpiresIn indicates the lifetime (in seconds) of the refresh token. + RefreshExpiresIn int `json:"refresh_expires_in"` + // RefreshToken contains a token used to refresh the issued access token. + RefreshToken string `json:"refresh_token"` + // TokenType indicates which HTTP authentication scheme is used (e.g. Bearer). + TokenType string `json:"token_type"` +} + +// TokenExpired indicates if the specified TTL has past. +func TokenExpired(ttl int, timestamp int64) bool { + d := time.Duration(ttl) * time.Second + ttlAgo := time.Now().Add(-d).Unix() + return timestamp < ttlAgo +} diff --git a/pkg/auth/doc.go b/pkg/auth/doc.go new file mode 100644 index 000000000..80936d07b --- /dev/null +++ b/pkg/auth/doc.go @@ -0,0 +1,2 @@ +// Package auth contains types to authenticate with Fastly. +package auth diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 2120ee5aa..2973e3dda 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -253,14 +253,20 @@ func IsVerboseAndQuiet(args []string) bool { // // args: [--verbose -v --endpoint ... --token ... -t ... --endpoint ...] 10 // total: 10 +// +// IMPORTANT: Kingpin doesn't support global flags. +// We hack a solution in ../app/run.go (`configureKingpin` function). func IsGlobalFlagsOnly(args []string) bool { // Global flags are defined in ../app/run.go globals := map[string]int{ "--accept-defaults": 0, "-d": 0, + "--account": 1, + "--api": 1, "--auto-yes": 0, "-y": 0, - "--endpoint": 1, + "--debug-mode": 0, + "--enable-sso": 0, "--help": 0, "--non-interactive": 0, "-i": 0, diff --git a/pkg/commands/acl/acl_test.go b/pkg/commands/acl/acl_test.go index 1d4a2828e..1c634af8f 100644 --- a/pkg/commands/acl/acl_test.go +++ b/pkg/commands/acl/acl_test.go @@ -2,11 +2,13 @@ package acl_test import ( "bytes" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -87,9 +89,13 @@ func TestACLCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) + t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -162,9 +168,12 @@ func TestACLDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -224,9 +233,12 @@ func TestACLDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -282,7 +294,7 @@ func TestACLList(t *testing.T) { ListACLsFn: listACLs, }, Args: args("acl list --service-id 123 --verbose --version 1"), - WantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\nID: 456\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\nID: 789\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\n", + WantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\nID: 456\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\nID: 789\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\n", }, } @@ -290,9 +302,12 @@ func TestACLList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -380,9 +395,12 @@ func TestACLUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/acl/create.go b/pkg/commands/acl/create.go index aebdbcf79..bc8e46695 100644 --- a/pkg/commands/acl/create.go +++ b/pkg/commands/acl/create.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a new ACL attached to the specified service version").Alias("add") @@ -40,7 +38,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -58,7 +56,6 @@ type CreateCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name cmd.OptionalString serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -70,7 +67,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, ErrLog: c.Globals.ErrLog, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/acl/delete.go b/pkg/commands/acl/delete.go index 01a7ffab9..90bb7a025 100644 --- a/pkg/commands/acl/delete.go +++ b/pkg/commands/acl/delete.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an ACL from the specified service version").Alias("remove") @@ -39,7 +37,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -57,7 +55,6 @@ type DeleteCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -68,7 +65,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/acl/describe.go b/pkg/commands/acl/describe.go index d6e2451cb..cfb7220a4 100644 --- a/pkg/commands/acl/describe.go +++ b/pkg/commands/acl/describe.go @@ -4,20 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Retrieve a single ACL by name for the version and service").Alias("get") @@ -35,7 +34,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -68,7 +66,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/acl/list.go b/pkg/commands/acl/list.go index 7b186d1b6..071a3a5c7 100644 --- a/pkg/commands/acl/list.go +++ b/pkg/commands/acl/list.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List ACLs") @@ -35,7 +34,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/acl/update.go b/pkg/commands/acl/update.go index 1a3acf6f8..3f7fc04a4 100644 --- a/pkg/commands/acl/update.go +++ b/pkg/commands/acl/update.go @@ -3,21 +3,20 @@ package acl import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update an ACL for a particular service and version") @@ -39,7 +38,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -57,7 +56,6 @@ type UpdateCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name string newName string serviceName cmd.OptionalServiceNameID @@ -69,7 +67,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/aclentry/aclentry_test.go b/pkg/commands/aclentry/aclentry_test.go index 297a42b4a..226850d06 100644 --- a/pkg/commands/aclentry/aclentry_test.go +++ b/pkg/commands/aclentry/aclentry_test.go @@ -2,11 +2,13 @@ package aclentry_test import ( "bytes" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -76,9 +78,12 @@ func TestACLEntryCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -129,9 +134,12 @@ func TestACLEntryDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -180,9 +188,12 @@ func TestACLEntryDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -326,9 +337,12 @@ func TestACLEntryList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -348,8 +362,8 @@ var listACLEntriesOutputPageTwo = `SERVICE ID ID IP SUBNET NEGATED 123 789 127.0.0.2 0 true ` -var listACLEntriesOutputVerbose = `Fastly API token not provided -Fastly API endpoint: https://api.fastly.com +var listACLEntriesOutputVerbose = `Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 @@ -455,9 +469,12 @@ func TestACLEntryUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/aclentry/create.go b/pkg/commands/aclentry/create.go index 640c7b840..a75cf349e 100644 --- a/pkg/commands/aclentry/create.go +++ b/pkg/commands/aclentry/create.go @@ -3,20 +3,19 @@ package aclentry import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Add an ACL entry to an ACL").Alias("add") @@ -30,7 +29,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -51,7 +50,6 @@ type CreateCommand struct { aclID string comment cmd.OptionalString ip cmd.OptionalString - manifest manifest.Data negated cmd.OptionalBool serviceName cmd.OptionalServiceNameID subnet cmd.OptionalInt @@ -59,7 +57,7 @@ type CreateCommand struct { // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/aclentry/delete.go b/pkg/commands/aclentry/delete.go index 3b5a98f26..04f596a79 100644 --- a/pkg/commands/aclentry/delete.go +++ b/pkg/commands/aclentry/delete.go @@ -7,17 +7,15 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an ACL entry from a specified ACL").Alias("remove") @@ -29,7 +27,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -48,13 +46,12 @@ type DeleteCommand struct { aclID string id string - manifest manifest.Data serviceName cmd.OptionalServiceNameID } // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/aclentry/describe.go b/pkg/commands/aclentry/describe.go index 37796a606..cbb1d92bf 100644 --- a/pkg/commands/aclentry/describe.go +++ b/pkg/commands/aclentry/describe.go @@ -4,20 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Retrieve a single ACL entry").Alias("get") @@ -30,7 +29,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -50,7 +49,6 @@ type DescribeCommand struct { aclID string id string - manifest manifest.Data serviceName cmd.OptionalServiceNameID } @@ -60,7 +58,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/aclentry/list.go b/pkg/commands/aclentry/list.go index 115d41d43..55b3a634b 100644 --- a/pkg/commands/aclentry/list.go +++ b/pkg/commands/aclentry/list.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List ACLs") @@ -30,7 +29,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -55,7 +54,6 @@ type ListCommand struct { aclID string direction string - manifest manifest.Data page int perPage int serviceName cmd.OptionalServiceNameID @@ -68,7 +66,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/aclentry/update.go b/pkg/commands/aclentry/update.go index d5466c960..946512401 100644 --- a/pkg/commands/aclentry/update.go +++ b/pkg/commands/aclentry/update.go @@ -10,17 +10,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update an ACL entry for a specified ACL") @@ -36,7 +34,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -59,7 +57,6 @@ type UpdateCommand struct { file cmd.OptionalString id cmd.OptionalString ip cmd.OptionalString - manifest manifest.Data negated cmd.OptionalBool serviceName cmd.OptionalServiceNameID subnet cmd.OptionalInt @@ -67,7 +64,7 @@ type UpdateCommand struct { // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/authtoken/authtoken_test.go b/pkg/commands/authtoken/authtoken_test.go index 14e57dfbc..654922963 100644 --- a/pkg/commands/authtoken/authtoken_test.go +++ b/pkg/commands/authtoken/authtoken_test.go @@ -3,13 +3,14 @@ package authtoken_test import ( "bytes" "fmt" + "io" "os" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" - "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -22,11 +23,6 @@ func TestCreate(t *testing.T) { Args: args("auth-token create"), WantError: "error parsing arguments: required flag --password not provided", }, - { - Name: "validate missing --token flag", - Args: args("auth-token create --password secure"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate CreateToken API error", API: mock.API{ @@ -75,9 +71,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -87,11 +86,6 @@ func TestCreate(t *testing.T) { func TestDelete(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing --token flag", - Args: args("auth-token delete"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate missing optional flags", Args: args("auth-token delete --token 123"), @@ -173,9 +167,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -185,11 +182,6 @@ func TestDelete(t *testing.T) { func TestDescribe(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing --token flag", - Args: args("auth-token describe"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate GetTokenSelf API error", API: mock.API{ @@ -214,9 +206,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -230,13 +225,6 @@ func TestList(t *testing.T) { SetEnv bool } scenarios := []ts{ - { - TestScenario: testutil.TestScenario{ - Name: "validate missing --token flag", - Args: args("auth-token list"), - WantError: errors.ErrNoToken.Inner.Error(), - }, - }, { TestScenario: testutil.TestScenario{ Name: "validate ListTokens API error", @@ -245,7 +233,7 @@ func TestList(t *testing.T) { return nil, testutil.Err }, }, - Args: args("auth-token list --token 123"), + Args: args("auth-token list"), WantError: testutil.Err.Error(), }, }, @@ -257,7 +245,7 @@ func TestList(t *testing.T) { return nil, testutil.Err }, }, - Args: args("auth-token list --customer-id 123 --token 123"), + Args: args("auth-token list --customer-id 123"), WantError: testutil.Err.Error(), }, }, @@ -267,7 +255,7 @@ func TestList(t *testing.T) { API: mock.API{ ListTokensFn: listTokens, }, - Args: args("auth-token list --token 123"), + Args: args("auth-token list"), WantOutput: listTokenOutputSummary(false), }, }, @@ -277,7 +265,7 @@ func TestList(t *testing.T) { API: mock.API{ ListCustomerTokensFn: listCustomerTokens, }, - Args: args("auth-token list --customer-id 123 --token 123"), + Args: args("auth-token list --customer-id 123"), WantOutput: listTokenOutputSummary(false), }, }, @@ -287,7 +275,7 @@ func TestList(t *testing.T) { API: mock.API{ ListCustomerTokensFn: listCustomerTokens, }, - Args: args("auth-token list --token 123"), + Args: args("auth-token list"), WantOutput: listTokenOutputSummary(true), }, SetEnv: true, @@ -298,7 +286,7 @@ func TestList(t *testing.T) { API: mock.API{ ListTokensFn: listTokens, }, - Args: args("auth-token list --token 123 --verbose"), + Args: args("auth-token list --verbose"), WantOutput: listTokenOutputVerbose(), }, }, @@ -318,9 +306,12 @@ func TestList(t *testing.T) { }() } var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -391,8 +382,8 @@ Expires at: 2021-06-15 23:00:00 +0000 UTC` } func listTokenOutputVerbose() string { - return `Fastly API token provided via --token -Fastly API endpoint: https://api.fastly.com + return `Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) ID: 123 diff --git a/pkg/commands/authtoken/create.go b/pkg/commands/authtoken/create.go index 4a509d12e..f677fc753 100644 --- a/pkg/commands/authtoken/create.go +++ b/pkg/commands/authtoken/create.go @@ -5,14 +5,12 @@ import ( "strings" "time" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/kingpin" + "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" - "github.com/fastly/kingpin" ) // Scopes is a list of purging scope options. @@ -20,12 +18,11 @@ import ( var Scopes = []string{"global", "purge_select", "purge_all", "global:read"} // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create an API token").Alias("add") @@ -56,7 +53,6 @@ type CreateCommand struct { cmd.Base expires time.Time - manifest manifest.Data name string password string scope []string @@ -65,11 +61,6 @@ type CreateCommand struct { // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - input := c.constructInput() r, err := c.Globals.APIClient.CreateToken(input) diff --git a/pkg/commands/authtoken/delete.go b/pkg/commands/authtoken/delete.go index 7f5d79be2..1ccc3ecfe 100644 --- a/pkg/commands/authtoken/delete.go +++ b/pkg/commands/authtoken/delete.go @@ -10,20 +10,16 @@ import ( "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Revoke an API token").Alias("remove") @@ -37,19 +33,13 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base - current bool - file string - id string - manifest manifest.Data + current bool + file string + id string } // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - if !c.current && c.file == "" && c.id == "" { return fmt.Errorf("error parsing arguments: must provide either the --current, --file or --id flag") } diff --git a/pkg/commands/authtoken/describe.go b/pkg/commands/authtoken/describe.go index e4dc3c5c8..8ac545098 100644 --- a/pkg/commands/authtoken/describe.go +++ b/pkg/commands/authtoken/describe.go @@ -5,21 +5,19 @@ import ( "io" "strings" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Get the current API token").Alias("get") @@ -31,16 +29,10 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) type DescribeCommand struct { cmd.Base cmd.JSONOutput - - manifest manifest.Data } // Exec invokes the application logic for the command. func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } diff --git a/pkg/commands/authtoken/list.go b/pkg/commands/authtoken/list.go index b9f9a014c..4b871534f 100644 --- a/pkg/commands/authtoken/list.go +++ b/pkg/commands/authtoken/list.go @@ -10,18 +10,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List API tokens") @@ -41,15 +38,10 @@ type ListCommand struct { cmd.JSONOutput customerID cmd.OptionalCustomerID - manifest manifest.Data } // Exec invokes the application logic for the command. func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } diff --git a/pkg/commands/backend/backend_test.go b/pkg/commands/backend/backend_test.go index dc96a93e4..601f6df20 100644 --- a/pkg/commands/backend/backend_test.go +++ b/pkg/commands/backend/backend_test.go @@ -3,6 +3,7 @@ package backend_test import ( "bytes" "errors" + "io" "strings" "testing" @@ -10,6 +11,7 @@ import ( "github.com/fastly/cli/pkg/app" fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -130,9 +132,12 @@ func TestBackendCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -211,9 +216,12 @@ func TestBackendList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) if testcase.WantError == "" { testutil.AssertString(t, testcase.WantOutput, stdout.String()) @@ -250,9 +258,12 @@ func TestBackendDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -291,9 +302,12 @@ func TestBackendUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -330,9 +344,12 @@ func TestBackendDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -477,8 +494,8 @@ SERVICE VERSION NAME ADDRESS PORT COMMENT `) + "\n" var listBackendsVerboseOutput = strings.Join([]string{ - "Fastly API token not provided", "Fastly API endpoint: https://api.fastly.com", + "Fastly API token provided via config file (profile: user)", "", "Service ID (via --service-id): 123", "", diff --git a/pkg/commands/backend/create.go b/pkg/commands/backend/create.go index 09749e918..d529dba12 100644 --- a/pkg/commands/backend/create.go +++ b/pkg/commands/backend/create.go @@ -9,14 +9,12 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // CreateCommand calls the Fastly API to create backends. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceVersion cmd.OptionalServiceVersion @@ -52,12 +50,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a backend on a Fastly service version").Alias("add") @@ -93,7 +90,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -121,7 +118,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/backend/delete.go b/pkg/commands/backend/delete.go index 50632dbdd..d45f096dc 100644 --- a/pkg/commands/backend/delete.go +++ b/pkg/commands/backend/delete.go @@ -3,18 +3,17 @@ package backend import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete backends. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteBackendInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a backend on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -66,7 +64,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/backend/describe.go b/pkg/commands/backend/describe.go index 9cecba7ef..a838ba786 100644 --- a/pkg/commands/backend/describe.go +++ b/pkg/commands/backend/describe.go @@ -4,11 +4,11 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a backend. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetBackendInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a backend on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/backend/list.go b/pkg/commands/backend/list.go index 0fafa4ed9..634573316 100644 --- a/pkg/commands/backend/list.go +++ b/pkg/commands/backend/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list backends. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListBackendsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List backends on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/backend/update.go b/pkg/commands/backend/update.go index 1c85b7c1d..1c4f3c484 100644 --- a/pkg/commands/backend/update.go +++ b/pkg/commands/backend/update.go @@ -8,14 +8,12 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // UpdateCommand calls the Fastly API to update backends. type UpdateCommand struct { cmd.Base - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion autoClone cmd.OptionalAutoClone @@ -50,12 +48,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a backend on a Fastly service version") @@ -91,7 +88,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -118,7 +115,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/app/commands.go b/pkg/commands/commands.go similarity index 74% rename from pkg/app/commands.go rename to pkg/commands/commands.go index c8138e84e..a83351476 100644 --- a/pkg/app/commands.go +++ b/pkg/commands/commands.go @@ -1,4 +1,4 @@ -package app +package commands import ( "github.com/fastly/kingpin" @@ -59,6 +59,7 @@ import ( "github.com/fastly/cli/pkg/commands/serviceauth" "github.com/fastly/cli/pkg/commands/serviceversion" "github.com/fastly/cli/pkg/commands/shellcomplete" + "github.com/fastly/cli/pkg/commands/sso" "github.com/fastly/cli/pkg/commands/stats" tlsconfig "github.com/fastly/cli/pkg/commands/tls/config" tlscustom "github.com/fastly/cli/pkg/commands/tls/custom" @@ -77,379 +78,386 @@ import ( "github.com/fastly/cli/pkg/commands/version" "github.com/fastly/cli/pkg/commands/whoami" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" ) -func defineCommands( +// Define constructs all the commands exposed by the CLI. +func Define( app *kingpin.Application, - g *global.Data, - m manifest.Data, - opts RunOpts, + data *global.Data, ) []cmd.Command { - shellcompleteCmdRoot := shellcomplete.NewRootCommand(app, g) - aclCmdRoot := acl.NewRootCommand(app, g) - aclCreate := acl.NewCreateCommand(aclCmdRoot.CmdClause, g, m) - aclDelete := acl.NewDeleteCommand(aclCmdRoot.CmdClause, g, m) - aclDescribe := acl.NewDescribeCommand(aclCmdRoot.CmdClause, g, m) - aclList := acl.NewListCommand(aclCmdRoot.CmdClause, g, m) - aclUpdate := acl.NewUpdateCommand(aclCmdRoot.CmdClause, g, m) - aclEntryCmdRoot := aclentry.NewRootCommand(app, g) - aclEntryCreate := aclentry.NewCreateCommand(aclEntryCmdRoot.CmdClause, g, m) - aclEntryDelete := aclentry.NewDeleteCommand(aclEntryCmdRoot.CmdClause, g, m) - aclEntryDescribe := aclentry.NewDescribeCommand(aclEntryCmdRoot.CmdClause, g, m) - aclEntryList := aclentry.NewListCommand(aclEntryCmdRoot.CmdClause, g, m) - aclEntryUpdate := aclentry.NewUpdateCommand(aclEntryCmdRoot.CmdClause, g, m) - authtokenCmdRoot := authtoken.NewRootCommand(app, g) - authtokenCreate := authtoken.NewCreateCommand(authtokenCmdRoot.CmdClause, g, m) - authtokenDelete := authtoken.NewDeleteCommand(authtokenCmdRoot.CmdClause, g, m) - authtokenDescribe := authtoken.NewDescribeCommand(authtokenCmdRoot.CmdClause, g, m) - authtokenList := authtoken.NewListCommand(authtokenCmdRoot.CmdClause, g, m) - backendCmdRoot := backend.NewRootCommand(app, g) - backendCreate := backend.NewCreateCommand(backendCmdRoot.CmdClause, g, m) - backendDelete := backend.NewDeleteCommand(backendCmdRoot.CmdClause, g, m) - backendDescribe := backend.NewDescribeCommand(backendCmdRoot.CmdClause, g, m) - backendList := backend.NewListCommand(backendCmdRoot.CmdClause, g, m) - backendUpdate := backend.NewUpdateCommand(backendCmdRoot.CmdClause, g, m) - computeCmdRoot := compute.NewRootCommand(app, g) - computeBuild := compute.NewBuildCommand(computeCmdRoot.CmdClause, g, opts.Versioners.WasmTools) - computeDeploy := compute.NewDeployCommand(computeCmdRoot.CmdClause, g) - computeHashFiles := compute.NewHashFilesCommand(computeCmdRoot.CmdClause, g, computeBuild) - computeHashsum := compute.NewHashsumCommand(computeCmdRoot.CmdClause, g, computeBuild) - computeInit := compute.NewInitCommand(computeCmdRoot.CmdClause, g, m) - computeMetadata := compute.NewMetadataCommand(computeCmdRoot.CmdClause, g) - computePack := compute.NewPackCommand(computeCmdRoot.CmdClause, g, m) - computePublish := compute.NewPublishCommand(computeCmdRoot.CmdClause, g, computeBuild, computeDeploy) - computeServe := compute.NewServeCommand(computeCmdRoot.CmdClause, g, computeBuild, opts.Versioners.Viceroy) - computeUpdate := compute.NewUpdateCommand(computeCmdRoot.CmdClause, g, m) - computeValidate := compute.NewValidateCommand(computeCmdRoot.CmdClause, g) - configCmdRoot := config.NewRootCommand(app, g) - configstoreCmdRoot := configstore.NewRootCommand(app, g) - configstoreCreate := configstore.NewCreateCommand(configstoreCmdRoot.CmdClause, g, m) - configstoreDelete := configstore.NewDeleteCommand(configstoreCmdRoot.CmdClause, g, m) - configstoreDescribe := configstore.NewDescribeCommand(configstoreCmdRoot.CmdClause, g, m) - configstoreList := configstore.NewListCommand(configstoreCmdRoot.CmdClause, g, m) - configstoreListServices := configstore.NewListServicesCommand(configstoreCmdRoot.CmdClause, g, m) - configstoreUpdate := configstore.NewUpdateCommand(configstoreCmdRoot.CmdClause, g, m) - configstoreentryCmdRoot := configstoreentry.NewRootCommand(app, g) - configstoreentryCreate := configstoreentry.NewCreateCommand(configstoreentryCmdRoot.CmdClause, g, m) - configstoreentryDelete := configstoreentry.NewDeleteCommand(configstoreentryCmdRoot.CmdClause, g, m) - configstoreentryDescribe := configstoreentry.NewDescribeCommand(configstoreentryCmdRoot.CmdClause, g, m) - configstoreentryList := configstoreentry.NewListCommand(configstoreentryCmdRoot.CmdClause, g, m) - configstoreentryUpdate := configstoreentry.NewUpdateCommand(configstoreentryCmdRoot.CmdClause, g, m) - dictionaryCmdRoot := dictionary.NewRootCommand(app, g) - dictionaryCreate := dictionary.NewCreateCommand(dictionaryCmdRoot.CmdClause, g, m) - dictionaryDelete := dictionary.NewDeleteCommand(dictionaryCmdRoot.CmdClause, g, m) - dictionaryDescribe := dictionary.NewDescribeCommand(dictionaryCmdRoot.CmdClause, g, m) - dictionaryEntryCmdRoot := dictionaryentry.NewRootCommand(app, g) - dictionaryEntryCreate := dictionaryentry.NewCreateCommand(dictionaryEntryCmdRoot.CmdClause, g, m) - dictionaryEntryDelete := dictionaryentry.NewDeleteCommand(dictionaryEntryCmdRoot.CmdClause, g, m) - dictionaryEntryDescribe := dictionaryentry.NewDescribeCommand(dictionaryEntryCmdRoot.CmdClause, g, m) - dictionaryEntryList := dictionaryentry.NewListCommand(dictionaryEntryCmdRoot.CmdClause, g, m) - dictionaryEntryUpdate := dictionaryentry.NewUpdateCommand(dictionaryEntryCmdRoot.CmdClause, g, m) - dictionaryList := dictionary.NewListCommand(dictionaryCmdRoot.CmdClause, g, m) - dictionaryUpdate := dictionary.NewUpdateCommand(dictionaryCmdRoot.CmdClause, g, m) - domainCmdRoot := domain.NewRootCommand(app, g) - domainCreate := domain.NewCreateCommand(domainCmdRoot.CmdClause, g, m) - domainDelete := domain.NewDeleteCommand(domainCmdRoot.CmdClause, g, m) - domainDescribe := domain.NewDescribeCommand(domainCmdRoot.CmdClause, g, m) - domainList := domain.NewListCommand(domainCmdRoot.CmdClause, g, m) - domainUpdate := domain.NewUpdateCommand(domainCmdRoot.CmdClause, g, m) - domainValidate := domain.NewValidateCommand(domainCmdRoot.CmdClause, g, m) - healthcheckCmdRoot := healthcheck.NewRootCommand(app, g) - healthcheckCreate := healthcheck.NewCreateCommand(healthcheckCmdRoot.CmdClause, g, m) - healthcheckDelete := healthcheck.NewDeleteCommand(healthcheckCmdRoot.CmdClause, g, m) - healthcheckDescribe := healthcheck.NewDescribeCommand(healthcheckCmdRoot.CmdClause, g, m) - healthcheckList := healthcheck.NewListCommand(healthcheckCmdRoot.CmdClause, g, m) - healthcheckUpdate := healthcheck.NewUpdateCommand(healthcheckCmdRoot.CmdClause, g, m) - ipCmdRoot := ip.NewRootCommand(app, g) - kvstoreCmdRoot := kvstore.NewRootCommand(app, g) - kvstoreCreate := kvstore.NewCreateCommand(kvstoreCmdRoot.CmdClause, g, m) - kvstoreDelete := kvstore.NewDeleteCommand(kvstoreCmdRoot.CmdClause, g, m) - kvstoreDescribe := kvstore.NewDescribeCommand(kvstoreCmdRoot.CmdClause, g, m) - kvstoreList := kvstore.NewListCommand(kvstoreCmdRoot.CmdClause, g, m) - kvstoreentryCmdRoot := kvstoreentry.NewRootCommand(app, g) - kvstoreentryCreate := kvstoreentry.NewCreateCommand(kvstoreentryCmdRoot.CmdClause, g, m) - kvstoreentryDelete := kvstoreentry.NewDeleteCommand(kvstoreentryCmdRoot.CmdClause, g, m) - kvstoreentryDescribe := kvstoreentry.NewDescribeCommand(kvstoreentryCmdRoot.CmdClause, g, m) - kvstoreentryList := kvstoreentry.NewListCommand(kvstoreentryCmdRoot.CmdClause, g, m) - logtailCmdRoot := logtail.NewRootCommand(app, g, m) - loggingCmdRoot := logging.NewRootCommand(app, g) - loggingAzureblobCmdRoot := azureblob.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingAzureblobCreate := azureblob.NewCreateCommand(loggingAzureblobCmdRoot.CmdClause, g, m) - loggingAzureblobDelete := azureblob.NewDeleteCommand(loggingAzureblobCmdRoot.CmdClause, g, m) - loggingAzureblobDescribe := azureblob.NewDescribeCommand(loggingAzureblobCmdRoot.CmdClause, g, m) - loggingAzureblobList := azureblob.NewListCommand(loggingAzureblobCmdRoot.CmdClause, g, m) - loggingAzureblobUpdate := azureblob.NewUpdateCommand(loggingAzureblobCmdRoot.CmdClause, g, m) - loggingBigQueryCmdRoot := bigquery.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingBigQueryCreate := bigquery.NewCreateCommand(loggingBigQueryCmdRoot.CmdClause, g, m) - loggingBigQueryDelete := bigquery.NewDeleteCommand(loggingBigQueryCmdRoot.CmdClause, g, m) - loggingBigQueryDescribe := bigquery.NewDescribeCommand(loggingBigQueryCmdRoot.CmdClause, g, m) - loggingBigQueryList := bigquery.NewListCommand(loggingBigQueryCmdRoot.CmdClause, g, m) - loggingBigQueryUpdate := bigquery.NewUpdateCommand(loggingBigQueryCmdRoot.CmdClause, g, m) - loggingCloudfilesCmdRoot := cloudfiles.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingCloudfilesCreate := cloudfiles.NewCreateCommand(loggingCloudfilesCmdRoot.CmdClause, g, m) - loggingCloudfilesDelete := cloudfiles.NewDeleteCommand(loggingCloudfilesCmdRoot.CmdClause, g, m) - loggingCloudfilesDescribe := cloudfiles.NewDescribeCommand(loggingCloudfilesCmdRoot.CmdClause, g, m) - loggingCloudfilesList := cloudfiles.NewListCommand(loggingCloudfilesCmdRoot.CmdClause, g, m) - loggingCloudfilesUpdate := cloudfiles.NewUpdateCommand(loggingCloudfilesCmdRoot.CmdClause, g, m) - loggingDatadogCmdRoot := datadog.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingDatadogCreate := datadog.NewCreateCommand(loggingDatadogCmdRoot.CmdClause, g, m) - loggingDatadogDelete := datadog.NewDeleteCommand(loggingDatadogCmdRoot.CmdClause, g, m) - loggingDatadogDescribe := datadog.NewDescribeCommand(loggingDatadogCmdRoot.CmdClause, g, m) - loggingDatadogList := datadog.NewListCommand(loggingDatadogCmdRoot.CmdClause, g, m) - loggingDatadogUpdate := datadog.NewUpdateCommand(loggingDatadogCmdRoot.CmdClause, g, m) - loggingDigitaloceanCmdRoot := digitalocean.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingDigitaloceanCreate := digitalocean.NewCreateCommand(loggingDigitaloceanCmdRoot.CmdClause, g, m) - loggingDigitaloceanDelete := digitalocean.NewDeleteCommand(loggingDigitaloceanCmdRoot.CmdClause, g, m) - loggingDigitaloceanDescribe := digitalocean.NewDescribeCommand(loggingDigitaloceanCmdRoot.CmdClause, g, m) - loggingDigitaloceanList := digitalocean.NewListCommand(loggingDigitaloceanCmdRoot.CmdClause, g, m) - loggingDigitaloceanUpdate := digitalocean.NewUpdateCommand(loggingDigitaloceanCmdRoot.CmdClause, g, m) - loggingElasticsearchCmdRoot := elasticsearch.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingElasticsearchCreate := elasticsearch.NewCreateCommand(loggingElasticsearchCmdRoot.CmdClause, g, m) - loggingElasticsearchDelete := elasticsearch.NewDeleteCommand(loggingElasticsearchCmdRoot.CmdClause, g, m) - loggingElasticsearchDescribe := elasticsearch.NewDescribeCommand(loggingElasticsearchCmdRoot.CmdClause, g, m) - loggingElasticsearchList := elasticsearch.NewListCommand(loggingElasticsearchCmdRoot.CmdClause, g, m) - loggingElasticsearchUpdate := elasticsearch.NewUpdateCommand(loggingElasticsearchCmdRoot.CmdClause, g, m) - loggingFtpCmdRoot := ftp.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingFtpCreate := ftp.NewCreateCommand(loggingFtpCmdRoot.CmdClause, g, m) - loggingFtpDelete := ftp.NewDeleteCommand(loggingFtpCmdRoot.CmdClause, g, m) - loggingFtpDescribe := ftp.NewDescribeCommand(loggingFtpCmdRoot.CmdClause, g, m) - loggingFtpList := ftp.NewListCommand(loggingFtpCmdRoot.CmdClause, g, m) - loggingFtpUpdate := ftp.NewUpdateCommand(loggingFtpCmdRoot.CmdClause, g, m) - loggingGcsCmdRoot := gcs.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingGcsCreate := gcs.NewCreateCommand(loggingGcsCmdRoot.CmdClause, g, m) - loggingGcsDelete := gcs.NewDeleteCommand(loggingGcsCmdRoot.CmdClause, g, m) - loggingGcsDescribe := gcs.NewDescribeCommand(loggingGcsCmdRoot.CmdClause, g, m) - loggingGcsList := gcs.NewListCommand(loggingGcsCmdRoot.CmdClause, g, m) - loggingGcsUpdate := gcs.NewUpdateCommand(loggingGcsCmdRoot.CmdClause, g, m) - loggingGooglepubsubCmdRoot := googlepubsub.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingGooglepubsubCreate := googlepubsub.NewCreateCommand(loggingGooglepubsubCmdRoot.CmdClause, g, m) - loggingGooglepubsubDelete := googlepubsub.NewDeleteCommand(loggingGooglepubsubCmdRoot.CmdClause, g, m) - loggingGooglepubsubDescribe := googlepubsub.NewDescribeCommand(loggingGooglepubsubCmdRoot.CmdClause, g, m) - loggingGooglepubsubList := googlepubsub.NewListCommand(loggingGooglepubsubCmdRoot.CmdClause, g, m) - loggingGooglepubsubUpdate := googlepubsub.NewUpdateCommand(loggingGooglepubsubCmdRoot.CmdClause, g, m) - loggingHerokuCmdRoot := heroku.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingHerokuCreate := heroku.NewCreateCommand(loggingHerokuCmdRoot.CmdClause, g, m) - loggingHerokuDelete := heroku.NewDeleteCommand(loggingHerokuCmdRoot.CmdClause, g, m) - loggingHerokuDescribe := heroku.NewDescribeCommand(loggingHerokuCmdRoot.CmdClause, g, m) - loggingHerokuList := heroku.NewListCommand(loggingHerokuCmdRoot.CmdClause, g, m) - loggingHerokuUpdate := heroku.NewUpdateCommand(loggingHerokuCmdRoot.CmdClause, g, m) - loggingHoneycombCmdRoot := honeycomb.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingHoneycombCreate := honeycomb.NewCreateCommand(loggingHoneycombCmdRoot.CmdClause, g, m) - loggingHoneycombDelete := honeycomb.NewDeleteCommand(loggingHoneycombCmdRoot.CmdClause, g, m) - loggingHoneycombDescribe := honeycomb.NewDescribeCommand(loggingHoneycombCmdRoot.CmdClause, g, m) - loggingHoneycombList := honeycomb.NewListCommand(loggingHoneycombCmdRoot.CmdClause, g, m) - loggingHoneycombUpdate := honeycomb.NewUpdateCommand(loggingHoneycombCmdRoot.CmdClause, g, m) - loggingHTTPSCmdRoot := https.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingHTTPSCreate := https.NewCreateCommand(loggingHTTPSCmdRoot.CmdClause, g, m) - loggingHTTPSDelete := https.NewDeleteCommand(loggingHTTPSCmdRoot.CmdClause, g, m) - loggingHTTPSDescribe := https.NewDescribeCommand(loggingHTTPSCmdRoot.CmdClause, g, m) - loggingHTTPSList := https.NewListCommand(loggingHTTPSCmdRoot.CmdClause, g, m) - loggingHTTPSUpdate := https.NewUpdateCommand(loggingHTTPSCmdRoot.CmdClause, g, m) - loggingKafkaCmdRoot := kafka.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingKafkaCreate := kafka.NewCreateCommand(loggingKafkaCmdRoot.CmdClause, g, m) - loggingKafkaDelete := kafka.NewDeleteCommand(loggingKafkaCmdRoot.CmdClause, g, m) - loggingKafkaDescribe := kafka.NewDescribeCommand(loggingKafkaCmdRoot.CmdClause, g, m) - loggingKafkaList := kafka.NewListCommand(loggingKafkaCmdRoot.CmdClause, g, m) - loggingKafkaUpdate := kafka.NewUpdateCommand(loggingKafkaCmdRoot.CmdClause, g, m) - loggingKinesisCmdRoot := kinesis.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingKinesisCreate := kinesis.NewCreateCommand(loggingKinesisCmdRoot.CmdClause, g, m) - loggingKinesisDelete := kinesis.NewDeleteCommand(loggingKinesisCmdRoot.CmdClause, g, m) - loggingKinesisDescribe := kinesis.NewDescribeCommand(loggingKinesisCmdRoot.CmdClause, g, m) - loggingKinesisList := kinesis.NewListCommand(loggingKinesisCmdRoot.CmdClause, g, m) - loggingKinesisUpdate := kinesis.NewUpdateCommand(loggingKinesisCmdRoot.CmdClause, g, m) - loggingLogglyCmdRoot := loggly.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingLogglyCreate := loggly.NewCreateCommand(loggingLogglyCmdRoot.CmdClause, g, m) - loggingLogglyDelete := loggly.NewDeleteCommand(loggingLogglyCmdRoot.CmdClause, g, m) - loggingLogglyDescribe := loggly.NewDescribeCommand(loggingLogglyCmdRoot.CmdClause, g, m) - loggingLogglyList := loggly.NewListCommand(loggingLogglyCmdRoot.CmdClause, g, m) - loggingLogglyUpdate := loggly.NewUpdateCommand(loggingLogglyCmdRoot.CmdClause, g, m) - loggingLogshuttleCmdRoot := logshuttle.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingLogshuttleCreate := logshuttle.NewCreateCommand(loggingLogshuttleCmdRoot.CmdClause, g, m) - loggingLogshuttleDelete := logshuttle.NewDeleteCommand(loggingLogshuttleCmdRoot.CmdClause, g, m) - loggingLogshuttleDescribe := logshuttle.NewDescribeCommand(loggingLogshuttleCmdRoot.CmdClause, g, m) - loggingLogshuttleList := logshuttle.NewListCommand(loggingLogshuttleCmdRoot.CmdClause, g, m) - loggingLogshuttleUpdate := logshuttle.NewUpdateCommand(loggingLogshuttleCmdRoot.CmdClause, g, m) - loggingNewRelicCmdRoot := newrelic.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingNewRelicCreate := newrelic.NewCreateCommand(loggingNewRelicCmdRoot.CmdClause, g, m) - loggingNewRelicDelete := newrelic.NewDeleteCommand(loggingNewRelicCmdRoot.CmdClause, g, m) - loggingNewRelicDescribe := newrelic.NewDescribeCommand(loggingNewRelicCmdRoot.CmdClause, g, m) - loggingNewRelicList := newrelic.NewListCommand(loggingNewRelicCmdRoot.CmdClause, g, m) - loggingNewRelicUpdate := newrelic.NewUpdateCommand(loggingNewRelicCmdRoot.CmdClause, g, m) - loggingNewRelicOTLPCmdRoot := newrelicotlp.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingNewRelicOTLPCreate := newrelicotlp.NewCreateCommand(loggingNewRelicOTLPCmdRoot.CmdClause, g, m) - loggingNewRelicOTLPDelete := newrelicotlp.NewDeleteCommand(loggingNewRelicOTLPCmdRoot.CmdClause, g, m) - loggingNewRelicOTLPDescribe := newrelicotlp.NewDescribeCommand(loggingNewRelicOTLPCmdRoot.CmdClause, g, m) - loggingNewRelicOTLPList := newrelicotlp.NewListCommand(loggingNewRelicOTLPCmdRoot.CmdClause, g, m) - loggingNewRelicOTLPUpdate := newrelicotlp.NewUpdateCommand(loggingNewRelicOTLPCmdRoot.CmdClause, g, m) - loggingOpenstackCmdRoot := openstack.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingOpenstackCreate := openstack.NewCreateCommand(loggingOpenstackCmdRoot.CmdClause, g, m) - loggingOpenstackDelete := openstack.NewDeleteCommand(loggingOpenstackCmdRoot.CmdClause, g, m) - loggingOpenstackDescribe := openstack.NewDescribeCommand(loggingOpenstackCmdRoot.CmdClause, g, m) - loggingOpenstackList := openstack.NewListCommand(loggingOpenstackCmdRoot.CmdClause, g, m) - loggingOpenstackUpdate := openstack.NewUpdateCommand(loggingOpenstackCmdRoot.CmdClause, g, m) - loggingPapertrailCmdRoot := papertrail.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingPapertrailCreate := papertrail.NewCreateCommand(loggingPapertrailCmdRoot.CmdClause, g, m) - loggingPapertrailDelete := papertrail.NewDeleteCommand(loggingPapertrailCmdRoot.CmdClause, g, m) - loggingPapertrailDescribe := papertrail.NewDescribeCommand(loggingPapertrailCmdRoot.CmdClause, g, m) - loggingPapertrailList := papertrail.NewListCommand(loggingPapertrailCmdRoot.CmdClause, g, m) - loggingPapertrailUpdate := papertrail.NewUpdateCommand(loggingPapertrailCmdRoot.CmdClause, g, m) - loggingS3CmdRoot := s3.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingS3Create := s3.NewCreateCommand(loggingS3CmdRoot.CmdClause, g, m) - loggingS3Delete := s3.NewDeleteCommand(loggingS3CmdRoot.CmdClause, g, m) - loggingS3Describe := s3.NewDescribeCommand(loggingS3CmdRoot.CmdClause, g, m) - loggingS3List := s3.NewListCommand(loggingS3CmdRoot.CmdClause, g, m) - loggingS3Update := s3.NewUpdateCommand(loggingS3CmdRoot.CmdClause, g, m) - loggingScalyrCmdRoot := scalyr.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingScalyrCreate := scalyr.NewCreateCommand(loggingScalyrCmdRoot.CmdClause, g, m) - loggingScalyrDelete := scalyr.NewDeleteCommand(loggingScalyrCmdRoot.CmdClause, g, m) - loggingScalyrDescribe := scalyr.NewDescribeCommand(loggingScalyrCmdRoot.CmdClause, g, m) - loggingScalyrList := scalyr.NewListCommand(loggingScalyrCmdRoot.CmdClause, g, m) - loggingScalyrUpdate := scalyr.NewUpdateCommand(loggingScalyrCmdRoot.CmdClause, g, m) - loggingSftpCmdRoot := sftp.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingSftpCreate := sftp.NewCreateCommand(loggingSftpCmdRoot.CmdClause, g, m) - loggingSftpDelete := sftp.NewDeleteCommand(loggingSftpCmdRoot.CmdClause, g, m) - loggingSftpDescribe := sftp.NewDescribeCommand(loggingSftpCmdRoot.CmdClause, g, m) - loggingSftpList := sftp.NewListCommand(loggingSftpCmdRoot.CmdClause, g, m) - loggingSftpUpdate := sftp.NewUpdateCommand(loggingSftpCmdRoot.CmdClause, g, m) - loggingSplunkCmdRoot := splunk.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingSplunkCreate := splunk.NewCreateCommand(loggingSplunkCmdRoot.CmdClause, g, m) - loggingSplunkDelete := splunk.NewDeleteCommand(loggingSplunkCmdRoot.CmdClause, g, m) - loggingSplunkDescribe := splunk.NewDescribeCommand(loggingSplunkCmdRoot.CmdClause, g, m) - loggingSplunkList := splunk.NewListCommand(loggingSplunkCmdRoot.CmdClause, g, m) - loggingSplunkUpdate := splunk.NewUpdateCommand(loggingSplunkCmdRoot.CmdClause, g, m) - loggingSumologicCmdRoot := sumologic.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingSumologicCreate := sumologic.NewCreateCommand(loggingSumologicCmdRoot.CmdClause, g, m) - loggingSumologicDelete := sumologic.NewDeleteCommand(loggingSumologicCmdRoot.CmdClause, g, m) - loggingSumologicDescribe := sumologic.NewDescribeCommand(loggingSumologicCmdRoot.CmdClause, g, m) - loggingSumologicList := sumologic.NewListCommand(loggingSumologicCmdRoot.CmdClause, g, m) - loggingSumologicUpdate := sumologic.NewUpdateCommand(loggingSumologicCmdRoot.CmdClause, g, m) - loggingSyslogCmdRoot := syslog.NewRootCommand(loggingCmdRoot.CmdClause, g) - loggingSyslogCreate := syslog.NewCreateCommand(loggingSyslogCmdRoot.CmdClause, g, m) - loggingSyslogDelete := syslog.NewDeleteCommand(loggingSyslogCmdRoot.CmdClause, g, m) - loggingSyslogDescribe := syslog.NewDescribeCommand(loggingSyslogCmdRoot.CmdClause, g, m) - loggingSyslogList := syslog.NewListCommand(loggingSyslogCmdRoot.CmdClause, g, m) - loggingSyslogUpdate := syslog.NewUpdateCommand(loggingSyslogCmdRoot.CmdClause, g, m) - popCmdRoot := pop.NewRootCommand(app, g) - productsCmdRoot := products.NewRootCommand(app, g, m) - profileCmdRoot := profile.NewRootCommand(app, g) - profileCreate := profile.NewCreateCommand(profileCmdRoot.CmdClause, profile.APIClientFactory(opts.APIClient), g) - profileDelete := profile.NewDeleteCommand(profileCmdRoot.CmdClause, g) - profileList := profile.NewListCommand(profileCmdRoot.CmdClause, g) - profileSwitch := profile.NewSwitchCommand(profileCmdRoot.CmdClause, g) - profileToken := profile.NewTokenCommand(profileCmdRoot.CmdClause, g) - profileUpdate := profile.NewUpdateCommand(profileCmdRoot.CmdClause, profile.APIClientFactory(opts.APIClient), g) - purgeCmdRoot := purge.NewRootCommand(app, g, m) - rateLimitCmdRoot := ratelimit.NewRootCommand(app, g) - rateLimitCreate := ratelimit.NewCreateCommand(rateLimitCmdRoot.CmdClause, g, m) - rateLimitDelete := ratelimit.NewDeleteCommand(rateLimitCmdRoot.CmdClause, g, m) - rateLimitDescribe := ratelimit.NewDescribeCommand(rateLimitCmdRoot.CmdClause, g, m) - rateLimitList := ratelimit.NewListCommand(rateLimitCmdRoot.CmdClause, g, m) - rateLimitUpdate := ratelimit.NewUpdateCommand(rateLimitCmdRoot.CmdClause, g, m) - resourcelinkCmdRoot := resourcelink.NewRootCommand(app, g) - resourcelinkCreate := resourcelink.NewCreateCommand(resourcelinkCmdRoot.CmdClause, g, m) - resourcelinkDelete := resourcelink.NewDeleteCommand(resourcelinkCmdRoot.CmdClause, g, m) - resourcelinkDescribe := resourcelink.NewDescribeCommand(resourcelinkCmdRoot.CmdClause, g, m) - resourcelinkList := resourcelink.NewListCommand(resourcelinkCmdRoot.CmdClause, g, m) - resourcelinkUpdate := resourcelink.NewUpdateCommand(resourcelinkCmdRoot.CmdClause, g, m) - secretstoreCmdRoot := secretstore.NewRootCommand(app, g) - secretstoreCreate := secretstore.NewCreateCommand(secretstoreCmdRoot.CmdClause, g, m) - secretstoreDescribe := secretstore.NewDescribeCommand(secretstoreCmdRoot.CmdClause, g, m) - secretstoreDelete := secretstore.NewDeleteCommand(secretstoreCmdRoot.CmdClause, g, m) - secretstoreList := secretstore.NewListCommand(secretstoreCmdRoot.CmdClause, g, m) - secretstoreentryCmdRoot := secretstoreentry.NewRootCommand(app, g) - secretstoreentryCreate := secretstoreentry.NewCreateCommand(secretstoreentryCmdRoot.CmdClause, g, m) - secretstoreentryDescribe := secretstoreentry.NewDescribeCommand(secretstoreentryCmdRoot.CmdClause, g, m) - secretstoreentryDelete := secretstoreentry.NewDeleteCommand(secretstoreentryCmdRoot.CmdClause, g, m) - secretstoreentryList := secretstoreentry.NewListCommand(secretstoreentryCmdRoot.CmdClause, g, m) - serviceCmdRoot := service.NewRootCommand(app, g) - serviceCreate := service.NewCreateCommand(serviceCmdRoot.CmdClause, g) - serviceDelete := service.NewDeleteCommand(serviceCmdRoot.CmdClause, g, m) - serviceDescribe := service.NewDescribeCommand(serviceCmdRoot.CmdClause, g, m) - serviceList := service.NewListCommand(serviceCmdRoot.CmdClause, g) - serviceSearch := service.NewSearchCommand(serviceCmdRoot.CmdClause, g, m) - serviceUpdate := service.NewUpdateCommand(serviceCmdRoot.CmdClause, g, m) - serviceauthCmdRoot := serviceauth.NewRootCommand(app, g) - serviceauthCreate := serviceauth.NewCreateCommand(serviceauthCmdRoot.CmdClause, g, m) - serviceauthDelete := serviceauth.NewDeleteCommand(serviceauthCmdRoot.CmdClause, g, m) - serviceauthDescribe := serviceauth.NewDescribeCommand(serviceauthCmdRoot.CmdClause, g, m) - serviceauthList := serviceauth.NewListCommand(serviceauthCmdRoot.CmdClause, g) - serviceauthUpdate := serviceauth.NewUpdateCommand(serviceauthCmdRoot.CmdClause, g, m) - serviceVersionCmdRoot := serviceversion.NewRootCommand(app, g) - serviceVersionActivate := serviceversion.NewActivateCommand(serviceVersionCmdRoot.CmdClause, g, m) - serviceVersionClone := serviceversion.NewCloneCommand(serviceVersionCmdRoot.CmdClause, g, m) - serviceVersionDeactivate := serviceversion.NewDeactivateCommand(serviceVersionCmdRoot.CmdClause, g, m) - serviceVersionList := serviceversion.NewListCommand(serviceVersionCmdRoot.CmdClause, g, m) - serviceVersionLock := serviceversion.NewLockCommand(serviceVersionCmdRoot.CmdClause, g, m) - serviceVersionUpdate := serviceversion.NewUpdateCommand(serviceVersionCmdRoot.CmdClause, g, m) - statsCmdRoot := stats.NewRootCommand(app, g) - statsHistorical := stats.NewHistoricalCommand(statsCmdRoot.CmdClause, g, m) - statsRealtime := stats.NewRealtimeCommand(statsCmdRoot.CmdClause, g, m) - statsRegions := stats.NewRegionsCommand(statsCmdRoot.CmdClause, g) - tlsConfigCmdRoot := tlsconfig.NewRootCommand(app, g) - tlsConfigDescribe := tlsconfig.NewDescribeCommand(tlsConfigCmdRoot.CmdClause, g, m) - tlsConfigList := tlsconfig.NewListCommand(tlsConfigCmdRoot.CmdClause, g, m) - tlsConfigUpdate := tlsconfig.NewUpdateCommand(tlsConfigCmdRoot.CmdClause, g, m) - tlsCustomCmdRoot := tlscustom.NewRootCommand(app, g) - tlsCustomActivationCmdRoot := tlscustomactivation.NewRootCommand(tlsCustomCmdRoot.CmdClause, g) - tlsCustomActivationCreate := tlscustomactivation.NewCreateCommand(tlsCustomActivationCmdRoot.CmdClause, g, m) - tlsCustomActivationDelete := tlscustomactivation.NewDeleteCommand(tlsCustomActivationCmdRoot.CmdClause, g, m) - tlsCustomActivationDescribe := tlscustomactivation.NewDescribeCommand(tlsCustomActivationCmdRoot.CmdClause, g, m) - tlsCustomActivationList := tlscustomactivation.NewListCommand(tlsCustomActivationCmdRoot.CmdClause, g, m) - tlsCustomActivationUpdate := tlscustomactivation.NewUpdateCommand(tlsCustomActivationCmdRoot.CmdClause, g, m) - tlsCustomCertificateCmdRoot := tlscustomcertificate.NewRootCommand(tlsCustomCmdRoot.CmdClause, g) - tlsCustomCertificateCreate := tlscustomcertificate.NewCreateCommand(tlsCustomCertificateCmdRoot.CmdClause, g, m) - tlsCustomCertificateDelete := tlscustomcertificate.NewDeleteCommand(tlsCustomCertificateCmdRoot.CmdClause, g, m) - tlsCustomCertificateDescribe := tlscustomcertificate.NewDescribeCommand(tlsCustomCertificateCmdRoot.CmdClause, g, m) - tlsCustomCertificateList := tlscustomcertificate.NewListCommand(tlsCustomCertificateCmdRoot.CmdClause, g, m) - tlsCustomCertificateUpdate := tlscustomcertificate.NewUpdateCommand(tlsCustomCertificateCmdRoot.CmdClause, g, m) - tlsCustomDomainCmdRoot := tlscustomdomain.NewRootCommand(tlsCustomCmdRoot.CmdClause, g) - tlsCustomDomainList := tlscustomdomain.NewListCommand(tlsCustomDomainCmdRoot.CmdClause, g, m) - tlsCustomPrivateKeyCmdRoot := tlscustomprivatekey.NewRootCommand(tlsCustomCmdRoot.CmdClause, g) - tlsCustomPrivateKeyCreate := tlscustomprivatekey.NewCreateCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, g, m) - tlsCustomPrivateKeyDelete := tlscustomprivatekey.NewDeleteCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, g, m) - tlsCustomPrivateKeyDescribe := tlscustomprivatekey.NewDescribeCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, g, m) - tlsCustomPrivateKeyList := tlscustomprivatekey.NewListCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, g, m) - tlsPlatformCmdRoot := tlsplatform.NewRootCommand(app, g) - tlsPlatformCreate := tlsplatform.NewCreateCommand(tlsPlatformCmdRoot.CmdClause, g, m) - tlsPlatformDelete := tlsplatform.NewDeleteCommand(tlsPlatformCmdRoot.CmdClause, g, m) - tlsPlatformDescribe := tlsplatform.NewDescribeCommand(tlsPlatformCmdRoot.CmdClause, g, m) - tlsPlatformList := tlsplatform.NewListCommand(tlsPlatformCmdRoot.CmdClause, g, m) - tlsPlatformUpdate := tlsplatform.NewUpdateCommand(tlsPlatformCmdRoot.CmdClause, g, m) - tlsSubscriptionCmdRoot := tlssubscription.NewRootCommand(app, g) - tlsSubscriptionCreate := tlssubscription.NewCreateCommand(tlsSubscriptionCmdRoot.CmdClause, g, m) - tlsSubscriptionDelete := tlssubscription.NewDeleteCommand(tlsSubscriptionCmdRoot.CmdClause, g, m) - tlsSubscriptionDescribe := tlssubscription.NewDescribeCommand(tlsSubscriptionCmdRoot.CmdClause, g, m) - tlsSubscriptionList := tlssubscription.NewListCommand(tlsSubscriptionCmdRoot.CmdClause, g, m) - tlsSubscriptionUpdate := tlssubscription.NewUpdateCommand(tlsSubscriptionCmdRoot.CmdClause, g, m) - updateRoot := update.NewRootCommand(app, opts.ConfigPath, opts.Versioners.CLI, g) - userCmdRoot := user.NewRootCommand(app, g) - userCreate := user.NewCreateCommand(userCmdRoot.CmdClause, g, m) - userDelete := user.NewDeleteCommand(userCmdRoot.CmdClause, g, m) - userDescribe := user.NewDescribeCommand(userCmdRoot.CmdClause, g, m) - userList := user.NewListCommand(userCmdRoot.CmdClause, g, m) - userUpdate := user.NewUpdateCommand(userCmdRoot.CmdClause, g, m) - vclCmdRoot := vcl.NewRootCommand(app, g) - vclConditionCmdRoot := condition.NewRootCommand(vclCmdRoot.CmdClause, g) - vclConditionCreate := condition.NewCreateCommand(vclConditionCmdRoot.CmdClause, g, m) - vclConditionDelete := condition.NewDeleteCommand(vclConditionCmdRoot.CmdClause, g, m) - vclConditionDescribe := condition.NewDescribeCommand(vclConditionCmdRoot.CmdClause, g, m) - vclConditionList := condition.NewListCommand(vclConditionCmdRoot.CmdClause, g, m) - vclConditionUpdate := condition.NewUpdateCommand(vclConditionCmdRoot.CmdClause, g, m) - vclCustomCmdRoot := custom.NewRootCommand(vclCmdRoot.CmdClause, g) - vclCustomCreate := custom.NewCreateCommand(vclCustomCmdRoot.CmdClause, g, m) - vclCustomDelete := custom.NewDeleteCommand(vclCustomCmdRoot.CmdClause, g, m) - vclCustomDescribe := custom.NewDescribeCommand(vclCustomCmdRoot.CmdClause, g, m) - vclCustomList := custom.NewListCommand(vclCustomCmdRoot.CmdClause, g, m) - vclCustomUpdate := custom.NewUpdateCommand(vclCustomCmdRoot.CmdClause, g, m) - vclSnippetCmdRoot := snippet.NewRootCommand(vclCmdRoot.CmdClause, g) - vclSnippetCreate := snippet.NewCreateCommand(vclSnippetCmdRoot.CmdClause, g, m) - vclSnippetDelete := snippet.NewDeleteCommand(vclSnippetCmdRoot.CmdClause, g, m) - vclSnippetDescribe := snippet.NewDescribeCommand(vclSnippetCmdRoot.CmdClause, g, m) - vclSnippetList := snippet.NewListCommand(vclSnippetCmdRoot.CmdClause, g, m) - vclSnippetUpdate := snippet.NewUpdateCommand(vclSnippetCmdRoot.CmdClause, g, m) - versionCmdRoot := version.NewRootCommand(app, opts.Versioners.Viceroy) - whoamiCmdRoot := whoami.NewRootCommand(app, g) + shellcompleteCmdRoot := shellcomplete.NewRootCommand(app, data) + + // NOTE: The order commands are created are the order they appear in 'help'. + // But because we need to pass the SSO command into the profile commands, it + // means the SSO command must be created _before_ the profile commands. This + // messes up the order of the commands in the `--help` output. So to make the + // placement of the `sso` subcommand not look too odd we place it at the + // beginning of the list of commands. + ssoCmdRoot := sso.NewRootCommand(app, data) + + aclCmdRoot := acl.NewRootCommand(app, data) + aclCreate := acl.NewCreateCommand(aclCmdRoot.CmdClause, data) + aclDelete := acl.NewDeleteCommand(aclCmdRoot.CmdClause, data) + aclDescribe := acl.NewDescribeCommand(aclCmdRoot.CmdClause, data) + aclList := acl.NewListCommand(aclCmdRoot.CmdClause, data) + aclUpdate := acl.NewUpdateCommand(aclCmdRoot.CmdClause, data) + aclEntryCmdRoot := aclentry.NewRootCommand(app, data) + aclEntryCreate := aclentry.NewCreateCommand(aclEntryCmdRoot.CmdClause, data) + aclEntryDelete := aclentry.NewDeleteCommand(aclEntryCmdRoot.CmdClause, data) + aclEntryDescribe := aclentry.NewDescribeCommand(aclEntryCmdRoot.CmdClause, data) + aclEntryList := aclentry.NewListCommand(aclEntryCmdRoot.CmdClause, data) + aclEntryUpdate := aclentry.NewUpdateCommand(aclEntryCmdRoot.CmdClause, data) + authtokenCmdRoot := authtoken.NewRootCommand(app, data) + authtokenCreate := authtoken.NewCreateCommand(authtokenCmdRoot.CmdClause, data) + authtokenDelete := authtoken.NewDeleteCommand(authtokenCmdRoot.CmdClause, data) + authtokenDescribe := authtoken.NewDescribeCommand(authtokenCmdRoot.CmdClause, data) + authtokenList := authtoken.NewListCommand(authtokenCmdRoot.CmdClause, data) + backendCmdRoot := backend.NewRootCommand(app, data) + backendCreate := backend.NewCreateCommand(backendCmdRoot.CmdClause, data) + backendDelete := backend.NewDeleteCommand(backendCmdRoot.CmdClause, data) + backendDescribe := backend.NewDescribeCommand(backendCmdRoot.CmdClause, data) + backendList := backend.NewListCommand(backendCmdRoot.CmdClause, data) + backendUpdate := backend.NewUpdateCommand(backendCmdRoot.CmdClause, data) + computeCmdRoot := compute.NewRootCommand(app, data) + computeBuild := compute.NewBuildCommand(computeCmdRoot.CmdClause, data) + computeDeploy := compute.NewDeployCommand(computeCmdRoot.CmdClause, data) + computeHashFiles := compute.NewHashFilesCommand(computeCmdRoot.CmdClause, data, computeBuild) + computeHashsum := compute.NewHashsumCommand(computeCmdRoot.CmdClause, data, computeBuild) + computeInit := compute.NewInitCommand(computeCmdRoot.CmdClause, data) + computeMetadata := compute.NewMetadataCommand(computeCmdRoot.CmdClause, data) + computePack := compute.NewPackCommand(computeCmdRoot.CmdClause, data) + computePublish := compute.NewPublishCommand(computeCmdRoot.CmdClause, data, computeBuild, computeDeploy) + computeServe := compute.NewServeCommand(computeCmdRoot.CmdClause, data, computeBuild) + computeUpdate := compute.NewUpdateCommand(computeCmdRoot.CmdClause, data) + computeValidate := compute.NewValidateCommand(computeCmdRoot.CmdClause, data) + configCmdRoot := config.NewRootCommand(app, data) + configstoreCmdRoot := configstore.NewRootCommand(app, data) + configstoreCreate := configstore.NewCreateCommand(configstoreCmdRoot.CmdClause, data) + configstoreDelete := configstore.NewDeleteCommand(configstoreCmdRoot.CmdClause, data) + configstoreDescribe := configstore.NewDescribeCommand(configstoreCmdRoot.CmdClause, data) + configstoreList := configstore.NewListCommand(configstoreCmdRoot.CmdClause, data) + configstoreListServices := configstore.NewListServicesCommand(configstoreCmdRoot.CmdClause, data) + configstoreUpdate := configstore.NewUpdateCommand(configstoreCmdRoot.CmdClause, data) + configstoreentryCmdRoot := configstoreentry.NewRootCommand(app, data) + configstoreentryCreate := configstoreentry.NewCreateCommand(configstoreentryCmdRoot.CmdClause, data) + configstoreentryDelete := configstoreentry.NewDeleteCommand(configstoreentryCmdRoot.CmdClause, data) + configstoreentryDescribe := configstoreentry.NewDescribeCommand(configstoreentryCmdRoot.CmdClause, data) + configstoreentryList := configstoreentry.NewListCommand(configstoreentryCmdRoot.CmdClause, data) + configstoreentryUpdate := configstoreentry.NewUpdateCommand(configstoreentryCmdRoot.CmdClause, data) + dictionaryCmdRoot := dictionary.NewRootCommand(app, data) + dictionaryCreate := dictionary.NewCreateCommand(dictionaryCmdRoot.CmdClause, data) + dictionaryDelete := dictionary.NewDeleteCommand(dictionaryCmdRoot.CmdClause, data) + dictionaryDescribe := dictionary.NewDescribeCommand(dictionaryCmdRoot.CmdClause, data) + dictionaryEntryCmdRoot := dictionaryentry.NewRootCommand(app, data) + dictionaryEntryCreate := dictionaryentry.NewCreateCommand(dictionaryEntryCmdRoot.CmdClause, data) + dictionaryEntryDelete := dictionaryentry.NewDeleteCommand(dictionaryEntryCmdRoot.CmdClause, data) + dictionaryEntryDescribe := dictionaryentry.NewDescribeCommand(dictionaryEntryCmdRoot.CmdClause, data) + dictionaryEntryList := dictionaryentry.NewListCommand(dictionaryEntryCmdRoot.CmdClause, data) + dictionaryEntryUpdate := dictionaryentry.NewUpdateCommand(dictionaryEntryCmdRoot.CmdClause, data) + dictionaryList := dictionary.NewListCommand(dictionaryCmdRoot.CmdClause, data) + dictionaryUpdate := dictionary.NewUpdateCommand(dictionaryCmdRoot.CmdClause, data) + domainCmdRoot := domain.NewRootCommand(app, data) + domainCreate := domain.NewCreateCommand(domainCmdRoot.CmdClause, data) + domainDelete := domain.NewDeleteCommand(domainCmdRoot.CmdClause, data) + domainDescribe := domain.NewDescribeCommand(domainCmdRoot.CmdClause, data) + domainList := domain.NewListCommand(domainCmdRoot.CmdClause, data) + domainUpdate := domain.NewUpdateCommand(domainCmdRoot.CmdClause, data) + domainValidate := domain.NewValidateCommand(domainCmdRoot.CmdClause, data) + healthcheckCmdRoot := healthcheck.NewRootCommand(app, data) + healthcheckCreate := healthcheck.NewCreateCommand(healthcheckCmdRoot.CmdClause, data) + healthcheckDelete := healthcheck.NewDeleteCommand(healthcheckCmdRoot.CmdClause, data) + healthcheckDescribe := healthcheck.NewDescribeCommand(healthcheckCmdRoot.CmdClause, data) + healthcheckList := healthcheck.NewListCommand(healthcheckCmdRoot.CmdClause, data) + healthcheckUpdate := healthcheck.NewUpdateCommand(healthcheckCmdRoot.CmdClause, data) + ipCmdRoot := ip.NewRootCommand(app, data) + kvstoreCmdRoot := kvstore.NewRootCommand(app, data) + kvstoreCreate := kvstore.NewCreateCommand(kvstoreCmdRoot.CmdClause, data) + kvstoreDelete := kvstore.NewDeleteCommand(kvstoreCmdRoot.CmdClause, data) + kvstoreDescribe := kvstore.NewDescribeCommand(kvstoreCmdRoot.CmdClause, data) + kvstoreList := kvstore.NewListCommand(kvstoreCmdRoot.CmdClause, data) + kvstoreentryCmdRoot := kvstoreentry.NewRootCommand(app, data) + kvstoreentryCreate := kvstoreentry.NewCreateCommand(kvstoreentryCmdRoot.CmdClause, data) + kvstoreentryDelete := kvstoreentry.NewDeleteCommand(kvstoreentryCmdRoot.CmdClause, data) + kvstoreentryDescribe := kvstoreentry.NewDescribeCommand(kvstoreentryCmdRoot.CmdClause, data) + kvstoreentryList := kvstoreentry.NewListCommand(kvstoreentryCmdRoot.CmdClause, data) + logtailCmdRoot := logtail.NewRootCommand(app, data) + loggingCmdRoot := logging.NewRootCommand(app, data) + loggingAzureblobCmdRoot := azureblob.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingAzureblobCreate := azureblob.NewCreateCommand(loggingAzureblobCmdRoot.CmdClause, data) + loggingAzureblobDelete := azureblob.NewDeleteCommand(loggingAzureblobCmdRoot.CmdClause, data) + loggingAzureblobDescribe := azureblob.NewDescribeCommand(loggingAzureblobCmdRoot.CmdClause, data) + loggingAzureblobList := azureblob.NewListCommand(loggingAzureblobCmdRoot.CmdClause, data) + loggingAzureblobUpdate := azureblob.NewUpdateCommand(loggingAzureblobCmdRoot.CmdClause, data) + loggingBigQueryCmdRoot := bigquery.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingBigQueryCreate := bigquery.NewCreateCommand(loggingBigQueryCmdRoot.CmdClause, data) + loggingBigQueryDelete := bigquery.NewDeleteCommand(loggingBigQueryCmdRoot.CmdClause, data) + loggingBigQueryDescribe := bigquery.NewDescribeCommand(loggingBigQueryCmdRoot.CmdClause, data) + loggingBigQueryList := bigquery.NewListCommand(loggingBigQueryCmdRoot.CmdClause, data) + loggingBigQueryUpdate := bigquery.NewUpdateCommand(loggingBigQueryCmdRoot.CmdClause, data) + loggingCloudfilesCmdRoot := cloudfiles.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingCloudfilesCreate := cloudfiles.NewCreateCommand(loggingCloudfilesCmdRoot.CmdClause, data) + loggingCloudfilesDelete := cloudfiles.NewDeleteCommand(loggingCloudfilesCmdRoot.CmdClause, data) + loggingCloudfilesDescribe := cloudfiles.NewDescribeCommand(loggingCloudfilesCmdRoot.CmdClause, data) + loggingCloudfilesList := cloudfiles.NewListCommand(loggingCloudfilesCmdRoot.CmdClause, data) + loggingCloudfilesUpdate := cloudfiles.NewUpdateCommand(loggingCloudfilesCmdRoot.CmdClause, data) + loggingDatadogCmdRoot := datadog.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingDatadogCreate := datadog.NewCreateCommand(loggingDatadogCmdRoot.CmdClause, data) + loggingDatadogDelete := datadog.NewDeleteCommand(loggingDatadogCmdRoot.CmdClause, data) + loggingDatadogDescribe := datadog.NewDescribeCommand(loggingDatadogCmdRoot.CmdClause, data) + loggingDatadogList := datadog.NewListCommand(loggingDatadogCmdRoot.CmdClause, data) + loggingDatadogUpdate := datadog.NewUpdateCommand(loggingDatadogCmdRoot.CmdClause, data) + loggingDigitaloceanCmdRoot := digitalocean.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingDigitaloceanCreate := digitalocean.NewCreateCommand(loggingDigitaloceanCmdRoot.CmdClause, data) + loggingDigitaloceanDelete := digitalocean.NewDeleteCommand(loggingDigitaloceanCmdRoot.CmdClause, data) + loggingDigitaloceanDescribe := digitalocean.NewDescribeCommand(loggingDigitaloceanCmdRoot.CmdClause, data) + loggingDigitaloceanList := digitalocean.NewListCommand(loggingDigitaloceanCmdRoot.CmdClause, data) + loggingDigitaloceanUpdate := digitalocean.NewUpdateCommand(loggingDigitaloceanCmdRoot.CmdClause, data) + loggingElasticsearchCmdRoot := elasticsearch.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingElasticsearchCreate := elasticsearch.NewCreateCommand(loggingElasticsearchCmdRoot.CmdClause, data) + loggingElasticsearchDelete := elasticsearch.NewDeleteCommand(loggingElasticsearchCmdRoot.CmdClause, data) + loggingElasticsearchDescribe := elasticsearch.NewDescribeCommand(loggingElasticsearchCmdRoot.CmdClause, data) + loggingElasticsearchList := elasticsearch.NewListCommand(loggingElasticsearchCmdRoot.CmdClause, data) + loggingElasticsearchUpdate := elasticsearch.NewUpdateCommand(loggingElasticsearchCmdRoot.CmdClause, data) + loggingFtpCmdRoot := ftp.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingFtpCreate := ftp.NewCreateCommand(loggingFtpCmdRoot.CmdClause, data) + loggingFtpDelete := ftp.NewDeleteCommand(loggingFtpCmdRoot.CmdClause, data) + loggingFtpDescribe := ftp.NewDescribeCommand(loggingFtpCmdRoot.CmdClause, data) + loggingFtpList := ftp.NewListCommand(loggingFtpCmdRoot.CmdClause, data) + loggingFtpUpdate := ftp.NewUpdateCommand(loggingFtpCmdRoot.CmdClause, data) + loggingGcsCmdRoot := gcs.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingGcsCreate := gcs.NewCreateCommand(loggingGcsCmdRoot.CmdClause, data) + loggingGcsDelete := gcs.NewDeleteCommand(loggingGcsCmdRoot.CmdClause, data) + loggingGcsDescribe := gcs.NewDescribeCommand(loggingGcsCmdRoot.CmdClause, data) + loggingGcsList := gcs.NewListCommand(loggingGcsCmdRoot.CmdClause, data) + loggingGcsUpdate := gcs.NewUpdateCommand(loggingGcsCmdRoot.CmdClause, data) + loggingGooglepubsubCmdRoot := googlepubsub.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingGooglepubsubCreate := googlepubsub.NewCreateCommand(loggingGooglepubsubCmdRoot.CmdClause, data) + loggingGooglepubsubDelete := googlepubsub.NewDeleteCommand(loggingGooglepubsubCmdRoot.CmdClause, data) + loggingGooglepubsubDescribe := googlepubsub.NewDescribeCommand(loggingGooglepubsubCmdRoot.CmdClause, data) + loggingGooglepubsubList := googlepubsub.NewListCommand(loggingGooglepubsubCmdRoot.CmdClause, data) + loggingGooglepubsubUpdate := googlepubsub.NewUpdateCommand(loggingGooglepubsubCmdRoot.CmdClause, data) + loggingHerokuCmdRoot := heroku.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingHerokuCreate := heroku.NewCreateCommand(loggingHerokuCmdRoot.CmdClause, data) + loggingHerokuDelete := heroku.NewDeleteCommand(loggingHerokuCmdRoot.CmdClause, data) + loggingHerokuDescribe := heroku.NewDescribeCommand(loggingHerokuCmdRoot.CmdClause, data) + loggingHerokuList := heroku.NewListCommand(loggingHerokuCmdRoot.CmdClause, data) + loggingHerokuUpdate := heroku.NewUpdateCommand(loggingHerokuCmdRoot.CmdClause, data) + loggingHoneycombCmdRoot := honeycomb.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingHoneycombCreate := honeycomb.NewCreateCommand(loggingHoneycombCmdRoot.CmdClause, data) + loggingHoneycombDelete := honeycomb.NewDeleteCommand(loggingHoneycombCmdRoot.CmdClause, data) + loggingHoneycombDescribe := honeycomb.NewDescribeCommand(loggingHoneycombCmdRoot.CmdClause, data) + loggingHoneycombList := honeycomb.NewListCommand(loggingHoneycombCmdRoot.CmdClause, data) + loggingHoneycombUpdate := honeycomb.NewUpdateCommand(loggingHoneycombCmdRoot.CmdClause, data) + loggingHTTPSCmdRoot := https.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingHTTPSCreate := https.NewCreateCommand(loggingHTTPSCmdRoot.CmdClause, data) + loggingHTTPSDelete := https.NewDeleteCommand(loggingHTTPSCmdRoot.CmdClause, data) + loggingHTTPSDescribe := https.NewDescribeCommand(loggingHTTPSCmdRoot.CmdClause, data) + loggingHTTPSList := https.NewListCommand(loggingHTTPSCmdRoot.CmdClause, data) + loggingHTTPSUpdate := https.NewUpdateCommand(loggingHTTPSCmdRoot.CmdClause, data) + loggingKafkaCmdRoot := kafka.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingKafkaCreate := kafka.NewCreateCommand(loggingKafkaCmdRoot.CmdClause, data) + loggingKafkaDelete := kafka.NewDeleteCommand(loggingKafkaCmdRoot.CmdClause, data) + loggingKafkaDescribe := kafka.NewDescribeCommand(loggingKafkaCmdRoot.CmdClause, data) + loggingKafkaList := kafka.NewListCommand(loggingKafkaCmdRoot.CmdClause, data) + loggingKafkaUpdate := kafka.NewUpdateCommand(loggingKafkaCmdRoot.CmdClause, data) + loggingKinesisCmdRoot := kinesis.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingKinesisCreate := kinesis.NewCreateCommand(loggingKinesisCmdRoot.CmdClause, data) + loggingKinesisDelete := kinesis.NewDeleteCommand(loggingKinesisCmdRoot.CmdClause, data) + loggingKinesisDescribe := kinesis.NewDescribeCommand(loggingKinesisCmdRoot.CmdClause, data) + loggingKinesisList := kinesis.NewListCommand(loggingKinesisCmdRoot.CmdClause, data) + loggingKinesisUpdate := kinesis.NewUpdateCommand(loggingKinesisCmdRoot.CmdClause, data) + loggingLogglyCmdRoot := loggly.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingLogglyCreate := loggly.NewCreateCommand(loggingLogglyCmdRoot.CmdClause, data) + loggingLogglyDelete := loggly.NewDeleteCommand(loggingLogglyCmdRoot.CmdClause, data) + loggingLogglyDescribe := loggly.NewDescribeCommand(loggingLogglyCmdRoot.CmdClause, data) + loggingLogglyList := loggly.NewListCommand(loggingLogglyCmdRoot.CmdClause, data) + loggingLogglyUpdate := loggly.NewUpdateCommand(loggingLogglyCmdRoot.CmdClause, data) + loggingLogshuttleCmdRoot := logshuttle.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingLogshuttleCreate := logshuttle.NewCreateCommand(loggingLogshuttleCmdRoot.CmdClause, data) + loggingLogshuttleDelete := logshuttle.NewDeleteCommand(loggingLogshuttleCmdRoot.CmdClause, data) + loggingLogshuttleDescribe := logshuttle.NewDescribeCommand(loggingLogshuttleCmdRoot.CmdClause, data) + loggingLogshuttleList := logshuttle.NewListCommand(loggingLogshuttleCmdRoot.CmdClause, data) + loggingLogshuttleUpdate := logshuttle.NewUpdateCommand(loggingLogshuttleCmdRoot.CmdClause, data) + loggingNewRelicCmdRoot := newrelic.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingNewRelicCreate := newrelic.NewCreateCommand(loggingNewRelicCmdRoot.CmdClause, data) + loggingNewRelicDelete := newrelic.NewDeleteCommand(loggingNewRelicCmdRoot.CmdClause, data) + loggingNewRelicDescribe := newrelic.NewDescribeCommand(loggingNewRelicCmdRoot.CmdClause, data) + loggingNewRelicList := newrelic.NewListCommand(loggingNewRelicCmdRoot.CmdClause, data) + loggingNewRelicUpdate := newrelic.NewUpdateCommand(loggingNewRelicCmdRoot.CmdClause, data) + loggingNewRelicOTLPCmdRoot := newrelicotlp.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingNewRelicOTLPCreate := newrelicotlp.NewCreateCommand(loggingNewRelicOTLPCmdRoot.CmdClause, data) + loggingNewRelicOTLPDelete := newrelicotlp.NewDeleteCommand(loggingNewRelicOTLPCmdRoot.CmdClause, data) + loggingNewRelicOTLPDescribe := newrelicotlp.NewDescribeCommand(loggingNewRelicOTLPCmdRoot.CmdClause, data) + loggingNewRelicOTLPList := newrelicotlp.NewListCommand(loggingNewRelicOTLPCmdRoot.CmdClause, data) + loggingNewRelicOTLPUpdate := newrelicotlp.NewUpdateCommand(loggingNewRelicOTLPCmdRoot.CmdClause, data) + loggingOpenstackCmdRoot := openstack.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingOpenstackCreate := openstack.NewCreateCommand(loggingOpenstackCmdRoot.CmdClause, data) + loggingOpenstackDelete := openstack.NewDeleteCommand(loggingOpenstackCmdRoot.CmdClause, data) + loggingOpenstackDescribe := openstack.NewDescribeCommand(loggingOpenstackCmdRoot.CmdClause, data) + loggingOpenstackList := openstack.NewListCommand(loggingOpenstackCmdRoot.CmdClause, data) + loggingOpenstackUpdate := openstack.NewUpdateCommand(loggingOpenstackCmdRoot.CmdClause, data) + loggingPapertrailCmdRoot := papertrail.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingPapertrailCreate := papertrail.NewCreateCommand(loggingPapertrailCmdRoot.CmdClause, data) + loggingPapertrailDelete := papertrail.NewDeleteCommand(loggingPapertrailCmdRoot.CmdClause, data) + loggingPapertrailDescribe := papertrail.NewDescribeCommand(loggingPapertrailCmdRoot.CmdClause, data) + loggingPapertrailList := papertrail.NewListCommand(loggingPapertrailCmdRoot.CmdClause, data) + loggingPapertrailUpdate := papertrail.NewUpdateCommand(loggingPapertrailCmdRoot.CmdClause, data) + loggingS3CmdRoot := s3.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingS3Create := s3.NewCreateCommand(loggingS3CmdRoot.CmdClause, data) + loggingS3Delete := s3.NewDeleteCommand(loggingS3CmdRoot.CmdClause, data) + loggingS3Describe := s3.NewDescribeCommand(loggingS3CmdRoot.CmdClause, data) + loggingS3List := s3.NewListCommand(loggingS3CmdRoot.CmdClause, data) + loggingS3Update := s3.NewUpdateCommand(loggingS3CmdRoot.CmdClause, data) + loggingScalyrCmdRoot := scalyr.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingScalyrCreate := scalyr.NewCreateCommand(loggingScalyrCmdRoot.CmdClause, data) + loggingScalyrDelete := scalyr.NewDeleteCommand(loggingScalyrCmdRoot.CmdClause, data) + loggingScalyrDescribe := scalyr.NewDescribeCommand(loggingScalyrCmdRoot.CmdClause, data) + loggingScalyrList := scalyr.NewListCommand(loggingScalyrCmdRoot.CmdClause, data) + loggingScalyrUpdate := scalyr.NewUpdateCommand(loggingScalyrCmdRoot.CmdClause, data) + loggingSftpCmdRoot := sftp.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingSftpCreate := sftp.NewCreateCommand(loggingSftpCmdRoot.CmdClause, data) + loggingSftpDelete := sftp.NewDeleteCommand(loggingSftpCmdRoot.CmdClause, data) + loggingSftpDescribe := sftp.NewDescribeCommand(loggingSftpCmdRoot.CmdClause, data) + loggingSftpList := sftp.NewListCommand(loggingSftpCmdRoot.CmdClause, data) + loggingSftpUpdate := sftp.NewUpdateCommand(loggingSftpCmdRoot.CmdClause, data) + loggingSplunkCmdRoot := splunk.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingSplunkCreate := splunk.NewCreateCommand(loggingSplunkCmdRoot.CmdClause, data) + loggingSplunkDelete := splunk.NewDeleteCommand(loggingSplunkCmdRoot.CmdClause, data) + loggingSplunkDescribe := splunk.NewDescribeCommand(loggingSplunkCmdRoot.CmdClause, data) + loggingSplunkList := splunk.NewListCommand(loggingSplunkCmdRoot.CmdClause, data) + loggingSplunkUpdate := splunk.NewUpdateCommand(loggingSplunkCmdRoot.CmdClause, data) + loggingSumologicCmdRoot := sumologic.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingSumologicCreate := sumologic.NewCreateCommand(loggingSumologicCmdRoot.CmdClause, data) + loggingSumologicDelete := sumologic.NewDeleteCommand(loggingSumologicCmdRoot.CmdClause, data) + loggingSumologicDescribe := sumologic.NewDescribeCommand(loggingSumologicCmdRoot.CmdClause, data) + loggingSumologicList := sumologic.NewListCommand(loggingSumologicCmdRoot.CmdClause, data) + loggingSumologicUpdate := sumologic.NewUpdateCommand(loggingSumologicCmdRoot.CmdClause, data) + loggingSyslogCmdRoot := syslog.NewRootCommand(loggingCmdRoot.CmdClause, data) + loggingSyslogCreate := syslog.NewCreateCommand(loggingSyslogCmdRoot.CmdClause, data) + loggingSyslogDelete := syslog.NewDeleteCommand(loggingSyslogCmdRoot.CmdClause, data) + loggingSyslogDescribe := syslog.NewDescribeCommand(loggingSyslogCmdRoot.CmdClause, data) + loggingSyslogList := syslog.NewListCommand(loggingSyslogCmdRoot.CmdClause, data) + loggingSyslogUpdate := syslog.NewUpdateCommand(loggingSyslogCmdRoot.CmdClause, data) + popCmdRoot := pop.NewRootCommand(app, data) + productsCmdRoot := products.NewRootCommand(app, data) + profileCmdRoot := profile.NewRootCommand(app, data) + profileCreate := profile.NewCreateCommand(profileCmdRoot.CmdClause, data, ssoCmdRoot) + profileDelete := profile.NewDeleteCommand(profileCmdRoot.CmdClause, data) + profileList := profile.NewListCommand(profileCmdRoot.CmdClause, data) + profileSwitch := profile.NewSwitchCommand(profileCmdRoot.CmdClause, data) + profileToken := profile.NewTokenCommand(profileCmdRoot.CmdClause, data) + profileUpdate := profile.NewUpdateCommand(profileCmdRoot.CmdClause, data, ssoCmdRoot) + purgeCmdRoot := purge.NewRootCommand(app, data) + rateLimitCmdRoot := ratelimit.NewRootCommand(app, data) + rateLimitCreate := ratelimit.NewCreateCommand(rateLimitCmdRoot.CmdClause, data) + rateLimitDelete := ratelimit.NewDeleteCommand(rateLimitCmdRoot.CmdClause, data) + rateLimitDescribe := ratelimit.NewDescribeCommand(rateLimitCmdRoot.CmdClause, data) + rateLimitList := ratelimit.NewListCommand(rateLimitCmdRoot.CmdClause, data) + rateLimitUpdate := ratelimit.NewUpdateCommand(rateLimitCmdRoot.CmdClause, data) + resourcelinkCmdRoot := resourcelink.NewRootCommand(app, data) + resourcelinkCreate := resourcelink.NewCreateCommand(resourcelinkCmdRoot.CmdClause, data) + resourcelinkDelete := resourcelink.NewDeleteCommand(resourcelinkCmdRoot.CmdClause, data) + resourcelinkDescribe := resourcelink.NewDescribeCommand(resourcelinkCmdRoot.CmdClause, data) + resourcelinkList := resourcelink.NewListCommand(resourcelinkCmdRoot.CmdClause, data) + resourcelinkUpdate := resourcelink.NewUpdateCommand(resourcelinkCmdRoot.CmdClause, data) + secretstoreCmdRoot := secretstore.NewRootCommand(app, data) + secretstoreCreate := secretstore.NewCreateCommand(secretstoreCmdRoot.CmdClause, data) + secretstoreDescribe := secretstore.NewDescribeCommand(secretstoreCmdRoot.CmdClause, data) + secretstoreDelete := secretstore.NewDeleteCommand(secretstoreCmdRoot.CmdClause, data) + secretstoreList := secretstore.NewListCommand(secretstoreCmdRoot.CmdClause, data) + secretstoreentryCmdRoot := secretstoreentry.NewRootCommand(app, data) + secretstoreentryCreate := secretstoreentry.NewCreateCommand(secretstoreentryCmdRoot.CmdClause, data) + secretstoreentryDescribe := secretstoreentry.NewDescribeCommand(secretstoreentryCmdRoot.CmdClause, data) + secretstoreentryDelete := secretstoreentry.NewDeleteCommand(secretstoreentryCmdRoot.CmdClause, data) + secretstoreentryList := secretstoreentry.NewListCommand(secretstoreentryCmdRoot.CmdClause, data) + serviceCmdRoot := service.NewRootCommand(app, data) + serviceCreate := service.NewCreateCommand(serviceCmdRoot.CmdClause, data) + serviceDelete := service.NewDeleteCommand(serviceCmdRoot.CmdClause, data) + serviceDescribe := service.NewDescribeCommand(serviceCmdRoot.CmdClause, data) + serviceList := service.NewListCommand(serviceCmdRoot.CmdClause, data) + serviceSearch := service.NewSearchCommand(serviceCmdRoot.CmdClause, data) + serviceUpdate := service.NewUpdateCommand(serviceCmdRoot.CmdClause, data) + serviceauthCmdRoot := serviceauth.NewRootCommand(app, data) + serviceauthCreate := serviceauth.NewCreateCommand(serviceauthCmdRoot.CmdClause, data) + serviceauthDelete := serviceauth.NewDeleteCommand(serviceauthCmdRoot.CmdClause, data) + serviceauthDescribe := serviceauth.NewDescribeCommand(serviceauthCmdRoot.CmdClause, data) + serviceauthList := serviceauth.NewListCommand(serviceauthCmdRoot.CmdClause, data) + serviceauthUpdate := serviceauth.NewUpdateCommand(serviceauthCmdRoot.CmdClause, data) + serviceVersionCmdRoot := serviceversion.NewRootCommand(app, data) + serviceVersionActivate := serviceversion.NewActivateCommand(serviceVersionCmdRoot.CmdClause, data) + serviceVersionClone := serviceversion.NewCloneCommand(serviceVersionCmdRoot.CmdClause, data) + serviceVersionDeactivate := serviceversion.NewDeactivateCommand(serviceVersionCmdRoot.CmdClause, data) + serviceVersionList := serviceversion.NewListCommand(serviceVersionCmdRoot.CmdClause, data) + serviceVersionLock := serviceversion.NewLockCommand(serviceVersionCmdRoot.CmdClause, data) + serviceVersionUpdate := serviceversion.NewUpdateCommand(serviceVersionCmdRoot.CmdClause, data) + statsCmdRoot := stats.NewRootCommand(app, data) + statsHistorical := stats.NewHistoricalCommand(statsCmdRoot.CmdClause, data) + statsRealtime := stats.NewRealtimeCommand(statsCmdRoot.CmdClause, data) + statsRegions := stats.NewRegionsCommand(statsCmdRoot.CmdClause, data) + tlsConfigCmdRoot := tlsconfig.NewRootCommand(app, data) + tlsConfigDescribe := tlsconfig.NewDescribeCommand(tlsConfigCmdRoot.CmdClause, data) + tlsConfigList := tlsconfig.NewListCommand(tlsConfigCmdRoot.CmdClause, data) + tlsConfigUpdate := tlsconfig.NewUpdateCommand(tlsConfigCmdRoot.CmdClause, data) + tlsCustomCmdRoot := tlscustom.NewRootCommand(app, data) + tlsCustomActivationCmdRoot := tlscustomactivation.NewRootCommand(tlsCustomCmdRoot.CmdClause, data) + tlsCustomActivationCreate := tlscustomactivation.NewCreateCommand(tlsCustomActivationCmdRoot.CmdClause, data) + tlsCustomActivationDelete := tlscustomactivation.NewDeleteCommand(tlsCustomActivationCmdRoot.CmdClause, data) + tlsCustomActivationDescribe := tlscustomactivation.NewDescribeCommand(tlsCustomActivationCmdRoot.CmdClause, data) + tlsCustomActivationList := tlscustomactivation.NewListCommand(tlsCustomActivationCmdRoot.CmdClause, data) + tlsCustomActivationUpdate := tlscustomactivation.NewUpdateCommand(tlsCustomActivationCmdRoot.CmdClause, data) + tlsCustomCertificateCmdRoot := tlscustomcertificate.NewRootCommand(tlsCustomCmdRoot.CmdClause, data) + tlsCustomCertificateCreate := tlscustomcertificate.NewCreateCommand(tlsCustomCertificateCmdRoot.CmdClause, data) + tlsCustomCertificateDelete := tlscustomcertificate.NewDeleteCommand(tlsCustomCertificateCmdRoot.CmdClause, data) + tlsCustomCertificateDescribe := tlscustomcertificate.NewDescribeCommand(tlsCustomCertificateCmdRoot.CmdClause, data) + tlsCustomCertificateList := tlscustomcertificate.NewListCommand(tlsCustomCertificateCmdRoot.CmdClause, data) + tlsCustomCertificateUpdate := tlscustomcertificate.NewUpdateCommand(tlsCustomCertificateCmdRoot.CmdClause, data) + tlsCustomDomainCmdRoot := tlscustomdomain.NewRootCommand(tlsCustomCmdRoot.CmdClause, data) + tlsCustomDomainList := tlscustomdomain.NewListCommand(tlsCustomDomainCmdRoot.CmdClause, data) + tlsCustomPrivateKeyCmdRoot := tlscustomprivatekey.NewRootCommand(tlsCustomCmdRoot.CmdClause, data) + tlsCustomPrivateKeyCreate := tlscustomprivatekey.NewCreateCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, data) + tlsCustomPrivateKeyDelete := tlscustomprivatekey.NewDeleteCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, data) + tlsCustomPrivateKeyDescribe := tlscustomprivatekey.NewDescribeCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, data) + tlsCustomPrivateKeyList := tlscustomprivatekey.NewListCommand(tlsCustomPrivateKeyCmdRoot.CmdClause, data) + tlsPlatformCmdRoot := tlsplatform.NewRootCommand(app, data) + tlsPlatformCreate := tlsplatform.NewCreateCommand(tlsPlatformCmdRoot.CmdClause, data) + tlsPlatformDelete := tlsplatform.NewDeleteCommand(tlsPlatformCmdRoot.CmdClause, data) + tlsPlatformDescribe := tlsplatform.NewDescribeCommand(tlsPlatformCmdRoot.CmdClause, data) + tlsPlatformList := tlsplatform.NewListCommand(tlsPlatformCmdRoot.CmdClause, data) + tlsPlatformUpdate := tlsplatform.NewUpdateCommand(tlsPlatformCmdRoot.CmdClause, data) + tlsSubscriptionCmdRoot := tlssubscription.NewRootCommand(app, data) + tlsSubscriptionCreate := tlssubscription.NewCreateCommand(tlsSubscriptionCmdRoot.CmdClause, data) + tlsSubscriptionDelete := tlssubscription.NewDeleteCommand(tlsSubscriptionCmdRoot.CmdClause, data) + tlsSubscriptionDescribe := tlssubscription.NewDescribeCommand(tlsSubscriptionCmdRoot.CmdClause, data) + tlsSubscriptionList := tlssubscription.NewListCommand(tlsSubscriptionCmdRoot.CmdClause, data) + tlsSubscriptionUpdate := tlssubscription.NewUpdateCommand(tlsSubscriptionCmdRoot.CmdClause, data) + updateRoot := update.NewRootCommand(app, data) + userCmdRoot := user.NewRootCommand(app, data) + userCreate := user.NewCreateCommand(userCmdRoot.CmdClause, data) + userDelete := user.NewDeleteCommand(userCmdRoot.CmdClause, data) + userDescribe := user.NewDescribeCommand(userCmdRoot.CmdClause, data) + userList := user.NewListCommand(userCmdRoot.CmdClause, data) + userUpdate := user.NewUpdateCommand(userCmdRoot.CmdClause, data) + vclCmdRoot := vcl.NewRootCommand(app, data) + vclConditionCmdRoot := condition.NewRootCommand(vclCmdRoot.CmdClause, data) + vclConditionCreate := condition.NewCreateCommand(vclConditionCmdRoot.CmdClause, data) + vclConditionDelete := condition.NewDeleteCommand(vclConditionCmdRoot.CmdClause, data) + vclConditionDescribe := condition.NewDescribeCommand(vclConditionCmdRoot.CmdClause, data) + vclConditionList := condition.NewListCommand(vclConditionCmdRoot.CmdClause, data) + vclConditionUpdate := condition.NewUpdateCommand(vclConditionCmdRoot.CmdClause, data) + vclCustomCmdRoot := custom.NewRootCommand(vclCmdRoot.CmdClause, data) + vclCustomCreate := custom.NewCreateCommand(vclCustomCmdRoot.CmdClause, data) + vclCustomDelete := custom.NewDeleteCommand(vclCustomCmdRoot.CmdClause, data) + vclCustomDescribe := custom.NewDescribeCommand(vclCustomCmdRoot.CmdClause, data) + vclCustomList := custom.NewListCommand(vclCustomCmdRoot.CmdClause, data) + vclCustomUpdate := custom.NewUpdateCommand(vclCustomCmdRoot.CmdClause, data) + vclSnippetCmdRoot := snippet.NewRootCommand(vclCmdRoot.CmdClause, data) + vclSnippetCreate := snippet.NewCreateCommand(vclSnippetCmdRoot.CmdClause, data) + vclSnippetDelete := snippet.NewDeleteCommand(vclSnippetCmdRoot.CmdClause, data) + vclSnippetDescribe := snippet.NewDescribeCommand(vclSnippetCmdRoot.CmdClause, data) + vclSnippetList := snippet.NewListCommand(vclSnippetCmdRoot.CmdClause, data) + vclSnippetUpdate := snippet.NewUpdateCommand(vclSnippetCmdRoot.CmdClause, data) + versionCmdRoot := version.NewRootCommand(app, data) + whoamiCmdRoot := whoami.NewRootCommand(app, data) return []cmd.Command{ shellcompleteCmdRoot, @@ -744,6 +752,7 @@ func defineCommands( serviceVersionList, serviceVersionLock, serviceVersionUpdate, + ssoCmdRoot, statsCmdRoot, statsHistorical, statsRealtime, diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 4a4033324..f0684babc 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -57,7 +57,6 @@ type Flags struct { // BuildCommand produces a deployable artifact from files on the local disk. type BuildCommand struct { cmd.Base - wasmtoolsVersioner github.AssetVersioner // NOTE: Composite commands require these build flags to be public. // e.g. serve, publish, hashsum, hash-files @@ -69,11 +68,9 @@ type BuildCommand struct { } // NewBuildCommand returns a usable command registered under the parent. -func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner github.AssetVersioner) *BuildCommand { +func NewBuildCommand(parent cmd.Registerer, g *global.Data) *BuildCommand { var c BuildCommand c.Globals = g - c.wasmtoolsVersioner = wasmtoolsVersioner - c.CmdClause = parent.Command("build", "Build a Compute package locally") // NOTE: when updating these flags, be sure to update the composite commands: @@ -157,7 +154,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - wasmtools, wasmtoolsErr := GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) + wasmtools, wasmtoolsErr := GetWasmTools(spinner, out, c.Globals.Versioners.WasmTools, c.Globals) var pkgName string err = spinner.Process("Identifying package name", func(_ *text.SpinnerWrapper) error { diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index 6143d869d..8f4d70864 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -2,6 +2,7 @@ package compute_test import ( "fmt" + "io" "os" "os/exec" "path/filepath" @@ -11,6 +12,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" @@ -28,7 +30,7 @@ func TestBuildRust(t *testing.T) { scenarios := []struct { name string args []string - applicationConfig config.File + applicationConfig *config.File // a pointer so we can assert if configured fastlyManifest string cargoManifest string wantError string @@ -67,7 +69,8 @@ func TestBuildRust(t *testing.T) { { name: "build script inserted dynamically when missing", args: args("compute build --verbose"), - applicationConfig: config.File{ + applicationConfig: &config.File{ + Profiles: testutil.TokenProfile(), Language: config.Language{ Rust: config.Rust{ ToolchainConstraint: ">= 1.54.0", @@ -95,7 +98,8 @@ func TestBuildRust(t *testing.T) { { name: "build error", args: args("compute build"), - applicationConfig: config.File{ + applicationConfig: &config.File{ + Profiles: testutil.TokenProfile(), Language: config.Language{ Rust: config.Rust{ ToolchainConstraint: ">= 1.54.0", @@ -123,7 +127,8 @@ func TestBuildRust(t *testing.T) { { name: "successful build", args: args("compute build --verbose"), - applicationConfig: config.File{ + applicationConfig: &config.File{ + Profiles: testutil.TokenProfile(), Language: config.Language{ Rust: config.Rust{ ToolchainConstraint: ">= 1.54.0", @@ -213,19 +218,23 @@ func TestBuildRust(t *testing.T) { }() var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.ConfigFile = testcase.applicationConfig - opts.Versioners = app.Versioners{ - WasmTools: mock.AssetVersioner{ - AssetVersion: "1.2.3", - BinaryFilename: wasmtoolsBinName, - DownloadOK: true, - DownloadedFile: latestDownloaded, - InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install - }, + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + if testcase.applicationConfig != nil { + opts.Config = *testcase.applicationConfig + } + opts.Versioners = global.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: latestDownloaded, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, + } + return opts, nil } - - err = app.Run(opts) + err = app.Run(testcase.args, nil) t.Log(stdout.String()) @@ -254,7 +263,7 @@ func TestBuildGo(t *testing.T) { scenarios := []struct { name string args []string - applicationConfig config.File + applicationConfig *config.File fastlyManifest string wantError string wantRemediationError string @@ -291,7 +300,8 @@ func TestBuildGo(t *testing.T) { { name: "build success", args: args("compute build --verbose"), - applicationConfig: config.File{ + applicationConfig: &config.File{ + Profiles: testutil.TokenProfile(), Language: config.Language{ Go: config.Go{ TinyGoConstraint: ">= 0.26.0-0", @@ -322,7 +332,8 @@ func TestBuildGo(t *testing.T) { { name: "build error", args: args("compute build"), - applicationConfig: config.File{ + applicationConfig: &config.File{ + Profiles: testutil.TokenProfile(), Language: config.Language{ Go: config.Go{ TinyGoConstraint: ">= 0.26.0-0", @@ -400,19 +411,23 @@ func TestBuildGo(t *testing.T) { }() var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.ConfigFile = testcase.applicationConfig - opts.Versioners = app.Versioners{ - WasmTools: mock.AssetVersioner{ - AssetVersion: "1.2.3", - BinaryFilename: wasmtoolsBinName, - DownloadOK: true, - DownloadedFile: latestDownloaded, - InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install - }, + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + if testcase.applicationConfig != nil { + opts.Config = *testcase.applicationConfig + } + opts.Versioners = global.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: latestDownloaded, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, + } + return opts, nil } - - err = app.Run(opts) + err = app.Run(testcase.args, nil) t.Log(stdout.String()) @@ -446,7 +461,7 @@ func TestBuildJavaScript(t *testing.T) { wantRemediationError string wantOutput []string npmInstall bool - versioners *app.Versioners + versioners *global.Versioners }{ { name: "no fastly.toml manifest", @@ -594,18 +609,20 @@ func TestBuildJavaScript(t *testing.T) { } var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.Versioners = app.Versioners{ - WasmTools: mock.AssetVersioner{ - AssetVersion: "1.2.3", - BinaryFilename: wasmtoolsBinName, - DownloadOK: true, - DownloadedFile: latestDownloaded, - InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install - }, + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.Versioners = global.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: latestDownloaded, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, + } + return opts, nil } - - err = app.Run(opts) + err = app.Run(testcase.args, nil) t.Log(stdout.String()) @@ -787,18 +804,20 @@ func TestBuildAssemblyScript(t *testing.T) { } var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.Versioners = app.Versioners{ - WasmTools: mock.AssetVersioner{ - AssetVersion: "1.2.3", - BinaryFilename: wasmtoolsBinName, - DownloadOK: true, - DownloadedFile: latestDownloaded, - InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install - }, + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.Versioners = global.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: latestDownloaded, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, + } + return opts, nil } - - err = app.Run(opts) + err = app.Run(testcase.args, nil) t.Log(stdout.String()) @@ -997,19 +1016,21 @@ func TestBuildOther(t *testing.T) { } var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.Stdin = strings.NewReader(testcase.stdin) // NOTE: build only has one prompt when dealing with a custom build - opts.Versioners = app.Versioners{ - WasmTools: mock.AssetVersioner{ - AssetVersion: "1.2.3", - BinaryFilename: wasmtoolsBinName, - DownloadOK: true, - DownloadedFile: latestDownloaded, - InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install - }, + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.Input = strings.NewReader(testcase.stdin) // NOTE: build only has one prompt when dealing with a custom build + opts.Versioners = global.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: latestDownloaded, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, + } + return opts, nil } - - err = app.Run(opts) + err = app.Run(testcase.args, nil) t.Log(stdout.String()) diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index 2a6883ea8..4c77357e5 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -10,8 +10,8 @@ import ( "github.com/mholt/archiver/v3" "github.com/fastly/cli/pkg/commands/compute" - "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/testutil" ) @@ -20,10 +20,11 @@ import ( // `compute build` and `compute deploy` commands from which publish is composed. func TestFlagDivergencePublish(t *testing.T) { var g global.Data + g.Manifest = &manifest.Data{} acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &g) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &g, nil) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &g) dcmd := compute.NewDeployCommand(rcmd.CmdClause, &g) pcmd := compute.NewPublishCommand(rcmd.CmdClause, &g, bcmd, dcmd) @@ -68,16 +69,11 @@ func TestFlagDivergencePublish(t *testing.T) { // `compute build` command as `compute serve` delegates to build. func TestFlagDivergenceServe(t *testing.T) { var cfg global.Data - versioner := github.New(github.Opts{ - Org: "fastly", - Repo: "viceroy", - Binary: "viceroy", - }) acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &cfg) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg, nil) - scmd := compute.NewServeCommand(rcmd.CmdClause, &cfg, bcmd, versioner) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg) + scmd := compute.NewServeCommand(rcmd.CmdClause, &cfg, bcmd) buildFlags := getFlags(bcmd.CmdClause) serveFlags := getFlags(scmd.CmdClause) @@ -135,7 +131,7 @@ func TestFlagDivergenceHashSum(t *testing.T) { acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &cfg) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg, nil) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg) hcmd := compute.NewHashsumCommand(rcmd.CmdClause, &cfg, bcmd) buildFlags := getFlags(bcmd.CmdClause) @@ -186,7 +182,7 @@ func TestFlagDivergenceHashFiles(t *testing.T) { acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &cfg) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg, nil) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg) hcmd := compute.NewHashFilesCommand(rcmd.CmdClause, &cfg, bcmd) buildFlags := getFlags(bcmd.CmdClause) diff --git a/pkg/commands/compute/deploy.go b/pkg/commands/compute/deploy.go index fc8c76e65..811978738 100644 --- a/pkg/commands/compute/deploy.go +++ b/pkg/commands/compute/deploy.go @@ -9,6 +9,7 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -146,7 +147,7 @@ func (c *DeployCommand) Exec(in io.Reader, out io.Writer) (err error) { } // Otherwise, we'll attempt to read the manifest from within the given // package archive. - if err := readManifestFromPackageArchive(&c.Globals.Manifest, c.PackagePath, manifestFilename); err != nil { + if err := readManifestFromPackageArchive(c.Globals.Manifest, c.PackagePath, manifestFilename); err != nil { return err } if c.Globals.Verbose() { @@ -357,7 +358,7 @@ func (c *DeployCommand) Setup(out io.Writer) (fnActivateTrial Activator, service // IMPORTANT: We don't handle the error when looking up the Service ID. // This is because later in the Exec() flow we might create a 'new' service. - serviceID, source, flag, err := cmd.ServiceID(c.ServiceName, c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.ServiceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err == nil && c.Globals.Verbose() { cmd.DisplayServiceID(serviceID, flag, source, out) } @@ -378,8 +379,8 @@ func (c *DeployCommand) Setup(out io.Writer) (fnActivateTrial Activator, service return defaultActivator, serviceID, err } - endpoint, _ := c.Globals.Endpoint() - fnActivateTrial = preconfigureActivateTrial(endpoint, token, c.Globals.HTTPClient) + endpoint, _ := c.Globals.APIEndpoint() + fnActivateTrial = preconfigureActivateTrial(endpoint, token, c.Globals.HTTPClient, c.Globals.Env.DebugMode) return fnActivateTrial, serviceID, err } @@ -495,7 +496,8 @@ func packageSize(path string) (size int64, err error) { type Activator func(customerID string) error // preconfigureActivateTrial activates a free trial on the customer account. -func preconfigureActivateTrial(endpoint, token string, httpClient api.HTTPClient) Activator { +func preconfigureActivateTrial(endpoint, token string, httpClient api.HTTPClient, debugMode string) Activator { + debug, _ := strconv.ParseBool(debugMode) return func(customerID string) error { _, err := undocumented.Call(undocumented.CallOptions{ APIEndpoint: endpoint, @@ -503,6 +505,7 @@ func preconfigureActivateTrial(endpoint, token string, httpClient api.HTTPClient Method: http.MethodPost, Path: fmt.Sprintf(undocumented.EdgeComputeTrial, customerID), Token: token, + Debug: debug, }) if err != nil { apiErr, ok := err.(undocumented.APIError) diff --git a/pkg/commands/compute/deploy_test.go b/pkg/commands/compute/deploy_test.go index 0f4b492af..f098c7d49 100644 --- a/pkg/commands/compute/deploy_test.go +++ b/pkg/commands/compute/deploy_test.go @@ -17,6 +17,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" @@ -108,11 +109,6 @@ func TestDeploy(t *testing.T) { wantRemediationError string wantOutput []string }{ - { - name: "no token", - args: args("compute deploy"), - wantError: "no token provided", - }, { name: "no fastly.toml manifest", args: args("compute deploy --token 123"), @@ -2158,8 +2154,8 @@ func TestDeploy(t *testing.T) { } var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) if testcase.httpClientRes != nil || testcase.httpClientErr != nil { opts.HTTPClient = mock.HTMLClient(testcase.httpClientRes, testcase.httpClientErr) @@ -2177,7 +2173,7 @@ func TestDeploy(t *testing.T) { // To handle multiple prompt input from the user we need to do some // coordination around io pipes to mimic the required user behaviour. stdin, prompt := io.Pipe() - opts.Stdin = stdin + opts.Input = stdin // Wait for user input and write it to the prompt inputc := make(chan string) @@ -2192,7 +2188,10 @@ func TestDeploy(t *testing.T) { // Call `app.Run()` and wait for response go func() { - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.args, nil) done <- true }() @@ -2217,8 +2216,11 @@ func TestDeploy(t *testing.T) { if len(testcase.stdin) > 0 { stdin = testcase.stdin[0] } - opts.Stdin = strings.NewReader(stdin) - err = app.Run(opts) + opts.Input = strings.NewReader(stdin) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.args, nil) } t.Log(stdout.String()) diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 67ac88588..d508ed5cf 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -43,7 +43,6 @@ type InitCommand struct { dir string cloneFrom string language string - manifest manifest.Data tag string } @@ -51,13 +50,12 @@ type InitCommand struct { var Languages = []string{"rust", "javascript", "go", "other"} // NewInitCommand returns a usable command registered under the parent. -func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *InitCommand { +func NewInitCommand(parent cmd.Registerer, g *global.Data) *InitCommand { var c InitCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("init", "Initialize a new Compute package locally") - c.CmdClause.Flag("author", "Author(s) of the package").Short('a').StringsVar(&c.manifest.File.Authors) + c.CmdClause.Flag("author", "Author(s) of the package").Short('a').StringsVar(&g.Manifest.File.Authors) c.CmdClause.Flag("branch", "Git branch name to clone from package template repository").Hidden().StringVar(&c.branch) c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) c.CmdClause.Flag("from", "Local project directory, or Git repository URL, or URL referencing a .zip/.tar.gz file, containing a package template").Short('f').StringVar(&c.cloneFrom) @@ -106,7 +104,7 @@ func (c *InitCommand) Exec(in io.Reader, out io.Writer) (err error) { return fmt.Errorf("error determining current directory: %w", err) } - mf := c.manifest.File + mf := c.Globals.Manifest.File if c.Globals.Flags.Quiet { mf.SetQuiet(true) } @@ -139,8 +137,7 @@ func (c *InitCommand) Exec(in io.Reader, out io.Writer) (err error) { // Assign the default profile email if available. email := "" - profileName, p := profile.Default(c.Globals.Config.Profiles) - if profileName != "" { + if _, p := profile.Default(c.Globals.Config.Profiles); p != nil { email = p.Email } @@ -442,9 +439,9 @@ func validateDirectoryPermissions(dst string) text.SpinnerProcess { // returned as is. func (c *InitCommand) PromptOrReturn(email string, in io.Reader, out io.Writer) (name, description string, authors []string, err error) { flags := c.Globals.Flags - name, _ = c.manifest.Name() - description, _ = c.manifest.Description() - authors, _ = c.manifest.Authors() + name, _ = c.Globals.Manifest.Name() + description, _ = c.Globals.Manifest.Description() + authors, _ = c.Globals.Manifest.Authors() if name == "" && !flags.AcceptDefaults && !flags.NonInteractive { text.Break(out) diff --git a/pkg/commands/compute/init_test.go b/pkg/commands/compute/init_test.go index 95e99321a..ecfc161d7 100644 --- a/pkg/commands/compute/init_test.go +++ b/pkg/commands/compute/init_test.go @@ -3,6 +3,7 @@ package compute_test import ( "bytes" "errors" + "io" "os" "path/filepath" "strings" @@ -10,6 +11,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/testutil" ) @@ -358,15 +360,17 @@ func TestInit(t *testing.T) { }() var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.ConfigFile = testcase.configFile + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.Config = testcase.configFile - // we need to define stdin as the init process prompts the user multiple - // times, but we don't need to provide any values as all our prompts will - // fallback to default values if the input is unrecognised. - opts.Stdin = strings.NewReader(testcase.stdin) - - err = app.Run(opts) + // we need to define stdin as the init process prompts the user multiple + // times, but we don't need to provide any values as all our prompts will + // fallback to default values if the input is unrecognised. + opts.Input = strings.NewReader(testcase.stdin) + return opts, nil + } + err = app.Run(testcase.args, nil) t.Log(stdout.String()) diff --git a/pkg/commands/compute/metadata_test.go b/pkg/commands/compute/metadata_test.go index def87b21c..0c756682b 100644 --- a/pkg/commands/compute/metadata_test.go +++ b/pkg/commands/compute/metadata_test.go @@ -2,6 +2,7 @@ package compute_test import ( "bytes" + "io" "os" "path/filepath" "strings" @@ -11,6 +12,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/revision" "github.com/fastly/cli/pkg/testutil" ) @@ -123,7 +125,7 @@ func TestMetadata(t *testing.T) { t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) + opts := testutil.MockGlobalData(testcase.Args, &stdout) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -140,14 +142,17 @@ func TestMetadata(t *testing.T) { // The read of the config file only happens in the main() function, so for // the sake of the test environment we need to construct an in-memory // representation of the config file we want to be using. - opts.ConfigFile = config.File{ + opts.Config = config.File{ ConfigVersion: staticConfig.ConfigVersion, CLI: config.CLI{ Version: revision.SemVer(revision.AppVersion), }, } - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) t.Log(stdout.String()) @@ -159,19 +164,19 @@ func TestMetadata(t *testing.T) { in := strings.NewReader("") verboseMode := false - err = opts.ConfigFile.Read(configPath, in, opts.Stdout, opts.ErrLog, verboseMode) + err = opts.Config.Read(configPath, in, opts.Output, opts.ErrLog, verboseMode) if err != nil { t.Error(err) } - if opts.ConfigFile.WasmMetadata.BuildInfo != testcase.ExpectedConfig.BuildInfo { - t.Errorf("want: %s, got: %s", testcase.ExpectedConfig.BuildInfo, opts.ConfigFile.WasmMetadata.BuildInfo) + if opts.Config.WasmMetadata.BuildInfo != testcase.ExpectedConfig.BuildInfo { + t.Errorf("want: %s, got: %s", testcase.ExpectedConfig.BuildInfo, opts.Config.WasmMetadata.BuildInfo) } - if opts.ConfigFile.WasmMetadata.MachineInfo != testcase.ExpectedConfig.MachineInfo { - t.Errorf("want: %s, got: %s", testcase.ExpectedConfig.MachineInfo, opts.ConfigFile.WasmMetadata.MachineInfo) + if opts.Config.WasmMetadata.MachineInfo != testcase.ExpectedConfig.MachineInfo { + t.Errorf("want: %s, got: %s", testcase.ExpectedConfig.MachineInfo, opts.Config.WasmMetadata.MachineInfo) } - if opts.ConfigFile.WasmMetadata.PackageInfo != testcase.ExpectedConfig.PackageInfo { - t.Errorf("want: %s, got: %s", testcase.ExpectedConfig.PackageInfo, opts.ConfigFile.WasmMetadata.PackageInfo) + if opts.Config.WasmMetadata.PackageInfo != testcase.ExpectedConfig.PackageInfo { + t.Errorf("want: %s, got: %s", testcase.ExpectedConfig.PackageInfo, opts.Config.WasmMetadata.PackageInfo) } }) } diff --git a/pkg/commands/compute/pack.go b/pkg/commands/compute/pack.go index 3afbaff46..3d551257d 100644 --- a/pkg/commands/compute/pack.go +++ b/pkg/commands/compute/pack.go @@ -19,16 +19,13 @@ import ( // PackCommand takes a .wasm and builds the required tar/gzip package ready to be uploaded. type PackCommand struct { cmd.Base - manifest manifest.Data wasmBinary string } // NewPackCommand returns a usable command registered under the parent. -func NewPackCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *PackCommand { +func NewPackCommand(parent cmd.Registerer, g *global.Data) *PackCommand { var c PackCommand c.Globals = g - c.manifest = m - c.CmdClause = parent.Command("pack", "Package a pre-compiled Wasm binary for a Fastly Compute service") c.CmdClause.Flag("wasm-binary", "Path to a pre-compiled Wasm binary").Short('w').Required().StringVar(&c.wasmBinary) @@ -51,7 +48,7 @@ func (c *PackCommand) Exec(_ io.Reader, out io.Writer) (err error) { } }(c.Globals.ErrLog) - if err = c.manifest.File.ReadError(); err != nil { + if err = c.Globals.Manifest.File.ReadError(); err != nil { return err } diff --git a/pkg/commands/compute/pack_test.go b/pkg/commands/compute/pack_test.go index 85c59c240..905cd691e 100644 --- a/pkg/commands/compute/pack_test.go +++ b/pkg/commands/compute/pack_test.go @@ -2,11 +2,13 @@ package compute_test import ( "bytes" + "io" "os" "path/filepath" "testing" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/testutil" ) @@ -81,8 +83,10 @@ func TestPack(t *testing.T) { }() var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return testutil.MockGlobalData(testcase.args, &stdout), nil + } + err = app.Run(testcase.args, nil) t.Log(stdout.String()) diff --git a/pkg/commands/compute/serve.go b/pkg/commands/compute/serve.go index 9cc9045cf..f4563a30b 100644 --- a/pkg/commands/compute/serve.go +++ b/pkg/commands/compute/serve.go @@ -71,13 +71,11 @@ type ServeCommand struct { } // NewServeCommand returns a usable command registered under the parent. -func NewServeCommand(parent cmd.Registerer, g *global.Data, build *BuildCommand, viceroyVersioner github.AssetVersioner) *ServeCommand { +func NewServeCommand(parent cmd.Registerer, g *global.Data, build *BuildCommand) *ServeCommand { var c ServeCommand - c.build = build - c.ViceroyVersioner = viceroyVersioner - c.Globals = g + c.ViceroyVersioner = g.Versioners.Viceroy c.CmdClause = parent.Command("serve", "Build and run a Compute package locally") c.CmdClause.Flag("addr", "The IPv4 address and port to listen on").Default("127.0.0.1:7676").StringVar(&c.addr) diff --git a/pkg/commands/compute/update.go b/pkg/commands/compute/update.go index 1a1226d27..99ddf21d3 100644 --- a/pkg/commands/compute/update.go +++ b/pkg/commands/compute/update.go @@ -11,7 +11,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -19,7 +18,6 @@ import ( // UpdateCommand calls the Fastly API to update packages. type UpdateCommand struct { cmd.Base - manifest manifest.Data path string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -27,18 +25,17 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a package on a Fastly Compute service version") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -63,15 +60,10 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) (err error) { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, @@ -87,7 +79,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) (err error) { packagePath := c.path if packagePath == "" { - projectName, source := c.manifest.Name() + projectName, source := c.Globals.Manifest.Name() if source == manifest.SourceUndefined { return fsterr.RemediationError{ Inner: fmt.Errorf("failed to read project name: %w", fsterr.ErrReadingManifest), diff --git a/pkg/commands/compute/update_test.go b/pkg/commands/compute/update_test.go index baedc3ba5..85c6a659f 100644 --- a/pkg/commands/compute/update_test.go +++ b/pkg/commands/compute/update_test.go @@ -3,11 +3,13 @@ package compute_test import ( "bytes" "fmt" + "io" "os" "path/filepath" "testing" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -46,7 +48,7 @@ func TestUpdate(t *testing.T) { scenarios := []testutil.TestScenario{ { Name: "package API error", - Args: args("compute update -s 123 --version 1 --package pkg/package.tar.gz -t 123 --autoclone"), + Args: args("compute update -s 123 --version 1 --package pkg/package.tar.gz --autoclone"), API: mock.API{ ListVersionsFn: testutil.ListVersions, CloneVersionFn: testutil.CloneVersionResult(4), @@ -59,7 +61,7 @@ func TestUpdate(t *testing.T) { }, { Name: "success", - Args: args("compute update -s 123 --version 2 --package pkg/package.tar.gz -t 123 --autoclone"), + Args: args("compute update -s 123 --version 2 --package pkg/package.tar.gz --autoclone"), API: mock.API{ ListVersionsFn: testutil.ListVersions, CloneVersionFn: testutil.CloneVersionResult(4), @@ -75,9 +77,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err = app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) for _, s := range testcase.WantOutputs { testutil.AssertStringContains(t, stdout.String(), s) diff --git a/pkg/commands/compute/validate_test.go b/pkg/commands/compute/validate_test.go index 386730434..152768f44 100644 --- a/pkg/commands/compute/validate_test.go +++ b/pkg/commands/compute/validate_test.go @@ -2,11 +2,13 @@ package compute_test import ( "bytes" + "io" "os" "path/filepath" "testing" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/testutil" ) @@ -53,8 +55,10 @@ func TestValidate(t *testing.T) { }() var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return testutil.MockGlobalData(testcase.Args, &stdout), nil + } + err = app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/config/config_test.go b/pkg/commands/config/config_test.go index c1d0e3054..caa14fa97 100644 --- a/pkg/commands/config/config_test.go +++ b/pkg/commands/config/config_test.go @@ -2,11 +2,13 @@ package config_test import ( "bytes" + "io" "os" "path/filepath" "testing" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -70,10 +72,13 @@ func TestConfig(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - opts.ConfigPath = configPath - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + opts.ConfigPath = configPath + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/configstore/configstore_test.go b/pkg/commands/configstore/configstore_test.go index f657fb9ac..9c47d4abe 100644 --- a/pkg/commands/configstore/configstore_test.go +++ b/pkg/commands/configstore/configstore_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "io" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/configstore" fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -74,12 +76,12 @@ func TestCreateStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -137,12 +139,12 @@ func TestDeleteStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -241,12 +243,12 @@ func TestDescribeStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -309,12 +311,12 @@ func TestListStoresCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -375,12 +377,12 @@ func TestListStoreServicesCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -446,12 +448,12 @@ func TestUpdateStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) diff --git a/pkg/commands/configstore/create.go b/pkg/commands/configstore/create.go index a4ba6d36e..c00e29052 100644 --- a/pkg/commands/configstore/create.go +++ b/pkg/commands/configstore/create.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a new config store") @@ -42,9 +40,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C type CreateCommand struct { cmd.Base cmd.JSONOutput - - input fastly.CreateConfigStoreInput - manifest manifest.Data + input fastly.CreateConfigStoreInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstore/delete.go b/pkg/commands/configstore/delete.go index af019dbe6..484ce746d 100644 --- a/pkg/commands/configstore/delete.go +++ b/pkg/commands/configstore/delete.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a config store") @@ -36,9 +34,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base cmd.JSONOutput - - input fastly.DeleteConfigStoreInput - manifest manifest.Data + input fastly.DeleteConfigStoreInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstore/describe.go b/pkg/commands/configstore/describe.go index ebb5935ab..82fa7d1bd 100644 --- a/pkg/commands/configstore/describe.go +++ b/pkg/commands/configstore/describe.go @@ -3,21 +3,20 @@ package configstore import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Retrieve a single config store").Alias("get") @@ -41,9 +40,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) type DescribeCommand struct { cmd.Base cmd.JSONOutput - input fastly.GetConfigStoreInput - manifest manifest.Data metadata bool } diff --git a/pkg/commands/configstore/list.go b/pkg/commands/configstore/list.go index 6dd3a3a48..03187f3ef 100644 --- a/pkg/commands/configstore/list.go +++ b/pkg/commands/configstore/list.go @@ -6,17 +6,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List config stores") @@ -31,8 +29,6 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis type ListCommand struct { cmd.Base cmd.JSONOutput - - manifest manifest.Data } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstore/list_services.go b/pkg/commands/configstore/list_services.go index 807b8e0cf..8031da294 100644 --- a/pkg/commands/configstore/list_services.go +++ b/pkg/commands/configstore/list_services.go @@ -3,21 +3,20 @@ package configstore import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListServicesCommand returns a usable command registered under the parent. -func NewListServicesCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListServicesCommand { +func NewListServicesCommand(parent cmd.Registerer, g *global.Data) *ListServicesCommand { c := ListServicesCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list-services", "List config store's services") @@ -35,9 +34,7 @@ func NewListServicesCommand(parent cmd.Registerer, g *global.Data, m manifest.Da type ListServicesCommand struct { cmd.Base cmd.JSONOutput - - input fastly.ListConfigStoreServicesInput - manifest manifest.Data + input fastly.ListConfigStoreServicesInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstore/update.go b/pkg/commands/configstore/update.go index 0e1409d52..bdbe5f444 100644 --- a/pkg/commands/configstore/update.go +++ b/pkg/commands/configstore/update.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a config store") @@ -43,9 +41,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U type UpdateCommand struct { cmd.Base cmd.JSONOutput - - input fastly.UpdateConfigStoreInput - manifest manifest.Data + input fastly.UpdateConfigStoreInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstoreentry/configstoreentry_test.go b/pkg/commands/configstoreentry/configstoreentry_test.go index 0d94d2337..693d1a954 100644 --- a/pkg/commands/configstoreentry/configstoreentry_test.go +++ b/pkg/commands/configstoreentry/configstoreentry_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "io" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/configstoreentry" fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" "github.com/fastly/cli/pkg/text" @@ -80,12 +82,12 @@ func TestCreateEntryCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -198,14 +200,13 @@ SUCCESS: Deleted all keys from Config Store '%s' testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) t.Log(stdout.String()) - testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -277,12 +278,12 @@ func TestDescribeEntryCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -343,12 +344,12 @@ func TestListEntriesCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -417,12 +418,12 @@ func TestUpdateEntryCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) diff --git a/pkg/commands/configstoreentry/create.go b/pkg/commands/configstoreentry/create.go index 63d890457..65ffb3967 100644 --- a/pkg/commands/configstoreentry/create.go +++ b/pkg/commands/configstoreentry/create.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a new config store item").Alias("insert") @@ -57,10 +55,8 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C type CreateCommand struct { cmd.Base cmd.JSONOutput - - input fastly.CreateConfigStoreItemInput - stdin bool - manifest manifest.Data + input fastly.CreateConfigStoreItemInput + stdin bool } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstoreentry/delete.go b/pkg/commands/configstoreentry/delete.go index 97f4b2323..dfd36cc7f 100644 --- a/pkg/commands/configstoreentry/delete.go +++ b/pkg/commands/configstoreentry/delete.go @@ -11,7 +11,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -24,12 +23,11 @@ const deleteKeysConcurrencyLimit int = 100 const batchLimit int = 100 // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a config store item") @@ -61,7 +59,6 @@ type DeleteCommand struct { concurrency cmd.OptionalInt deleteAll bool input fastly.DeleteConfigStoreItemInput - manifest manifest.Data } // Exec invokes the application logic for the command. @@ -83,7 +80,7 @@ func (c *DeleteCommand) Exec(in io.Reader, out io.Writer) error { if c.deleteAll { if !c.Globals.Flags.AutoYes && !c.Globals.Flags.NonInteractive { text.Warning(out, "This will delete ALL entries from your store!\n\n") - cont, err := text.AskYesNo(out, "Are you sure you want to continue? [yes/no]: ", in) + cont, err := text.AskYesNo(out, "Are you sure you want to continue? [y/N]: ", in) if err != nil { return err } diff --git a/pkg/commands/configstoreentry/describe.go b/pkg/commands/configstoreentry/describe.go index 6cc5a8db6..d55586b2f 100644 --- a/pkg/commands/configstoreentry/describe.go +++ b/pkg/commands/configstoreentry/describe.go @@ -3,21 +3,20 @@ package configstoreentry import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Retrieve a single config store item").Alias("get") @@ -42,9 +41,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) type DescribeCommand struct { cmd.Base cmd.JSONOutput - - input fastly.GetConfigStoreItemInput - manifest manifest.Data + input fastly.GetConfigStoreItemInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstoreentry/list.go b/pkg/commands/configstoreentry/list.go index 588ec9faf..1485ed698 100644 --- a/pkg/commands/configstoreentry/list.go +++ b/pkg/commands/configstoreentry/list.go @@ -3,21 +3,20 @@ package configstoreentry import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List config store items") @@ -35,9 +34,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis type ListCommand struct { cmd.Base cmd.JSONOutput - - input fastly.ListConfigStoreItemsInput - manifest manifest.Data + input fastly.ListConfigStoreItemsInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/configstoreentry/update.go b/pkg/commands/configstoreentry/update.go index 9ba313554..bd845e103 100644 --- a/pkg/commands/configstoreentry/update.go +++ b/pkg/commands/configstoreentry/update.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a config store item") @@ -63,10 +61,8 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U type UpdateCommand struct { cmd.Base cmd.JSONOutput - - input fastly.UpdateConfigStoreItemInput - stdin bool - manifest manifest.Data + input fastly.UpdateConfigStoreItemInput + stdin bool } // Exec invokes the application logic for the command. diff --git a/pkg/commands/dictionary/create.go b/pkg/commands/dictionary/create.go index ca098f826..7abd04191 100644 --- a/pkg/commands/dictionary/create.go +++ b/pkg/commands/dictionary/create.go @@ -8,14 +8,12 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // CreateCommand calls the Fastly API to create a service. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceVersion cmd.OptionalServiceVersion @@ -28,12 +26,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a Fastly edge dictionary on a Fastly service version") @@ -54,7 +51,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -72,7 +69,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/dictionary/delete.go b/pkg/commands/dictionary/delete.go index 04776f150..598d25f16 100644 --- a/pkg/commands/dictionary/delete.go +++ b/pkg/commands/dictionary/delete.go @@ -8,14 +8,12 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // DeleteCommand calls the Fastly API to delete a service. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteDictionaryInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -23,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Fastly edge dictionary from a Fastly service version") @@ -49,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -66,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/dictionary/describe.go b/pkg/commands/dictionary/describe.go index b6a3ca99e..dbd4a36a7 100644 --- a/pkg/commands/dictionary/describe.go +++ b/pkg/commands/dictionary/describe.go @@ -3,12 +3,12 @@ package dictionary import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a dictionary. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetDictionaryInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Fastly edge dictionary").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/dictionary/dictionary_test.go b/pkg/commands/dictionary/dictionary_test.go index a878132bc..cd54e10a3 100644 --- a/pkg/commands/dictionary/dictionary_test.go +++ b/pkg/commands/dictionary/dictionary_test.go @@ -3,12 +3,14 @@ package dictionary_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -56,9 +58,12 @@ func TestDictionaryDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -117,9 +122,12 @@ func TestDictionaryCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -161,9 +169,12 @@ func TestDeleteDictionary(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -203,9 +214,12 @@ func TestListDictionary(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -290,9 +304,12 @@ func TestUpdateDictionary(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -466,8 +483,8 @@ var ( var updateDictionaryOutputVerbose = strings.Join( []string{ - "Fastly API token not provided", "Fastly API endpoint: https://api.fastly.com", + "Fastly API token provided via config file (profile: user)", "", "Service ID (via --service-id): 123", "", @@ -511,8 +528,8 @@ Deleted (UTC): 2001-02-03 04:05 `) + "\n" var describeDictionaryOutputVerbose = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/dictionary/list.go b/pkg/commands/dictionary/list.go index 2a345df16..65cada422 100644 --- a/pkg/commands/dictionary/list.go +++ b/pkg/commands/dictionary/list.go @@ -9,7 +9,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -18,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListDictionariesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List all dictionaries on a Fastly service version") @@ -47,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +64,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/dictionary/update.go b/pkg/commands/dictionary/update.go index f7cd41dc8..5e98948b2 100644 --- a/pkg/commands/dictionary/update.go +++ b/pkg/commands/dictionary/update.go @@ -10,14 +10,13 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // UpdateCommand calls the Fastly API to update a dictionary. type UpdateCommand struct { cmd.Base - manifest manifest.Data + // TODO: make input consistent across commands (most are title case) input fastly.UpdateDictionaryInput serviceName cmd.OptionalServiceNameID @@ -29,12 +28,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update name of dictionary on a Fastly service version").Alias("get") @@ -56,7 +54,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -74,7 +72,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/dictionaryentry/create.go b/pkg/commands/dictionaryentry/create.go index 82dcefda9..2f347a8e8 100644 --- a/pkg/commands/dictionaryentry/create.go +++ b/pkg/commands/dictionaryentry/create.go @@ -7,25 +7,22 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // CreateCommand calls the Fastly API to create a dictionary item. type CreateCommand struct { cmd.Base - manifest manifest.Data Input fastly.CreateDictionaryItemInput serviceName cmd.OptionalServiceNameID } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a new item on a Fastly edge dictionary") @@ -38,7 +35,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -52,7 +49,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/dictionaryentry/delete.go b/pkg/commands/dictionaryentry/delete.go index c78886306..7220e3815 100644 --- a/pkg/commands/dictionaryentry/delete.go +++ b/pkg/commands/dictionaryentry/delete.go @@ -7,25 +7,22 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // DeleteCommand calls the Fastly API to delete a service. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteDictionaryItemInput serviceName cmd.OptionalServiceNameID } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an item from a Fastly edge dictionary") @@ -37,7 +34,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -51,7 +48,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/dictionaryentry/describe.go b/pkg/commands/dictionaryentry/describe.go index a1afa9629..5bd265194 100644 --- a/pkg/commands/dictionaryentry/describe.go +++ b/pkg/commands/dictionaryentry/describe.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a dictionary item. @@ -17,18 +17,16 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetDictionaryItemInput serviceName cmd.OptionalServiceNameID } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Fastly edge dictionary item").Alias("get") @@ -41,7 +39,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -60,7 +58,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/dictionaryentry/dictionaryitem_test.go b/pkg/commands/dictionaryentry/dictionaryitem_test.go index 9422b2a05..f2d2df4be 100644 --- a/pkg/commands/dictionaryentry/dictionaryitem_test.go +++ b/pkg/commands/dictionaryentry/dictionaryitem_test.go @@ -3,6 +3,7 @@ package dictionaryentry_test import ( "bytes" "errors" + "io" "os" "strings" "testing" @@ -10,6 +11,7 @@ import ( "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -47,9 +49,12 @@ func TestDictionaryItemDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -172,9 +177,12 @@ func TestDictionaryItemsList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -209,9 +217,12 @@ func TestDictionaryItemCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -285,9 +296,12 @@ func TestDictionaryItemUpdate(t *testing.T) { } var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -322,9 +336,12 @@ func TestDictionaryItemDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) diff --git a/pkg/commands/dictionaryentry/list.go b/pkg/commands/dictionaryentry/list.go index c07149ad1..c581d116d 100644 --- a/pkg/commands/dictionaryentry/list.go +++ b/pkg/commands/dictionaryentry/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list dictionary items. @@ -17,18 +17,16 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data input fastly.ListDictionaryItemsInput serviceName cmd.OptionalServiceNameID } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List items in a Fastly edge dictionary") @@ -43,7 +41,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -62,7 +60,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/dictionaryentry/update.go b/pkg/commands/dictionaryentry/update.go index 8a13fc06c..ee50f9ffa 100644 --- a/pkg/commands/dictionaryentry/update.go +++ b/pkg/commands/dictionaryentry/update.go @@ -10,7 +10,6 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -21,17 +20,15 @@ type UpdateCommand struct { Input fastly.UpdateDictionaryItemInput InputBatch fastly.BatchModifyDictionaryItemsInput file cmd.OptionalString - manifest manifest.Data serviceName cmd.OptionalServiceNameID } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update or insert an item on a Fastly edge dictionary") @@ -44,7 +41,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -59,7 +56,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/doc.go b/pkg/commands/doc.go new file mode 100644 index 000000000..41caccb96 --- /dev/null +++ b/pkg/commands/doc.go @@ -0,0 +1,2 @@ +// Package commands contains functions for managing exposed CLI commands. +package commands diff --git a/pkg/commands/domain/create.go b/pkg/commands/domain/create.go index 733ed81cf..9d731aab5 100644 --- a/pkg/commands/domain/create.go +++ b/pkg/commands/domain/create.go @@ -3,18 +3,17 @@ package domain import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create domains. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceVersion cmd.OptionalServiceVersion @@ -27,12 +26,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a domain on a Fastly service version").Alias("add") @@ -54,7 +52,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -71,7 +69,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/domain/delete.go b/pkg/commands/domain/delete.go index 994f6a911..b41360af8 100644 --- a/pkg/commands/domain/delete.go +++ b/pkg/commands/domain/delete.go @@ -3,18 +3,17 @@ package domain import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete domains. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteDomainInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a domain on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/domain/describe.go b/pkg/commands/domain/describe.go index 863e64b24..0bb2c4c65 100644 --- a/pkg/commands/domain/describe.go +++ b/pkg/commands/domain/describe.go @@ -4,11 +4,11 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a domain. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetDomainInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a domain on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/domain/domain_test.go b/pkg/commands/domain/domain_test.go index 00bfabe71..ea06f0e8d 100644 --- a/pkg/commands/domain/domain_test.go +++ b/pkg/commands/domain/domain_test.go @@ -4,13 +4,14 @@ import ( "bytes" "errors" "fmt" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" - fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -45,9 +46,12 @@ func TestDomainCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -110,9 +114,12 @@ func TestDomainList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -147,9 +154,12 @@ func TestDomainDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -195,9 +205,12 @@ func TestDomainUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -234,9 +247,12 @@ func TestDomainDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -251,14 +267,9 @@ func TestDomainValidate(t *testing.T) { Args: args("domain validate"), WantError: "error parsing arguments: required flag --version not provided", }, - { - Name: "validate missing --token flag", - Args: args("domain validate --version 3"), - WantError: fsterr.ErrNoToken.Inner.Error(), - }, { Name: "validate missing --service-id flag", - Args: args("domain validate --token 123 --version 3"), + Args: args("domain validate --version 3"), WantError: "error reading service: no service ID found", }, { @@ -266,7 +277,7 @@ func TestDomainValidate(t *testing.T) { API: mock.API{ ListVersionsFn: testutil.ListVersions, }, - Args: args("domain validate --service-id 123 --token 123 --version 3"), + Args: args("domain validate --service-id 123 --version 3"), WantError: "error parsing arguments: must provide --name flag", }, { @@ -277,7 +288,7 @@ func TestDomainValidate(t *testing.T) { return nil, testutil.Err }, }, - Args: args("domain validate --name foo.example.com --service-id 123 --token 123 --version 3"), + Args: args("domain validate --name foo.example.com --service-id 123 --version 3"), WantError: testutil.Err.Error(), }, { @@ -288,7 +299,7 @@ func TestDomainValidate(t *testing.T) { return nil, testutil.Err }, }, - Args: args("domain validate --all --service-id 123 --token 123 --version 3"), + Args: args("domain validate --all --service-id 123 --version 3"), WantError: testutil.Err.Error(), }, { @@ -297,7 +308,7 @@ func TestDomainValidate(t *testing.T) { ListVersionsFn: testutil.ListVersions, ValidateDomainFn: validateDomain, }, - Args: args("domain validate --name foo.example.com --service-id 123 --token 123 --version 3"), + Args: args("domain validate --name foo.example.com --service-id 123 --version 3"), WantOutput: validateAPISuccess(3), }, { @@ -306,7 +317,7 @@ func TestDomainValidate(t *testing.T) { ListVersionsFn: testutil.ListVersions, ValidateAllDomainsFn: validateAllDomains, }, - Args: args("domain validate --all --service-id 123 --token 123 --version 3"), + Args: args("domain validate --all --service-id 123 --version 3"), WantOutput: validateAllAPISuccess(), }, { @@ -315,7 +326,7 @@ func TestDomainValidate(t *testing.T) { ListVersionsFn: testutil.ListVersions, ValidateDomainFn: validateDomain, }, - Args: args("domain validate --name foo.example.com --service-id 123 --token 123 --version 1"), + Args: args("domain validate --name foo.example.com --service-id 123 --version 1"), WantOutput: validateAPISuccess(1), }, } @@ -324,9 +335,12 @@ func TestDomainValidate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -375,8 +389,8 @@ SERVICE VERSION NAME COMMENT `) + "\n" var listDomainsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/domain/list.go b/pkg/commands/domain/list.go index d2495fe6f..96044799e 100644 --- a/pkg/commands/domain/list.go +++ b/pkg/commands/domain/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list domains. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListDomainsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List domains on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/domain/update.go b/pkg/commands/domain/update.go index 9421d7afc..6530c48bc 100644 --- a/pkg/commands/domain/update.go +++ b/pkg/commands/domain/update.go @@ -4,18 +4,17 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update domains. type UpdateCommand struct { cmd.Base - manifest manifest.Data input fastly.UpdateDomainInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -26,12 +25,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a domain on a Fastly service version") @@ -54,7 +52,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -71,7 +69,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/domain/validate.go b/pkg/commands/domain/validate.go index 3ab7068df..3aaeec5c8 100644 --- a/pkg/commands/domain/validate.go +++ b/pkg/commands/domain/validate.go @@ -4,20 +4,18 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewValidateCommand returns a usable command registered under the parent. -func NewValidateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ValidateCommand { +func NewValidateCommand(parent cmd.Registerer, g *global.Data) *ValidateCommand { var c ValidateCommand c.CmdClause = parent.Command("validate", "Checks the status of a specific domain's DNS record for a Service Version") c.Globals = g - c.manifest = m // Required. c.RegisterFlag(cmd.StringFlagOpts{ @@ -33,7 +31,7 @@ func NewValidateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -51,7 +49,6 @@ type ValidateCommand struct { cmd.Base all bool - manifest manifest.Data name cmd.OptionalString serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -59,15 +56,10 @@ type ValidateCommand struct { // Exec invokes the application logic for the command. func (c *ValidateCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/healthcheck/create.go b/pkg/commands/healthcheck/create.go index e1642e076..b2bd368ca 100644 --- a/pkg/commands/healthcheck/create.go +++ b/pkg/commands/healthcheck/create.go @@ -3,18 +3,17 @@ package healthcheck import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create healthchecks. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceVersion cmd.OptionalServiceVersion @@ -37,12 +36,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a healthcheck on a Fastly service version").Alias("add") @@ -71,7 +69,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -91,7 +89,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/healthcheck/delete.go b/pkg/commands/healthcheck/delete.go index 3fd8c6624..a003c1098 100644 --- a/pkg/commands/healthcheck/delete.go +++ b/pkg/commands/healthcheck/delete.go @@ -3,18 +3,17 @@ package healthcheck import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete healthchecks. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteHealthCheckInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a healthcheck on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/healthcheck/describe.go b/pkg/commands/healthcheck/describe.go index 72222f2d9..342854e7d 100644 --- a/pkg/commands/healthcheck/describe.go +++ b/pkg/commands/healthcheck/describe.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a healthcheck. @@ -17,19 +17,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetHealthCheckInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a healthcheck on a Fastly service version").Alias("get") @@ -47,7 +45,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -68,7 +66,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/healthcheck/healthcheck_test.go b/pkg/commands/healthcheck/healthcheck_test.go index 5c38d14af..e9a4c838a 100644 --- a/pkg/commands/healthcheck/healthcheck_test.go +++ b/pkg/commands/healthcheck/healthcheck_test.go @@ -3,12 +3,14 @@ package healthcheck_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -50,9 +52,12 @@ func TestHealthCheckCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -120,9 +125,12 @@ func TestHealthCheckList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -162,9 +170,12 @@ func TestHealthCheckDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -214,9 +225,12 @@ func TestHealthCheckUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -258,9 +272,12 @@ func TestHealthCheckDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -317,8 +334,8 @@ SERVICE VERSION NAME METHOD HOST PATH `) + "\n" var listHealthChecksVerboseOutput = strings.Join([]string{ - "Fastly API token not provided", "Fastly API endpoint: https://api.fastly.com", + "Fastly API token provided via config file (profile: user)", "", "Service ID (via --service-id): 123", "", diff --git a/pkg/commands/healthcheck/list.go b/pkg/commands/healthcheck/list.go index fa910e371..5096056c4 100644 --- a/pkg/commands/healthcheck/list.go +++ b/pkg/commands/healthcheck/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list healthchecks. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListHealthChecksInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List healthchecks on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/healthcheck/update.go b/pkg/commands/healthcheck/update.go index ac7ca536e..700b77b53 100644 --- a/pkg/commands/healthcheck/update.go +++ b/pkg/commands/healthcheck/update.go @@ -3,18 +3,17 @@ package healthcheck import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update healthchecks. type UpdateCommand struct { cmd.Base - manifest manifest.Data input fastly.UpdateHealthCheckInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -35,12 +34,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a healthcheck on a Fastly service version") @@ -70,7 +68,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -90,7 +88,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/ip/ip_test.go b/pkg/commands/ip/ip_test.go index 57e4305ec..f905a6bde 100644 --- a/pkg/commands/ip/ip_test.go +++ b/pkg/commands/ip/ip_test.go @@ -2,18 +2,20 @@ package ip_test import ( "bytes" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) func TestAllIPs(t *testing.T) { var stdout bytes.Buffer - args := testutil.Args("ip-list --token 123") + args := testutil.Args("ip-list") api := mock.API{ AllIPsFn: func() (v4, v6 fastly.IPAddrs, err error) { return []string{ @@ -23,9 +25,12 @@ func TestAllIPs(t *testing.T) { }, nil }, } - opts := testutil.NewRunOpts(args, &stdout) - opts.APIClient = mock.APIClient(api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(args, &stdout) + opts.APIClientFactory = mock.APIClient(api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertNoError(t, err) testutil.AssertString(t, "\nIPv4\n\t00.123.45.6/78\n\nIPv6\n\t0a12:3b45::/67\n", stdout.String()) } diff --git a/pkg/commands/ip/root.go b/pkg/commands/ip/root.go index 979f9e377..8fb2e9200 100644 --- a/pkg/commands/ip/root.go +++ b/pkg/commands/ip/root.go @@ -5,9 +5,7 @@ import ( "io" "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" "github.com/fastly/cli/pkg/text" ) @@ -27,11 +25,6 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { // Exec implements the command interface. func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - ipv4, ipv6, err := c.Globals.APIClient.AllIPs() if err != nil { c.Globals.ErrLog.Add(err) diff --git a/pkg/commands/kvstore/create.go b/pkg/commands/kvstore/create.go index c994f5d1d..a29252239 100644 --- a/pkg/commands/kvstore/create.go +++ b/pkg/commands/kvstore/create.go @@ -8,7 +8,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -17,17 +16,15 @@ type CreateCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data - Input fastly.CreateKVStoreInput + Input fastly.CreateKVStoreInput } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create an kv store") c.CmdClause.Flag("name", "Name of KV Store").Short('n').Required().StringVar(&c.Input.Name) diff --git a/pkg/commands/kvstore/delete.go b/pkg/commands/kvstore/delete.go index a379bb254..eaff97dfc 100644 --- a/pkg/commands/kvstore/delete.go +++ b/pkg/commands/kvstore/delete.go @@ -8,7 +8,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -17,17 +16,15 @@ type DeleteCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data - Input fastly.DeleteKVStoreInput + Input fastly.DeleteKVStoreInput } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an kv store") diff --git a/pkg/commands/kvstore/describe.go b/pkg/commands/kvstore/describe.go index ad0a26249..db83b0c2d 100644 --- a/pkg/commands/kvstore/describe.go +++ b/pkg/commands/kvstore/describe.go @@ -8,7 +8,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -17,17 +16,15 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data - Input fastly.GetKVStoreInput + Input fastly.GetKVStoreInput } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Describe an kv store").Alias("get") diff --git a/pkg/commands/kvstore/kvstore_test.go b/pkg/commands/kvstore/kvstore_test.go index 2a85bc73f..966c7bf35 100644 --- a/pkg/commands/kvstore/kvstore_test.go +++ b/pkg/commands/kvstore/kvstore_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "io" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/kvstore" fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" "github.com/fastly/cli/pkg/text" @@ -75,12 +77,12 @@ func TestCreateStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -138,12 +140,12 @@ func TestDeleteStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -216,12 +218,12 @@ func TestDescribeStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -286,12 +288,12 @@ func TestListStoresCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) diff --git a/pkg/commands/kvstore/list.go b/pkg/commands/kvstore/list.go index 866be738f..e69f3cce2 100644 --- a/pkg/commands/kvstore/list.go +++ b/pkg/commands/kvstore/list.go @@ -8,7 +8,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -16,17 +15,14 @@ import ( type ListCommand struct { cmd.Base cmd.JSONOutput - - manifest manifest.Data } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List kv stores") @@ -69,7 +65,7 @@ func (c *ListCommand) Exec(in io.Reader, out io.Writer) error { // Check if 'out' is interactive before prompting. if !c.Globals.Flags.NonInteractive && !c.Globals.Flags.AutoYes && text.IsTTY(out) { text.Break(out) - printNext, err := text.AskYesNo(out, "Print next page [yes/no]: ", in) + printNext, err := text.AskYesNo(out, "Print next page [y/N]: ", in) if err != nil { return err } diff --git a/pkg/commands/kvstoreentry/create.go b/pkg/commands/kvstoreentry/create.go index f2a7c3ebb..72bdf05f8 100644 --- a/pkg/commands/kvstoreentry/create.go +++ b/pkg/commands/kvstoreentry/create.go @@ -17,18 +17,16 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/runtime" "github.com/fastly/cli/pkg/text" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Insert a key-value pair").Alias("insert") @@ -57,7 +55,6 @@ type CreateCommand struct { dirConcurrency int dirPath string filePath string - manifest manifest.Data stdin bool Input fastly.InsertKVStoreKeyInput diff --git a/pkg/commands/kvstoreentry/delete.go b/pkg/commands/kvstoreentry/delete.go index 7ddb165cc..e5dd78bde 100644 --- a/pkg/commands/kvstoreentry/delete.go +++ b/pkg/commands/kvstoreentry/delete.go @@ -12,7 +12,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -28,17 +27,15 @@ type DeleteCommand struct { concurrency cmd.OptionalInt deleteAll bool key cmd.OptionalString - manifest manifest.Data storeID string } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a key") @@ -73,7 +70,7 @@ func (c *DeleteCommand) Exec(in io.Reader, out io.Writer) error { if c.deleteAll { if !c.Globals.Flags.AutoYes && !c.Globals.Flags.NonInteractive { text.Warning(out, "This will delete ALL entries from your store!\n\n") - cont, err := text.AskYesNo(out, "Are you sure you want to continue? [yes/no]: ", in) + cont, err := text.AskYesNo(out, "Are you sure you want to continue? [y/N]: ", in) if err != nil { return err } diff --git a/pkg/commands/kvstoreentry/describe.go b/pkg/commands/kvstoreentry/describe.go index b93fb574f..087cd8167 100644 --- a/pkg/commands/kvstoreentry/describe.go +++ b/pkg/commands/kvstoreentry/describe.go @@ -9,7 +9,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -18,17 +17,15 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data - Input fastly.GetKVStoreKeyInput + Input fastly.GetKVStoreKeyInput } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Get the value associated with a key").Alias("get") diff --git a/pkg/commands/kvstoreentry/kvstoreentry_test.go b/pkg/commands/kvstoreentry/kvstoreentry_test.go index e096bd041..9225d0aaf 100644 --- a/pkg/commands/kvstoreentry/kvstoreentry_test.go +++ b/pkg/commands/kvstoreentry/kvstoreentry_test.go @@ -14,6 +14,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/kvstoreentry" fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" "github.com/fastly/cli/pkg/threadsafe" @@ -128,14 +129,15 @@ func TestCreateCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - - if testcase.Stdin != nil { - opts.Stdin = testcase.Stdin + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + if testcase.Stdin != nil { + opts.Input = testcase.Stdin + } + return opts, nil } - - err := app.Run(opts) + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) @@ -250,14 +252,13 @@ SUCCESS: Deleted all keys from KV Store '%s' testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout threadsafe.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) t.Log(stdout.String()) - testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -309,12 +310,12 @@ func TestDescribeCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -367,12 +368,12 @@ func TestListCommand(t *testing.T) { testcase := testcase t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - - opts.APIClient = mock.APIClient(testcase.API) - - err := app.Run(opts) - + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/kvstoreentry/list.go b/pkg/commands/kvstoreentry/list.go index 2cf3fd386..31f0f481e 100644 --- a/pkg/commands/kvstoreentry/list.go +++ b/pkg/commands/kvstoreentry/list.go @@ -9,7 +9,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -19,7 +18,6 @@ type ListCommand struct { cmd.JSONOutput consistency string - manifest manifest.Data Input fastly.ListKVStoreKeysInput } @@ -30,12 +28,11 @@ var ConsistencyOptions = []string{ } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List keys") diff --git a/pkg/commands/logging/azureblob/azureblob_integration_test.go b/pkg/commands/logging/azureblob/azureblob_integration_test.go index 586be3912..54a56539a 100644 --- a/pkg/commands/logging/azureblob/azureblob_integration_test.go +++ b/pkg/commands/logging/azureblob/azureblob_integration_test.go @@ -3,12 +3,14 @@ package azureblob_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -53,9 +55,12 @@ func TestBlobStorageCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -123,9 +128,12 @@ func TestBlobStorageList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -165,9 +173,12 @@ func TestBlobStorageDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -209,9 +220,12 @@ func TestBlobStorageUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -253,9 +267,12 @@ func TestBlobStorageDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -343,8 +360,8 @@ SERVICE VERSION NAME `) + "\n" var listBlobStoragesVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/azureblob/create.go b/pkg/commands/logging/azureblob/create.go index 41a9c8f6c..cee048b6a 100644 --- a/pkg/commands/logging/azureblob/create.go +++ b/pkg/commands/logging/azureblob/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an Azure Blob Storage logging endpoint. @@ -43,12 +44,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an Azure Blob Storage logging endpoint on a Fastly service version").Alias("add") @@ -83,7 +83,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -181,7 +181,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/azureblob/delete.go b/pkg/commands/logging/azureblob/delete.go index 8a92c228e..12b1cd75f 100644 --- a/pkg/commands/logging/azureblob/delete.go +++ b/pkg/commands/logging/azureblob/delete.go @@ -3,18 +3,17 @@ package azureblob import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an Azure Blob Storage logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteBlobStorageInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an Azure Blob Storage logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/azureblob/describe.go b/pkg/commands/logging/azureblob/describe.go index d37b6c60f..335f23e35 100644 --- a/pkg/commands/logging/azureblob/describe.go +++ b/pkg/commands/logging/azureblob/describe.go @@ -3,12 +3,12 @@ package azureblob import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an Azure Blob Storage logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetBlobStorageInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about an Azure Blob Storage logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/azureblob/list.go b/pkg/commands/logging/azureblob/list.go index 5f950a64d..1534fbbe1 100644 --- a/pkg/commands/logging/azureblob/list.go +++ b/pkg/commands/logging/azureblob/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Azure Blob Storage logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListBlobStoragesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Azure Blob Storage logging endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/azureblob/update.go b/pkg/commands/logging/azureblob/update.go index 5e0c6956f..51724ca36 100644 --- a/pkg/commands/logging/azureblob/update.go +++ b/pkg/commands/logging/azureblob/update.go @@ -3,13 +3,14 @@ package azureblob import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an Azure Blob Storage logging endpoint. @@ -43,12 +44,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update an Azure Blob Storage logging endpoint on a Fastly service version") @@ -86,7 +86,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -180,7 +180,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/bigquery/bigquery_integration_test.go b/pkg/commands/logging/bigquery/bigquery_integration_test.go index afffa14e7..a11cec0ac 100644 --- a/pkg/commands/logging/bigquery/bigquery_integration_test.go +++ b/pkg/commands/logging/bigquery/bigquery_integration_test.go @@ -3,12 +3,14 @@ package bigquery_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestBigQueryCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestBigQueryList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestBigQueryDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestBigQueryUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestBigQueryDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -313,8 +330,8 @@ SERVICE VERSION NAME `) + "\n" var listBigQueriesVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/bigquery/create.go b/pkg/commands/logging/bigquery/create.go index d97d082b8..c2c822793 100644 --- a/pkg/commands/logging/bigquery/create.go +++ b/pkg/commands/logging/bigquery/create.go @@ -39,12 +39,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a BigQuery logging endpoint on a Fastly service version").Alias("add") @@ -73,7 +72,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -140,7 +139,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/bigquery/delete.go b/pkg/commands/logging/bigquery/delete.go index f18a1370c..a9c20ddf2 100644 --- a/pkg/commands/logging/bigquery/delete.go +++ b/pkg/commands/logging/bigquery/delete.go @@ -3,18 +3,17 @@ package bigquery import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a BigQuery logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteBigQueryInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a BigQuery logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/bigquery/describe.go b/pkg/commands/logging/bigquery/describe.go index bdab599cd..9a08ed428 100644 --- a/pkg/commands/logging/bigquery/describe.go +++ b/pkg/commands/logging/bigquery/describe.go @@ -3,12 +3,12 @@ package bigquery import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a BigQuery logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetBigQueryInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a BigQuery logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/bigquery/list.go b/pkg/commands/logging/bigquery/list.go index 7b8b10b70..4966edd49 100644 --- a/pkg/commands/logging/bigquery/list.go +++ b/pkg/commands/logging/bigquery/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list BigQuery logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListBigQueriesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List BigQuery endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/bigquery/update.go b/pkg/commands/logging/bigquery/update.go index 570069bb3..868eb6bcd 100644 --- a/pkg/commands/logging/bigquery/update.go +++ b/pkg/commands/logging/bigquery/update.go @@ -40,12 +40,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a BigQuery logging endpoint on a Fastly service version") @@ -75,7 +74,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -143,7 +142,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/cloudfiles/cloudfiles_integration_test.go b/pkg/commands/logging/cloudfiles/cloudfiles_integration_test.go index ee022b8d4..de88f74e7 100644 --- a/pkg/commands/logging/cloudfiles/cloudfiles_integration_test.go +++ b/pkg/commands/logging/cloudfiles/cloudfiles_integration_test.go @@ -3,13 +3,16 @@ package cloudfiles_test import ( "bytes" "errors" + "io" "strings" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestCloudfilesCreate(t *testing.T) { @@ -51,9 +54,12 @@ func TestCloudfilesCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -121,9 +127,12 @@ func TestCloudfilesList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -163,9 +172,12 @@ func TestCloudfilesDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -207,9 +219,12 @@ func TestCloudfilesUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -251,9 +266,12 @@ func TestCloudfilesDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -333,8 +351,8 @@ SERVICE VERSION NAME `) + "\n" var listCloudfilesVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/cloudfiles/create.go b/pkg/commands/logging/cloudfiles/create.go index 56912c910..75e11edc7 100644 --- a/pkg/commands/logging/cloudfiles/create.go +++ b/pkg/commands/logging/cloudfiles/create.go @@ -45,12 +45,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Cloudfiles logging endpoint on a Fastly service version").Alias("add") @@ -84,7 +83,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -179,7 +178,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/cloudfiles/delete.go b/pkg/commands/logging/cloudfiles/delete.go index 417f23a75..f0c87bfde 100644 --- a/pkg/commands/logging/cloudfiles/delete.go +++ b/pkg/commands/logging/cloudfiles/delete.go @@ -3,18 +3,17 @@ package cloudfiles import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Cloudfiles logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteCloudfilesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Cloudfiles logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/cloudfiles/describe.go b/pkg/commands/logging/cloudfiles/describe.go index 8cb67b9a5..7d0b8ff13 100644 --- a/pkg/commands/logging/cloudfiles/describe.go +++ b/pkg/commands/logging/cloudfiles/describe.go @@ -3,12 +3,12 @@ package cloudfiles import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Cloudfiles logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetCloudfilesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Cloudfiles logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/cloudfiles/list.go b/pkg/commands/logging/cloudfiles/list.go index 2cca155f7..f9b9e793d 100644 --- a/pkg/commands/logging/cloudfiles/list.go +++ b/pkg/commands/logging/cloudfiles/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Cloudfiles logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListCloudfilesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Cloudfiles endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/cloudfiles/update.go b/pkg/commands/logging/cloudfiles/update.go index e547ccde5..30aeff046 100644 --- a/pkg/commands/logging/cloudfiles/update.go +++ b/pkg/commands/logging/cloudfiles/update.go @@ -44,12 +44,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Cloudfiles logging endpoint on a Fastly service version") @@ -85,7 +84,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -179,7 +178,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/datadog/create.go b/pkg/commands/logging/datadog/create.go index 781b64240..2e5c8e7ff 100644 --- a/pkg/commands/logging/datadog/create.go +++ b/pkg/commands/logging/datadog/create.go @@ -3,13 +3,14 @@ package datadog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Datadog logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Datadog logging endpoint on a Fastly service version").Alias("add") @@ -65,7 +65,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -118,7 +118,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/datadog/datadog_integration_test.go b/pkg/commands/logging/datadog/datadog_integration_test.go index 81abe9a0c..0edbdd848 100644 --- a/pkg/commands/logging/datadog/datadog_integration_test.go +++ b/pkg/commands/logging/datadog/datadog_integration_test.go @@ -3,12 +3,14 @@ package datadog_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestDatadogCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestDatadogList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestDatadogDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestDatadogUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestDatadogDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -310,8 +327,8 @@ SERVICE VERSION NAME `) + "\n" var listDatadogsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/datadog/delete.go b/pkg/commands/logging/datadog/delete.go index 29435ba77..d53570cbe 100644 --- a/pkg/commands/logging/datadog/delete.go +++ b/pkg/commands/logging/datadog/delete.go @@ -3,18 +3,17 @@ package datadog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Datadog logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteDatadogInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Datadog logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/datadog/describe.go b/pkg/commands/logging/datadog/describe.go index bf0700611..716fdbcef 100644 --- a/pkg/commands/logging/datadog/describe.go +++ b/pkg/commands/logging/datadog/describe.go @@ -3,12 +3,12 @@ package datadog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Datadog logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetDatadogInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Datadog logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/datadog/list.go b/pkg/commands/logging/datadog/list.go index 789a6045c..c32a06142 100644 --- a/pkg/commands/logging/datadog/list.go +++ b/pkg/commands/logging/datadog/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Datadog logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListDatadogInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Datadog endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/datadog/update.go b/pkg/commands/logging/datadog/update.go index 445d4ad70..631b3de2e 100644 --- a/pkg/commands/logging/datadog/update.go +++ b/pkg/commands/logging/datadog/update.go @@ -3,13 +3,14 @@ package datadog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Datadog logging endpoint. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Datadog logging endpoint on a Fastly service version") @@ -67,7 +67,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -123,7 +123,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/digitalocean/create.go b/pkg/commands/logging/digitalocean/create.go index 2d007a388..94ed0b83f 100644 --- a/pkg/commands/logging/digitalocean/create.go +++ b/pkg/commands/logging/digitalocean/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a DigitalOcean Spaces logging endpoint. @@ -43,12 +44,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a DigitalOcean Spaces logging endpoint on a Fastly service version").Alias("add") @@ -83,7 +83,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -177,7 +177,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/digitalocean/delete.go b/pkg/commands/logging/digitalocean/delete.go index 3b2f628eb..67ede2c56 100644 --- a/pkg/commands/logging/digitalocean/delete.go +++ b/pkg/commands/logging/digitalocean/delete.go @@ -3,18 +3,17 @@ package digitalocean import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a DigitalOcean Spaces logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteDigitalOceanInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a DigitalOcean Spaces logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/digitalocean/describe.go b/pkg/commands/logging/digitalocean/describe.go index 6037e9f81..b2e5d201a 100644 --- a/pkg/commands/logging/digitalocean/describe.go +++ b/pkg/commands/logging/digitalocean/describe.go @@ -3,12 +3,12 @@ package digitalocean import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a DigitalOcean Spaces logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetDigitalOceanInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a DigitalOcean Spaces logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/digitalocean/digitalocean_integration_test.go b/pkg/commands/logging/digitalocean/digitalocean_integration_test.go index 87383fd05..8cc3220ba 100644 --- a/pkg/commands/logging/digitalocean/digitalocean_integration_test.go +++ b/pkg/commands/logging/digitalocean/digitalocean_integration_test.go @@ -3,12 +3,14 @@ package digitalocean_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -52,9 +54,12 @@ func TestDigitalOceanCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -122,9 +127,12 @@ func TestDigitalOceanList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -164,9 +172,12 @@ func TestDigitalOceanDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -208,9 +219,12 @@ func TestDigitalOceanUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -252,9 +266,12 @@ func TestDigitalOceanDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -334,8 +351,8 @@ SERVICE VERSION NAME `) + "\n" var listDigitalOceansVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/digitalocean/list.go b/pkg/commands/logging/digitalocean/list.go index c7808374d..eb8e8df06 100644 --- a/pkg/commands/logging/digitalocean/list.go +++ b/pkg/commands/logging/digitalocean/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list DigitalOcean Spaces logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListDigitalOceansInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List DigitalOcean Spaces logging endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/digitalocean/update.go b/pkg/commands/logging/digitalocean/update.go index e671b4688..f55c4d18d 100644 --- a/pkg/commands/logging/digitalocean/update.go +++ b/pkg/commands/logging/digitalocean/update.go @@ -3,13 +3,14 @@ package digitalocean import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a DigitalOcean Spaces logging endpoint. @@ -43,12 +44,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a DigitalOcean Spaces logging endpoint on a Fastly service version") @@ -84,7 +84,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -178,7 +178,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/elasticsearch/create.go b/pkg/commands/logging/elasticsearch/create.go index 36dbeb140..0b570b0b3 100644 --- a/pkg/commands/logging/elasticsearch/create.go +++ b/pkg/commands/logging/elasticsearch/create.go @@ -3,13 +3,14 @@ package elasticsearch import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an Elasticsearch logging endpoint. @@ -42,12 +43,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an Elasticsearch logging endpoint on a Fastly service version").Alias("add") @@ -76,7 +76,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -169,7 +169,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/elasticsearch/delete.go b/pkg/commands/logging/elasticsearch/delete.go index bfdba2960..5dd751e25 100644 --- a/pkg/commands/logging/elasticsearch/delete.go +++ b/pkg/commands/logging/elasticsearch/delete.go @@ -3,18 +3,17 @@ package elasticsearch import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an Elasticsearch logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteElasticsearchInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an Elasticsearch logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/elasticsearch/describe.go b/pkg/commands/logging/elasticsearch/describe.go index d90ee52e3..cc72397f1 100644 --- a/pkg/commands/logging/elasticsearch/describe.go +++ b/pkg/commands/logging/elasticsearch/describe.go @@ -3,12 +3,12 @@ package elasticsearch import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an Elasticsearch logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetElasticsearchInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about an Elasticsearch logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/elasticsearch/elasticsearch_integration_test.go b/pkg/commands/logging/elasticsearch/elasticsearch_integration_test.go index 164b2b39e..690898fdd 100644 --- a/pkg/commands/logging/elasticsearch/elasticsearch_integration_test.go +++ b/pkg/commands/logging/elasticsearch/elasticsearch_integration_test.go @@ -3,12 +3,14 @@ package elasticsearch_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestElasticsearchCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestElasticsearchList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestElasticsearchDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestElasticsearchUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestElasticsearchDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -338,8 +355,8 @@ SERVICE VERSION NAME `) + "\n" var listElasticsearchsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/elasticsearch/list.go b/pkg/commands/logging/elasticsearch/list.go index a2caaec94..20af9da99 100644 --- a/pkg/commands/logging/elasticsearch/list.go +++ b/pkg/commands/logging/elasticsearch/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Elasticsearch logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListElasticsearchInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Elasticsearch endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/elasticsearch/update.go b/pkg/commands/logging/elasticsearch/update.go index bf804f303..360311590 100644 --- a/pkg/commands/logging/elasticsearch/update.go +++ b/pkg/commands/logging/elasticsearch/update.go @@ -3,13 +3,14 @@ package elasticsearch import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an Elasticsearch logging endpoint. @@ -43,12 +44,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update an Elasticsearch logging endpoint on a Fastly service version") @@ -78,7 +78,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -175,7 +175,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/ftp/create.go b/pkg/commands/logging/ftp/create.go index c9409d87d..927e2ee86 100644 --- a/pkg/commands/logging/ftp/create.go +++ b/pkg/commands/logging/ftp/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an FTP logging endpoint. @@ -41,12 +42,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an FTP logging endpoint on a Fastly service version").Alias("add") @@ -79,7 +79,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -165,7 +165,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/ftp/delete.go b/pkg/commands/logging/ftp/delete.go index b623ade23..871eb1b2d 100644 --- a/pkg/commands/logging/ftp/delete.go +++ b/pkg/commands/logging/ftp/delete.go @@ -3,18 +3,17 @@ package ftp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an FTP logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteFTPInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an FTP logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/ftp/describe.go b/pkg/commands/logging/ftp/describe.go index 7d7cd9c7f..5ddcedc0c 100644 --- a/pkg/commands/logging/ftp/describe.go +++ b/pkg/commands/logging/ftp/describe.go @@ -3,12 +3,12 @@ package ftp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an FTP logging endpoint. @@ -16,26 +16,24 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetFTPInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about an FTP logging endpoint on a Fastly service version").Alias("get") c.RegisterFlagBool(c.JSONFlag()) // --json c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -63,7 +61,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/ftp/ftp_integration_test.go b/pkg/commands/logging/ftp/ftp_integration_test.go index 97c196cca..fb3c3cde1 100644 --- a/pkg/commands/logging/ftp/ftp_integration_test.go +++ b/pkg/commands/logging/ftp/ftp_integration_test.go @@ -3,12 +3,14 @@ package ftp_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -52,9 +54,12 @@ func TestFTPCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -122,9 +127,12 @@ func TestFTPList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -164,9 +172,12 @@ func TestFTPDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -208,9 +219,12 @@ func TestFTPUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -252,9 +266,12 @@ func TestFTPDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -330,8 +347,8 @@ SERVICE VERSION NAME `) + "\n" var listFTPsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/ftp/list.go b/pkg/commands/logging/ftp/list.go index 4e0d4aa21..fe52ed62e 100644 --- a/pkg/commands/logging/ftp/list.go +++ b/pkg/commands/logging/ftp/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list FTP logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListFTPsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List FTP endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/ftp/update.go b/pkg/commands/logging/ftp/update.go index 692095bfd..a3b4e77d7 100644 --- a/pkg/commands/logging/ftp/update.go +++ b/pkg/commands/logging/ftp/update.go @@ -3,13 +3,14 @@ package ftp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an FTP logging endpoint. @@ -42,12 +43,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update an FTP logging endpoint on a Fastly service version") @@ -81,7 +81,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -172,7 +172,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/gcs/create.go b/pkg/commands/logging/gcs/create.go index 8a2c974da..51a5f31fb 100644 --- a/pkg/commands/logging/gcs/create.go +++ b/pkg/commands/logging/gcs/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a GCS logging endpoint. @@ -42,12 +43,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a GCS logging endpoint on a Fastly service version").Alias("add") @@ -80,7 +80,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -161,7 +161,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/gcs/delete.go b/pkg/commands/logging/gcs/delete.go index 6120652e6..b545ebbc1 100644 --- a/pkg/commands/logging/gcs/delete.go +++ b/pkg/commands/logging/gcs/delete.go @@ -3,18 +3,17 @@ package gcs import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a GCS logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteGCSInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a GCS logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/gcs/describe.go b/pkg/commands/logging/gcs/describe.go index d7d03c7ed..97a938fab 100644 --- a/pkg/commands/logging/gcs/describe.go +++ b/pkg/commands/logging/gcs/describe.go @@ -3,12 +3,12 @@ package gcs import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a GCS logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetGCSInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a GCS logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/gcs/gcs_integration_test.go b/pkg/commands/logging/gcs/gcs_integration_test.go index 566792684..ccac331a4 100644 --- a/pkg/commands/logging/gcs/gcs_integration_test.go +++ b/pkg/commands/logging/gcs/gcs_integration_test.go @@ -3,12 +3,14 @@ package gcs_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -52,9 +54,12 @@ func TestGCSCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -122,9 +127,12 @@ func TestGCSList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -164,9 +172,12 @@ func TestGCSDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -208,9 +219,12 @@ func TestGCSUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -252,9 +266,12 @@ func TestGCSDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -329,8 +346,8 @@ SERVICE VERSION NAME `) + "\n" var listGCSsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/gcs/list.go b/pkg/commands/logging/gcs/list.go index 12db8738d..e1b1fabc7 100644 --- a/pkg/commands/logging/gcs/list.go +++ b/pkg/commands/logging/gcs/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list GCS logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListGCSsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List GCS endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/gcs/update.go b/pkg/commands/logging/gcs/update.go index 0fd229a86..c62a04336 100644 --- a/pkg/commands/logging/gcs/update.go +++ b/pkg/commands/logging/gcs/update.go @@ -3,13 +3,14 @@ package gcs import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a GCS logging endpoint. @@ -42,12 +43,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a GCS logging endpoint on a Fastly service version") @@ -81,7 +81,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -157,7 +157,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/googlepubsub/create.go b/pkg/commands/logging/googlepubsub/create.go index 08b1bc2dc..6f90b4322 100644 --- a/pkg/commands/logging/googlepubsub/create.go +++ b/pkg/commands/logging/googlepubsub/create.go @@ -3,13 +3,14 @@ package googlepubsub import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Google Cloud Pub/Sub logging endpoint. @@ -36,12 +37,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Google Cloud Pub/Sub logging endpoint on a Fastly service version").Alias("add") @@ -69,7 +69,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -129,7 +129,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/googlepubsub/delete.go b/pkg/commands/logging/googlepubsub/delete.go index a684adf57..d2342240d 100644 --- a/pkg/commands/logging/googlepubsub/delete.go +++ b/pkg/commands/logging/googlepubsub/delete.go @@ -3,18 +3,17 @@ package googlepubsub import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Google Cloud Pub/Sub logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeletePubsubInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Google Cloud Pub/Sub logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/googlepubsub/describe.go b/pkg/commands/logging/googlepubsub/describe.go index a6d93e3bc..011e2267f 100644 --- a/pkg/commands/logging/googlepubsub/describe.go +++ b/pkg/commands/logging/googlepubsub/describe.go @@ -3,12 +3,12 @@ package googlepubsub import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Google Cloud Pub/Sub logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetPubsubInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Google Cloud Pub/Sub logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/googlepubsub/googlepubsub_integration_test.go b/pkg/commands/logging/googlepubsub/googlepubsub_integration_test.go index 7a2d2ddfb..b151699e9 100644 --- a/pkg/commands/logging/googlepubsub/googlepubsub_integration_test.go +++ b/pkg/commands/logging/googlepubsub/googlepubsub_integration_test.go @@ -3,12 +3,14 @@ package googlepubsub_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestGooglePubSubCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestGooglePubSubList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestGooglePubSubDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestGooglePubSubUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestGooglePubSubDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -320,8 +337,8 @@ SERVICE VERSION NAME `) + "\n" var listGooglePubSubsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/googlepubsub/list.go b/pkg/commands/logging/googlepubsub/list.go index ca132487d..a9ae5b661 100644 --- a/pkg/commands/logging/googlepubsub/list.go +++ b/pkg/commands/logging/googlepubsub/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Google Cloud Pub/Sub logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListPubsubsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Google Cloud Pub/Sub endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/googlepubsub/update.go b/pkg/commands/logging/googlepubsub/update.go index a9c1a5051..106ed3f7f 100644 --- a/pkg/commands/logging/googlepubsub/update.go +++ b/pkg/commands/logging/googlepubsub/update.go @@ -3,13 +3,14 @@ package googlepubsub import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Google Cloud Pub/Sub logging endpoint. @@ -37,12 +38,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Google Cloud Pub/Sub logging endpoint on a Fastly service version") @@ -71,7 +71,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -132,7 +132,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/heroku/create.go b/pkg/commands/logging/heroku/create.go index 92e485e2c..c23505289 100644 --- a/pkg/commands/logging/heroku/create.go +++ b/pkg/commands/logging/heroku/create.go @@ -3,13 +3,14 @@ package heroku import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Heroku logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Heroku logging endpoint on a Fastly service version").Alias("add") @@ -64,7 +64,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -117,7 +117,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/heroku/delete.go b/pkg/commands/logging/heroku/delete.go index 5c50640d2..0572798f8 100644 --- a/pkg/commands/logging/heroku/delete.go +++ b/pkg/commands/logging/heroku/delete.go @@ -3,18 +3,17 @@ package heroku import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Heroku logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteHerokuInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Heroku logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/heroku/describe.go b/pkg/commands/logging/heroku/describe.go index 938d72599..8c49da15b 100644 --- a/pkg/commands/logging/heroku/describe.go +++ b/pkg/commands/logging/heroku/describe.go @@ -3,12 +3,12 @@ package heroku import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Heroku logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetHerokuInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Heroku logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/heroku/heroku_integration_test.go b/pkg/commands/logging/heroku/heroku_integration_test.go index c11b44aa5..0de173704 100644 --- a/pkg/commands/logging/heroku/heroku_integration_test.go +++ b/pkg/commands/logging/heroku/heroku_integration_test.go @@ -3,13 +3,16 @@ package heroku_test import ( "bytes" "errors" + "io" "strings" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestHerokuCreate(t *testing.T) { @@ -43,9 +46,12 @@ func TestHerokuCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -113,9 +119,12 @@ func TestHerokuList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -155,9 +164,12 @@ func TestHerokuDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -199,9 +211,12 @@ func TestHerokuUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -243,9 +258,12 @@ func TestHerokuDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -309,8 +327,8 @@ SERVICE VERSION NAME `) + "\n" var listHerokusVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/heroku/list.go b/pkg/commands/logging/heroku/list.go index dd8825882..e4345164f 100644 --- a/pkg/commands/logging/heroku/list.go +++ b/pkg/commands/logging/heroku/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Heroku logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListHerokusInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Heroku endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/heroku/update.go b/pkg/commands/logging/heroku/update.go index dbe09a5d6..d46c0b406 100644 --- a/pkg/commands/logging/heroku/update.go +++ b/pkg/commands/logging/heroku/update.go @@ -3,13 +3,14 @@ package heroku import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Heroku logging endpoint. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Heroku logging endpoint on a Fastly service version") @@ -66,7 +66,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -123,7 +123,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/honeycomb/create.go b/pkg/commands/logging/honeycomb/create.go index a018b62e8..93ff7431b 100644 --- a/pkg/commands/logging/honeycomb/create.go +++ b/pkg/commands/logging/honeycomb/create.go @@ -3,13 +3,14 @@ package honeycomb import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Honeycomb logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Honeycomb logging endpoint on a Fastly service version").Alias("add") @@ -65,7 +65,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -117,7 +117,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/honeycomb/delete.go b/pkg/commands/logging/honeycomb/delete.go index 9f93b5279..9f6fe7672 100644 --- a/pkg/commands/logging/honeycomb/delete.go +++ b/pkg/commands/logging/honeycomb/delete.go @@ -3,18 +3,17 @@ package honeycomb import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Honeycomb logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteHoneycombInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Honeycomb logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/honeycomb/describe.go b/pkg/commands/logging/honeycomb/describe.go index 554fe1779..9a6b79e63 100644 --- a/pkg/commands/logging/honeycomb/describe.go +++ b/pkg/commands/logging/honeycomb/describe.go @@ -3,12 +3,12 @@ package honeycomb import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Honeycomb logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetHoneycombInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Honeycomb logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/honeycomb/honeycomb_integration_test.go b/pkg/commands/logging/honeycomb/honeycomb_integration_test.go index 36abb323a..d7ac97ff3 100644 --- a/pkg/commands/logging/honeycomb/honeycomb_integration_test.go +++ b/pkg/commands/logging/honeycomb/honeycomb_integration_test.go @@ -3,12 +3,14 @@ package honeycomb_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestHoneycombCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestHoneycombList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestHoneycombDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestHoneycombUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestHoneycombDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -310,8 +327,8 @@ SERVICE VERSION NAME `) + "\n" var listHoneycombsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/honeycomb/list.go b/pkg/commands/logging/honeycomb/list.go index 8af9bd835..508594f94 100644 --- a/pkg/commands/logging/honeycomb/list.go +++ b/pkg/commands/logging/honeycomb/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Honeycomb logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListHoneycombsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Honeycomb endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/honeycomb/update.go b/pkg/commands/logging/honeycomb/update.go index 3fe7905bd..7dd9550d8 100644 --- a/pkg/commands/logging/honeycomb/update.go +++ b/pkg/commands/logging/honeycomb/update.go @@ -3,13 +3,14 @@ package honeycomb import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Honeycomb logging endpoint. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Honeycomb logging endpoint on a Fastly service version") @@ -67,7 +67,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -123,7 +123,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/https/create.go b/pkg/commands/logging/https/create.go index fbb5c2a1f..5afb0a62d 100644 --- a/pkg/commands/logging/https/create.go +++ b/pkg/commands/logging/https/create.go @@ -3,13 +3,14 @@ package https import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an HTTPS logging endpoint. @@ -44,12 +45,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an HTTPS logging endpoint on a Fastly service version").Alias("add") @@ -82,7 +82,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -184,7 +184,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/https/delete.go b/pkg/commands/logging/https/delete.go index 8e9fcb484..052d0d7b4 100644 --- a/pkg/commands/logging/https/delete.go +++ b/pkg/commands/logging/https/delete.go @@ -3,18 +3,17 @@ package https import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an HTTPS logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteHTTPSInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an HTTPS logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/https/describe.go b/pkg/commands/logging/https/describe.go index 7b05200d5..b378fd7d6 100644 --- a/pkg/commands/logging/https/describe.go +++ b/pkg/commands/logging/https/describe.go @@ -3,12 +3,12 @@ package https import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an HTTPS logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetHTTPSInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about an HTTPS logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/https/https_integration_test.go b/pkg/commands/logging/https/https_integration_test.go index 4888307c7..960d58ede 100644 --- a/pkg/commands/logging/https/https_integration_test.go +++ b/pkg/commands/logging/https/https_integration_test.go @@ -3,12 +3,14 @@ package https_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestHTTPSCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestHTTPSList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestHTTPSDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestHTTPSUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestHTTPSDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -344,8 +361,8 @@ SERVICE VERSION NAME `) + "\n" var listHTTPSsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/https/list.go b/pkg/commands/logging/https/list.go index 8be2ca602..5af3ec9d7 100644 --- a/pkg/commands/logging/https/list.go +++ b/pkg/commands/logging/https/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list HTTPS logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListHTTPSInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List HTTPS endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/https/update.go b/pkg/commands/logging/https/update.go index bb9edbc80..1cbb5aab7 100644 --- a/pkg/commands/logging/https/update.go +++ b/pkg/commands/logging/https/update.go @@ -3,13 +3,14 @@ package https import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an HTTPS logging endpoint. @@ -45,12 +46,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update an HTTPS logging endpoint on a Fastly service version") @@ -84,7 +84,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -189,7 +189,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/kafka/create.go b/pkg/commands/logging/kafka/create.go index 6fcf2b856..f9d3a387b 100644 --- a/pkg/commands/logging/kafka/create.go +++ b/pkg/commands/logging/kafka/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Kafka logging endpoint. @@ -47,12 +48,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Kafka logging endpoint on a Fastly service version").Alias("add") @@ -84,7 +84,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -200,7 +200,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/kafka/delete.go b/pkg/commands/logging/kafka/delete.go index bdf8f0a43..a5a4d6050 100644 --- a/pkg/commands/logging/kafka/delete.go +++ b/pkg/commands/logging/kafka/delete.go @@ -3,18 +3,17 @@ package kafka import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Kafka logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteKafkaInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Kafka logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/kafka/describe.go b/pkg/commands/logging/kafka/describe.go index d61c23094..511680e05 100644 --- a/pkg/commands/logging/kafka/describe.go +++ b/pkg/commands/logging/kafka/describe.go @@ -3,12 +3,12 @@ package kafka import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Kafka logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetKafkaInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Kafka logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/kafka/kafka_integration_test.go b/pkg/commands/logging/kafka/kafka_integration_test.go index c45954360..2c2e4793e 100644 --- a/pkg/commands/logging/kafka/kafka_integration_test.go +++ b/pkg/commands/logging/kafka/kafka_integration_test.go @@ -3,13 +3,16 @@ package kafka_test import ( "bytes" "errors" + "io" "strings" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestKafkaCreate(t *testing.T) { @@ -43,9 +46,12 @@ func TestKafkaCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -113,9 +119,12 @@ func TestKafkaList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -155,9 +164,12 @@ func TestKafkaDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -208,9 +220,12 @@ func TestKafkaUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -252,9 +267,12 @@ func TestKafkaDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -314,9 +332,9 @@ func listKafkasOK(i *fastly.ListKafkasInput) ([]*fastly.Kafka, error) { FormatVersion: 2, ParseLogKeyvals: false, RequestMaxBytes: 0, - AuthMethod: "", - User: "", - Password: "", + AuthMethod: "plain", + User: "user", + Password: "password", }, { ServiceID: i.ServiceID, @@ -337,9 +355,9 @@ func listKafkasOK(i *fastly.ListKafkasInput) ([]*fastly.Kafka, error) { FormatVersion: 2, ParseLogKeyvals: false, RequestMaxBytes: 0, - AuthMethod: "", - User: "", - Password: "", + AuthMethod: "plain", + User: "user", + Password: "password", }, }, nil } @@ -355,8 +373,8 @@ SERVICE VERSION NAME `) + "\n" var listKafkasVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 @@ -380,9 +398,9 @@ Version: 1 Placement: none Parse log key-values: false Max batch size: 0 - SASL authentication method: - SASL authentication username: - SASL authentication password: + SASL authentication method: plain + SASL authentication username: user + SASL authentication password: password Kafka 2/2 Service ID: 123 Version: 1 @@ -402,10 +420,10 @@ Version: 1 Placement: none Parse log key-values: false Max batch size: 0 - SASL authentication method: - SASL authentication username: - SASL authentication password: -`) + " \n\n" + SASL authentication method: plain + SASL authentication username: user + SASL authentication password: password + `) + "\n\n" func getKafkaOK(i *fastly.GetKafkaInput) (*fastly.Kafka, error) { return &fastly.Kafka{ diff --git a/pkg/commands/logging/kafka/list.go b/pkg/commands/logging/kafka/list.go index 9b21cdffc..3c9b6c0b5 100644 --- a/pkg/commands/logging/kafka/list.go +++ b/pkg/commands/logging/kafka/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Kafka logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListKafkasInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Kafka endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/kafka/update.go b/pkg/commands/logging/kafka/update.go index 522eed61f..e703bd8e6 100644 --- a/pkg/commands/logging/kafka/update.go +++ b/pkg/commands/logging/kafka/update.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Kafka logging endpoint. @@ -49,12 +50,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Kafka logging endpoint on a Fastly service version") @@ -87,7 +87,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -213,7 +213,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/kinesis/create.go b/pkg/commands/logging/kinesis/create.go index 7e754046d..1b006ad6c 100644 --- a/pkg/commands/logging/kinesis/create.go +++ b/pkg/commands/logging/kinesis/create.go @@ -41,12 +41,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an Amazon Kinesis logging endpoint on a Fastly service version").Alias("add") @@ -78,7 +77,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -161,7 +160,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/kinesis/delete.go b/pkg/commands/logging/kinesis/delete.go index b61cc8653..1a1f44737 100644 --- a/pkg/commands/logging/kinesis/delete.go +++ b/pkg/commands/logging/kinesis/delete.go @@ -3,18 +3,17 @@ package kinesis import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an Amazon Kinesis logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteKinesisInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Kinesis logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -66,7 +64,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/kinesis/describe.go b/pkg/commands/logging/kinesis/describe.go index 4bdf3372a..fb2390410 100644 --- a/pkg/commands/logging/kinesis/describe.go +++ b/pkg/commands/logging/kinesis/describe.go @@ -3,12 +3,12 @@ package kinesis import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an Amazon Kinesis logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetKinesisInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Kinesis logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/kinesis/kinesis_integration_test.go b/pkg/commands/logging/kinesis/kinesis_integration_test.go index 4ad68dfb8..b01bcfb83 100644 --- a/pkg/commands/logging/kinesis/kinesis_integration_test.go +++ b/pkg/commands/logging/kinesis/kinesis_integration_test.go @@ -3,13 +3,16 @@ package kinesis_test import ( "bytes" "errors" + "io" "strings" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestKinesisCreate(t *testing.T) { @@ -85,9 +88,12 @@ func TestKinesisCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -155,9 +161,12 @@ func TestKinesisList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -197,9 +206,12 @@ func TestKinesisDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -241,9 +253,12 @@ func TestKinesisUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -285,9 +300,12 @@ func TestKinesisDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -304,7 +322,7 @@ func createKinesisOK(i *fastly.CreateKinesisInput) (*fastly.Kinesis, error) { }, nil } -func createKinesisError(i *fastly.CreateKinesisInput) (*fastly.Kinesis, error) { +func createKinesisError(_ *fastly.CreateKinesisInput) (*fastly.Kinesis, error) { return nil, errTest } @@ -339,7 +357,7 @@ func listKinesesOK(i *fastly.ListKinesisInput) ([]*fastly.Kinesis, error) { }, nil } -func listKinesesError(i *fastly.ListKinesisInput) ([]*fastly.Kinesis, error) { +func listKinesesError(_ *fastly.ListKinesisInput) ([]*fastly.Kinesis, error) { return nil, errTest } @@ -350,8 +368,8 @@ SERVICE VERSION NAME `) + "\n" var listKinesesVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 @@ -398,7 +416,7 @@ func getKinesisOK(i *fastly.GetKinesisInput) (*fastly.Kinesis, error) { }, nil } -func getKinesisError(i *fastly.GetKinesisInput) (*fastly.Kinesis, error) { +func getKinesisError(_ *fastly.GetKinesisInput) (*fastly.Kinesis, error) { return nil, errTest } @@ -432,14 +450,14 @@ func updateKinesisOK(i *fastly.UpdateKinesisInput) (*fastly.Kinesis, error) { }, nil } -func updateKinesisError(i *fastly.UpdateKinesisInput) (*fastly.Kinesis, error) { +func updateKinesisError(_ *fastly.UpdateKinesisInput) (*fastly.Kinesis, error) { return nil, errTest } -func deleteKinesisOK(i *fastly.DeleteKinesisInput) error { +func deleteKinesisOK(_ *fastly.DeleteKinesisInput) error { return nil } -func deleteKinesisError(i *fastly.DeleteKinesisInput) error { +func deleteKinesisError(_ *fastly.DeleteKinesisInput) error { return errTest } diff --git a/pkg/commands/logging/kinesis/list.go b/pkg/commands/logging/kinesis/list.go index a9fdf5412..b5d71a9ff 100644 --- a/pkg/commands/logging/kinesis/list.go +++ b/pkg/commands/logging/kinesis/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Amazon Kinesis logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListKinesisInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Kinesis endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/kinesis/update.go b/pkg/commands/logging/kinesis/update.go index 10515ada3..563f8bbb1 100644 --- a/pkg/commands/logging/kinesis/update.go +++ b/pkg/commands/logging/kinesis/update.go @@ -3,13 +3,14 @@ package kinesis import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an Amazon Kinesis logging endpoint. @@ -37,12 +38,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Kinesis logging endpoint on a Fastly service version") @@ -72,7 +72,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -141,7 +141,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/loggly/create.go b/pkg/commands/logging/loggly/create.go index d3808c3e8..fe457d98b 100644 --- a/pkg/commands/logging/loggly/create.go +++ b/pkg/commands/logging/loggly/create.go @@ -3,13 +3,14 @@ package loggly import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Loggly logging endpoint. @@ -32,12 +33,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Loggly logging endpoint on a Fastly service version").Alias("add") @@ -63,7 +63,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -112,7 +112,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/loggly/delete.go b/pkg/commands/logging/loggly/delete.go index 6cf69c81b..956078a5f 100644 --- a/pkg/commands/logging/loggly/delete.go +++ b/pkg/commands/logging/loggly/delete.go @@ -3,18 +3,17 @@ package loggly import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Loggly logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteLogglyInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Loggly logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/loggly/describe.go b/pkg/commands/logging/loggly/describe.go index dd1aaad4f..8567fc7a5 100644 --- a/pkg/commands/logging/loggly/describe.go +++ b/pkg/commands/logging/loggly/describe.go @@ -3,12 +3,12 @@ package loggly import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Loggly logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetLogglyInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Loggly logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/loggly/list.go b/pkg/commands/logging/loggly/list.go index a26456c63..382af5e34 100644 --- a/pkg/commands/logging/loggly/list.go +++ b/pkg/commands/logging/loggly/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Loggly logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListLogglyInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Loggly endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/loggly/loggly_integration_test.go b/pkg/commands/logging/loggly/loggly_integration_test.go index 6b12b44f8..403f61b8f 100644 --- a/pkg/commands/logging/loggly/loggly_integration_test.go +++ b/pkg/commands/logging/loggly/loggly_integration_test.go @@ -3,12 +3,14 @@ package loggly_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestLogglyCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestLogglyList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestLogglyDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestLogglyUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestLogglyDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -308,8 +325,8 @@ SERVICE VERSION NAME `) + "\n" var listLogglysVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/loggly/update.go b/pkg/commands/logging/loggly/update.go index c6d2f9e3c..3ca8fa8c6 100644 --- a/pkg/commands/logging/loggly/update.go +++ b/pkg/commands/logging/loggly/update.go @@ -3,13 +3,14 @@ package loggly import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Loggly logging endpoint. @@ -33,12 +34,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Loggly logging endpoint on a Fastly service version") @@ -65,7 +65,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -117,7 +117,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/logshuttle/create.go b/pkg/commands/logging/logshuttle/create.go index e37fdd8ef..c825f472b 100644 --- a/pkg/commands/logging/logshuttle/create.go +++ b/pkg/commands/logging/logshuttle/create.go @@ -3,13 +3,14 @@ package logshuttle import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Logshuttle logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Logshuttle logging endpoint on a Fastly service version").Alias("add") @@ -64,7 +64,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -117,7 +117,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/logshuttle/delete.go b/pkg/commands/logging/logshuttle/delete.go index 824b46807..ab434a3d7 100644 --- a/pkg/commands/logging/logshuttle/delete.go +++ b/pkg/commands/logging/logshuttle/delete.go @@ -3,18 +3,17 @@ package logshuttle import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Logshuttle logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteLogshuttleInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Logshuttle logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/logshuttle/describe.go b/pkg/commands/logging/logshuttle/describe.go index d24ee1527..aeaf3669e 100644 --- a/pkg/commands/logging/logshuttle/describe.go +++ b/pkg/commands/logging/logshuttle/describe.go @@ -3,12 +3,12 @@ package logshuttle import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Logshuttle logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetLogshuttleInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Logshuttle logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/logshuttle/list.go b/pkg/commands/logging/logshuttle/list.go index f834ddb9f..bb9db397d 100644 --- a/pkg/commands/logging/logshuttle/list.go +++ b/pkg/commands/logging/logshuttle/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Logshuttle logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListLogshuttlesInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Logshuttle endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/logshuttle/logshuttle_integration_test.go b/pkg/commands/logging/logshuttle/logshuttle_integration_test.go index 7dd2aa6b5..77984e463 100644 --- a/pkg/commands/logging/logshuttle/logshuttle_integration_test.go +++ b/pkg/commands/logging/logshuttle/logshuttle_integration_test.go @@ -3,12 +3,14 @@ package logshuttle_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestLogshuttleCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestLogshuttleList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestLogshuttleDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestLogshuttleUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestLogshuttleDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -310,8 +327,8 @@ SERVICE VERSION NAME `) + "\n" var listLogshuttlesVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/logshuttle/update.go b/pkg/commands/logging/logshuttle/update.go index 3641661f8..5578e5c50 100644 --- a/pkg/commands/logging/logshuttle/update.go +++ b/pkg/commands/logging/logshuttle/update.go @@ -3,13 +3,14 @@ package logshuttle import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Logshuttle logging endpoint. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Logshuttle logging endpoint on a Fastly service version") @@ -66,7 +66,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -124,7 +124,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/newrelic/create.go b/pkg/commands/logging/newrelic/create.go index 823e1324f..c6482ae12 100644 --- a/pkg/commands/logging/newrelic/create.go +++ b/pkg/commands/logging/newrelic/create.go @@ -3,19 +3,18 @@ package newrelic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an appropriate resource. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceName cmd.OptionalServiceNameID @@ -33,12 +32,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create an New Relic logging endpoint attached to the specified service version").Alias("add") @@ -65,7 +63,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -83,7 +81,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelic/delete.go b/pkg/commands/logging/newrelic/delete.go index f83e5b195..ad4c4115a 100644 --- a/pkg/commands/logging/newrelic/delete.go +++ b/pkg/commands/logging/newrelic/delete.go @@ -3,21 +3,20 @@ package newrelic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete the New Relic Logs logging object for a particular service and version").Alias("remove") @@ -38,7 +37,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -56,7 +55,6 @@ type DeleteCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -67,7 +65,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelic/describe.go b/pkg/commands/logging/newrelic/describe.go index 5dd422a8c..5d5bcc0d8 100644 --- a/pkg/commands/logging/newrelic/describe.go +++ b/pkg/commands/logging/newrelic/describe.go @@ -3,21 +3,20 @@ package newrelic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Get the details of a New Relic Logs logging object for a particular service and version").Alias("get") @@ -35,7 +34,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -68,7 +66,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelic/list.go b/pkg/commands/logging/newrelic/list.go index 66ddf999a..d66fe4077 100644 --- a/pkg/commands/logging/newrelic/list.go +++ b/pkg/commands/logging/newrelic/list.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List all of the New Relic Logs logging objects for a particular service and version") @@ -35,7 +34,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelic/newrelic_test.go b/pkg/commands/logging/newrelic/newrelic_test.go index 3bfcff6f8..c5e38deb9 100644 --- a/pkg/commands/logging/newrelic/newrelic_test.go +++ b/pkg/commands/logging/newrelic/newrelic_test.go @@ -2,12 +2,15 @@ package newrelic_test import ( "bytes" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestNewRelicCreate(t *testing.T) { @@ -74,9 +77,12 @@ func TestNewRelicCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -149,9 +155,12 @@ func TestNewRelicDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -211,9 +220,12 @@ func TestNewRelicDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -269,7 +281,7 @@ func TestNewRelicList(t *testing.T) { ListNewRelicFn: listNewRelic, }, Args: args("logging newrelic list --service-id 123 --verbose --version 1"), - WantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", + WantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", }, } @@ -277,9 +289,12 @@ func TestNewRelicList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -360,9 +375,12 @@ func TestNewRelicUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/logging/newrelic/update.go b/pkg/commands/logging/newrelic/update.go index ce48c0d28..6abe4e2cc 100644 --- a/pkg/commands/logging/newrelic/update.go +++ b/pkg/commands/logging/newrelic/update.go @@ -4,13 +4,13 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an appropriate resource. @@ -25,7 +25,6 @@ type UpdateCommand struct { format cmd.OptionalString formatVersion cmd.OptionalInt key cmd.OptionalString - manifest manifest.Data newName cmd.OptionalString placement cmd.OptionalString region cmd.OptionalString @@ -33,12 +32,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a New Relic Logs logging object for a particular service and version") @@ -66,7 +64,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -84,7 +82,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelicotlp/create.go b/pkg/commands/logging/newrelicotlp/create.go index cc19c9a8e..76f7bfaef 100644 --- a/pkg/commands/logging/newrelicotlp/create.go +++ b/pkg/commands/logging/newrelicotlp/create.go @@ -3,19 +3,18 @@ package newrelicotlp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an appropriate resource. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceName cmd.OptionalServiceNameID @@ -34,12 +33,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create an New Relic logging endpoint attached to the specified service version").Alias("add") @@ -67,7 +65,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -85,7 +83,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelicotlp/delete.go b/pkg/commands/logging/newrelicotlp/delete.go index c591be1fb..1867b87f3 100644 --- a/pkg/commands/logging/newrelicotlp/delete.go +++ b/pkg/commands/logging/newrelicotlp/delete.go @@ -3,21 +3,20 @@ package newrelicotlp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete the New Relic OTLP Logs logging object for a particular service and version").Alias("remove") @@ -38,7 +37,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -56,7 +55,6 @@ type DeleteCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -67,7 +65,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelicotlp/describe.go b/pkg/commands/logging/newrelicotlp/describe.go index ad16d99d5..4831ceea6 100644 --- a/pkg/commands/logging/newrelicotlp/describe.go +++ b/pkg/commands/logging/newrelicotlp/describe.go @@ -3,21 +3,20 @@ package newrelicotlp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Get the details of a New Relic OTLP Logs logging object for a particular service and version").Alias("get") @@ -35,7 +34,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -68,7 +66,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelicotlp/list.go b/pkg/commands/logging/newrelicotlp/list.go index e580b293b..205a75e2e 100644 --- a/pkg/commands/logging/newrelicotlp/list.go +++ b/pkg/commands/logging/newrelicotlp/list.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List all of the New Relic OTLP Logs logging objects for a particular service and version") @@ -35,7 +34,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/newrelicotlp/newrelicotlp_test.go b/pkg/commands/logging/newrelicotlp/newrelicotlp_test.go index 7e3b1121a..135fe50aa 100644 --- a/pkg/commands/logging/newrelicotlp/newrelicotlp_test.go +++ b/pkg/commands/logging/newrelicotlp/newrelicotlp_test.go @@ -2,12 +2,15 @@ package newrelicotlp_test import ( "bytes" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestNewRelicOTLPCreate(t *testing.T) { @@ -74,9 +77,12 @@ func TestNewRelicOTLPCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -149,9 +155,12 @@ func TestNewRelicOTLPDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -211,9 +220,12 @@ func TestNewRelicDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -269,7 +281,7 @@ func TestNewRelicList(t *testing.T) { ListNewRelicOTLPFn: listNewRelic, }, Args: args("logging newrelicotlp list --service-id 123 --verbose --version 1"), - WantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", + WantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\n\nToken: \n\nFormat: \n\nFormat Version: 0\n\nPlacement: \n\nRegion: \n\nResponse Condition: \n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", }, } @@ -277,9 +289,12 @@ func TestNewRelicList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -360,9 +375,12 @@ func TestNewRelicUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/logging/newrelicotlp/update.go b/pkg/commands/logging/newrelicotlp/update.go index f364373b7..72e09dfdf 100644 --- a/pkg/commands/logging/newrelicotlp/update.go +++ b/pkg/commands/logging/newrelicotlp/update.go @@ -4,13 +4,13 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an appropriate resource. @@ -25,7 +25,6 @@ type UpdateCommand struct { format cmd.OptionalString formatVersion cmd.OptionalInt key cmd.OptionalString - manifest manifest.Data newName cmd.OptionalString placement cmd.OptionalString region cmd.OptionalString @@ -34,12 +33,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a New Relic Logs logging object for a particular service and version") @@ -68,7 +66,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -86,7 +84,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/openstack/create.go b/pkg/commands/logging/openstack/create.go index ec7582917..3b09ac924 100644 --- a/pkg/commands/logging/openstack/create.go +++ b/pkg/commands/logging/openstack/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an OpenStack logging endpoint. @@ -43,12 +44,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an OpenStack logging endpoint on a Fastly service version").Alias("add") @@ -82,7 +82,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -176,7 +176,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/openstack/delete.go b/pkg/commands/logging/openstack/delete.go index c181d7142..2aad45bb2 100644 --- a/pkg/commands/logging/openstack/delete.go +++ b/pkg/commands/logging/openstack/delete.go @@ -3,18 +3,17 @@ package openstack import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an OpenStack logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteOpenstackInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an OpenStack logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/openstack/describe.go b/pkg/commands/logging/openstack/describe.go index ed95f271a..5f5c79d63 100644 --- a/pkg/commands/logging/openstack/describe.go +++ b/pkg/commands/logging/openstack/describe.go @@ -3,12 +3,12 @@ package openstack import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an OpenStack logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetOpenstackInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about an OpenStack logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/openstack/list.go b/pkg/commands/logging/openstack/list.go index 12f145140..f31be5e56 100644 --- a/pkg/commands/logging/openstack/list.go +++ b/pkg/commands/logging/openstack/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list OpenStack logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListOpenstackInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List OpenStack logging endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/openstack/openstack_integration_test.go b/pkg/commands/logging/openstack/openstack_integration_test.go index 06889118a..309356b44 100644 --- a/pkg/commands/logging/openstack/openstack_integration_test.go +++ b/pkg/commands/logging/openstack/openstack_integration_test.go @@ -3,12 +3,14 @@ package openstack_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -52,9 +54,12 @@ func TestOpenstackCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -122,9 +127,12 @@ func TestOpenstackList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -164,9 +172,12 @@ func TestOpenstackDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -208,9 +219,12 @@ func TestOpenstackUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -252,9 +266,12 @@ func TestOpenstackDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -336,8 +353,8 @@ SERVICE VERSION NAME `) + "\n" var listOpenstacksVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/openstack/update.go b/pkg/commands/logging/openstack/update.go index d342d314e..6e3bce1bc 100644 --- a/pkg/commands/logging/openstack/update.go +++ b/pkg/commands/logging/openstack/update.go @@ -3,13 +3,14 @@ package openstack import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an OpenStack logging endpoint. @@ -43,12 +44,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update an OpenStack logging endpoint on a Fastly service version") @@ -82,7 +82,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -179,7 +179,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/papertrail/create.go b/pkg/commands/logging/papertrail/create.go index c0c72a10a..ed54e2e53 100644 --- a/pkg/commands/logging/papertrail/create.go +++ b/pkg/commands/logging/papertrail/create.go @@ -3,13 +3,14 @@ package papertrail import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Papertrail logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Papertrail logging endpoint on a Fastly service version").Alias("add") @@ -65,7 +65,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -118,7 +118,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/papertrail/delete.go b/pkg/commands/logging/papertrail/delete.go index a6254aa8c..664905f45 100644 --- a/pkg/commands/logging/papertrail/delete.go +++ b/pkg/commands/logging/papertrail/delete.go @@ -3,18 +3,17 @@ package papertrail import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Papertrail logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeletePapertrailInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Papertrail logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/papertrail/describe.go b/pkg/commands/logging/papertrail/describe.go index 153f8d962..a9a51c12d 100644 --- a/pkg/commands/logging/papertrail/describe.go +++ b/pkg/commands/logging/papertrail/describe.go @@ -3,12 +3,12 @@ package papertrail import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Papertrail logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetPapertrailInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Papertrail logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/papertrail/list.go b/pkg/commands/logging/papertrail/list.go index 3c63dc779..67bade01e 100644 --- a/pkg/commands/logging/papertrail/list.go +++ b/pkg/commands/logging/papertrail/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Papertrail logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListPapertrailsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Papertrail endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/papertrail/papertrail_integration_test.go b/pkg/commands/logging/papertrail/papertrail_integration_test.go index 8efe1529b..11c2c772d 100644 --- a/pkg/commands/logging/papertrail/papertrail_integration_test.go +++ b/pkg/commands/logging/papertrail/papertrail_integration_test.go @@ -3,12 +3,14 @@ package papertrail_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestPapertrailCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestPapertrailList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestPapertrailDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestPapertrailUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestPapertrailDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -305,8 +322,8 @@ SERVICE VERSION NAME `) + "\n" var listPapertrailsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/papertrail/update.go b/pkg/commands/logging/papertrail/update.go index 14d30e662..2686fab7a 100644 --- a/pkg/commands/logging/papertrail/update.go +++ b/pkg/commands/logging/papertrail/update.go @@ -3,13 +3,14 @@ package papertrail import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Papertrail logging endpoint. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Papertrail logging endpoint on a Fastly service version") @@ -67,7 +67,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -128,7 +128,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/s3/create.go b/pkg/commands/logging/s3/create.go index 6d51c45a5..69fe4e953 100644 --- a/pkg/commands/logging/s3/create.go +++ b/pkg/commands/logging/s3/create.go @@ -52,12 +52,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an Amazon S3 logging endpoint on a Fastly service version").Alias("add") @@ -97,7 +96,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -266,7 +265,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/s3/delete.go b/pkg/commands/logging/s3/delete.go index d299411e8..ccfc12ea2 100644 --- a/pkg/commands/logging/s3/delete.go +++ b/pkg/commands/logging/s3/delete.go @@ -3,18 +3,17 @@ package s3 import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an Amazon S3 logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteS3Input serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a S3 logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/s3/describe.go b/pkg/commands/logging/s3/describe.go index 170175f8b..f832f02b6 100644 --- a/pkg/commands/logging/s3/describe.go +++ b/pkg/commands/logging/s3/describe.go @@ -3,12 +3,12 @@ package s3 import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an Amazon S3 logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetS3Input serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a S3 logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/s3/list.go b/pkg/commands/logging/s3/list.go index 39367bdac..85586b9a5 100644 --- a/pkg/commands/logging/s3/list.go +++ b/pkg/commands/logging/s3/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Amazon S3 logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListS3sInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List S3 endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/s3/s3_integration_test.go b/pkg/commands/logging/s3/s3_integration_test.go index 1bec4f01a..6c94092a5 100644 --- a/pkg/commands/logging/s3/s3_integration_test.go +++ b/pkg/commands/logging/s3/s3_integration_test.go @@ -3,12 +3,14 @@ package s3_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -102,9 +104,12 @@ func TestS3Create(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -172,9 +177,12 @@ func TestS3List(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -214,9 +222,12 @@ func TestS3Describe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -267,9 +278,12 @@ func TestS3Update(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -311,9 +325,12 @@ func TestS3Delete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -397,8 +414,8 @@ SERVICE VERSION NAME `) + "\n" var listS3sVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/s3/update.go b/pkg/commands/logging/s3/update.go index 991a0e10f..9c64f4d47 100644 --- a/pkg/commands/logging/s3/update.go +++ b/pkg/commands/logging/s3/update.go @@ -3,13 +3,14 @@ package s3 import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an Amazon S3 logging endpoint. @@ -49,12 +50,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a S3 logging endpoint on a Fastly service version") @@ -95,7 +95,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -216,7 +216,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/scalyr/create.go b/pkg/commands/logging/scalyr/create.go index 77d96afe4..e1e54e517 100644 --- a/pkg/commands/logging/scalyr/create.go +++ b/pkg/commands/logging/scalyr/create.go @@ -3,13 +3,14 @@ package scalyr import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Scalyr logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Scalyr logging endpoint on a Fastly service version").Alias("add") @@ -65,7 +65,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -118,7 +118,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/scalyr/delete.go b/pkg/commands/logging/scalyr/delete.go index bd1cceb1d..90178aa63 100644 --- a/pkg/commands/logging/scalyr/delete.go +++ b/pkg/commands/logging/scalyr/delete.go @@ -3,18 +3,17 @@ package scalyr import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Scalyr logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteScalyrInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Scalyr logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/scalyr/describe.go b/pkg/commands/logging/scalyr/describe.go index 2a99bfcd1..5ec914c2b 100644 --- a/pkg/commands/logging/scalyr/describe.go +++ b/pkg/commands/logging/scalyr/describe.go @@ -3,12 +3,12 @@ package scalyr import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Scalyr logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetScalyrInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Scalyr logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/scalyr/list.go b/pkg/commands/logging/scalyr/list.go index 287602c60..9d9fb274c 100644 --- a/pkg/commands/logging/scalyr/list.go +++ b/pkg/commands/logging/scalyr/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Scalyr logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListScalyrsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Scalyr endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/scalyr/scalyr_integration_test.go b/pkg/commands/logging/scalyr/scalyr_integration_test.go index 2454e83b6..df0669554 100644 --- a/pkg/commands/logging/scalyr/scalyr_integration_test.go +++ b/pkg/commands/logging/scalyr/scalyr_integration_test.go @@ -3,6 +3,7 @@ package scalyr_test import ( "bytes" "errors" + "io" "strings" "testing" @@ -10,6 +11,7 @@ import ( "github.com/fastly/cli/pkg/app" fsterrs "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -53,9 +55,12 @@ func TestScalyrCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -123,9 +128,12 @@ func TestScalyrList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -165,9 +173,12 @@ func TestScalyrDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -209,9 +220,12 @@ func TestScalyrUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -253,9 +267,12 @@ func TestScalyrDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -341,8 +358,8 @@ SERVICE VERSION NAME `) + "\n" var listScalyrsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/scalyr/update.go b/pkg/commands/logging/scalyr/update.go index 8ffc6ded5..e5b1300cb 100644 --- a/pkg/commands/logging/scalyr/update.go +++ b/pkg/commands/logging/scalyr/update.go @@ -3,13 +3,14 @@ package scalyr import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update Scalyr logging endpoints. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Scalyr logging endpoint on a Fastly service version") @@ -67,7 +67,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -123,7 +123,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/sftp/create.go b/pkg/commands/logging/sftp/create.go index 7fbdce271..1519eaae5 100644 --- a/pkg/commands/logging/sftp/create.go +++ b/pkg/commands/logging/sftp/create.go @@ -4,13 +4,14 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create an SFTP logging endpoint. @@ -45,12 +46,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create an SFTP logging endpoint on a Fastly service version").Alias("add") @@ -85,7 +85,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -189,7 +189,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/sftp/delete.go b/pkg/commands/logging/sftp/delete.go index 125162138..da6af0aea 100644 --- a/pkg/commands/logging/sftp/delete.go +++ b/pkg/commands/logging/sftp/delete.go @@ -3,18 +3,17 @@ package sftp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an SFTP logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteSFTPInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete an SFTP logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/sftp/describe.go b/pkg/commands/logging/sftp/describe.go index ad28b0aa0..086329891 100644 --- a/pkg/commands/logging/sftp/describe.go +++ b/pkg/commands/logging/sftp/describe.go @@ -3,12 +3,12 @@ package sftp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe an SFTP logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetSFTPInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about an SFTP logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/sftp/list.go b/pkg/commands/logging/sftp/list.go index 73111719c..24d6faaa0 100644 --- a/pkg/commands/logging/sftp/list.go +++ b/pkg/commands/logging/sftp/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list SFTP logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListSFTPsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List SFTP endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/sftp/sftp_integration_test.go b/pkg/commands/logging/sftp/sftp_integration_test.go index d41a9fb78..f4757fbd3 100644 --- a/pkg/commands/logging/sftp/sftp_integration_test.go +++ b/pkg/commands/logging/sftp/sftp_integration_test.go @@ -3,12 +3,14 @@ package sftp_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -52,9 +54,12 @@ func TestSFTPCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -122,9 +127,12 @@ func TestSFTPList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -164,9 +172,12 @@ func TestSFTPDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -208,9 +219,12 @@ func TestSFTPUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -252,9 +266,12 @@ func TestSFTPDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -339,8 +356,8 @@ SERVICE VERSION NAME `) + "\n" var listSFTPsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/sftp/update.go b/pkg/commands/logging/sftp/update.go index 686f26679..5d4c0c970 100644 --- a/pkg/commands/logging/sftp/update.go +++ b/pkg/commands/logging/sftp/update.go @@ -3,13 +3,14 @@ package sftp import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update an SFTP logging endpoint. @@ -45,12 +46,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update an SFTP logging endpoint on a Fastly service version") @@ -86,7 +86,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -189,7 +189,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/splunk/create.go b/pkg/commands/logging/splunk/create.go index b0bed74d6..aea271774 100644 --- a/pkg/commands/logging/splunk/create.go +++ b/pkg/commands/logging/splunk/create.go @@ -3,13 +3,14 @@ package splunk import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Splunk logging endpoint. @@ -38,12 +39,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Splunk logging endpoint on a Fastly service version").Alias("add") @@ -69,7 +69,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -143,7 +143,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/splunk/delete.go b/pkg/commands/logging/splunk/delete.go index 796c16fdc..3f8b2f3cf 100644 --- a/pkg/commands/logging/splunk/delete.go +++ b/pkg/commands/logging/splunk/delete.go @@ -3,18 +3,17 @@ package splunk import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Splunk logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteSplunkInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Splunk logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/splunk/describe.go b/pkg/commands/logging/splunk/describe.go index 1aef369e5..e99554cf4 100644 --- a/pkg/commands/logging/splunk/describe.go +++ b/pkg/commands/logging/splunk/describe.go @@ -3,12 +3,12 @@ package splunk import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Splunk logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetSplunkInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Splunk logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/splunk/list.go b/pkg/commands/logging/splunk/list.go index 81a81f7d5..a89e92f39 100644 --- a/pkg/commands/logging/splunk/list.go +++ b/pkg/commands/logging/splunk/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Splunk logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListSplunksInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Splunk endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/splunk/splunk_integration_test.go b/pkg/commands/logging/splunk/splunk_integration_test.go index 37a42f31c..e86768228 100644 --- a/pkg/commands/logging/splunk/splunk_integration_test.go +++ b/pkg/commands/logging/splunk/splunk_integration_test.go @@ -3,13 +3,16 @@ package splunk_test import ( "bytes" "errors" + "io" "strings" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestSplunkCreate(t *testing.T) { @@ -43,9 +46,12 @@ func TestSplunkCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -113,9 +119,12 @@ func TestSplunkList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -155,9 +164,12 @@ func TestSplunkDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -199,9 +211,12 @@ func TestSplunkUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -243,9 +258,12 @@ func TestSplunkDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -262,7 +280,7 @@ func createSplunkOK(i *fastly.CreateSplunkInput) (*fastly.Splunk, error) { }, nil } -func createSplunkError(i *fastly.CreateSplunkInput) (*fastly.Splunk, error) { +func createSplunkError(_ *fastly.CreateSplunkInput) (*fastly.Splunk, error) { return nil, errTest } @@ -301,7 +319,7 @@ func listSplunksOK(i *fastly.ListSplunksInput) ([]*fastly.Splunk, error) { }, nil } -func listSplunksError(i *fastly.ListSplunksInput) ([]*fastly.Splunk, error) { +func listSplunksError(_ *fastly.ListSplunksInput) ([]*fastly.Splunk, error) { return nil, errTest } @@ -312,8 +330,8 @@ SERVICE VERSION NAME `) + "\n" var listSplunksVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 @@ -366,7 +384,7 @@ func getSplunkOK(i *fastly.GetSplunkInput) (*fastly.Splunk, error) { }, nil } -func getSplunkError(i *fastly.GetSplunkInput) (*fastly.Splunk, error) { +func getSplunkError(_ *fastly.GetSplunkInput) (*fastly.Splunk, error) { return nil, errTest } @@ -404,14 +422,14 @@ func updateSplunkOK(i *fastly.UpdateSplunkInput) (*fastly.Splunk, error) { }, nil } -func updateSplunkError(i *fastly.UpdateSplunkInput) (*fastly.Splunk, error) { +func updateSplunkError(_ *fastly.UpdateSplunkInput) (*fastly.Splunk, error) { return nil, errTest } -func deleteSplunkOK(i *fastly.DeleteSplunkInput) error { +func deleteSplunkOK(_ *fastly.DeleteSplunkInput) error { return nil } -func deleteSplunkError(i *fastly.DeleteSplunkInput) error { +func deleteSplunkError(_ *fastly.DeleteSplunkInput) error { return errTest } diff --git a/pkg/commands/logging/splunk/update.go b/pkg/commands/logging/splunk/update.go index 46a4795ac..41f100bb6 100644 --- a/pkg/commands/logging/splunk/update.go +++ b/pkg/commands/logging/splunk/update.go @@ -3,13 +3,14 @@ package splunk import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Splunk logging endpoint. @@ -38,12 +39,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Splunk logging endpoint on a Fastly service version") @@ -70,7 +70,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -148,7 +148,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/sumologic/create.go b/pkg/commands/logging/sumologic/create.go index fba3c5761..6cd0d1b97 100644 --- a/pkg/commands/logging/sumologic/create.go +++ b/pkg/commands/logging/sumologic/create.go @@ -3,13 +3,14 @@ package sumologic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Sumologic logging endpoint. @@ -33,12 +34,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Sumologic logging endpoint on a Fastly service version").Alias("add") @@ -64,7 +64,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -118,7 +118,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/sumologic/delete.go b/pkg/commands/logging/sumologic/delete.go index 38aec8568..568a6f6c1 100644 --- a/pkg/commands/logging/sumologic/delete.go +++ b/pkg/commands/logging/sumologic/delete.go @@ -3,18 +3,17 @@ package sumologic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Sumologic logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteSumologicInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Sumologic logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/sumologic/describe.go b/pkg/commands/logging/sumologic/describe.go index 12cdc65e4..54432c617 100644 --- a/pkg/commands/logging/sumologic/describe.go +++ b/pkg/commands/logging/sumologic/describe.go @@ -3,12 +3,12 @@ package sumologic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Sumologic logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetSumologicInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Sumologic logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/sumologic/list.go b/pkg/commands/logging/sumologic/list.go index 4a088f9bf..8734beedd 100644 --- a/pkg/commands/logging/sumologic/list.go +++ b/pkg/commands/logging/sumologic/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Sumologic logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListSumologicsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Sumologic endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/sumologic/sumologic_integration_test.go b/pkg/commands/logging/sumologic/sumologic_integration_test.go index 70570d88f..62bf6e99c 100644 --- a/pkg/commands/logging/sumologic/sumologic_integration_test.go +++ b/pkg/commands/logging/sumologic/sumologic_integration_test.go @@ -3,12 +3,14 @@ package sumologic_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestSumologicCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestSumologicList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestSumologicDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestSumologicUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestSumologicDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -305,8 +322,8 @@ SERVICE VERSION NAME `) + "\n" var listSumologicsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/logging/sumologic/update.go b/pkg/commands/logging/sumologic/update.go index cc1fcc442..ba9937ece 100644 --- a/pkg/commands/logging/sumologic/update.go +++ b/pkg/commands/logging/sumologic/update.go @@ -3,13 +3,14 @@ package sumologic import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Sumologic logging endpoint. @@ -34,12 +35,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Sumologic logging endpoint on a Fastly service version") @@ -66,7 +66,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -124,7 +124,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/syslog/create.go b/pkg/commands/logging/syslog/create.go index e53fa93b4..8819355c5 100644 --- a/pkg/commands/logging/syslog/create.go +++ b/pkg/commands/logging/syslog/create.go @@ -3,13 +3,14 @@ package syslog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a Syslog logging endpoint. @@ -40,12 +41,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("create", "Create a Syslog logging endpoint on a Fastly service version").Alias("add") @@ -68,7 +68,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) common.Format(c.CmdClause, &c.Format) @@ -159,7 +159,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logging/syslog/delete.go b/pkg/commands/logging/syslog/delete.go index 9e7f5f143..09fbab3b5 100644 --- a/pkg/commands/logging/syslog/delete.go +++ b/pkg/commands/logging/syslog/delete.go @@ -3,18 +3,17 @@ package syslog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete a Syslog logging endpoint. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteSyslogInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Syslog logging endpoint on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -65,7 +63,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/syslog/describe.go b/pkg/commands/logging/syslog/describe.go index e6be17ad4..a96c0e2de 100644 --- a/pkg/commands/logging/syslog/describe.go +++ b/pkg/commands/logging/syslog/describe.go @@ -3,12 +3,12 @@ package syslog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a Syslog logging endpoint. @@ -16,19 +16,17 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetSyslogInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Syslog logging endpoint on a Fastly service version").Alias("get") @@ -46,7 +44,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/syslog/list.go b/pkg/commands/logging/syslog/list.go index 8df31e5e0..72e140896 100644 --- a/pkg/commands/logging/syslog/list.go +++ b/pkg/commands/logging/syslog/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list Syslog logging endpoints. @@ -17,19 +17,17 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListSyslogsInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Syslog endpoints on a Fastly service version") @@ -46,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/logging/syslog/syslog_integration_test.go b/pkg/commands/logging/syslog/syslog_integration_test.go index 51bd334f8..311a807e3 100644 --- a/pkg/commands/logging/syslog/syslog_integration_test.go +++ b/pkg/commands/logging/syslog/syslog_integration_test.go @@ -3,12 +3,14 @@ package syslog_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -44,9 +46,12 @@ func TestSyslogCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -114,9 +119,12 @@ func TestSyslogList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -156,9 +164,12 @@ func TestSyslogDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -200,9 +211,12 @@ func TestSyslogUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -244,9 +258,12 @@ func TestSyslogDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -274,7 +291,7 @@ func listSyslogsOK(i *fastly.ListSyslogsInput) ([]*fastly.Syslog, error) { ServiceVersion: i.ServiceVersion, Name: "logs", Address: "127.0.0.1", - Hostname: "", + Hostname: "127.0.0.1", Port: 514, UseTLS: false, IPV4: "127.0.0.1", @@ -297,7 +314,7 @@ func listSyslogsOK(i *fastly.ListSyslogsInput) ([]*fastly.Syslog, error) { Hostname: "example.com", Port: 789, UseTLS: true, - IPV4: "", + IPV4: "127.0.0.1", TLSCACert: "-----BEGIN CERTIFICATE-----baz", TLSHostname: "example.com", TLSClientCert: "-----BEGIN CERTIFICATE-----qux", @@ -323,8 +340,8 @@ SERVICE VERSION NAME `) + "\n" var listSyslogsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 @@ -334,7 +351,7 @@ Version: 1 Version: 1 Name: logs Address: 127.0.0.1 - Hostname: + Hostname: 127.0.0.1 Port: 514 Use TLS: false IPV4: 127.0.0.1 @@ -356,7 +373,7 @@ Version: 1 Hostname: example.com Port: 789 Use TLS: true - IPV4: + IPV4: 127.0.0.1 TLS CA certificate: -----BEGIN CERTIFICATE-----baz TLS hostname: example.com TLS client certificate: -----BEGIN CERTIFICATE-----qux diff --git a/pkg/commands/logging/syslog/update.go b/pkg/commands/logging/syslog/update.go index 5c406fa02..155a7a91d 100644 --- a/pkg/commands/logging/syslog/update.go +++ b/pkg/commands/logging/syslog/update.go @@ -3,13 +3,14 @@ package syslog import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/logging/common" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a Syslog logging endpoint. @@ -41,12 +42,11 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - Manifest: m, } c.CmdClause = parent.Command("update", "Update a Syslog logging endpoint on a Fastly service version") @@ -75,7 +75,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.Manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -166,7 +166,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.AutoClone, APIClient: c.Globals.APIClient, - Manifest: c.Manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.ServiceName, ServiceVersionFlag: c.ServiceVersion, diff --git a/pkg/commands/logtail/root.go b/pkg/commands/logtail/root.go index 542559619..98228ea71 100644 --- a/pkg/commands/logtail/root.go +++ b/pkg/commands/logtail/root.go @@ -22,7 +22,6 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -37,21 +36,19 @@ type RootCommand struct { dieCh chan struct{} // channel to end output/printing doneCh chan struct{} // channel to signal we've reached the end of the run hClient *http.Client // TODO: this will go away when GET is in go-fastly - manifest manifest.Data serviceName cmd.OptionalServiceNameID token string // TODO: this will go away when GET is in go-fastly } // NewRootCommand returns a new command registered in the parent. -func NewRootCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *RootCommand { +func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { var c RootCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("log-tail", "Tail Compute logs") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -70,7 +67,7 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Roo // Exec implements the command interface. func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } @@ -81,7 +78,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { c.Input.ServiceID = serviceID c.Input.Kind = fastly.ManagedLoggingInstanceOutput - endpoint, _ := c.Globals.Endpoint() + endpoint, _ := c.Globals.APIEndpoint() c.cfg.path = fmt.Sprintf("%s/service/%s/log_stream/managed/instance_output", endpoint, c.Input.ServiceID) c.dieCh = make(chan struct{}) diff --git a/pkg/commands/pop/pop_test.go b/pkg/commands/pop/pop_test.go index d9598dcc0..faaa3751f 100644 --- a/pkg/commands/pop/pop_test.go +++ b/pkg/commands/pop/pop_test.go @@ -2,17 +2,20 @@ package pop_test import ( "bytes" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestAllDatacenters(t *testing.T) { var stdout bytes.Buffer - args := testutil.Args("pops --token 123") + args := testutil.Args("pops") api := mock.API{ AllDatacentersFn: func() ([]fastly.Datacenter, error) { return []fastly.Datacenter{ @@ -31,9 +34,12 @@ func TestAllDatacenters(t *testing.T) { }, nil }, } - opts := testutil.NewRunOpts(args, &stdout) - opts.APIClient = mock.APIClient(api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(args, &stdout) + opts.APIClientFactory = mock.APIClient(api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertNoError(t, err) testutil.AssertString(t, "\nNAME CODE GROUP SHIELD COORDINATES\nFoobar FBR Bar Baz {Latitude:1 Longtitude:2 X:3 Y:4}\n", stdout.String()) } diff --git a/pkg/commands/pop/root.go b/pkg/commands/pop/root.go index 9e34ccc3d..f32880ecc 100644 --- a/pkg/commands/pop/root.go +++ b/pkg/commands/pop/root.go @@ -5,9 +5,7 @@ import ( "io" "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" "github.com/fastly/cli/pkg/text" ) @@ -27,11 +25,6 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { // Exec implements the command interface. func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - dcs, err := c.Globals.APIClient.AllDatacenters() if err != nil { c.Globals.ErrLog.Add(err) diff --git a/pkg/commands/products/products_test.go b/pkg/commands/products/products_test.go index 0d3a7ccbb..cb7689806 100644 --- a/pkg/commands/products/products_test.go +++ b/pkg/commands/products/products_test.go @@ -2,11 +2,13 @@ package products_test import ( "bytes" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -133,9 +135,12 @@ Web Sockets true testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/products/root.go b/pkg/commands/products/root.go index ec2b13390..052a832e5 100644 --- a/pkg/commands/products/root.go +++ b/pkg/commands/products/root.go @@ -10,7 +10,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -22,7 +21,6 @@ type RootCommand struct { disableProduct string enableProduct string - manifest manifest.Data serviceName cmd.OptionalServiceNameID } @@ -37,10 +35,9 @@ var ProductEnablementOptions = []string{ } // NewRootCommand returns a new command registered in the parent. -func NewRootCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *RootCommand { +func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { var c RootCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("products", "Enable, disable, and check the enablement status of products") // Optional. @@ -50,7 +47,7 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Roo c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -74,7 +71,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, _, _, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, _, _, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return fmt.Errorf("failed to identify Service ID: %w", err) } diff --git a/pkg/commands/profile/create.go b/pkg/commands/profile/create.go index 1685c5696..a177b8c83 100644 --- a/pkg/commands/profile/create.go +++ b/pkg/commands/profile/create.go @@ -13,6 +13,7 @@ import ( "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/cmd" + "github.com/fastly/cli/pkg/commands/sso" "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -23,44 +24,76 @@ import ( // CreateCommand represents a Kingpin command. type CreateCommand struct { cmd.Base + authCmd *sso.RootCommand automationToken bool - clientFactory APIClientFactory profile string + sso bool } // NewCreateCommand returns a new command registered in the parent. -func NewCreateCommand(parent cmd.Registerer, cf APIClientFactory, g *global.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data, authCmd *sso.RootCommand) *CreateCommand { var c CreateCommand c.Globals = g + c.authCmd = authCmd c.CmdClause = parent.Command("create", "Create user profile") - c.CmdClause.Arg("profile", "Profile to create (default 'user')").Default("user").Short('p').StringVar(&c.profile) + c.CmdClause.Arg("profile", "Profile to create (default 'user')").Default(profile.DefaultName).Short('p').StringVar(&c.profile) c.CmdClause.Flag("automation-token", "Expected input will be an 'automation token' instead of a 'user token'").BoolVar(&c.automationToken) - c.clientFactory = cf + c.CmdClause.Flag("sso", "Create an SSO-based token").Hidden().BoolVar(&c.sso) return &c } // Exec implements the command interface. func (c *CreateCommand) Exec(in io.Reader, out io.Writer) (err error) { + if c.sso && c.automationToken { + return fsterr.ErrInvalidProfileSSOCombo + } + if profile.Exist(c.profile, c.Globals.Config.Profiles) { - return fmt.Errorf("profile '%s' already exists", c.profile) + return fsterr.RemediationError{ + Inner: fmt.Errorf("profile '%s' already exists", c.profile), + Remediation: "Re-run the command and pass a different value for the 'profile' argument.", + } } + // FIXME: Put back messaging once SSO is GA. + // if !c.sso { + // text.Info(out, "When creating a profile you can either paste in a long-lived token or allow the Fastly CLI to generate a short-lived token that can be automatically refreshed. To create an SSO-based token, pass the `--sso` flag: `fastly profile create --sso`.") + // text.Break(out) + // } + // The Default status of a new profile should always be true unless there is // an existing profile already set to be the default. In the latter scenario // we should prompt the user to see if the new profile they're creating needs // to become the new default. - def := true - if profileName, _ := profile.Default(c.Globals.Config.Profiles); profileName != "" { - def, err = c.promptForDefault(in, out) + makeDefault := true + if _, p := profile.Default(c.Globals.Config.Profiles); p != nil && !c.Globals.Flags.AutoYes && !c.Globals.Flags.NonInteractive { + makeDefault, err = c.promptForDefault(in, out) if err != nil { return err } } - if err := c.tokenFlow(def, in, out); err != nil { - return err + if c.sso { + // IMPORTANT: We need to set profile fields for `sso` command. + // + // This is so the `sso` command will use this information to create + // a new 'non-default' profile. + c.authCmd.InvokedFromProfileCreate = true + c.authCmd.ProfileCreateName = c.profile + c.authCmd.ProfileDefault = makeDefault + + err = c.authCmd.Exec(in, out) + if err != nil { + return fmt.Errorf("failed to authenticate: %w", err) + } + text.Break(out) + } else { + if err := c.staticTokenFlow(makeDefault, in, out); err != nil { + return err + } } + if err := c.persistCfg(); err != nil { return err } @@ -70,15 +103,15 @@ func (c *CreateCommand) Exec(in io.Reader, out io.Writer) (err error) { return nil } -// tokenFlow initialises the token flow. -func (c *CreateCommand) tokenFlow(def bool, in io.Reader, out io.Writer) error { +// staticTokenFlow initialises the token flow for a non-OAuth token. +func (c *CreateCommand) staticTokenFlow(makeDefault bool, in io.Reader, out io.Writer) error { token, err := promptForToken(in, out, c.Globals.ErrLog) if err != nil { return err } text.Break(out) - endpoint, _ := c.Globals.Endpoint() + endpoint, _ := c.Globals.APIEndpoint() spinner, err := text.NewSpinner(out) if err != nil { @@ -96,7 +129,7 @@ func (c *CreateCommand) tokenFlow(def bool, in io.Reader, out io.Writer) error { return err } - return c.updateInMemCfg(email, token, endpoint, def, spinner) + return c.updateInMemCfg(email, token, endpoint, makeDefault, spinner) } func promptForToken(in io.Reader, out io.Writer, errLog fsterr.LogInterface) (string, error) { @@ -129,7 +162,7 @@ func (c *CreateCommand) validateToken(token, endpoint string, spinner text.Spinn t *fastly.Token ) err = spinner.Process("Validating token", func(_ *text.SpinnerWrapper) error { - client, err = c.clientFactory(token, endpoint, c.Globals.Flags.Debug) + client, err = c.Globals.APIClientFactory(token, endpoint, c.Globals.Flags.Debug) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Endpoint": endpoint, @@ -174,7 +207,7 @@ func (c *CreateCommand) validateToken(token, endpoint string, spinner text.Spinn } // updateInMemCfg persists the updated configuration data in-memory. -func (c *CreateCommand) updateInMemCfg(email, token, endpoint string, def bool, spinner text.Spinner) error { +func (c *CreateCommand) updateInMemCfg(email, token, endpoint string, makeDefault bool, spinner text.Spinner) error { return spinner.Process("Persisting configuration", func(_ *text.SpinnerWrapper) error { c.Globals.Config.Fastly.APIEndpoint = endpoint @@ -182,7 +215,7 @@ func (c *CreateCommand) updateInMemCfg(email, token, endpoint string, def bool, c.Globals.Config.Profiles = make(config.Profiles) } c.Globals.Config.Profiles[c.profile] = &config.Profile{ - Default: def, + Default: makeDefault, Email: email, Token: token, } @@ -190,7 +223,7 @@ func (c *CreateCommand) updateInMemCfg(email, token, endpoint string, def bool, // If the user wants the newly created profile to be their new default, then // we'll call SetDefault for its side effect of resetting all other profiles // to have their Default field set to false. - if def { + if makeDefault { if p, ok := profile.SetDefault(c.profile, c.Globals.Config.Profiles); ok { c.Globals.Config.Profiles = p } diff --git a/pkg/commands/profile/delete.go b/pkg/commands/profile/delete.go index f490696ce..8641b9062 100644 --- a/pkg/commands/profile/delete.go +++ b/pkg/commands/profile/delete.go @@ -34,7 +34,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { } text.Success(out, "Profile '%s' deleted", c.profile) - if p, _ := profile.Default(c.Globals.Config.Profiles); p == "" && len(c.Globals.Config.Profiles) > 0 { + if _, p := profile.Default(c.Globals.Config.Profiles); p == nil && len(c.Globals.Config.Profiles) > 0 { text.Break(out) text.Warning(out, profile.NoDefaults) } diff --git a/pkg/commands/profile/list.go b/pkg/commands/profile/list.go index 1984c991b..f522251c4 100644 --- a/pkg/commands/profile/list.go +++ b/pkg/commands/profile/list.go @@ -52,7 +52,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { } name, p := profile.Default(c.Globals.Config.Profiles) - if name == "" { + if p == nil { text.Warning(out, profile.NoDefaults) } else { text.Info(out, "Default profile highlighted in red.\n\n") diff --git a/pkg/commands/profile/profile_test.go b/pkg/commands/profile/profile_test.go index df8eef39a..3f5a6f7f1 100644 --- a/pkg/commands/profile/profile_test.go +++ b/pkg/commands/profile/profile_test.go @@ -14,6 +14,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -113,8 +114,8 @@ func TestCreate(t *testing.T) { stdout bytes.Buffer ) - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -123,7 +124,7 @@ func TestCreate(t *testing.T) { // The read of the config file only really happens in the main() // function, so for the sake of the test environment we need to construct // an in-memory representation of the config file we want to be using. - opts.ConfigFile = testcase.ConfigFile + opts.Config = testcase.ConfigFile // TODO: abstract the logic for handling interactive stdin prompts. // This same if/else block is fundamentally duplicated across test files. @@ -131,7 +132,7 @@ func TestCreate(t *testing.T) { // To handle multiple prompt input from the user we need to do some // coordination around io pipes to mimic the required user behaviour. stdin, prompt := io.Pipe() - opts.Stdin = stdin + opts.Input = stdin // Wait for user input and write it to the prompt inputc := make(chan string) @@ -146,7 +147,10 @@ func TestCreate(t *testing.T) { // Call `app.Run()` and wait for response go func() { - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) done <- true }() @@ -170,8 +174,11 @@ func TestCreate(t *testing.T) { if len(testcase.Stdin) > 0 { stdin = testcase.Stdin[0] } - opts.Stdin = strings.NewReader(stdin) - err = app.Run(opts) + opts.Input = strings.NewReader(stdin) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) } t.Log(stdout.String()) @@ -258,8 +265,8 @@ func TestDelete(t *testing.T) { stdout bytes.Buffer ) - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -268,9 +275,12 @@ func TestDelete(t *testing.T) { // The read of the config file only really happens in the main() // function, so for the sake of the test environment we need to construct // an in-memory representation of the config file we want to be using. - opts.ConfigFile = testcase.ConfigFile + opts.Config = testcase.ConfigFile - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) t.Log(stdout.String()) @@ -424,13 +434,25 @@ func TestList(t *testing.T) { Args: args("profile list --json"), WantOutput: `{ "bar": { + "access_token": "", + "access_token_created": 0, + "access_token_ttl": 0, "default": false, "email": "bar@example.com", + "refresh_token": "", + "refresh_token_created": 0, + "refresh_token_ttl": 0, "token": "456" }, "foo": { + "access_token": "", + "access_token_created": 0, + "access_token_ttl": 0, "default": false, "email": "foo@example.com", + "refresh_token": "", + "refresh_token_created": 0, + "refresh_token_ttl": 0, "token": "123" } }`, @@ -460,8 +482,8 @@ func TestList(t *testing.T) { stdout bytes.Buffer ) - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -470,9 +492,12 @@ func TestList(t *testing.T) { // The read of the config file only really happens in the main() // function, so for the sake of the test environment we need to construct // an in-memory representation of the config file we want to be using. - opts.ConfigFile = testcase.ConfigFile + opts.Config = testcase.ConfigFile - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) t.Log(stdout.String()) @@ -563,8 +588,8 @@ func TestSwitch(t *testing.T) { stdout bytes.Buffer ) - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -573,9 +598,12 @@ func TestSwitch(t *testing.T) { // The read of the config file only really happens in the main() // function, so for the sake of the test environment we need to construct // an in-memory representation of the config file we want to be using. - opts.ConfigFile = testcase.ConfigFile + opts.Config = testcase.ConfigFile - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) t.Log(stdout.String()) @@ -708,8 +736,8 @@ func TestToken(t *testing.T) { stdout bytes.Buffer ) - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -718,9 +746,12 @@ func TestToken(t *testing.T) { // The read of the config file only really happens in the main() // function, so for the sake of the test environment we need to construct // an in-memory representation of the config file we want to be using. - opts.ConfigFile = testcase.ConfigFile + opts.Config = testcase.ConfigFile - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) t.Log(stdout.String()) @@ -805,6 +836,7 @@ func TestUpdate(t *testing.T) { }, }, Stdin: []string{ + "", // we skip SSO prompt "", // we skip updating the token "y", // we set the profile to be the default }, @@ -819,8 +851,8 @@ func TestUpdate(t *testing.T) { stdout bytes.Buffer ) - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) // We override the config path so that we don't accidentally write over // our own configuration file. @@ -829,13 +861,13 @@ func TestUpdate(t *testing.T) { // The read of the config file only really happens in the main() // function, so for the sake of the test environment we need to construct // an in-memory representation of the config file we want to be using. - opts.ConfigFile = testcase.ConfigFile + opts.Config = testcase.ConfigFile if len(testcase.Stdin) > 1 { // To handle multiple prompt input from the user we need to do some // coordination around io pipes to mimic the required user behaviour. stdin, prompt := io.Pipe() - opts.Stdin = stdin + opts.Input = stdin // Wait for user input and write it to the prompt inputc := make(chan string) @@ -850,7 +882,10 @@ func TestUpdate(t *testing.T) { // Call `app.Run()` and wait for response go func() { - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) done <- true }() @@ -874,8 +909,11 @@ func TestUpdate(t *testing.T) { if len(testcase.Stdin) > 0 { stdin = testcase.Stdin[0] } - opts.Stdin = strings.NewReader(stdin) - err = app.Run(opts) + opts.Input = strings.NewReader(stdin) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) } t.Log(stdout.String()) diff --git a/pkg/commands/profile/token.go b/pkg/commands/profile/token.go index 3ab84f881..d3cbab996 100644 --- a/pkg/commands/profile/token.go +++ b/pkg/commands/profile/token.go @@ -39,7 +39,7 @@ func (c *TokenCommand) Exec(_ io.Reader, out io.Writer) (err error) { } if p != "" { - if name, p := profile.Get(p, c.Globals.Config.Profiles); name != "" { + if p := profile.Get(p, c.Globals.Config.Profiles); p != nil { text.Output(out, p.Token) return nil } @@ -51,7 +51,7 @@ func (c *TokenCommand) Exec(_ io.Reader, out io.Writer) (err error) { } // If no 'profile' arg or global --profile, then we'll use 'active' profile. - if name, p := profile.Default(c.Globals.Config.Profiles); name != "" { + if _, p := profile.Default(c.Globals.Config.Profiles); p != nil { text.Output(out, p.Token) return nil } diff --git a/pkg/commands/profile/update.go b/pkg/commands/profile/update.go index ac6cb990d..81ffe6802 100644 --- a/pkg/commands/profile/update.go +++ b/pkg/commands/profile/update.go @@ -9,6 +9,7 @@ import ( "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/cmd" + "github.com/fastly/cli/pkg/commands/sso" "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -19,138 +20,149 @@ import ( // APIClientFactory allows the profile command to regenerate the global Fastly // API client when a new token is provided, in order to validate that token. // It's a redeclaration of the app.APIClientFactory to avoid an import loop. -type APIClientFactory func(token, endpoint string, debugMode bool) (api.Interface, error) +type APIClientFactory func(token, apiEndpoint string, debugMode bool) (api.Interface, error) // UpdateCommand represents a Kingpin command. type UpdateCommand struct { cmd.Base + authCmd *sso.RootCommand automationToken bool - clientFactory APIClientFactory profile string + sso bool } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, cf APIClientFactory, g *global.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data, authCmd *sso.RootCommand) *UpdateCommand { var c UpdateCommand c.Globals = g + c.authCmd = authCmd c.CmdClause = parent.Command("update", "Update user profile") c.CmdClause.Arg("profile", "Profile to update (defaults to the currently active profile)").Short('p').StringVar(&c.profile) c.CmdClause.Flag("automation-token", "Expected input will be an 'automation token' instead of a 'user token'").BoolVar(&c.automationToken) - c.clientFactory = cf + c.CmdClause.Flag("sso", "Update profile to use an SSO-based token").Hidden().BoolVar(&c.sso) return &c } // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(in io.Reader, out io.Writer) error { + profileName, p, err := c.identifyProfile() + if err != nil { + return fmt.Errorf("failed to identify the profile to update: %w", err) + } + text.Info(out, "Profile being updated: '%s'.\n\n", profileName) + + err = c.updateToken(profileName, p, in, out) + if err != nil { + return fmt.Errorf("failed to update token: %w", err) + } + + // Set to true for --auto-yes/--non-interactive flags, otherwise prompt user. + makeDefault := true + + if !c.Globals.Flags.AutoYes && !c.Globals.Flags.NonInteractive { + text.Break(out) + makeDefault, err = text.AskYesNo(out, text.BoldYellow("Make profile the default? [y/N] "), in) + text.Break(out) + if err != nil { + return err + } + } + + if makeDefault { + err := c.setAsDefault(profileName) + if err != nil { + return fmt.Errorf("failed to update token: %w", err) + } + } + + text.Success(out, "\nProfile '%s' updated", profileName) + return nil +} + +func (c *UpdateCommand) identifyProfile() (string, *config.Profile, error) { var ( - name string - p *config.Profile + profileName string + p *config.Profile ) - if c.profile == "" { - name, p = profile.Default(c.Globals.Config.Profiles) - if name == "" { - return fsterr.RemediationError{ + // If profile argument not set and no --profile flag set, then identify the + // default profile to update. + if c.profile == "" && c.Globals.Flags.Profile == "" { + profileName, p = profile.Default(c.Globals.Config.Profiles) + if p == nil { + return "", nil, fsterr.RemediationError{ Inner: fmt.Errorf("no active profile"), Remediation: profile.NoDefaults, } } } else { - name, p = profile.Get(c.profile, c.Globals.Config.Profiles) - if name == "" { + // Otherwise, acquire the profile the user has specified. + profileName = c.profile + if c.Globals.Flags.Profile != "" { + profileName = c.Globals.Flags.Profile + } + p = profile.Get(profileName, c.Globals.Config.Profiles) + if p == nil { msg := fmt.Sprintf(profile.DoesNotExist, c.profile) - return fsterr.RemediationError{ + return "", nil, fsterr.RemediationError{ Inner: fmt.Errorf(msg), Remediation: fsterr.ProfileRemediation, } } } - text.Info(out, "Profile being updated: '%s'.\n\n", name) - - opts := []profile.EditOption{} - - token, err := text.InputSecure(out, text.Prompt("Profile token: (leave blank to skip): "), in) - if err != nil { - c.Globals.ErrLog.Add(err) - return err - } - if token != "" { - opts = append(opts, func(p *config.Profile) { - p.Token = token - }) - } - - text.Break(out) - text.Break(out) - - makeDefault, err := text.AskYesNo(out, "Make profile the default? [y/N] ", in) - if err != nil { - return err - } - opts = append(opts, func(p *config.Profile) { - p.Default = makeDefault - }) + return profileName, p, nil +} - // User didn't want to change their token value so reassign original. - if token == "" { - token = p.Token - } +func (c *UpdateCommand) updateToken(profileName string, p *config.Profile, in io.Reader, out io.Writer) error { + // FIXME: Put back messaging once SSO is GA. + // if !c.sso && !isSSOToken(p) { + // text.Info(out, "When updating a profile you can either paste in a long-lived token or allow the Fastly CLI to generate a short-lived token that can be automatically refreshed. To update this profile to use an SSO-based token, pass the `--sso` flag: `fastly profile update --sso`.\n\n") + // } - text.Break(out) + if c.sso || isSSOToken(p) { + // IMPORTANT: We need to set profile fields for `sso` command. + // + // This is so the `sso` command will use this information to update + // the specific profile. + c.authCmd.InvokedFromProfileUpdate = true + c.authCmd.ProfileUpdateName = profileName + c.authCmd.ProfileDefault = false // set to false, as later we prompt for this - spinner, err := text.NewSpinner(out) - if err != nil { - return err - } - defer func() { + // NOTE: The `sso` command already handles writing config back to disk. + // So unlike `c.staticTokenFlow` (below) we don't have to do that here. + err := c.authCmd.Exec(in, out) if err != nil { + return fmt.Errorf("failed to authenticate: %w", err) + } + text.Break(out) + } else { + if err := c.staticTokenFlow(profileName, p, in, out); err != nil { + return fmt.Errorf("failed to process the static token flow: %w", err) + } + // Write the in-memory representation back to disk. + if err := c.Globals.Config.Write(c.Globals.ConfigPath); err != nil { c.Globals.ErrLog.Add(err) + return fmt.Errorf("error saving config file: %w", err) } - }() - - endpoint, _ := c.Globals.Endpoint() - - email, err := c.validateToken(token, endpoint, spinner) - if err != nil { - return err } - opts = append(opts, func(p *config.Profile) { - p.Email = email - }) - var ok bool + return nil +} - ps, ok := profile.Edit(name, c.Globals.Config.Profiles, opts...) +func (c *UpdateCommand) setAsDefault(profileName string) error { + p, ok := profile.SetDefault(profileName, c.Globals.Config.Profiles) if !ok { - msg := fmt.Sprintf(profile.DoesNotExist, name) - return fsterr.RemediationError{ - Inner: fmt.Errorf(msg), - Remediation: fsterr.ProfileRemediation, - } + return errors.New("failed to update the profile's default field") } + c.Globals.Config.Profiles = p - if makeDefault { - // We call SetDefault for its side effect of resetting all other profiles to have - // their Default field set to false. - ps, ok = profile.SetDefault(c.profile, ps) - if !ok { - msg := fmt.Sprintf(profile.DoesNotExist, c.profile) - err := errors.New(msg) - c.Globals.ErrLog.Add(err) - return err - } - } - - c.Globals.Config.Profiles = ps - + // Write the in-memory representation back to disk. if err := c.Globals.Config.Write(c.Globals.ConfigPath); err != nil { c.Globals.ErrLog.Add(err) return fmt.Errorf("error saving config file: %w", err) } - - text.Success(out, "\nProfile '%s' updated", name) return nil } @@ -162,7 +174,7 @@ func (c *UpdateCommand) validateToken(token, endpoint string, spinner text.Spinn t *fastly.Token ) err = spinner.Process("Validating token", func(_ *text.SpinnerWrapper) error { - client, err = c.clientFactory(token, endpoint, c.Globals.Flags.Debug) + client, err = c.Globals.APIClientFactory(token, endpoint, c.Globals.Flags.Debug) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Endpoint": endpoint, @@ -205,3 +217,65 @@ func (c *UpdateCommand) validateToken(token, endpoint string, spinner text.Spinn } return user.Login, nil } + +func (c *UpdateCommand) staticTokenFlow(profileName string, p *config.Profile, in io.Reader, out io.Writer) error { + opts := []profile.EditOption{} + + token, err := text.InputSecure(out, text.BoldYellow("Profile token: (leave blank to skip): "), in) + if err != nil { + c.Globals.ErrLog.Add(err) + return err + } + + // User didn't want to change their token value so reassign original. + if token == "" { + token = p.Token + } else { + opts = append(opts, func(p *config.Profile) { + p.Token = token + }) + } + text.Break(out) + + opts = append(opts, func(p *config.Profile) { + p.Default = false // set to false, as later we prompt for this + }) + + text.Break(out) + + spinner, err := text.NewSpinner(out) + if err != nil { + return err + } + defer func() { + if err != nil { + c.Globals.ErrLog.Add(err) + } + }() + + endpoint, _ := c.Globals.APIEndpoint() + + email, err := c.validateToken(token, endpoint, spinner) + if err != nil { + return err + } + opts = append(opts, func(p *config.Profile) { + p.Email = email + }) + + ps, ok := profile.Edit(profileName, c.Globals.Config.Profiles, opts...) + if !ok { + msg := fmt.Sprintf(profile.DoesNotExist, profileName) + return fsterr.RemediationError{ + Inner: fmt.Errorf(msg), + Remediation: fsterr.ProfileRemediation, + } + } + c.Globals.Config.Profiles = ps + + return nil +} + +func isSSOToken(p *config.Profile) bool { + return p.AccessToken != "" && p.RefreshToken != "" && p.AccessTokenCreated > 0 && p.RefreshTokenCreated > 0 +} diff --git a/pkg/commands/purge/purge_test.go b/pkg/commands/purge/purge_test.go index d75f2af78..c758765e5 100644 --- a/pkg/commands/purge/purge_test.go +++ b/pkg/commands/purge/purge_test.go @@ -2,31 +2,29 @@ package purge_test import ( "bytes" + "io" "reflect" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestPurgeAll(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing token", - Args: args("purge --all"), - WantError: "no token provided", - }, { Name: "validate missing --service-id flag", - Args: args("purge --all --token 123"), + Args: args("purge --all"), WantError: "error reading service: no service ID found", }, { Name: "validate --soft flag isn't usable", - Args: args("purge --all --service-id 123 --soft --token 456"), + Args: args("purge --all --service-id 123 --soft"), WantError: "purge-all requests cannot be done in soft mode (--soft) and will always immediately invalidate all cached content associated with the service", }, { @@ -36,7 +34,7 @@ func TestPurgeAll(t *testing.T) { return nil, testutil.Err }, }, - Args: args("purge --all --service-id 123 --token 456"), + Args: args("purge --all --service-id 123"), WantError: testutil.Err.Error(), }, { @@ -48,7 +46,7 @@ func TestPurgeAll(t *testing.T) { }, nil }, }, - Args: args("purge --all --service-id 123 --token 456"), + Args: args("purge --all --service-id 123"), WantOutput: "Purge all status: ok", }, } @@ -57,9 +55,12 @@ func TestPurgeAll(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -70,14 +71,9 @@ func TestPurgeKeys(t *testing.T) { var keys []string args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing token", - Args: args("purge --file ./testdata/keys"), - WantError: "no token provided", - }, { Name: "validate missing --service-id flag", - Args: args("purge --file ./testdata/keys --token 123"), + Args: args("purge --file ./testdata/keys"), WantError: "error reading service: no service ID found", }, { @@ -87,7 +83,7 @@ func TestPurgeKeys(t *testing.T) { return nil, testutil.Err }, }, - Args: args("purge --file ./testdata/keys --service-id 123 --token 456"), + Args: args("purge --file ./testdata/keys --service-id 123"), WantError: testutil.Err.Error(), }, { @@ -104,7 +100,7 @@ func TestPurgeKeys(t *testing.T) { }, nil }, }, - Args: args("purge --file ./testdata/keys --service-id 123 --token 456"), + Args: args("purge --file ./testdata/keys --service-id 123"), WantOutput: "KEY ID\nbar 456\nbaz 789\nfoo 123\n", }, } @@ -113,9 +109,12 @@ func TestPurgeKeys(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) assertKeys(testcase.WantError, testcase.Args, keys, t) @@ -143,14 +142,9 @@ func assertKeys(wantError string, args []string, keys []string, t *testing.T) { func TestPurgeKey(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing token", - Args: args("purge --key foobar"), - WantError: "no token provided", - }, { Name: "validate missing --service-id flag", - Args: args("purge --key foobar --token 123"), + Args: args("purge --key foobar"), WantError: "error reading service: no service ID found", }, { @@ -160,7 +154,7 @@ func TestPurgeKey(t *testing.T) { return nil, testutil.Err }, }, - Args: args("purge --key foobar --service-id 123 --token 456"), + Args: args("purge --key foobar --service-id 123"), WantError: testutil.Err.Error(), }, { @@ -173,7 +167,7 @@ func TestPurgeKey(t *testing.T) { }, nil }, }, - Args: args("purge --key foobar --service-id 123 --token 456"), + Args: args("purge --key foobar --service-id 123"), WantOutput: "Purged key: foobar (soft: false). Status: ok, ID: 123", }, { @@ -186,7 +180,7 @@ func TestPurgeKey(t *testing.T) { }, nil }, }, - Args: args("purge --key foobar --service-id 123 --soft --token 456"), + Args: args("purge --key foobar --service-id 123 --soft"), WantOutput: "Purged key: foobar (soft: true). Status: ok, ID: 123", }, } @@ -195,9 +189,13 @@ func TestPurgeKey(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) + t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -207,11 +205,6 @@ func TestPurgeKey(t *testing.T) { func TestPurgeURL(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing token", - Args: args("purge --url https://example.com"), - WantError: "no token provided", - }, { Name: "validate Purge API error", API: mock.API{ @@ -219,7 +212,7 @@ func TestPurgeURL(t *testing.T) { return nil, testutil.Err }, }, - Args: args("purge --service-id 123 --token 456 --url https://example.com"), + Args: args("purge --service-id 123 --url https://example.com"), WantError: testutil.Err.Error(), }, { @@ -232,7 +225,7 @@ func TestPurgeURL(t *testing.T) { }, nil }, }, - Args: args("purge --service-id 123 --token 456 --url https://example.com"), + Args: args("purge --service-id 123 --url https://example.com"), WantOutput: "Purged URL: https://example.com (soft: false). Status: ok, ID: 123", }, { @@ -245,7 +238,7 @@ func TestPurgeURL(t *testing.T) { }, nil }, }, - Args: args("purge --service-id 123 --soft --token 456 --url https://example.com"), + Args: args("purge --service-id 123 --soft --url https://example.com"), WantOutput: "Purged URL: https://example.com (soft: true). Status: ok, ID: 123", }, } @@ -254,9 +247,12 @@ func TestPurgeURL(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/purge/root.go b/pkg/commands/purge/root.go index d6659bb71..c0ca73fd7 100644 --- a/pkg/commands/purge/root.go +++ b/pkg/commands/purge/root.go @@ -13,17 +13,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewRootCommand returns a new command registered in the parent. -func NewRootCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *RootCommand { +func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { var c RootCommand c.CmdClause = parent.Command("purge", "Invalidate objects in the Fastly cache") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("all", "Purge everything from a service").BoolVar(&c.all) @@ -32,7 +30,7 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Roo c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -55,7 +53,6 @@ type RootCommand struct { all bool file string key string - manifest manifest.Data serviceName cmd.OptionalServiceNameID soft bool url string @@ -63,12 +60,7 @@ type RootCommand struct { // Exec implements the command interface. func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } - - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/ratelimit/create.go b/pkg/commands/ratelimit/create.go index f05c0cd1c..b6cc6e672 100644 --- a/pkg/commands/ratelimit/create.go +++ b/pkg/commands/ratelimit/create.go @@ -6,13 +6,12 @@ import ( "io" "strings" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // rateLimitActionFlagOpts is a string representation of rateLimitActions @@ -43,12 +42,11 @@ var rateLimitWindowSizeFlagOpts = func() (windowSizes []string) { }() // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a rate limiter for a particular service and version").Alias("add") @@ -82,7 +80,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -108,7 +106,6 @@ type CreateCommand struct { featRevision int httpMethods string loggerType string - manifest manifest.Data name string penaltyDuration int responseContent string @@ -124,11 +121,6 @@ type CreateCommand struct { // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } - if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } @@ -143,7 +135,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/ratelimit/delete.go b/pkg/commands/ratelimit/delete.go index cd9598df9..68ed9f054 100644 --- a/pkg/commands/ratelimit/delete.go +++ b/pkg/commands/ratelimit/delete.go @@ -6,19 +6,15 @@ import ( "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, globals *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, globals *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("delete", "Delete a rate limiter by its ID").Alias("remove") c.Globals = globals - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying the rate limiter").Required().StringVar(&c.id) @@ -30,17 +26,11 @@ func NewDeleteCommand(parent cmd.Registerer, globals *global.Data, m manifest.Da type DeleteCommand struct { cmd.Base - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - input := c.constructInput() err := c.Globals.APIClient.DeleteERL(input) diff --git a/pkg/commands/ratelimit/describe.go b/pkg/commands/ratelimit/describe.go index 708ec0f16..cc648f94e 100644 --- a/pkg/commands/ratelimit/describe.go +++ b/pkg/commands/ratelimit/describe.go @@ -9,16 +9,13 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Get a rate limiter by its ID").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying the rate limiter").Required().StringVar(&c.id) @@ -34,17 +31,11 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } - if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } diff --git a/pkg/commands/ratelimit/list.go b/pkg/commands/ratelimit/list.go index 32d4431f3..c3161b180 100644 --- a/pkg/commands/ratelimit/list.go +++ b/pkg/commands/ratelimit/list.go @@ -4,21 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all rate limiters for a particular service and version") c.Globals = g - c.manifest = m // Required. c.RegisterFlag(cmd.StringFlagOpts{ @@ -33,7 +31,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -50,18 +48,12 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // Exec invokes the application logic for the command. func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } - if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } @@ -69,7 +61,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/ratelimit/ratelimit_test.go b/pkg/commands/ratelimit/ratelimit_test.go index 4b263552b..a14bbc64e 100644 --- a/pkg/commands/ratelimit/ratelimit_test.go +++ b/pkg/commands/ratelimit/ratelimit_test.go @@ -2,11 +2,13 @@ package ratelimit_test import ( "bytes" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -22,7 +24,7 @@ func TestCreate(t *testing.T) { }, ListVersionsFn: testutil.ListVersions, }, - Args: args("rate-limit create --name example --service-id 123 --token abc --version 3"), + Args: args("rate-limit create --name example --service-id 123 --version 3"), WantError: testutil.Err.Error(), }, { @@ -36,7 +38,7 @@ func TestCreate(t *testing.T) { }, ListVersionsFn: testutil.ListVersions, }, - Args: args("rate-limit create --name example --service-id 123 --token abc --version 3"), + Args: args("rate-limit create --name example --service-id 123 --version 3"), WantOutput: "Created rate limiter 'example' (123)", }, } @@ -45,9 +47,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -64,7 +69,7 @@ func TestDelete(t *testing.T) { return testutil.Err }, }, - Args: args("rate-limit delete --id 123 --token abc"), + Args: args("rate-limit delete --id 123"), WantError: testutil.Err.Error(), }, { @@ -74,7 +79,7 @@ func TestDelete(t *testing.T) { return nil }, }, - Args: args("rate-limit delete --id 123 --token abc"), + Args: args("rate-limit delete --id 123"), WantOutput: "SUCCESS: Deleted rate limiter '123'\n", }, } @@ -83,9 +88,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -102,7 +110,7 @@ func TestDescribe(t *testing.T) { return nil, testutil.Err }, }, - Args: args("rate-limit describe --id 123 --token abc"), + Args: args("rate-limit describe --id 123"), WantError: testutil.Err.Error(), }, { @@ -119,7 +127,7 @@ func TestDescribe(t *testing.T) { }, nil }, }, - Args: args("rate-limit describe --id 123 --token abc"), + Args: args("rate-limit describe --id 123"), WantOutput: "\nAction: response\nClient Key: []\nFeature Revision: 0\nHTTP Methods: []\nID: 123\nLogger Type: \nName: example\nPenalty Box Duration: 20\nResponse: \nResponse Object Name: \nRPS Limit: 10\nService ID: \nURI Dictionary Name: \nVersion: 0\nWindowSize: 60\n", }, } @@ -128,9 +136,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -148,7 +159,7 @@ func TestList(t *testing.T) { }, ListVersionsFn: testutil.ListVersions, }, - Args: args("rate-limit list --service-id 123 --token abc --version 3"), + Args: args("rate-limit list --service-id 123 --version 3"), WantError: testutil.Err.Error(), }, { @@ -168,7 +179,7 @@ func TestList(t *testing.T) { }, ListVersionsFn: testutil.ListVersions, }, - Args: args("rate-limit list --service-id 123 --token abc --version 3"), + Args: args("rate-limit list --service-id 123 --version 3"), WantOutput: "ID NAME ACTION RPS LIMIT WINDOW SIZE PENALTY BOX DURATION\n123 example response 10 60 20\n", }, } @@ -177,9 +188,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -196,7 +210,7 @@ func TestUpdate(t *testing.T) { return nil, testutil.Err }, }, - Args: args("rate-limit update --id 123 --name example --token abc"), + Args: args("rate-limit update --id 123 --name example"), WantError: testutil.Err.Error(), }, { @@ -209,7 +223,7 @@ func TestUpdate(t *testing.T) { }, nil }, }, - Args: args("rate-limit update --id 123 --name example --token abc"), + Args: args("rate-limit update --id 123 --name example"), WantOutput: "Updated rate limiter 'example' (123)", }, } @@ -218,9 +232,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/ratelimit/update.go b/pkg/commands/ratelimit/update.go index 622939393..c4a9d3b2b 100644 --- a/pkg/commands/ratelimit/update.go +++ b/pkg/commands/ratelimit/update.go @@ -11,18 +11,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a rate limiter by its ID") @@ -61,7 +58,6 @@ type UpdateCommand struct { httpMethods string id string loggerType string - manifest manifest.Data name string penaltyDuration int responseContent string @@ -75,10 +71,6 @@ type UpdateCommand struct { // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } diff --git a/pkg/commands/resourcelink/create.go b/pkg/commands/resourcelink/create.go index e30876df1..11cb0b3d9 100644 --- a/pkg/commands/resourcelink/create.go +++ b/pkg/commands/resourcelink/create.go @@ -3,12 +3,12 @@ package resourcelink import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create a resource link. @@ -18,18 +18,16 @@ type CreateCommand struct { autoClone cmd.OptionalAutoClone input fastly.CreateResourceInput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, input: fastly.CreateResourceInput{ // Kingpin requires the following to be initialized. ResourceID: new(string), @@ -58,7 +56,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C Name: cmd.FlagServiceIDName, Short: 's', Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, }) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceName, @@ -92,7 +90,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, @@ -100,7 +98,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { }) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ - "Service ID": c.manifest.Flag.ServiceID, + "Service ID": c.Globals.Manifest.Flag.ServiceID, "Service Version": fsterr.ServiceVersion(serviceVersion), }) return err diff --git a/pkg/commands/resourcelink/delete.go b/pkg/commands/resourcelink/delete.go index ec1c7a228..fee8b6c3b 100644 --- a/pkg/commands/resourcelink/delete.go +++ b/pkg/commands/resourcelink/delete.go @@ -3,12 +3,12 @@ package resourcelink import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete service resource links. @@ -18,18 +18,16 @@ type DeleteCommand struct { autoClone cmd.OptionalAutoClone input fastly.DeleteResourceInput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a resource link for a Fastly service version").Alias("remove") @@ -52,7 +50,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D Name: cmd.FlagServiceIDName, Short: 's', Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, }) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceName, @@ -80,7 +78,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, @@ -88,7 +86,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { }) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ - "Service ID": c.manifest.Flag.ServiceID, + "Service ID": c.Globals.Manifest.Flag.ServiceID, "Service Version": fsterr.ServiceVersion(serviceVersion), }) return err diff --git a/pkg/commands/resourcelink/describe.go b/pkg/commands/resourcelink/describe.go index 9c460f8c9..04871dd52 100644 --- a/pkg/commands/resourcelink/describe.go +++ b/pkg/commands/resourcelink/describe.go @@ -3,12 +3,12 @@ package resourcelink import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a service resource link. @@ -17,18 +17,16 @@ type DescribeCommand struct { cmd.JSONOutput input fastly.GetResourceInput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Fastly service resource link").Alias("get") @@ -51,7 +49,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) Name: cmd.FlagServiceIDName, Short: 's', Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, }) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceName, @@ -72,7 +70,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/resourcelink/list.go b/pkg/commands/resourcelink/list.go index c5f64ec08..46f91183d 100644 --- a/pkg/commands/resourcelink/list.go +++ b/pkg/commands/resourcelink/list.go @@ -9,7 +9,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -19,18 +18,16 @@ type ListCommand struct { cmd.JSONOutput input fastly.ListResourcesInput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List all resource links for a Fastly service version") @@ -47,7 +44,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis Name: cmd.FlagServiceIDName, Short: 's', Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, }) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceName, @@ -68,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/resourcelink/resourcelink_test.go b/pkg/commands/resourcelink/resourcelink_test.go index 6d4577410..6a046f579 100644 --- a/pkg/commands/resourcelink/resourcelink_test.go +++ b/pkg/commands/resourcelink/resourcelink_test.go @@ -3,15 +3,18 @@ package resourcelink_test import ( "bytes" "fmt" + "io" "strings" "testing" "time" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/resourcelink" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestCreateServiceResourceCommand(t *testing.T) { @@ -144,7 +147,8 @@ func TestCreateServiceResourceCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(resourcelink.RootName+" "+testcase.args), &stdout) + args := testutil.Args(resourcelink.RootName + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.CreateResourceFn var apiInvoked bool @@ -153,9 +157,11 @@ func TestCreateServiceResourceCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, strings.TrimSpace(stdout.String())) @@ -246,7 +252,8 @@ func TestDeleteServiceResourceCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(resourcelink.RootName+" "+testcase.args), &stdout) + args := testutil.Args(resourcelink.RootName + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.DeleteResourceFn var apiInvoked bool @@ -255,9 +262,11 @@ func TestDeleteServiceResourceCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, strings.TrimSpace(stdout.String())) @@ -340,7 +349,8 @@ Last edited (UTC): 2023-10-15 12:18`, testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(resourcelink.RootName+" "+testcase.args), &stdout) + args := testutil.Args(resourcelink.RootName + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.GetResourceFn var apiInvoked bool @@ -349,9 +359,11 @@ Last edited (UTC): 2023-10-15 12:18`, return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, strings.TrimSpace(stdout.String())) @@ -452,7 +464,8 @@ Resource Link 3/3 testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(resourcelink.RootName+" "+testcase.args), &stdout) + args := testutil.Args(resourcelink.RootName + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.ListResourcesFn var apiInvoked bool @@ -461,9 +474,11 @@ Resource Link 3/3 return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, strings.ReplaceAll(strings.TrimSpace(stdout.String()), "\t", " ")) @@ -587,7 +602,8 @@ func TestUpdateServiceResourceCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(resourcelink.RootName+" "+testcase.args), &stdout) + args := testutil.Args(resourcelink.RootName + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.UpdateResourceFn var apiInvoked bool @@ -596,9 +612,11 @@ func TestUpdateServiceResourceCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, strings.TrimSpace(stdout.String())) diff --git a/pkg/commands/resourcelink/update.go b/pkg/commands/resourcelink/update.go index 5c8d1fca5..c83673452 100644 --- a/pkg/commands/resourcelink/update.go +++ b/pkg/commands/resourcelink/update.go @@ -3,12 +3,12 @@ package resourcelink import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update a dictionary. @@ -18,18 +18,16 @@ type UpdateCommand struct { autoClone cmd.OptionalAutoClone input fastly.UpdateResourceInput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, input: fastly.UpdateResourceInput{ // Kingpin requires the following to be initialized. Name: new(string), @@ -63,7 +61,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U Name: cmd.FlagServiceIDName, Short: 's', Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, }) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceName, @@ -91,7 +89,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, @@ -99,7 +97,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { }) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ - "Service ID": c.manifest.Flag.ServiceID, + "Service ID": c.Globals.Manifest.Flag.ServiceID, "Service Version": fsterr.ServiceVersion(serviceVersion), }) return err diff --git a/pkg/commands/secretstore/create.go b/pkg/commands/secretstore/create.go index 05f3ac448..26b14129e 100644 --- a/pkg/commands/secretstore/create.go +++ b/pkg/commands/secretstore/create.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a new secret store") @@ -37,8 +35,7 @@ type CreateCommand struct { cmd.Base cmd.JSONOutput - Input fastly.CreateSecretStoreInput - manifest manifest.Data + Input fastly.CreateSecretStoreInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/secretstore/delete.go b/pkg/commands/secretstore/delete.go index 2982a0722..2cbe18c6d 100644 --- a/pkg/commands/secretstore/delete.go +++ b/pkg/commands/secretstore/delete.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a secret store") @@ -37,8 +35,7 @@ type DeleteCommand struct { cmd.Base cmd.JSONOutput - Input fastly.DeleteSecretStoreInput - manifest manifest.Data + Input fastly.DeleteSecretStoreInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/secretstore/describe.go b/pkg/commands/secretstore/describe.go index fab9086c9..be8cb1b5c 100644 --- a/pkg/commands/secretstore/describe.go +++ b/pkg/commands/secretstore/describe.go @@ -3,21 +3,20 @@ package secretstore import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Retrieve a single secret store").Alias("get") @@ -36,8 +35,7 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - Input fastly.GetSecretStoreInput - manifest manifest.Data + Input fastly.GetSecretStoreInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/secretstore/list.go b/pkg/commands/secretstore/list.go index 0c799c166..a89309fa4 100644 --- a/pkg/commands/secretstore/list.go +++ b/pkg/commands/secretstore/list.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List secret stores") @@ -37,8 +35,7 @@ type ListCommand struct { cmd.JSONOutput // NOTE: API returns 10 items even when --limit is set to smaller. - Input fastly.ListSecretStoresInput - manifest manifest.Data + Input fastly.ListSecretStoresInput } // Exec invokes the application logic for the command. @@ -71,7 +68,7 @@ func (c *ListCommand) Exec(in io.Reader, out io.Writer) error { if o.Meta.NextCursor != "" { text.Break(out) - printNext, err := text.AskYesNo(out, "Print next page [yes/no]: ", in) + printNext, err := text.AskYesNo(out, "Print next page [y/N]: ", in) if err != nil { return err } diff --git a/pkg/commands/secretstore/secretstore_test.go b/pkg/commands/secretstore/secretstore_test.go index 7a0dca56b..0308d2c56 100644 --- a/pkg/commands/secretstore/secretstore_test.go +++ b/pkg/commands/secretstore/secretstore_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "io" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/secretstore" fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -77,7 +79,8 @@ func TestCreateStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstore.RootNameStore+" "+testcase.args), &stdout) + args := testutil.Args(secretstore.RootNameStore + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.CreateSecretStoreFn var apiInvoked bool @@ -86,9 +89,11 @@ func TestCreateStoreCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -159,7 +164,8 @@ func TestDeleteStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstore.RootNameStore+" "+testcase.args), &stdout) + args := testutil.Args(secretstore.RootNameStore + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.DeleteSecretStoreFn var apiInvoked bool @@ -168,9 +174,11 @@ func TestDeleteStoreCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -246,7 +254,8 @@ func TestDescribeStoreCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstore.RootNameStore+" "+testcase.args), &stdout) + args := testutil.Args(secretstore.RootNameStore + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.GetSecretStoreFn var apiInvoked bool @@ -255,9 +264,11 @@ func TestDescribeStoreCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -335,7 +346,8 @@ func TestListStoresCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstore.RootNameStore+" "+testcase.args), &stdout) + args := testutil.Args(secretstore.RootNameStore + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.ListSecretStoresFn var apiInvoked bool @@ -344,9 +356,11 @@ func TestListStoresCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) diff --git a/pkg/commands/secretstoreentry/create.go b/pkg/commands/secretstoreentry/create.go index ce7bd7bf6..0d6a9559d 100644 --- a/pkg/commands/secretstoreentry/create.go +++ b/pkg/commands/secretstoreentry/create.go @@ -14,7 +14,6 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -43,12 +42,11 @@ func mustDecode(s string) []byte { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a new secret within specified store") @@ -83,7 +81,6 @@ type CreateCommand struct { cmd.JSONOutput Input fastly.CreateSecretInput - manifest manifest.Data recreate bool recreateAllow bool secretFile string diff --git a/pkg/commands/secretstoreentry/delete.go b/pkg/commands/secretstoreentry/delete.go index 05d8bcb8b..eda3b040d 100644 --- a/pkg/commands/secretstoreentry/delete.go +++ b/pkg/commands/secretstoreentry/delete.go @@ -8,17 +8,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a secret") @@ -38,8 +36,7 @@ type DeleteCommand struct { cmd.Base cmd.JSONOutput - Input fastly.DeleteSecretInput - manifest manifest.Data + Input fastly.DeleteSecretInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/secretstoreentry/describe.go b/pkg/commands/secretstoreentry/describe.go index 654cf1fd3..45d7551ba 100644 --- a/pkg/commands/secretstoreentry/describe.go +++ b/pkg/commands/secretstoreentry/describe.go @@ -3,21 +3,20 @@ package secretstoreentry import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Retrieve a single secret").Alias("get") @@ -37,8 +36,7 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - Input fastly.GetSecretInput - manifest manifest.Data + Input fastly.GetSecretInput } // Exec invokes the application logic for the command. diff --git a/pkg/commands/secretstoreentry/list.go b/pkg/commands/secretstoreentry/list.go index 87c361647..2185d1f9a 100644 --- a/pkg/commands/secretstoreentry/list.go +++ b/pkg/commands/secretstoreentry/list.go @@ -3,21 +3,20 @@ package secretstoreentry import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List secrets within a specified store") @@ -38,8 +37,7 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - Input fastly.ListSecretsInput - manifest manifest.Data + Input fastly.ListSecretsInput } // Exec invokes the application logic for the command. @@ -65,7 +63,7 @@ func (c *ListCommand) Exec(in io.Reader, out io.Writer) error { if o != nil && o.Meta.NextCursor != "" { // Check if 'out' is interactive before prompting. if !c.Globals.Flags.NonInteractive && !c.Globals.Flags.AutoYes && text.IsTTY(out) { - printNext, err := text.AskYesNo(out, "Print next page [yes/no]: ", in) + printNext, err := text.AskYesNo(out, "Print next page [y/N]: ", in) if err != nil { return err } diff --git a/pkg/commands/secretstoreentry/secretstoreentry_test.go b/pkg/commands/secretstoreentry/secretstoreentry_test.go index cd731c135..2eea5bf9b 100644 --- a/pkg/commands/secretstoreentry/secretstoreentry_test.go +++ b/pkg/commands/secretstoreentry/secretstoreentry_test.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "errors" "fmt" + "io" "net/http" "os" "path" @@ -20,6 +21,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/secretstoreentry" fstfmt "github.com/fastly/cli/pkg/fmt" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -227,11 +229,12 @@ func TestCreateSecretCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstoreentry.RootNameSecret+" "+testcase.args), &stdout) + args := testutil.Args(secretstoreentry.RootNameSecret + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) if testcase.stdin != "" { var stdin bytes.Buffer stdin.WriteString(testcase.stdin) - opts.Stdin = &stdin + opts.Input = &stdin } f := testcase.api.CreateSecretFn @@ -241,14 +244,16 @@ func TestCreateSecretCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - // Tests generate their own signing keys, which won't match // the hardcoded value. Disable the check against the // hardcoded value. t.Setenv("FASTLY_USE_API_SIGNING_KEY", "1") - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -325,7 +330,8 @@ func TestDeleteSecretCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstoreentry.RootNameSecret+" "+testcase.args), &stdout) + args := testutil.Args(secretstoreentry.RootNameSecret + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.DeleteSecretFn var apiInvoked bool @@ -334,9 +340,11 @@ func TestDeleteSecretCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -429,7 +437,8 @@ func TestDescribeSecretCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstoreentry.RootNameSecret+" "+testcase.args), &stdout) + args := testutil.Args(secretstoreentry.RootNameSecret + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.GetSecretFn var apiInvoked bool @@ -438,9 +447,11 @@ func TestDescribeSecretCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) @@ -514,7 +525,8 @@ func TestListSecretsCommand(t *testing.T) { testcase := testcase t.Run(testcase.args, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testutil.Args(secretstoreentry.RootNameSecret+" "+testcase.args), &stdout) + args := testutil.Args(secretstoreentry.RootNameSecret + " " + testcase.args) + opts := testutil.MockGlobalData(args, &stdout) f := testcase.api.ListSecretsFn var apiInvoked bool @@ -523,9 +535,11 @@ func TestListSecretsCommand(t *testing.T) { return f(i) } - opts.APIClient = mock.APIClient(testcase.api) - - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) diff --git a/pkg/commands/service/create.go b/pkg/commands/service/create.go index a3f2915d1..f1cd726e0 100644 --- a/pkg/commands/service/create.go +++ b/pkg/commands/service/create.go @@ -3,10 +3,11 @@ package service import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CreateCommand calls the Fastly API to create services. diff --git a/pkg/commands/service/delete.go b/pkg/commands/service/delete.go index e79d36ab3..7edf72bdc 100644 --- a/pkg/commands/service/delete.go +++ b/pkg/commands/service/delete.go @@ -4,30 +4,29 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete services. type DeleteCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeleteServiceInput force bool serviceName cmd.OptionalServiceNameID } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a Fastly service").Alias("remove") @@ -36,7 +35,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -50,7 +49,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } @@ -99,12 +98,12 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { // Ensure that VCL service users are unaffected by checking if the Service ID // was acquired via the fastly.toml manifest. if source == manifest.SourceFile { - if err := c.manifest.File.Read(manifest.Filename); err != nil { + if err := c.Globals.Manifest.File.Read(manifest.Filename); err != nil { c.Globals.ErrLog.Add(err) return fmt.Errorf("error reading fastly.toml: %w", err) } - c.manifest.File.ServiceID = "" - if err := c.manifest.File.Write(manifest.Filename); err != nil { + c.Globals.Manifest.File.ServiceID = "" + if err := c.Globals.Manifest.File.Write(manifest.Filename); err != nil { c.Globals.ErrLog.Add(err) return fmt.Errorf("error updating fastly.toml: %w", err) } diff --git a/pkg/commands/service/describe.go b/pkg/commands/service/describe.go index 7a6836b25..d4598ac8c 100644 --- a/pkg/commands/service/describe.go +++ b/pkg/commands/service/describe.go @@ -5,13 +5,14 @@ import ( "io" "strconv" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" "github.com/fastly/cli/pkg/time" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a service. @@ -19,18 +20,16 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.GetServiceInput serviceName cmd.OptionalServiceNameID } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show detailed information about a Fastly service").Alias("get") @@ -39,7 +38,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -57,7 +56,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/service/search.go b/pkg/commands/service/search.go index c02e1ec1d..eaa0391b0 100644 --- a/pkg/commands/service/search.go +++ b/pkg/commands/service/search.go @@ -3,12 +3,12 @@ package service import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // SearchCommand calls the Fastly API to describe a service. @@ -16,17 +16,15 @@ type SearchCommand struct { cmd.Base cmd.JSONOutput - Input fastly.SearchServiceInput - manifest manifest.Data + Input fastly.SearchServiceInput } // NewSearchCommand returns a usable command registered under the parent. -func NewSearchCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *SearchCommand { +func NewSearchCommand(parent cmd.Registerer, g *global.Data) *SearchCommand { c := SearchCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("search", "Search for a Fastly service by name") diff --git a/pkg/commands/service/service_test.go b/pkg/commands/service/service_test.go index d7f8942ea..5bf506b5f 100644 --- a/pkg/commands/service/service_test.go +++ b/pkg/commands/service/service_test.go @@ -3,6 +3,7 @@ package service_test import ( "bytes" "errors" + "io" "os" "path/filepath" "regexp" @@ -12,6 +13,7 @@ import ( "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" @@ -60,9 +62,12 @@ func TestServiceCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -133,9 +138,12 @@ func TestServiceList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -190,9 +198,12 @@ func TestServiceDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -231,9 +242,12 @@ func TestServiceSearch(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -296,9 +310,12 @@ func TestServiceUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -384,9 +401,12 @@ func TestServiceDelete(t *testing.T) { }() var stdout bytes.Buffer - runOpts := testutil.NewRunOpts(testcase.args, &stdout) - runOpts.APIClient = mock.APIClient(testcase.api) - runErr := app.Run(runOpts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + runOpts := testutil.MockGlobalData(testcase.args, &stdout) + runOpts.APIClientFactory = mock.APIClient(testcase.api) + return runOpts, nil + } + runErr := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, runErr, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) @@ -445,8 +465,8 @@ Bar 456 wasm 1 2015-03-14 12:59 `) + "\n" var listServicesVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service 1/3 ID: 123 @@ -592,8 +612,8 @@ Versions: 2 `) + "\n" var describeServiceVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 @@ -702,8 +722,8 @@ Versions: 2 `) + "\n" var searchServiceVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) ID: 123 Name: Foo diff --git a/pkg/commands/service/update.go b/pkg/commands/service/update.go index e5721457b..26da2248b 100644 --- a/pkg/commands/service/update.go +++ b/pkg/commands/service/update.go @@ -4,11 +4,11 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to create services. @@ -17,18 +17,16 @@ type UpdateCommand struct { comment cmd.OptionalString input fastly.UpdateServiceInput - manifest manifest.Data name cmd.OptionalString serviceName cmd.OptionalServiceNameID } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a Fastly service") @@ -38,7 +36,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -52,7 +50,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/serviceauth/create.go b/pkg/commands/serviceauth/create.go index 94461b3c1..da62f1ae1 100644 --- a/pkg/commands/serviceauth/create.go +++ b/pkg/commands/serviceauth/create.go @@ -7,7 +7,6 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -19,18 +18,16 @@ var Permissions = []string{"full", "read_only", "purge_select", "purge_all"} type CreateCommand struct { cmd.Base input fastly.CreateServiceAuthorizationInput - manifest manifest.Data serviceName cmd.OptionalServiceNameID userID string } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create service authorization").Alias("add") @@ -44,7 +41,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -58,10 +55,10 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ - "Service ID": c.manifest.Flag.ServiceID, + "Service ID": c.Globals.Manifest.Flag.ServiceID, "Service Name": c.serviceName.Value, }) return err diff --git a/pkg/commands/serviceauth/delete.go b/pkg/commands/serviceauth/delete.go index 7526127c3..aa6d34224 100644 --- a/pkg/commands/serviceauth/delete.go +++ b/pkg/commands/serviceauth/delete.go @@ -3,27 +3,25 @@ package serviceauth import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete service authorizations. type DeleteCommand struct { cmd.Base - manifest manifest.Data - Input fastly.DeleteServiceAuthorizationInput + Input fastly.DeleteServiceAuthorizationInput } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete service authorization").Alias("remove") diff --git a/pkg/commands/serviceauth/describe.go b/pkg/commands/serviceauth/describe.go index dc141ca14..6d127c004 100644 --- a/pkg/commands/serviceauth/describe.go +++ b/pkg/commands/serviceauth/describe.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/time" - "github.com/fastly/go-fastly/v8/fastly" ) // DescribeCommand calls the Fastly API to describe a service authorization. @@ -17,17 +17,15 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data - Input fastly.GetServiceAuthorizationInput + Input fastly.GetServiceAuthorizationInput } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Show service authorization").Alias("get") diff --git a/pkg/commands/serviceauth/service_test.go b/pkg/commands/serviceauth/service_test.go index bd2187463..88941b1e1 100644 --- a/pkg/commands/serviceauth/service_test.go +++ b/pkg/commands/serviceauth/service_test.go @@ -3,12 +3,14 @@ package serviceauth_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -40,9 +42,12 @@ func TestServiceAuthCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -99,16 +104,19 @@ func TestServiceAuthList(t *testing.T) { { args: args("service-auth list --verbose"), api: mock.API{ListServiceAuthorizationsFn: listServiceAuthOK}, - wantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nAuth ID: 123\nUser ID: 456\nService ID: 789\nPermission: read_only\n", + wantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nAuth ID: 123\nUser ID: 456\nService ID: 789\nPermission: read_only\n", }, } for testcaseIdx := range scenarios { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) @@ -164,9 +172,12 @@ func TestServiceAuthDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) @@ -205,9 +216,12 @@ func TestServiceAuthUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -241,9 +255,12 @@ func TestServiceAuthDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) diff --git a/pkg/commands/serviceauth/update.go b/pkg/commands/serviceauth/update.go index 38b215072..c0b4079a5 100644 --- a/pkg/commands/serviceauth/update.go +++ b/pkg/commands/serviceauth/update.go @@ -3,28 +3,26 @@ package serviceauth import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // UpdateCommand calls the Fastly API to update service authorizations. type UpdateCommand struct { cmd.Base - input fastly.UpdateServiceAuthorizationInput - manifest manifest.Data + input fastly.UpdateServiceAuthorizationInput } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update service authorization") diff --git a/pkg/commands/serviceversion/activate.go b/pkg/commands/serviceversion/activate.go index ee2c69233..fd85144ae 100644 --- a/pkg/commands/serviceversion/activate.go +++ b/pkg/commands/serviceversion/activate.go @@ -3,18 +3,17 @@ package serviceversion import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ActivateCommand calls the Fastly API to activate a service version. type ActivateCommand struct { cmd.Base - manifest manifest.Data Input fastly.ActivateVersionInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,15 +21,14 @@ type ActivateCommand struct { } // NewActivateCommand returns a usable command registered under the parent. -func NewActivateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ActivateCommand { +func NewActivateCommand(parent cmd.Registerer, g *global.Data) *ActivateCommand { var c ActivateCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("activate", "Activate a Fastly service version") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -57,7 +55,7 @@ func (c *ActivateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/serviceversion/clone.go b/pkg/commands/serviceversion/clone.go index 10c1c5b1d..69f66e507 100644 --- a/pkg/commands/serviceversion/clone.go +++ b/pkg/commands/serviceversion/clone.go @@ -3,33 +3,31 @@ package serviceversion import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // CloneCommand calls the Fastly API to clone a service version. type CloneCommand struct { cmd.Base - manifest manifest.Data Input fastly.CloneVersionInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewCloneCommand returns a usable command registered under the parent. -func NewCloneCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CloneCommand { +func NewCloneCommand(parent cmd.Registerer, g *global.Data) *CloneCommand { var c CloneCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("clone", "Clone a Fastly service version") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -52,7 +50,7 @@ func (c *CloneCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/serviceversion/deactivate.go b/pkg/commands/serviceversion/deactivate.go index d569e5a9e..64056afc0 100644 --- a/pkg/commands/serviceversion/deactivate.go +++ b/pkg/commands/serviceversion/deactivate.go @@ -3,33 +3,31 @@ package serviceversion import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeactivateCommand calls the Fastly API to deactivate a service version. type DeactivateCommand struct { cmd.Base - manifest manifest.Data Input fastly.DeactivateVersionInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDeactivateCommand returns a usable command registered under the parent. -func NewDeactivateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeactivateCommand { +func NewDeactivateCommand(parent cmd.Registerer, g *global.Data) *DeactivateCommand { var c DeactivateCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("deactivate", "Deactivate a Fastly service version") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -52,7 +50,7 @@ func (c *DeactivateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/serviceversion/list.go b/pkg/commands/serviceversion/list.go index 17d6c775c..20aca08eb 100644 --- a/pkg/commands/serviceversion/list.go +++ b/pkg/commands/serviceversion/list.go @@ -4,13 +4,13 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" "github.com/fastly/cli/pkg/time" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list services. @@ -18,25 +18,23 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data Input fastly.ListVersionsInput serviceName cmd.OptionalServiceNameID } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List Fastly service versions") c.RegisterFlagBool(c.JSONFlag()) // --json c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -54,7 +52,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { return fsterr.ErrInvalidVerboseJSONCombo } - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/serviceversion/lock.go b/pkg/commands/serviceversion/lock.go index 64e6133a1..3aaf91db7 100644 --- a/pkg/commands/serviceversion/lock.go +++ b/pkg/commands/serviceversion/lock.go @@ -3,33 +3,31 @@ package serviceversion import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // LockCommand calls the Fastly API to lock a service version. type LockCommand struct { cmd.Base - manifest manifest.Data Input fastly.LockVersionInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewLockCommand returns a usable command registered under the parent. -func NewLockCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *LockCommand { +func NewLockCommand(parent cmd.Registerer, g *global.Data) *LockCommand { var c LockCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("lock", "Lock a Fastly service version") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -52,7 +50,7 @@ func (c *LockCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/serviceversion/serviceversion_test.go b/pkg/commands/serviceversion/serviceversion_test.go index fc5413d82..401a3970d 100644 --- a/pkg/commands/serviceversion/serviceversion_test.go +++ b/pkg/commands/serviceversion/serviceversion_test.go @@ -2,12 +2,14 @@ package serviceversion_test import ( "bytes" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -49,9 +51,12 @@ func TestVersionClone(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -101,9 +106,12 @@ func TestVersionList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertString(t, testcase.wantOutput, stdout.String()) }) @@ -149,9 +157,12 @@ func TestVersionUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -201,9 +212,12 @@ func TestVersionActivate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -251,9 +265,12 @@ func TestVersionDeactivate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -293,9 +310,12 @@ func TestVersionLock(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) @@ -310,8 +330,8 @@ NUMBER ACTIVE LAST EDITED (UTC) `) + "\n" var listVersionsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/serviceversion/update.go b/pkg/commands/serviceversion/update.go index b747f0c47..c1176f775 100644 --- a/pkg/commands/serviceversion/update.go +++ b/pkg/commands/serviceversion/update.go @@ -9,14 +9,12 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // UpdateCommand calls the Fastly API to update a service version. type UpdateCommand struct { cmd.Base - manifest manifest.Data input fastly.UpdateVersionInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -26,18 +24,17 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a Fastly service version") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -71,7 +68,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/sso/doc.go b/pkg/commands/sso/doc.go new file mode 100644 index 000000000..14585f77e --- /dev/null +++ b/pkg/commands/sso/doc.go @@ -0,0 +1,3 @@ +// Package sso contains commands to authenticate with Fastly and to acquire a +// temporary API token, which will be auto-rotated using an access/refresh token. +package sso diff --git a/pkg/commands/sso/root.go b/pkg/commands/sso/root.go new file mode 100644 index 000000000..67ef0c499 --- /dev/null +++ b/pkg/commands/sso/root.go @@ -0,0 +1,285 @@ +package sso + +import ( + "errors" + "fmt" + "io" + "time" + + "github.com/fastly/cli/pkg/auth" + "github.com/fastly/cli/pkg/cmd" + "github.com/fastly/cli/pkg/config" + fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/profile" + "github.com/fastly/cli/pkg/text" +) + +// RootCommand is the parent command for all subcommands in this package. +// It should be installed under the primary root command. +type RootCommand struct { + cmd.Base + profile string + + // IMPORTANT: The following fields are public to the `profile` subcommands. + + // InvokedFromProfileCreate indicates if we should create a new profile. + InvokedFromProfileCreate bool + // ProfileCreateName indicates the new profile name. + ProfileCreateName string + // ProfileDefault indicates if the affected profile should become the default. + ProfileDefault bool + // InvokedFromProfileUpdate indicates if we should update a profile. + InvokedFromProfileUpdate bool + // ProfileUpdateName indicates the profile name to update. + ProfileUpdateName string +} + +// NewRootCommand returns a new command registered in the parent. +func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { + var c RootCommand + c.Globals = g + // FIXME: Unhide this command once SSO is GA. + c.CmdClause = parent.Command("sso", "Single Sign-On authentication").Hidden() + c.CmdClause.Arg("profile", "Profile to authenticate (i.e. create/update a token for)").Short('p').StringVar(&c.profile) + return &c +} + +// Exec implements the command interface. +func (c *RootCommand) Exec(in io.Reader, out io.Writer) error { + // We need to prompt the user, so they know we're about to open their web + // browser, but we also need to handle the scenario where the `sso` command is + // invoked indirectly via ../../app/run.go as that package will have its own + // (similar) prompt before invoking this command. So to avoid a double prompt, + // the app package will set `SkipAuthPrompt: true`. + if !c.Globals.SkipAuthPrompt && !c.Globals.Flags.AutoYes && !c.Globals.Flags.NonInteractive { + profileName, _ := c.identifyProfileAndFlow() + msg := fmt.Sprintf("We're going to authenticate the '%s' profile", profileName) + text.Important(out, "%s. We need to open your browser to authenticate you.", msg) + text.Break(out) + cont, err := text.AskYesNo(out, text.BoldYellow("Do you want to continue? [y/N]: "), in) + text.Break(out) + if err != nil { + return err + } + if !cont { + return fsterr.SkipExitError{ + Skip: true, + Err: fsterr.ErrDontContinue, + } + } + } + + var serverErr error + go func() { + err := c.Globals.AuthServer.Start() + if err != nil { + serverErr = err + } + }() + if serverErr != nil { + return serverErr + } + + text.Info(out, "Starting a local server to handle the authentication flow.") + + authorizationURL, err := c.Globals.AuthServer.AuthURL() + if err != nil { + return fsterr.RemediationError{ + Inner: fmt.Errorf("failed to generate an authorization URL: %w", err), + Remediation: auth.Remediation, + } + } + + text.Break(out) + text.Description(out, "We're opening the following URL in your default web browser so you may authenticate with Fastly", authorizationURL) + + err = c.Globals.Opener(authorizationURL) + if err != nil { + return fmt.Errorf("failed to open your default browser: %w", err) + } + + ar := <-c.Globals.AuthServer.GetResult() + if ar.Err != nil || ar.SessionToken == "" { + err := ar.Err + if ar.Err == nil { + err = errors.New("no session token") + } + return fsterr.RemediationError{ + Inner: fmt.Errorf("failed to authorize: %w", err), + Remediation: auth.Remediation, + } + } + + err = c.processProfiles(ar) + if err != nil { + c.Globals.ErrLog.Add(err) + return fmt.Errorf("failed to process profile data: %w", err) + } + + textFn := text.Success + if c.InvokedFromProfileCreate || c.InvokedFromProfileUpdate { + textFn = text.Info + } + textFn(out, "Session token (persisted to your local configuration): %s", ar.SessionToken) + return nil +} + +// ProfileFlow enumerates which profile flow to take. +type ProfileFlow uint8 + +const ( + // ProfileNone indicates we need to create a new 'default' profile as no + // profiles currently exist. + ProfileNone ProfileFlow = iota + + // ProfileCreate indicates we need to create a new profile using details + // passed in either from the `sso` or `profile create` command. + ProfileCreate + + // ProfileUpdate indicates we need to update a profile using details passed in + // either from the `sso` or `profile update` command. + ProfileUpdate +) + +// identifyProfileAndFlow identifies the profile and the specific workflow. +func (c *RootCommand) identifyProfileAndFlow() (profileName string, flow ProfileFlow) { + var profileOverride string + switch { + case c.Globals.Flags.Profile != "": + profileOverride = c.Globals.Flags.Profile + case c.Globals.Manifest.File.Profile != "": + profileOverride = c.Globals.Manifest.File.Profile + } + + currentDefaultProfile, _ := profile.Default(c.Globals.Config.Profiles) + + var newDefaultProfile string + if currentDefaultProfile == "" && len(c.Globals.Config.Profiles) > 0 { + newDefaultProfile, c.Globals.Config.Profiles = profile.SetADefault(c.Globals.Config.Profiles) + } + + switch { + case profileOverride != "": + return profileOverride, ProfileUpdate + case c.profile != "": + return c.profile, ProfileUpdate + case c.InvokedFromProfileCreate && c.ProfileCreateName != "": + return c.ProfileCreateName, ProfileCreate + case c.InvokedFromProfileUpdate && c.ProfileUpdateName != "": + return c.ProfileUpdateName, ProfileUpdate + case currentDefaultProfile != "": + return currentDefaultProfile, ProfileUpdate + case newDefaultProfile != "": + return newDefaultProfile, ProfileUpdate + default: + return profile.DefaultName, ProfileCreate + } +} + +// processProfiles updates the relevant profile with the returned token data. +// +// First it checks the --profile flag and the `profile` fastly.toml field. +// Second it checks to see which profile is currently the default. +// Third it identifies which profile to be modified. +// Fourth it writes the updated in-memory data back to disk. +func (c *RootCommand) processProfiles(ar auth.AuthorizationResult) error { + profileName, flow := c.identifyProfileAndFlow() + + switch flow { + case ProfileCreate: + c.processCreateProfile(ar, profileName) + case ProfileUpdate: + err := c.processUpdateProfile(ar, profileName) + if err != nil { + return fmt.Errorf("failed to update profile: %w", err) + } + } + + if err := c.Globals.Config.Write(c.Globals.ConfigPath); err != nil { + return fmt.Errorf("failed to update config file: %w", err) + } + return nil +} + +// processCreateProfile handles creating a new profile. +func (c *RootCommand) processCreateProfile(ar auth.AuthorizationResult, profileName string) { + isDefault := true + if c.InvokedFromProfileCreate { + isDefault = c.ProfileDefault + } + + c.Globals.Config.Profiles = createNewProfile(profileName, isDefault, c.Globals.Config.Profiles, ar) + + // If the user wants the newly created profile to be their new default, then + // we'll call Set for its side effect of resetting all other profiles to have + // their Default field set to false. + if c.ProfileDefault { // this is set by the `profile create` command. + if p, ok := profile.SetDefault(c.ProfileCreateName, c.Globals.Config.Profiles); ok { + c.Globals.Config.Profiles = p + } + } +} + +// processUpdateProfile handles updating a profile. +func (c *RootCommand) processUpdateProfile(ar auth.AuthorizationResult, profileName string) error { + var isDefault bool + if p := profile.Get(profileName, c.Globals.Config.Profiles); p != nil { + isDefault = p.Default + } + if c.InvokedFromProfileUpdate { + isDefault = c.ProfileDefault + } + + ps, err := editProfile(profileName, isDefault, c.Globals.Config.Profiles, ar) + if err != nil { + return err + } + c.Globals.Config.Profiles = ps + return nil +} + +// IMPORTANT: Mutates the config.Profiles map type. +// We need to return the modified type so it can be safely reassigned. +func createNewProfile(profileName string, makeDefault bool, p config.Profiles, ar auth.AuthorizationResult) config.Profiles { + now := time.Now().Unix() + if p == nil { + p = make(config.Profiles) + } + p[profileName] = &config.Profile{ + AccessToken: ar.Jwt.AccessToken, + AccessTokenCreated: now, + AccessTokenTTL: ar.Jwt.ExpiresIn, + Default: makeDefault, + Email: ar.Email, + RefreshToken: ar.Jwt.RefreshToken, + RefreshTokenCreated: now, + RefreshTokenTTL: ar.Jwt.RefreshExpiresIn, + Token: ar.SessionToken, + } + return p +} + +// IMPORTANT: Mutates the config.Profiles map type. +// We need to return the modified type so it can be safely reassigned. +func editProfile(profileName string, makeDefault bool, p config.Profiles, ar auth.AuthorizationResult) (config.Profiles, error) { + ps, ok := profile.Edit(profileName, p, func(p *config.Profile) { + now := time.Now().Unix() + p.Default = makeDefault + p.AccessToken = ar.Jwt.AccessToken + p.AccessTokenCreated = now + p.AccessTokenTTL = ar.Jwt.ExpiresIn + p.Email = ar.Email + p.RefreshToken = ar.Jwt.RefreshToken + p.RefreshTokenCreated = now + p.RefreshTokenTTL = ar.Jwt.RefreshExpiresIn + p.Token = ar.SessionToken + }) + if !ok { + return ps, fsterr.RemediationError{ + Inner: fmt.Errorf("failed to update '%s' profile with new token data", profileName), + Remediation: "Run `fastly sso` to retry.", + } + } + return ps, nil +} diff --git a/pkg/commands/sso/sso_test.go b/pkg/commands/sso/sso_test.go new file mode 100644 index 000000000..2c848d91c --- /dev/null +++ b/pkg/commands/sso/sso_test.go @@ -0,0 +1,333 @@ +package sso_test + +import ( + "bytes" + "errors" + "fmt" + "io" + "strings" + "testing" + "time" + + "github.com/fastly/cli/pkg/api" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/auth" + "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/global" + "github.com/fastly/cli/pkg/mock" + "github.com/fastly/cli/pkg/testutil" +) + +func TestSSO(t *testing.T) { + args := testutil.Args + type ts struct { + testutil.TestScenario + + AuthResult *auth.AuthorizationResult + ConfigFile *config.File + ExpectedConfigProfile *config.Profile + HTTPClient api.HTTPClient + Opener func(input string) error + Stdin []string + } + scenarios := []ts{ + // 0. User cancels authentication prompt + { + TestScenario: testutil.TestScenario{ + Args: args("sso"), + WantError: "will not continue", + }, + Stdin: []string{ + "N", // when prompted to open a web browser to start authentication + }, + }, + // 1. Error opening web browser + { + TestScenario: testutil.TestScenario{ + Args: args("sso"), + WantError: "failed to open web browser", + }, + Opener: func(input string) error { + return errors.New("failed to open web browser") + }, + Stdin: []string{ + "Y", // when prompted to open a web browser to start authentication + }, + }, + // 2. Error processing OAuth flow (error encountered) + { + TestScenario: testutil.TestScenario{ + Args: args("sso"), + WantError: "failed to authorize: no authorization code returned", + }, + AuthResult: &auth.AuthorizationResult{ + Err: errors.New("no authorization code returned"), + }, + Stdin: []string{ + "Y", // when prompted to open a web browser to start authentication + }, + }, + // 3. Error processing OAuth flow (empty SessionToken field) + { + TestScenario: testutil.TestScenario{ + Args: args("sso"), + WantError: "failed to authorize: no session token", + }, + AuthResult: &auth.AuthorizationResult{ + SessionToken: "", + }, + Stdin: []string{ + "Y", // when prompted to open a web browser to start authentication + }, + }, + // 4. Success processing OAuth flow + { + TestScenario: testutil.TestScenario{ + Args: args("sso"), + WantOutputs: []string{ + "We're going to authenticate the 'user' profile.", + "We need to open your browser to authenticate you.", + "Session token (persisted to your local configuration): 123", + }, + }, + AuthResult: &auth.AuthorizationResult{ + SessionToken: "123", + }, + ExpectedConfigProfile: &config.Profile{ + Token: "123", + }, + Stdin: []string{ + "Y", // when prompted to open a web browser to start authentication + }, + }, + // 5. Success processing OAuth flow while setting specific profile (test_user) + { + TestScenario: testutil.TestScenario{ + Args: args("sso test_user"), + WantOutputs: []string{ + "We're going to authenticate the 'test_user' profile.", + "We need to open your browser to authenticate you.", + "Session token (persisted to your local configuration): 123", + }, + }, + AuthResult: &auth.AuthorizationResult{ + SessionToken: "123", + }, + ConfigFile: &config.File{ + Profiles: config.Profiles{ + "test_user": &config.Profile{ + Default: true, + Email: "test@example.com", + Token: "mock-token", + }, + }, + }, + ExpectedConfigProfile: &config.Profile{ + Token: "123", + }, + Stdin: []string{ + "Y", // when prompted to open a web browser to start authentication + }, + }, + // NOTE: The following tests indirectly validate our `app.Run()` logic. + // Specifically the processing of the token before invoking the subcommand. + // It allows us to check that the `sso` command is invoked when expected. + // + // 6. Success processing `whoami` command. + // We configure a non-SSO token so we can validate the INFO message. + // Otherwise no OAuth flow is happening here. + { + TestScenario: testutil.TestScenario{ + Args: args("whoami"), + WantOutputs: []string{ + // FIXME: Put back messaging once SSO is GA. + // "is not a Fastly SSO (Single Sign-On) generated token", + "Alice Programmer ", + }, + }, + ConfigFile: &config.File{ + Profiles: config.Profiles{ + "user": &config.Profile{ + Default: true, + Email: "test@example.com", + Token: "mock-token", + }, + }, + }, + ExpectedConfigProfile: &config.Profile{ + Token: "mock-token", + }, + HTTPClient: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), + }, + // 7. Success processing `whoami` command. + // We set an SSO token that has expired. + // This allows us to validate the output message about expiration. + // We don't respond "Y" to the prompt for reauthentication. + // But we've mocked the request to succeed still so it doesn't matter. + { + TestScenario: testutil.TestScenario{ + Args: args("whoami"), + WantOutput: "Your access token has expired and so has your refresh token.", + DontWantOutput: "Alice Programmer ", + }, + ConfigFile: &config.File{ + Profiles: config.Profiles{ + "user": &config.Profile{ + AccessTokenCreated: time.Now().Add(-(time.Duration(600) * time.Second)).Unix(), // 10 mins ago + Default: true, + Email: "test@example.com", + Token: "mock-token", + }, + }, + }, + ExpectedConfigProfile: &config.Profile{ + Token: "mock-token", + }, + HTTPClient: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), + }, + // 8. Success processing OAuth flow via `whoami` command + // We set an SSO token that has expired. + // This allows us to validate the output messages. + { + TestScenario: testutil.TestScenario{ + Args: args("whoami"), + WantOutputs: []string{ + "Your access token has expired and so has your refresh token.", + "Starting a local server to handle the authentication flow.", + "Session token (persisted to your local configuration): 123", + "Alice Programmer ", + }, + }, + AuthResult: &auth.AuthorizationResult{ + SessionToken: "123", + }, + ConfigFile: &config.File{ + Profiles: config.Profiles{ + "user": &config.Profile{ + AccessTokenCreated: time.Now().Add(-(time.Duration(300) * time.Second)).Unix(), // 5 mins ago + Default: true, + Email: "test@example.com", + Token: "mock-token", + }, + }, + }, + ExpectedConfigProfile: &config.Profile{ + Token: "123", + }, + HTTPClient: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), + Stdin: []string{ + "Y", // when prompted to open a web browser to start authentication + }, + }, + } + + for testcaseIdx := range scenarios { + testcase := &scenarios[testcaseIdx] + t.Run(testcase.Name, func(t *testing.T) { + var stdout bytes.Buffer + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + + if testcase.HTTPClient != nil { + opts.HTTPClient = testcase.HTTPClient + } + if testcase.ConfigFile != nil { + opts.Config = *testcase.ConfigFile + } + if testcase.Opener != nil { + opts.Opener = testcase.Opener + } + if testcase.AuthResult != nil { + result := make(chan auth.AuthorizationResult) + opts.AuthServer = testutil.MockAuthServer{ + Result: result, + } + go func() { + result <- *testcase.AuthResult + }() + } + + var err error + + if len(testcase.Stdin) > 1 { + // To handle multiple prompt input from the user we need to do some + // coordination around io pipes to mimic the required user behaviour. + stdin, prompt := io.Pipe() + opts.Input = stdin + + // Wait for user input and write it to the prompt + inputc := make(chan string) + go func() { + for input := range inputc { + fmt.Fprintln(prompt, input) + } + }() + + // We need a channel so we wait for `Run()` to complete + done := make(chan bool) + + // Call `app.Run()` and wait for response + go func() { + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) + done <- true + }() + + // User provides input + // + // NOTE: Must provide as much input as is expected to be waited on by `run()`. + // For example, if `run()` calls `input()` twice, then provide two messages. + // Otherwise the select statement will trigger the timeout error. + for _, input := range testcase.Stdin { + inputc <- input + } + + select { + case <-done: + // Wait for app.Run() to finish + case <-time.After(10 * time.Second): + t.Fatalf("unexpected timeout waiting for mocked prompt inputs to be processed") + } + } else { + stdin := "" + if len(testcase.Stdin) > 0 { + stdin = testcase.Stdin[0] + } + opts.Input = strings.NewReader(stdin) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(testcase.Args, nil) + } + + if testcase.ExpectedConfigProfile != nil { + profileName := "user" + if len(testcase.Args) > 1 { + profileName = testcase.Args[1] // use the `profile` command argument + } + userProfile := opts.Config.Profiles[profileName] + if userProfile.Token != testcase.ExpectedConfigProfile.Token { + t.Errorf("want token: %s, got token: %s", testcase.ExpectedConfigProfile.Token, userProfile.Token) + } + } + + t.Log(stdout.String()) + + testutil.AssertErrorContains(t, err, testcase.WantError) + + if testcase.WantOutputs != nil { + for _, s := range testcase.WantOutputs { + testutil.AssertStringContains(t, stdout.String(), s) + } + } else { + testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) + } + + for _, s := range testcase.DontWantOutputs { + testutil.AssertStringDoesntContain(t, stdout.String(), s) + } + }) + } +} diff --git a/pkg/commands/stats/historical.go b/pkg/commands/stats/historical.go index a05e46b37..4a2a3cb99 100644 --- a/pkg/commands/stats/historical.go +++ b/pkg/commands/stats/historical.go @@ -9,7 +9,6 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" ) const statusSuccess = "success" @@ -17,7 +16,6 @@ const statusSuccess = "success" // HistoricalCommand exposes the Historical Stats API. type HistoricalCommand struct { cmd.Base - manifest manifest.Data Input fastly.GetStatsInput formatFlag string @@ -25,16 +23,15 @@ type HistoricalCommand struct { } // NewHistoricalCommand is the "stats historical" subcommand. -func NewHistoricalCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *HistoricalCommand { +func NewHistoricalCommand(parent cmd.Registerer, g *global.Data) *HistoricalCommand { var c HistoricalCommand c.Globals = g - c.manifest = m c.CmdClause = parent.Command("historical", "View historical stats for a Fastly service") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -56,7 +53,7 @@ func NewHistoricalCommand(parent cmd.Registerer, g *global.Data, m manifest.Data // Exec implements the command interface. func (c *HistoricalCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/stats/historical_test.go b/pkg/commands/stats/historical_test.go index 9717fd5d5..3605c65bb 100644 --- a/pkg/commands/stats/historical_test.go +++ b/pkg/commands/stats/historical_test.go @@ -3,12 +3,14 @@ package stats_test import ( "bytes" "encoding/json" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -41,9 +43,12 @@ func TestHistorical(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) diff --git a/pkg/commands/stats/realtime.go b/pkg/commands/stats/realtime.go index d9c771b9b..d8df25c60 100644 --- a/pkg/commands/stats/realtime.go +++ b/pkg/commands/stats/realtime.go @@ -5,34 +5,32 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // RealtimeCommand exposes the Realtime Metrics API. type RealtimeCommand struct { cmd.Base - manifest manifest.Data formatFlag string serviceName cmd.OptionalServiceNameID } // NewRealtimeCommand is the "stats realtime" subcommand. -func NewRealtimeCommand(parent cmd.Registerer, g *global.Data, data manifest.Data) *RealtimeCommand { +func NewRealtimeCommand(parent cmd.Registerer, g *global.Data) *RealtimeCommand { var c RealtimeCommand c.Globals = g - c.manifest = data c.CmdClause = parent.Command("realtime", "View realtime stats for a Fastly service") c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -49,7 +47,7 @@ func NewRealtimeCommand(parent cmd.Registerer, g *global.Data, data manifest.Dat // Exec implements the command interface. func (c *RealtimeCommand) Exec(_ io.Reader, out io.Writer) error { - serviceID, source, flag, err := cmd.ServiceID(c.serviceName, c.manifest, c.Globals.APIClient, c.Globals.ErrLog) + serviceID, source, flag, err := cmd.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog) if err != nil { return err } diff --git a/pkg/commands/stats/regions_test.go b/pkg/commands/stats/regions_test.go index cac75754f..d01b09134 100644 --- a/pkg/commands/stats/regions_test.go +++ b/pkg/commands/stats/regions_test.go @@ -3,13 +3,16 @@ package stats_test import ( "bytes" "errors" + "io" "strings" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestRegions(t *testing.T) { @@ -35,9 +38,12 @@ func TestRegions(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) - opts.APIClient = mock.APIClient(testcase.api) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.api) + return opts, nil + } + err := app.Run(testcase.args, nil) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) diff --git a/pkg/commands/tls/config/config_test.go b/pkg/commands/tls/config/config_test.go index 283e40f6f..e455ad9ae 100644 --- a/pkg/commands/tls/config/config_test.go +++ b/pkg/commands/tls/config/config_test.go @@ -3,12 +3,15 @@ package config_test import ( "bytes" "fmt" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -68,9 +71,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -125,9 +131,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -175,9 +184,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/config/describe.go b/pkg/commands/tls/config/describe.go index 55c74fbbb..e4bae4ece 100644 --- a/pkg/commands/tls/config/describe.go +++ b/pkg/commands/tls/config/describe.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) const include = "dns_records" // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Show a TLS configuration").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS configuration").Required().StringVar(&c.id) @@ -35,9 +34,8 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - include string - manifest manifest.Data + id string + include string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/config/list.go b/pkg/commands/tls/config/list.go index 8bd2fde28..92e18b228 100644 --- a/pkg/commands/tls/config/list.go +++ b/pkg/commands/tls/config/list.go @@ -5,20 +5,19 @@ import ( "io" "strings" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all TLS configurations") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-bulk", "Optionally filter by the bulk attribute").Action(c.filterBulk.Set).BoolVar(&c.filterBulk.Value) @@ -37,7 +36,6 @@ type ListCommand struct { filterBulk cmd.OptionalBool include string - manifest manifest.Data pageNumber int pageSize int } diff --git a/pkg/commands/tls/config/update.go b/pkg/commands/tls/config/update.go index a3e1683e3..e5c1c3b85 100644 --- a/pkg/commands/tls/config/update.go +++ b/pkg/commands/tls/config/update.go @@ -3,19 +3,18 @@ package config import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command("update", "Update a TLS configuration") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS configuration").Required().StringVar(&c.id) @@ -27,9 +26,8 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U type UpdateCommand struct { cmd.Base - id string - manifest manifest.Data - name string + id string + name string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/activation/activation_test.go b/pkg/commands/tls/custom/activation/activation_test.go index 9e8885972..277dd6a1f 100644 --- a/pkg/commands/tls/custom/activation/activation_test.go +++ b/pkg/commands/tls/custom/activation/activation_test.go @@ -3,12 +3,15 @@ package activation_test import ( "bytes" "fmt" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -63,9 +66,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -106,9 +112,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -153,9 +162,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -197,9 +209,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -250,9 +265,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/custom/activation/create.go b/pkg/commands/tls/custom/activation/create.go index 878bdb6f1..80145488d 100644 --- a/pkg/commands/tls/custom/activation/create.go +++ b/pkg/commands/tls/custom/activation/create.go @@ -3,19 +3,18 @@ package activation import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { var c CreateCommand c.CmdClause = parent.Command("enable", "Enable TLS for a particular TLS domain and certificate combination").Alias("add") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("cert-id", "Alphanumeric string identifying a TLS certificate").Required().StringVar(&c.certID) @@ -28,9 +27,8 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C type CreateCommand struct { cmd.Base - certID string - id string - manifest manifest.Data + certID string + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/activation/delete.go b/pkg/commands/tls/custom/activation/delete.go index 8fe8f2360..5deb1ee3f 100644 --- a/pkg/commands/tls/custom/activation/delete.go +++ b/pkg/commands/tls/custom/activation/delete.go @@ -3,19 +3,18 @@ package activation import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("disable", "Disable TLS on the domain associated with this TLS activation").Alias("remove") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS activation").Required().StringVar(&c.id) @@ -27,8 +26,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/activation/describe.go b/pkg/commands/tls/custom/activation/describe.go index 966bbd952..bfd82d7bb 100644 --- a/pkg/commands/tls/custom/activation/describe.go +++ b/pkg/commands/tls/custom/activation/describe.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) var include = []string{"tls_certificate", "tls_configuration", "tls_domain"} // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Show a TLS configuration").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS activation").Required().StringVar(&c.id) @@ -35,9 +34,8 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - include string - manifest manifest.Data + id string + include string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/activation/list.go b/pkg/commands/tls/custom/activation/list.go index 831a6343b..9525e76fa 100644 --- a/pkg/commands/tls/custom/activation/list.go +++ b/pkg/commands/tls/custom/activation/list.go @@ -4,20 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all TLS activations") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-cert", "Limit the returned activations to a specific certificate").StringVar(&c.filterTLSCertID) @@ -40,7 +39,6 @@ type ListCommand struct { filterTLSConfigID string filterTLSDomainID string include string - manifest manifest.Data pageNumber int pageSize int } diff --git a/pkg/commands/tls/custom/activation/update.go b/pkg/commands/tls/custom/activation/update.go index 61ac31b4f..f8345ebf1 100644 --- a/pkg/commands/tls/custom/activation/update.go +++ b/pkg/commands/tls/custom/activation/update.go @@ -3,19 +3,18 @@ package activation import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command("update", "Update the certificate used to terminate TLS traffic for the domain associated with this TLS activation") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("cert-id", "Alphanumeric string identifying a TLS certificate").Required().StringVar(&c.certID) @@ -27,9 +26,8 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U type UpdateCommand struct { cmd.Base - certID string - id string - manifest manifest.Data + certID string + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/certificate/certificate_test.go b/pkg/commands/tls/custom/certificate/certificate_test.go index 0b72ec66b..1b62f25e0 100644 --- a/pkg/commands/tls/custom/certificate/certificate_test.go +++ b/pkg/commands/tls/custom/certificate/certificate_test.go @@ -3,12 +3,15 @@ package certificate_test import ( "bytes" "fmt" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -55,9 +58,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -98,9 +104,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -152,9 +161,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -195,7 +207,7 @@ func TestList(t *testing.T) { }, }, Args: args("tls-custom certificate list --verbose"), - WantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nID: " + mockResponseID + "\nIssued to: " + mockFieldValue + "\nIssuer: " + mockFieldValue + "\nName: " + mockFieldValue + "\nReplace: true\nSerial number: " + mockFieldValue + "\nSignature algorithm: " + mockFieldValue + "\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\n", + WantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nID: " + mockResponseID + "\nIssued to: " + mockFieldValue + "\nIssuer: " + mockFieldValue + "\nName: " + mockFieldValue + "\nReplace: true\nSerial number: " + mockFieldValue + "\nSignature algorithm: " + mockFieldValue + "\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\n", }, } @@ -203,9 +215,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -266,9 +281,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/custom/certificate/create.go b/pkg/commands/tls/custom/certificate/create.go index e240fdaaa..04aab4ff3 100644 --- a/pkg/commands/tls/custom/certificate/create.go +++ b/pkg/commands/tls/custom/certificate/create.go @@ -3,19 +3,18 @@ package certificate import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { var c CreateCommand c.CmdClause = parent.Command("create", "Create a TLS certificate").Alias("add") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("cert-blob", "The PEM-formatted certificate blob").Required().StringVar(&c.certBlob) @@ -33,7 +32,6 @@ type CreateCommand struct { certBlob string id string - manifest manifest.Data name string } diff --git a/pkg/commands/tls/custom/certificate/delete.go b/pkg/commands/tls/custom/certificate/delete.go index cf2d6b912..42d4c379b 100644 --- a/pkg/commands/tls/custom/certificate/delete.go +++ b/pkg/commands/tls/custom/certificate/delete.go @@ -3,19 +3,18 @@ package certificate import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("delete", "Destroy a TLS certificate. TLS certificates already enabled for a domain cannot be destroyed").Alias("remove") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS certificate").Required().StringVar(&c.id) @@ -27,8 +26,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/certificate/describe.go b/pkg/commands/tls/custom/certificate/describe.go index 1e4644a42..30f4e5d37 100644 --- a/pkg/commands/tls/custom/certificate/describe.go +++ b/pkg/commands/tls/custom/certificate/describe.go @@ -4,19 +4,18 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Show a TLS certificate").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS certificate").Required().StringVar(&c.id) @@ -32,8 +31,7 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/certificate/list.go b/pkg/commands/tls/custom/certificate/list.go index 1055d051b..a9aa9e35f 100644 --- a/pkg/commands/tls/custom/certificate/list.go +++ b/pkg/commands/tls/custom/certificate/list.go @@ -4,22 +4,21 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) const emptyString = "" // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all TLS certificates") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-not-after", "Limit the returned certificates to those that expire prior to the specified date in UTC").StringVar(&c.filterNotAfter) @@ -41,7 +40,6 @@ type ListCommand struct { filterNotAfter string filterTLSDomainID string include string - manifest manifest.Data pageNumber int pageSize int sort string diff --git a/pkg/commands/tls/custom/certificate/update.go b/pkg/commands/tls/custom/certificate/update.go index 3898de8be..42b45ca6b 100644 --- a/pkg/commands/tls/custom/certificate/update.go +++ b/pkg/commands/tls/custom/certificate/update.go @@ -3,19 +3,18 @@ package certificate import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command("update", "Replace a TLS certificate with a newly reissued TLS certificate, or update a TLS certificate's name") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("cert-blob", "The PEM-formatted certificate blob").Required().StringVar(&c.certBlob) @@ -32,7 +31,6 @@ type UpdateCommand struct { certBlob string id string - manifest manifest.Data name string } diff --git a/pkg/commands/tls/custom/domain/domain_test.go b/pkg/commands/tls/custom/domain/domain_test.go index 6d289ba4c..029bee357 100644 --- a/pkg/commands/tls/custom/domain/domain_test.go +++ b/pkg/commands/tls/custom/domain/domain_test.go @@ -2,12 +2,15 @@ package domain_test import ( "bytes" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -50,9 +53,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/custom/domain/list.go b/pkg/commands/tls/custom/domain/list.go index 9c70f39a8..26572346a 100644 --- a/pkg/commands/tls/custom/domain/list.go +++ b/pkg/commands/tls/custom/domain/list.go @@ -4,22 +4,21 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) const emptyString = "" // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all TLS domains") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-cert", "Limit the returned domains to those listed in the given TLS certificate's SAN list").StringVar(&c.filterTLSCertsID) @@ -43,7 +42,6 @@ type ListCommand struct { filterTLSCertsID string filterTLSSubsID string include string - manifest manifest.Data pageNumber int pageSize int sort string diff --git a/pkg/commands/tls/custom/privatekey/create.go b/pkg/commands/tls/custom/privatekey/create.go index f2568903d..c5172aee2 100644 --- a/pkg/commands/tls/custom/privatekey/create.go +++ b/pkg/commands/tls/custom/privatekey/create.go @@ -3,19 +3,18 @@ package privatekey import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { var c CreateCommand c.CmdClause = parent.Command("create", "Create a TLS certificate").Alias("add") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("key", "The contents of the private key. Must be a PEM-formatted key").Required().StringVar(&c.key) @@ -28,9 +27,8 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C type CreateCommand struct { cmd.Base - key string - manifest manifest.Data - name string + key string + name string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/privatekey/delete.go b/pkg/commands/tls/custom/privatekey/delete.go index 58aa8cfe3..8e80d2d7e 100644 --- a/pkg/commands/tls/custom/privatekey/delete.go +++ b/pkg/commands/tls/custom/privatekey/delete.go @@ -3,19 +3,18 @@ package privatekey import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("delete", "Destroy a TLS private key. Only private keys not already matched to any certificates can be deleted").Alias("remove") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a private Key").Required().StringVar(&c.id) @@ -27,8 +26,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/privatekey/describe.go b/pkg/commands/tls/custom/privatekey/describe.go index 1ae37cc72..e6af1f1e1 100644 --- a/pkg/commands/tls/custom/privatekey/describe.go +++ b/pkg/commands/tls/custom/privatekey/describe.go @@ -4,19 +4,18 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Show a TLS private key").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a private Key").Required().StringVar(&c.id) @@ -32,8 +31,7 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/custom/privatekey/list.go b/pkg/commands/tls/custom/privatekey/list.go index 6e4c7da31..2bc2882fa 100644 --- a/pkg/commands/tls/custom/privatekey/list.go +++ b/pkg/commands/tls/custom/privatekey/list.go @@ -4,20 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all TLS private keys") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-in-use", "Limit the returned keys to those without any matching TLS certificates").HintOptions("false").EnumVar(&c.filterInUse, "false") @@ -34,7 +33,6 @@ type ListCommand struct { cmd.JSONOutput filterInUse string - manifest manifest.Data pageNumber int pageSize int } diff --git a/pkg/commands/tls/custom/privatekey/privatekey_test.go b/pkg/commands/tls/custom/privatekey/privatekey_test.go index 640fb34e8..16891f8c0 100644 --- a/pkg/commands/tls/custom/privatekey/privatekey_test.go +++ b/pkg/commands/tls/custom/privatekey/privatekey_test.go @@ -2,12 +2,15 @@ package privatekey_test import ( "bytes" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -61,9 +64,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -104,9 +110,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -155,9 +164,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -203,9 +215,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/platform/create.go b/pkg/commands/tls/platform/create.go index ae987c5bc..e13e449ae 100644 --- a/pkg/commands/tls/platform/create.go +++ b/pkg/commands/tls/platform/create.go @@ -3,19 +3,18 @@ package platform import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { var c CreateCommand c.CmdClause = parent.Command("upload", "Upload a new certificate") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("cert-blob", "The PEM-formatted certificate blob").Required().StringVar(&c.certBlob) @@ -36,7 +35,6 @@ type CreateCommand struct { certBlob string config []string intermediatesBlob string - manifest manifest.Data } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/platform/delete.go b/pkg/commands/tls/platform/delete.go index 512a2e994..a7be1ff92 100644 --- a/pkg/commands/tls/platform/delete.go +++ b/pkg/commands/tls/platform/delete.go @@ -3,19 +3,18 @@ package platform import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("delete", "Destroy a certificate. This disables TLS for all domains listed as SAN entries").Alias("remove") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS bulk certificate").Required().StringVar(&c.id) @@ -27,8 +26,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/platform/describe.go b/pkg/commands/tls/platform/describe.go index 9c26bf759..cf91ca9da 100644 --- a/pkg/commands/tls/platform/describe.go +++ b/pkg/commands/tls/platform/describe.go @@ -4,19 +4,18 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Retrieve a single certificate").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS bulk certificate").Required().StringVar(&c.id) @@ -32,8 +31,7 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/platform/list.go b/pkg/commands/tls/platform/list.go index 0655f05db..91ac0cefb 100644 --- a/pkg/commands/tls/platform/list.go +++ b/pkg/commands/tls/platform/list.go @@ -4,20 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all certificates") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-domain", "Optionally filter by the bulk attribute").StringVar(&c.filterTLSDomainID) @@ -35,7 +34,6 @@ type ListCommand struct { cmd.JSONOutput filterTLSDomainID string - manifest manifest.Data pageNumber int pageSize int sort string diff --git a/pkg/commands/tls/platform/platform_test.go b/pkg/commands/tls/platform/platform_test.go index b26042270..21bfc060c 100644 --- a/pkg/commands/tls/platform/platform_test.go +++ b/pkg/commands/tls/platform/platform_test.go @@ -3,12 +3,15 @@ package platform_test import ( "bytes" "fmt" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -59,9 +62,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -102,9 +108,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -151,9 +160,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -197,9 +209,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -252,9 +267,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/platform/update.go b/pkg/commands/tls/platform/update.go index 2548eb75d..ce9549313 100644 --- a/pkg/commands/tls/platform/update.go +++ b/pkg/commands/tls/platform/update.go @@ -3,23 +3,20 @@ package platform import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand( - parent cmd.Registerer, g *global.Data, m manifest.Data, -) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command( "update", "Replace a certificate with a newly reissued certificate", ) c.Globals = g - c.manifest = m // Required. @@ -52,7 +49,6 @@ type UpdateCommand struct { certBlob string id string intermediatesBlob string - manifest manifest.Data } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/subscription/create.go b/pkg/commands/tls/subscription/create.go index 035be6b4a..b0a6f3ae9 100644 --- a/pkg/commands/tls/subscription/create.go +++ b/pkg/commands/tls/subscription/create.go @@ -3,11 +3,11 @@ package subscription import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) const emptyString = "" @@ -15,11 +15,10 @@ const emptyString = "" var certAuth = []string{"lets-encrypt", "globalsign"} // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { var c CreateCommand c.CmdClause = parent.Command("create", "Create a new TLS subscription").Alias("add") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("domain", "Domain(s) to add to the TLS certificates generated for the subscription (set flag once per domain)").Required().StringsVar(&c.domains) @@ -40,7 +39,6 @@ type CreateCommand struct { commonName string config string domains []string - manifest manifest.Data } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/subscription/delete.go b/pkg/commands/tls/subscription/delete.go index a2f5494bd..f84cd9e70 100644 --- a/pkg/commands/tls/subscription/delete.go +++ b/pkg/commands/tls/subscription/delete.go @@ -3,19 +3,18 @@ package subscription import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("delete", "Destroy a TLS subscription. A subscription cannot be destroyed if there are domains in the TLS enabled state").Alias("remove") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS subscription").Required().StringVar(&c.id) @@ -30,9 +29,8 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D type DeleteCommand struct { cmd.Base - force cmd.OptionalBool - id string - manifest manifest.Data + force cmd.OptionalBool + id string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/subscription/describe.go b/pkg/commands/tls/subscription/describe.go index a10f6b625..229ad55f0 100644 --- a/pkg/commands/tls/subscription/describe.go +++ b/pkg/commands/tls/subscription/describe.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) var include = []string{"tls_authorizations", "tls_authorizations.globalsign_email_challenge"} // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Show a TLS subscription").Alias("get") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS subscription").Required().StringVar(&c.id) @@ -35,9 +34,8 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - id string - include string - manifest manifest.Data + id string + include string } // Exec invokes the application logic for the command. diff --git a/pkg/commands/tls/subscription/list.go b/pkg/commands/tls/subscription/list.go index dcd4d300a..9589423c6 100644 --- a/pkg/commands/tls/subscription/list.go +++ b/pkg/commands/tls/subscription/list.go @@ -4,22 +4,21 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) var states = []string{"pending", "processing", "issued", "renewing"} // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all TLS subscriptions") c.Globals = g - c.manifest = m // Optional. c.CmdClause.Flag("filter-active", "Limit the returned subscriptions to those that have currently active orders").BoolVar(&c.filterHasActiveOrder) @@ -43,7 +42,6 @@ type ListCommand struct { filterState string filterTLSDomainID string include string - manifest manifest.Data pageNumber int pageSize int sort string diff --git a/pkg/commands/tls/subscription/subscription_test.go b/pkg/commands/tls/subscription/subscription_test.go index 48f0f0744..f600f46f3 100644 --- a/pkg/commands/tls/subscription/subscription_test.go +++ b/pkg/commands/tls/subscription/subscription_test.go @@ -3,12 +3,15 @@ package subscription_test import ( "bytes" "fmt" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) const ( @@ -59,9 +62,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -102,9 +108,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -152,9 +161,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -199,9 +211,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -248,9 +263,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) diff --git a/pkg/commands/tls/subscription/update.go b/pkg/commands/tls/subscription/update.go index 155dcda29..e983ee55e 100644 --- a/pkg/commands/tls/subscription/update.go +++ b/pkg/commands/tls/subscription/update.go @@ -3,19 +3,18 @@ package subscription import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command("update", "Change the TLS domains or common name associated with this subscription, or update the TLS configuration for this set of domains") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("id", "Alphanumeric string identifying a TLS subscription").Required().StringVar(&c.id) @@ -38,7 +37,6 @@ type UpdateCommand struct { domains []string force cmd.OptionalBool id string - manifest manifest.Data } // Exec invokes the application logic for the command. diff --git a/pkg/commands/update/root.go b/pkg/commands/update/root.go index 03a76f404..3a9ed90d5 100644 --- a/pkg/commands/update/root.go +++ b/pkg/commands/update/root.go @@ -10,7 +10,6 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/filesystem" - "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/revision" "github.com/fastly/cli/pkg/text" @@ -20,17 +19,13 @@ import ( // It should be installed under the primary root command. type RootCommand struct { cmd.Base - av github.AssetVersioner - configFilePath string } // NewRootCommand returns a new command registered in the parent. -func NewRootCommand(parent cmd.Registerer, configFilePath string, av github.AssetVersioner, g *global.Data) *RootCommand { +func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { var c RootCommand c.Globals = g c.CmdClause = parent.Command("update", "Update the CLI to the latest version") - c.av = av - c.configFilePath = configFilePath return &c } @@ -47,7 +42,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { ) err = spinner.Process("Updating versioning information", func(_ *text.SpinnerWrapper) error { - current, latest, shouldUpdate = Check(revision.AppVersion, c.av) + current, latest, shouldUpdate = Check(revision.AppVersion, c.Globals.Versioners.CLI) return nil }) if err != nil { @@ -66,7 +61,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { var downloadedBin string err = spinner.Process("Fetching latest release", func(_ *text.SpinnerWrapper) error { - downloadedBin, err = c.av.DownloadLatest() + downloadedBin, err = c.Globals.Versioners.CLI.DownloadLatest() if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Current CLI version": current, diff --git a/pkg/commands/user/create.go b/pkg/commands/user/create.go index 55c6826ee..2d65b001d 100644 --- a/pkg/commands/user/create.go +++ b/pkg/commands/user/create.go @@ -3,21 +3,18 @@ package user import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { var c CreateCommand c.CmdClause = parent.Command("create", "Create a user of the Fastly API and web interface").Alias("add") c.Globals = g - c.manifest = m // Required. c.CmdClause.Flag("login", "The login associated with the user (typically, an email address)").Action(c.login.Set).StringVar(&c.login.Value) @@ -32,7 +29,6 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C // CreateCommand calls the Fastly API to create an appropriate resource. type CreateCommand struct { cmd.Base - manifest manifest.Data login cmd.OptionalString name cmd.OptionalString @@ -41,11 +37,6 @@ type CreateCommand struct { // Exec invokes the application logic for the command. func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - input := c.constructInput() r, err := c.Globals.APIClient.CreateUser(input) diff --git a/pkg/commands/user/delete.go b/pkg/commands/user/delete.go index 67892e3e8..1cfbb785b 100644 --- a/pkg/commands/user/delete.go +++ b/pkg/commands/user/delete.go @@ -3,21 +3,18 @@ package user import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, globals *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, globals *global.Data) *DeleteCommand { var c DeleteCommand c.CmdClause = parent.Command("delete", "Delete a user of the Fastly API and web interface").Alias("remove") c.Globals = globals - c.manifest = m c.CmdClause.Flag("id", "Alphanumeric string identifying the user").Required().StringVar(&c.id) return &c } @@ -26,17 +23,11 @@ func NewDeleteCommand(parent cmd.Registerer, globals *global.Data, m manifest.Da type DeleteCommand struct { cmd.Base - id string - manifest manifest.Data + id string } // Exec invokes the application logic for the command. func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - input := c.constructInput() err := c.Globals.APIClient.DeleteUser(input) diff --git a/pkg/commands/user/describe.go b/pkg/commands/user/describe.go index f5d61313d..cfe4b9d07 100644 --- a/pkg/commands/user/describe.go +++ b/pkg/commands/user/describe.go @@ -4,20 +4,18 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Get a specific user of the Fastly API and web interface").Alias("get") c.Globals = g - c.manifest = m c.CmdClause.Flag("current", "Get the logged in user").BoolVar(&c.current) c.CmdClause.Flag("id", "Alphanumeric string identifying the user").StringVar(&c.id) c.RegisterFlagBool(c.JSONFlag()) // --json @@ -29,18 +27,12 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - current bool - id string - manifest manifest.Data + current bool + id string } // Exec invokes the application logic for the command. func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } - if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } diff --git a/pkg/commands/user/list.go b/pkg/commands/user/list.go index d2a28cabf..402ddc198 100644 --- a/pkg/commands/user/list.go +++ b/pkg/commands/user/list.go @@ -4,21 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List all users from a specified customer id") c.Globals = g - c.manifest = m c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagCustomerIDName, Description: cmd.FlagCustomerIDDesc, @@ -35,15 +33,10 @@ type ListCommand struct { cmd.JSONOutput customerID cmd.OptionalCustomerID - manifest manifest.Data } // Exec invokes the application logic for the command. func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return fsterr.ErrNoToken - } if c.Globals.Verbose() && c.JSONOutput.Enabled { return fsterr.ErrInvalidVerboseJSONCombo } diff --git a/pkg/commands/user/update.go b/pkg/commands/user/update.go index 75daf2a3f..068ae92a8 100644 --- a/pkg/commands/user/update.go +++ b/pkg/commands/user/update.go @@ -4,21 +4,18 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command("update", "Update a user of the Fastly API and web interface") c.Globals = g - c.manifest = m c.CmdClause.Flag("id", "Alphanumeric string identifying the user").StringVar(&c.id) c.CmdClause.Flag("login", "The login associated with the user (typically, an email address)").StringVar(&c.login) c.CmdClause.Flag("name", "The real life name of the user").StringVar(&c.name) @@ -32,21 +29,15 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U type UpdateCommand struct { cmd.Base - id string - login string - manifest manifest.Data - name string - reset bool - role string + id string + login string + name string + reset bool + role string } // Exec invokes the application logic for the command. func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { - _, s := c.Globals.Token() - if s == lookup.SourceUndefined { - return errors.ErrNoToken - } - if c.reset { input, err := c.constructInputReset() if err != nil { diff --git a/pkg/commands/user/user_test.go b/pkg/commands/user/user_test.go index 479d92840..dff1f93f1 100644 --- a/pkg/commands/user/user_test.go +++ b/pkg/commands/user/user_test.go @@ -3,12 +3,13 @@ package user_test import ( "bytes" "fmt" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" - "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -23,7 +24,7 @@ func TestCreate(t *testing.T) { return nil, testutil.Err }, }, - Args: args("user create --login foo@example.com --name foobar --token 123"), + Args: args("user create --login foo@example.com --name foobar"), WantError: testutil.Err.Error(), }, { @@ -36,7 +37,7 @@ func TestCreate(t *testing.T) { }, nil }, }, - Args: args("user create --login foo@example.com --name foobar --token 123"), + Args: args("user create --login foo@example.com --name foobar"), WantOutput: "Created user 'foobar' (role: user)", }, } @@ -45,9 +46,12 @@ func TestCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -62,11 +66,6 @@ func TestDelete(t *testing.T) { Args: args("user delete"), WantError: "error parsing arguments: required flag --id not provided", }, - { - Name: "validate missing --token flag", - Args: args("user delete --id foo123"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate DeleteUser API error", API: mock.API{ @@ -74,7 +73,7 @@ func TestDelete(t *testing.T) { return testutil.Err }, }, - Args: args("user delete --id foo123 --token 123"), + Args: args("user delete --id foo123"), WantError: testutil.Err.Error(), }, { @@ -84,7 +83,7 @@ func TestDelete(t *testing.T) { return nil }, }, - Args: args("user delete --id foo123 --token 123"), + Args: args("user delete --id foo123"), WantOutput: "Deleted user (id: foo123)", }, } @@ -93,9 +92,12 @@ func TestDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -105,14 +107,9 @@ func TestDelete(t *testing.T) { func TestDescribe(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing --token flag", - Args: args("user describe"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate missing --id flag", - Args: args("user describe --token 123"), + Args: args("user describe"), WantError: "error parsing arguments: must provide --id flag", }, { @@ -122,7 +119,7 @@ func TestDescribe(t *testing.T) { return nil, testutil.Err }, }, - Args: args("user describe --id 123 --token 123"), + Args: args("user describe --id 123"), WantError: testutil.Err.Error(), }, { @@ -132,7 +129,7 @@ func TestDescribe(t *testing.T) { return nil, testutil.Err }, }, - Args: args("user describe --current --token 123"), + Args: args("user describe --current"), WantError: testutil.Err.Error(), }, { @@ -140,7 +137,7 @@ func TestDescribe(t *testing.T) { API: mock.API{ GetUserFn: getUser, }, - Args: args("user describe --id 123 --token 123"), + Args: args("user describe --id 123"), WantOutput: describeUserOutput(), }, { @@ -148,7 +145,7 @@ func TestDescribe(t *testing.T) { API: mock.API{ GetCurrentUserFn: getCurrentUser, }, - Args: args("user describe --current --token 123"), + Args: args("user describe --current"), WantOutput: describeCurrentUserOutput(), }, } @@ -157,9 +154,12 @@ func TestDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -169,14 +169,9 @@ func TestDescribe(t *testing.T) { func TestList(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing --token flag", - Args: args("user list --customer-id abc"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate missing --customer-id flag", - Args: args("user list --token 123"), + Args: args("user list"), WantError: "error reading customer ID: no customer ID found", }, { @@ -186,7 +181,7 @@ func TestList(t *testing.T) { return nil, testutil.Err }, }, - Args: args("user list --customer-id abc --token 123"), + Args: args("user list --customer-id abc"), WantError: testutil.Err.Error(), }, { @@ -194,7 +189,7 @@ func TestList(t *testing.T) { API: mock.API{ ListCustomerUsersFn: listUsers, }, - Args: args("user list --customer-id abc --token 123"), + Args: args("user list --customer-id abc"), WantOutput: listOutput(), }, { @@ -202,7 +197,7 @@ func TestList(t *testing.T) { API: mock.API{ ListCustomerUsersFn: listUsers, }, - Args: args("user list --customer-id abc --token 123 --verbose"), + Args: args("user list --customer-id abc --verbose"), WantOutput: listVerboseOutput(), }, } @@ -211,9 +206,12 @@ func TestList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -223,29 +221,24 @@ func TestList(t *testing.T) { func TestUpdate(t *testing.T) { args := testutil.Args scenarios := []testutil.TestScenario{ - { - Name: "validate missing --token flag", - Args: args("user update --id 123"), - WantError: errors.ErrNoToken.Inner.Error(), - }, { Name: "validate missing --id flag", - Args: args("user update --token 123"), + Args: args("user update"), WantError: "error parsing arguments: must provide --id flag", }, { Name: "validate missing --name and --role flags", - Args: args("user update --id 123 --token 123"), + Args: args("user update --id 123"), WantError: "error parsing arguments: must provide either the --name or --role with the --id flag", }, { Name: "validate missing --login flag with --password-reset", - Args: args("user update --password-reset --token 123"), + Args: args("user update --password-reset"), WantError: "error parsing arguments: must provide --login when requesting a password reset", }, { Name: "validate invalid --role value", - Args: args("user update --id 123 --role foobar --token 123"), + Args: args("user update --id 123 --role foobar"), WantError: "error parsing arguments: enum value must be one of user,billing,engineer,superuser, got 'foobar'", }, { @@ -255,7 +248,7 @@ func TestUpdate(t *testing.T) { return nil, testutil.Err }, }, - Args: args("user update --id 123 --name foo --token 123"), + Args: args("user update --id 123 --name foo"), WantError: testutil.Err.Error(), }, { @@ -265,7 +258,7 @@ func TestUpdate(t *testing.T) { return testutil.Err }, }, - Args: args("user update --id 123 --login foo@example.com --password-reset --token 123"), + Args: args("user update --id 123 --login foo@example.com --password-reset"), WantError: testutil.Err.Error(), }, { @@ -279,7 +272,7 @@ func TestUpdate(t *testing.T) { }, nil }, }, - Args: args("user update --id 123 --name foo --role engineer --token 123"), + Args: args("user update --id 123 --name foo --role engineer"), WantOutput: "Updated user 'foo' (role: engineer)", }, { @@ -289,7 +282,7 @@ func TestUpdate(t *testing.T) { return nil }, }, - Args: args("user update --id 123 --login foo@example.com --password-reset --token 123"), + Args: args("user update --id 123 --login foo@example.com --password-reset"), WantOutput: "Reset user password (login: foo@example.com)", }, } @@ -298,9 +291,12 @@ func TestUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -407,8 +403,8 @@ bar@example.com bar superuser false current123 } func listVerboseOutput() string { - return fmt.Sprintf(`Fastly API token provided via --token -Fastly API endpoint: https://api.fastly.com + return fmt.Sprintf(`Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) %s%s`, describeUserOutput(), describeCurrentUserOutput()) } diff --git a/pkg/commands/vcl/condition/condition_test.go b/pkg/commands/vcl/condition/condition_test.go index c9c25fe09..20ce9bf3f 100644 --- a/pkg/commands/vcl/condition/condition_test.go +++ b/pkg/commands/vcl/condition/condition_test.go @@ -3,12 +3,14 @@ package condition_test import ( "bytes" "errors" + "io" "strings" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -43,9 +45,12 @@ func TestConditionCreate(t *testing.T) { for _, testcase := range scenarios { t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -82,9 +87,12 @@ func TestConditionDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -130,9 +138,12 @@ func TestConditionUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -167,9 +178,12 @@ func TestConditionDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -232,9 +246,12 @@ func TestConditionList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertString(t, testcase.WantOutput, stdout.String()) }) @@ -257,8 +274,8 @@ SERVICE VERSION NAME STATEMENT TYPE PRIORITY `) + "\n" var listConditionsVerboseOutput = strings.TrimSpace(` -Fastly API token not provided Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Service ID (via --service-id): 123 diff --git a/pkg/commands/vcl/condition/create.go b/pkg/commands/vcl/condition/create.go index 16423d8ce..db9fa4c45 100644 --- a/pkg/commands/vcl/condition/create.go +++ b/pkg/commands/vcl/condition/create.go @@ -8,7 +8,6 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) @@ -19,7 +18,6 @@ var ConditionTypes = []string{"REQUEST", "CACHE", "RESPONSE", "PREFETCH"} // CreateCommand calls the Fastly API to create an appropriate resource. type CreateCommand struct { cmd.Base - manifest manifest.Data // Required. serviceVersion cmd.OptionalServiceVersion @@ -34,12 +32,11 @@ type CreateCommand struct { } // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a condition on a Fastly service version").Alias("add") @@ -63,7 +60,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -81,7 +78,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/condition/delete.go b/pkg/commands/vcl/condition/delete.go index 1cd433f3b..9158a6439 100644 --- a/pkg/commands/vcl/condition/delete.go +++ b/pkg/commands/vcl/condition/delete.go @@ -3,18 +3,17 @@ package condition import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // DeleteCommand calls the Fastly API to delete an appropriate resource. type DeleteCommand struct { cmd.Base - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -22,12 +21,11 @@ type DeleteCommand struct { } // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a condition on a Fastly service version").Alias("remove") @@ -48,7 +46,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -66,7 +64,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/condition/describe.go b/pkg/commands/vcl/condition/describe.go index 55e3e2e89..8112be201 100644 --- a/pkg/commands/vcl/condition/describe.go +++ b/pkg/commands/vcl/condition/describe.go @@ -9,25 +9,22 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" ) // DescribeCommand calls the Fastly API to describe an appropriate resource. type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { var c DescribeCommand c.CmdClause = parent.Command("describe", "Show detailed information about a condition on a Fastly service version").Alias("get") c.Globals = g - c.manifest = m // Required flags c.CmdClause.Flag("name", "Name of condition").Short('n').Required().StringVar(&c.name) @@ -44,7 +41,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -66,7 +63,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/condition/list.go b/pkg/commands/vcl/condition/list.go index affc20eb2..98774aa59 100644 --- a/pkg/commands/vcl/condition/list.go +++ b/pkg/commands/vcl/condition/list.go @@ -4,12 +4,12 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // ListCommand calls the Fastly API to list appropriate resources. @@ -17,17 +17,15 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, data manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { var c ListCommand c.CmdClause = parent.Command("list", "List condition on a Fastly service version") c.Globals = g - c.manifest = data // Required flags c.RegisterFlag(cmd.StringFlagOpts{ @@ -41,7 +39,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, data manifest.Data) * c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -63,7 +61,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/condition/update.go b/pkg/commands/vcl/condition/update.go index 895fd8788..514ade8aa 100644 --- a/pkg/commands/vcl/condition/update.go +++ b/pkg/commands/vcl/condition/update.go @@ -9,14 +9,12 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // UpdateCommand calls the Fastly API to update an appropriate resource. type UpdateCommand struct { cmd.Base - manifest manifest.Data input fastly.UpdateConditionInput serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -30,11 +28,10 @@ type UpdateCommand struct { } // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, globals *global.Data, data manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { var c UpdateCommand c.CmdClause = parent.Command("update", "Update a condition on a Fastly service version") - c.Globals = globals - c.manifest = data + c.Globals = g // Required flags c.CmdClause.Flag("name", "Domain name").Short('n').Required().StringVar(&c.input.Name) @@ -59,7 +56,7 @@ func NewUpdateCommand(parent cmd.Registerer, globals *global.Data, data manifest c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -77,7 +74,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/custom/create.go b/pkg/commands/vcl/custom/create.go index b1545f6ed..1dfc30187 100644 --- a/pkg/commands/vcl/custom/create.go +++ b/pkg/commands/vcl/custom/create.go @@ -3,21 +3,20 @@ package custom import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Upload a VCL for a particular service and version").Alias("add") @@ -40,7 +39,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -60,7 +59,6 @@ type CreateCommand struct { autoClone cmd.OptionalAutoClone content cmd.OptionalString main cmd.OptionalBool - manifest manifest.Data name cmd.OptionalString serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -71,7 +69,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/custom/custom_test.go b/pkg/commands/vcl/custom/custom_test.go index 2bb54deed..7c4ffd3a9 100644 --- a/pkg/commands/vcl/custom/custom_test.go +++ b/pkg/commands/vcl/custom/custom_test.go @@ -2,12 +2,15 @@ package custom_test import ( "bytes" + "io" "testing" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" - "github.com/fastly/go-fastly/v8/fastly" ) func TestVCLCustomCreate(t *testing.T) { @@ -157,9 +160,12 @@ func TestVCLCustomCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) testutil.AssertPathContentFlag("content", testcase.WantError, testcase.Args, "example.vcl", content, t) @@ -233,9 +239,12 @@ func TestVCLCustomDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -295,9 +304,12 @@ func TestVCLCustomDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -353,7 +365,7 @@ func TestVCLCustomList(t *testing.T) { ListVCLsFn: listVCLs, }, Args: args("vcl custom list --service-id 123 --verbose --version 1"), - WantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\nMain: true\nContent: \n# some vcl content\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\nMain: false\nContent: \n# some vcl content\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", + WantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\nMain: true\nContent: \n# some vcl content\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\nMain: false\nContent: \n# some vcl content\n\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", }, } @@ -361,9 +373,12 @@ func TestVCLCustomList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -472,9 +487,12 @@ func TestVCLCustomUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) testutil.AssertPathContentFlag("content", testcase.WantError, testcase.Args, "example.vcl", content, t) diff --git a/pkg/commands/vcl/custom/delete.go b/pkg/commands/vcl/custom/delete.go index c193306e4..4c546af25 100644 --- a/pkg/commands/vcl/custom/delete.go +++ b/pkg/commands/vcl/custom/delete.go @@ -3,21 +3,20 @@ package custom import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete the uploaded VCL for a particular service and version").Alias("remove") @@ -38,7 +37,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -56,7 +55,6 @@ type DeleteCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -67,7 +65,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/custom/describe.go b/pkg/commands/vcl/custom/describe.go index 2a2327ff1..c7457a537 100644 --- a/pkg/commands/vcl/custom/describe.go +++ b/pkg/commands/vcl/custom/describe.go @@ -4,20 +4,19 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Get the uploaded VCL for a particular service and version").Alias("get") @@ -35,7 +34,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type DescribeCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -68,7 +66,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/custom/list.go b/pkg/commands/vcl/custom/list.go index 4faa3d688..766635229 100644 --- a/pkg/commands/vcl/custom/list.go +++ b/pkg/commands/vcl/custom/list.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List the uploaded VCLs for a particular service and version") @@ -35,7 +34,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/custom/update.go b/pkg/commands/vcl/custom/update.go index df0a8d5f0..18f9aa2fd 100644 --- a/pkg/commands/vcl/custom/update.go +++ b/pkg/commands/vcl/custom/update.go @@ -9,17 +9,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update the uploaded VCL for a particular service and version") @@ -42,7 +40,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -61,7 +59,6 @@ type UpdateCommand struct { autoClone cmd.OptionalAutoClone content cmd.OptionalString - manifest manifest.Data name string newName cmd.OptionalString serviceName cmd.OptionalServiceNameID @@ -73,7 +70,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/snippet/create.go b/pkg/commands/vcl/snippet/create.go index 6114e041e..fedd93951 100644 --- a/pkg/commands/vcl/snippet/create.go +++ b/pkg/commands/vcl/snippet/create.go @@ -3,24 +3,23 @@ package snippet import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // Locations is a list of VCL subroutines. var Locations = []string{"init", "recv", "hash", "hit", "miss", "pass", "fetch", "error", "deliver", "log", "none"} // NewCreateCommand returns a usable command registered under the parent. -func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *CreateCommand { +func NewCreateCommand(parent cmd.Registerer, g *global.Data) *CreateCommand { c := CreateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("create", "Create a snippet for a particular service and version").Alias("add") @@ -45,7 +44,7 @@ func NewCreateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *C c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -67,7 +66,6 @@ type CreateCommand struct { content cmd.OptionalString dynamic cmd.OptionalBool location cmd.OptionalString - manifest manifest.Data name cmd.OptionalString priority cmd.OptionalInt serviceName cmd.OptionalServiceNameID @@ -79,7 +77,7 @@ func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/snippet/delete.go b/pkg/commands/vcl/snippet/delete.go index 911be7d8f..552d1acb9 100644 --- a/pkg/commands/vcl/snippet/delete.go +++ b/pkg/commands/vcl/snippet/delete.go @@ -3,21 +3,20 @@ package snippet import ( "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewDeleteCommand returns a usable command registered under the parent. -func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DeleteCommand { +func NewDeleteCommand(parent cmd.Registerer, g *global.Data) *DeleteCommand { c := DeleteCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("delete", "Delete a specific snippet for a particular service and version").Alias("remove") @@ -38,7 +37,7 @@ func NewDeleteCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *D c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -56,7 +55,6 @@ type DeleteCommand struct { cmd.Base autoClone cmd.OptionalAutoClone - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -67,7 +65,7 @@ func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/snippet/describe.go b/pkg/commands/vcl/snippet/describe.go index ccc69fc0c..baf1b2ba0 100644 --- a/pkg/commands/vcl/snippet/describe.go +++ b/pkg/commands/vcl/snippet/describe.go @@ -9,16 +9,14 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" ) // NewDescribeCommand returns a usable command registered under the parent. -func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *DescribeCommand { +func NewDescribeCommand(parent cmd.Registerer, g *global.Data) *DescribeCommand { c := DescribeCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("describe", "Get the uploaded VCL snippet for a particular service and version").Alias("get") @@ -37,7 +35,7 @@ func NewDescribeCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -57,7 +55,6 @@ type DescribeCommand struct { cmd.JSONOutput dynamic cmd.OptionalBool - manifest manifest.Data name string serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion @@ -73,7 +70,7 @@ func (c *DescribeCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/snippet/list.go b/pkg/commands/vcl/snippet/list.go index 2a1d1d830..3c1e22ca0 100644 --- a/pkg/commands/vcl/snippet/list.go +++ b/pkg/commands/vcl/snippet/list.go @@ -4,21 +4,20 @@ import ( "fmt" "io" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" - "github.com/fastly/go-fastly/v8/fastly" ) // NewListCommand returns a usable command registered under the parent. -func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *ListCommand { +func NewListCommand(parent cmd.Registerer, g *global.Data) *ListCommand { c := ListCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("list", "List the uploaded VCL snippets for a particular service and version") @@ -35,7 +34,7 @@ func NewListCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Lis c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -53,7 +52,6 @@ type ListCommand struct { cmd.Base cmd.JSONOutput - manifest manifest.Data serviceName cmd.OptionalServiceNameID serviceVersion cmd.OptionalServiceVersion } @@ -67,7 +65,7 @@ func (c *ListCommand) Exec(_ io.Reader, out io.Writer) error { serviceID, serviceVersion, err := cmd.ServiceDetails(cmd.ServiceDetailsOpts{ AllowActiveLocked: true, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/vcl/snippet/snippet_test.go b/pkg/commands/vcl/snippet/snippet_test.go index f42ad410f..bfd5062d1 100644 --- a/pkg/commands/vcl/snippet/snippet_test.go +++ b/pkg/commands/vcl/snippet/snippet_test.go @@ -2,11 +2,13 @@ package snippet_test import ( "bytes" + "io" "testing" "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" ) @@ -192,9 +194,12 @@ func TestVCLSnippetCreate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, testutil.StripNewLines(stdout.String()), testcase.WantOutput) @@ -269,9 +274,12 @@ func TestVCLSnippetDelete(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -351,9 +359,12 @@ func TestVCLSnippetDescribe(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -409,7 +420,7 @@ func TestVCLSnippetList(t *testing.T) { ListSnippetsFn: listSnippets, }, Args: args("vcl snippet list --service-id 123 --verbose --version 1"), - WantOutput: "Fastly API token not provided\nFastly API endpoint: https://api.fastly.com\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\nID: abc\nPriority: 0\nDynamic: true\nType: recv\nContent: \n# some vcl content\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\nID: abc\nPriority: 0\nDynamic: false\nType: recv\nContent: \n# some vcl content\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", + WantOutput: "Fastly API endpoint: https://api.fastly.com\nFastly API token provided via config file (profile: user)\n\nService ID (via --service-id): 123\n\nService Version: 1\n\nName: foo\nID: abc\nPriority: 0\nDynamic: true\nType: recv\nContent: \n# some vcl content\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n\nName: bar\nID: abc\nPriority: 0\nDynamic: false\nType: recv\nContent: \n# some vcl content\nCreated at: 2021-06-15 23:00:00 +0000 UTC\nUpdated at: 2021-06-15 23:00:00 +0000 UTC\nDeleted at: 2021-06-15 23:00:00 +0000 UTC\n", }, } @@ -417,9 +428,12 @@ func TestVCLSnippetList(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, stdout.String(), testcase.WantOutput) }) @@ -558,9 +572,12 @@ func TestVCLSnippetUpdate(t *testing.T) { testcase := &scenarios[testcaseIdx] t.Run(testcase.Name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.Args, &stdout) - opts.APIClient = mock.APIClient(testcase.API) - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + opts := testutil.MockGlobalData(testcase.Args, &stdout) + opts.APIClientFactory = mock.APIClient(testcase.API) + return opts, nil + } + err := app.Run(testcase.Args, nil) testutil.AssertErrorContains(t, err, testcase.WantError) testutil.AssertStringContains(t, testutil.StripNewLines(stdout.String()), testcase.WantOutput) testutil.AssertPathContentFlag("content", testcase.WantError, testcase.Args, "snippet.vcl", content, t) diff --git a/pkg/commands/vcl/snippet/update.go b/pkg/commands/vcl/snippet/update.go index fa9d444f4..b62c1c0a1 100644 --- a/pkg/commands/vcl/snippet/update.go +++ b/pkg/commands/vcl/snippet/update.go @@ -9,17 +9,15 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" ) // NewUpdateCommand returns a usable command registered under the parent. -func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *UpdateCommand { +func NewUpdateCommand(parent cmd.Registerer, g *global.Data) *UpdateCommand { c := UpdateCommand{ Base: cmd.Base{ Globals: g, }, - manifest: m, } c.CmdClause = parent.Command("update", "Update a VCL snippet for a particular service and version") @@ -44,7 +42,7 @@ func NewUpdateCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *U c.RegisterFlag(cmd.StringFlagOpts{ Name: cmd.FlagServiceIDName, Description: cmd.FlagServiceIDDesc, - Dst: &c.manifest.Flag.ServiceID, + Dst: &g.Manifest.Flag.ServiceID, Short: 's', }) c.RegisterFlag(cmd.StringFlagOpts{ @@ -69,7 +67,6 @@ type UpdateCommand struct { content cmd.OptionalString dynamic cmd.OptionalBool location cmd.OptionalString - manifest manifest.Data name string newName cmd.OptionalString priority cmd.OptionalInt @@ -84,7 +81,7 @@ func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { AllowActiveLocked: c.dynamic.WasSet && c.dynamic.Value, AutoCloneFlag: c.autoClone, APIClient: c.Globals.APIClient, - Manifest: c.manifest, + Manifest: *c.Globals.Manifest, Out: out, ServiceNameFlag: c.serviceName, ServiceVersionFlag: c.serviceVersion, diff --git a/pkg/commands/version/root.go b/pkg/commands/version/root.go index e03485af6..5b72d78da 100644 --- a/pkg/commands/version/root.go +++ b/pkg/commands/version/root.go @@ -11,6 +11,7 @@ import ( "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/github" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/revision" "github.com/fastly/cli/pkg/useragent" ) @@ -27,13 +28,15 @@ func init() { // It should be installed under the primary root command. type RootCommand struct { cmd.Base - viceroyVersioner github.AssetVersioner } // NewRootCommand returns a new command registered in the parent. -func NewRootCommand(parent cmd.Registerer, viceroyVersioner github.AssetVersioner) *RootCommand { - var c RootCommand - c.viceroyVersioner = viceroyVersioner +func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { + c := RootCommand{ + Base: cmd.Base{ + Globals: g, + }, + } c.CmdClause = parent.Command("version", "Display version information for the Fastly CLI") return &c } @@ -43,7 +46,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { fmt.Fprintf(out, "Fastly CLI version %s (%s)\n", revision.AppVersion, revision.GitCommit) fmt.Fprintf(out, "Built with %s\n", revision.GoVersion) - viceroy := filepath.Join(github.InstallDir, c.viceroyVersioner.BinaryName()) + viceroy := filepath.Join(github.InstallDir, c.Globals.Versioners.Viceroy.BinaryName()) // gosec flagged this: // G204 (CWE-78): Subprocess launched with variable // Disabling as we lookup the binary in a trusted location. For this to be a diff --git a/pkg/commands/version/version_test.go b/pkg/commands/version/version_test.go index 59339b5ec..2cdaa9077 100644 --- a/pkg/commands/version/version_test.go +++ b/pkg/commands/version/version_test.go @@ -3,6 +3,7 @@ package version_test import ( "bytes" "fmt" + "io" "os" "path/filepath" "runtime" @@ -11,6 +12,7 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/github" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/testutil" ) @@ -66,15 +68,18 @@ func TestVersion(t *testing.T) { var stdout bytes.Buffer args := testutil.Args("version") - opts := testutil.NewRunOpts(args, &stdout) - opts.Versioners = app.Versioners{ + opts := testutil.MockGlobalData(args, &stdout) + opts.Versioners = global.Versioners{ Viceroy: github.New(github.Opts{ Org: "fastly", Repo: "viceroy", Binary: "viceroy", }), } - err = app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err = app.Run(args, nil) t.Log(stdout.String()) diff --git a/pkg/commands/whoami/root.go b/pkg/commands/whoami/root.go index 152841343..702111258 100644 --- a/pkg/commands/whoami/root.go +++ b/pkg/commands/whoami/root.go @@ -6,12 +6,11 @@ import ( "io" "net/http" "sort" - "strings" + "strconv" + "github.com/fastly/cli/pkg/api/undocumented" "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/lookup" "github.com/fastly/cli/pkg/useragent" ) @@ -31,34 +30,34 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { // Exec implements the command interface. func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { - endpoint, _ := c.Globals.Endpoint() - fullurl := fmt.Sprintf("%s/verify", strings.TrimSuffix(endpoint, "/")) - req, err := http.NewRequest("GET", fullurl, nil) - if err != nil { - return fmt.Errorf("error constructing API request: %w", err) - } - - token, source := c.Globals.Token() - if source == lookup.SourceUndefined { - return errors.ErrNoToken - } - - req.Header.Set("Fastly-Key", token) - req.Header.Set("Accept", "application/json") - req.Header.Set("User-Agent", useragent.Name) - resp, err := c.Globals.HTTPClient.Do(req) + debugMode, _ := strconv.ParseBool(c.Globals.Env.DebugMode) + token, _ := c.Globals.Token() + apiEndpoint, _ := c.Globals.APIEndpoint() + data, err := undocumented.Call(undocumented.CallOptions{ + APIEndpoint: apiEndpoint, + HTTPClient: c.Globals.HTTPClient, + HTTPHeaders: []undocumented.HTTPHeader{ + { + Key: "Accept", + Value: "application/json", + }, + { + Key: "User-Agent", + Value: useragent.Name, + }, + }, + Method: http.MethodGet, + Path: "/verify", + Token: token, + Debug: debugMode, + }) if err != nil { c.Globals.ErrLog.Add(err) return fmt.Errorf("error executing API request: %w", err) } - defer resp.Body.Close() // #nosec G307 - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("error from API: %s", resp.Status) - } var response VerifyResponse - if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { + if err := json.Unmarshal(data, &response); err != nil { c.Globals.ErrLog.Add(err) return fmt.Errorf("error decoding API response: %w", err) } diff --git a/pkg/commands/whoami/whoami_test.go b/pkg/commands/whoami/whoami_test.go index 7917fa72a..9cedbb8c2 100644 --- a/pkg/commands/whoami/whoami_test.go +++ b/pkg/commands/whoami/whoami_test.go @@ -2,9 +2,9 @@ package whoami_test import ( "bytes" - "encoding/json" "errors" "fmt" + "io" "net/http" "net/http/httptest" "strings" @@ -12,9 +12,9 @@ import ( "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/app" - "github.com/fastly/cli/pkg/commands/whoami" "github.com/fastly/cli/pkg/config" "github.com/fastly/cli/pkg/env" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/testutil" ) @@ -28,79 +28,67 @@ func TestWhoami(t *testing.T) { wantError string wantOutput string }{ - { - name: "no token", - args: args("whoami"), - client: verifyClient(basicResponse), - wantError: "no token provided", - }, { name: "basic response", - args: args("--token=x whoami"), - client: verifyClient(basicResponse), + args: args("whoami"), + client: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), wantOutput: basicOutput, }, { name: "basic response verbose", - args: args("--token=x whoami -v"), - client: verifyClient(basicResponse), + args: args("whoami -v"), + client: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), wantOutput: basicOutputVerbose, }, { name: "500 from API", - args: args("--token=x whoami"), + args: args("whoami"), client: codeClient{code: http.StatusInternalServerError}, - wantError: "error from API: 500 Internal Server Error", + wantError: "error executing API request: error response", }, { name: "local error", - args: args("--token=x whoami"), + args: args("whoami"), client: errorClient{err: errors.New("some network failure")}, wantError: "error executing API request: some network failure", }, { name: "alternative endpoint from flag", - args: args("--token=x whoami --endpoint=https://staging.fastly.com -v"), - client: verifyClient(basicResponse), + args: args("whoami --api=https://staging.fastly.com -v"), + client: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), wantOutput: strings.ReplaceAll(basicOutputVerbose, "Fastly API endpoint: https://api.fastly.com", - "Fastly API endpoint provided via --endpoint", + "Fastly API endpoint (via --api): https://staging.fastly.com", ), }, { name: "alternative endpoint from environment", - args: args("--token=x whoami -v"), - env: config.Environment{Endpoint: "https://alternative.example.com"}, - client: verifyClient(basicResponse), + args: args("whoami -v"), + env: config.Environment{APIEndpoint: "https://alternative.example.com"}, + client: testutil.WhoamiVerifyClient(testutil.WhoamiBasicResponse), wantOutput: strings.ReplaceAll(basicOutputVerbose, "Fastly API endpoint: https://api.fastly.com", - fmt.Sprintf("Fastly API endpoint (via %s): https://alternative.example.com", env.Endpoint), + fmt.Sprintf("Fastly API endpoint (via %s): https://alternative.example.com", env.APIEndpoint), ), }, } { t.Run(testcase.name, func(t *testing.T) { var stdout bytes.Buffer - opts := testutil.NewRunOpts(testcase.args, &stdout) + opts := testutil.MockGlobalData(testcase.args, &stdout) opts.Env = testcase.env opts.HTTPClient = testcase.client - err := app.Run(opts) + app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { + return opts, nil + } + err := app.Run(testcase.args, nil) + opts.Config = config.File{} + t.Log(stdout.String()) testutil.AssertErrorContains(t, err, testcase.wantError) testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) }) } } -type verifyClient whoami.VerifyResponse - -func (c verifyClient) Do(*http.Request) (*http.Response, error) { - rec := httptest.NewRecorder() - err := json.NewEncoder(rec).Encode(whoami.VerifyResponse(c)) - if err != nil { - return nil, fmt.Errorf("failed to encode response into json: %w", err) - } - return rec.Result(), nil -} - type codeClient struct { code int } @@ -119,34 +107,11 @@ func (c errorClient) Do(*http.Request) (*http.Response, error) { return nil, c.err } -var basicResponse = whoami.VerifyResponse{ - Customer: whoami.Customer{ - ID: "abc", - Name: "Computer Company", - }, - User: whoami.User{ - ID: "123", - Name: "Alice Programmer", - Login: "alice@example.com", - }, - Services: map[string]string{ - "1xxaa": "First service", - "2baba": "Second service", - }, - Token: whoami.Token{ - ID: "abcdefg", - Name: "Token name", - CreatedAt: "2019-01-01T12:00:00Z", - // no ExpiresAt - Scope: "global", - }, -} - var basicOutput = "Alice Programmer \n" var basicOutputVerbose = strings.TrimSpace(` -Fastly API token provided via --token Fastly API endpoint: https://api.fastly.com +Fastly API token provided via config file (profile: user) Customer ID: abc Customer name: Computer Company diff --git a/pkg/config/config.go b/pkg/config/config.go index 93af481b1..7d67cbe02 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -59,7 +59,8 @@ type LegacyUser struct { // Fastly represents fastly specific configuration. type Fastly struct { - APIEndpoint string `toml:"api_endpoint"` + APIEndpoint string `toml:"api_endpoint"` + AccountEndpoint string `toml:"account_endpoint"` } // WasmMetadata represents what metadata will be collected. @@ -139,9 +140,24 @@ type Profiles map[string]*Profile // Profile represents a specific profile account. type Profile struct { - Default bool `toml:"default" json:"default"` - Email string `toml:"email" json:"email"` - Token string `toml:"token" json:"token"` + // AccessToken is used to acquire an API token. + AccessToken string `toml:"access_token" json:"access_token"` + // AccessTokenCreated indicates when the access token was created. + AccessTokenCreated int64 `toml:"access_token_created" json:"access_token_created"` + // AccessTokenTTL indicates when the access token needs to be replaced. + AccessTokenTTL int `toml:"access_token_ttl" json:"access_token_ttl"` + // Default indicates if the profile is the default profile to use. + Default bool `toml:"default" json:"default"` + // Email is the email address associated with the token. + Email string `toml:"email" json:"email"` + // RefreshToken is used to acquire a new access token when it expires. + RefreshToken string `toml:"refresh_token" json:"refresh_token"` + // RefreshTokenCreated indicates when the refresh token was created. + RefreshTokenCreated int64 `toml:"refresh_token_created" json:"refresh_token_created"` + // RefreshTokenTTL indicates when the refresh token needs to be replaced. + RefreshTokenTTL int `toml:"refresh_token_ttl" json:"refresh_token_ttl"` + // Token is a temporary token used to interact with the Fastly API. + Token string `toml:"token" json:"token"` } // StarterKitLanguages represents language specific starter kits. @@ -211,11 +227,13 @@ type File struct { } // SetAutoYes sets the associated flag value. +// This controls how the interactive prompts are handled. func (f *File) SetAutoYes(v bool) { f.autoYes = v } // SetNonInteractive sets the associated flag value. +// This controls how the interactive prompts are handled. func (f *File) SetNonInteractive(v bool) { f.nonInteractive = v } @@ -424,10 +442,17 @@ func (f *File) Write(path string) error { // Environment represents all of the configuration parameters that can come // from environment variables. type Environment struct { - // Token is the env var we look in for the Fastly API token. - Token string - // Endpoint is the env var we look in for the API endpoint. - Endpoint string + // AccountEndpoint is the env var we look in for the Accounts endpoint. + AccountEndpoint string + // APIEndpoint is the API endpoint to call. + APIEndpoint string + // APIToken is the env var we look in for the Fastly API token. + APIToken string + // DebugMode indicates to the CLI it can display debug information. + DebugMode string + // UseSSO indicates if user wants to use SSO/OAuth token flow. + // 1: enabled, 0: disabled. + UseSSO string // WasmMetadataDisable is the env var we look in to disable all data // collection related to a Wasm binary. // Set to "true" to disable all forms of data collection. @@ -436,8 +461,11 @@ type Environment struct { // Read populates the fields from the provided environment. func (e *Environment) Read(state map[string]string) { - e.Token = state[env.Token] - e.Endpoint = state[env.Endpoint] + e.AccountEndpoint = state[env.AccountEndpoint] + e.APIEndpoint = state[env.APIEndpoint] + e.APIToken = state[env.APIToken] + e.DebugMode = state[env.DebugMode] + e.UseSSO = state[env.UseSSO] e.WasmMetadataDisable = state[env.WasmMetadataDisable] } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 0ff1f2cfe..20ab22858 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -229,8 +229,17 @@ func TestUseStatic(t *testing.T) { if strings.Contains(string(data), "[user]") { t.Error("expected legacy [user] section to be removed") } - if !strings.Contains(string(data), "[profile.user]\ndefault = true\nemail = \"testing@fastly.com\"\ntoken = \"foobar\"") { - t.Error("expected legacy [user] section to be migrated to [profile.user]") + if !strings.Contains(string(data), `[profile.user] +access_token = "" +access_token_created = 0 +access_token_ttl = 0 +default = true +email = "testing@fastly.com" +refresh_token = "" +refresh_token_created = 0 +refresh_token_ttl = 0 +token = "foobar"`) { + t.Errorf("expected legacy [user] section to be migrated to [profile.user]: %s", string(data)) } // Validate that invalid static configuration returns a specific error. diff --git a/pkg/env/env.go b/pkg/env/env.go index 86b150a66..dcf3643bc 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -9,21 +9,36 @@ import ( ) const ( - // Token is the env var we look in for the Fastly API token. + // AccountEndpoint is the env var we look in for the Accounts endpoint. + // e.g. https://accounts.fastly.com + AccountEndpoint = "FASTLY_ACCOUNT_ENDPOINT" + + // APIEndpoint is the env var we look in for the API endpoint. + // e.g. https://api.fastly.com + APIEndpoint = "FASTLY_API_ENDPOINT" + + // APIToken is the env var we look in for the Fastly API token. // gosec flagged this: // G101 (CWE-798): Potential hardcoded credentials // Disabling as we use the value in the command help output. - /* #nosec */ - Token = "FASTLY_API_TOKEN" + // #nosec + APIToken = "FASTLY_API_TOKEN" - // Endpoint is the env var we look in for the API endpoint. - Endpoint = "FASTLY_API_ENDPOINT" + // CustomerID is the env var we look in for a Customer ID. + CustomerID = "FASTLY_CUSTOMER_ID" + + // DebugMode indicates to the CLI it can display debug information. + // Set to "true" to enable debug mode. + DebugMode = "FASTLY_DEBUG_MODE" // ServiceID is the env var we look in for the required Service ID. ServiceID = "FASTLY_SERVICE_ID" - // CustomerID is the env var we look in for a Customer ID. - CustomerID = "FASTLY_CUSTOMER_ID" + // UseSSO enables the CLI to validate the token as an OAuth token. + // These tokens aren't traditional tokens generated by the UI. + // Instead they generated via an OAuth flow (producing access/refresh tokens). + // Assigned value should be a boolean 1/0 (enable/disable). + UseSSO = "FASTLY_USE_SSO" // WasmMetadataDisable is the env var we look in to disable all data // collection related to a Wasm binary. diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index b6f7d7869..33a634c44 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -15,6 +15,9 @@ var ErrSignalKilled = fmt.Errorf("a SIGTERM was received") // file modification noticed while running `compute serve --watch`. var ErrViceroyRestart = fmt.Errorf("a RESTART was initiated") +// ErrDontContinue means the user said "NO" when prompted whether to continue. +var ErrDontContinue = fmt.Errorf("will not continue") + // ErrIncompatibleServeFlags means no --skip-build can't be used with --watch // because it defeats the purpose of --watch which is designed to restart // Viceroy whenever changes are detected (those changes would not be seen if we @@ -155,6 +158,13 @@ var ErrInvalidStdinFileDirCombo = RemediationError{ Remediation: "Use only one of --stdin, --file or --dir.", } +// ErrInvalidProfileSSOCombo means the user specified both --sso and +// --automation-token and only one should be set. +var ErrInvalidProfileSSOCombo = RemediationError{ + Inner: fmt.Errorf("invalid command, both --sso and --automation-token provided"), + Remediation: "Provide at only one of: --sso or --automation-token, not both.", +} + // ErrInvalidEnableDisableFlagCombo means the user provided both a --enable // and --disable flag which are mutually exclusive behaviours. var ErrInvalidEnableDisableFlagCombo = RemediationError{ diff --git a/pkg/errors/remediation_error.go b/pkg/errors/remediation_error.go index b6b0aa163..008e6e325 100644 --- a/pkg/errors/remediation_error.go +++ b/pkg/errors/remediation_error.go @@ -57,7 +57,7 @@ var AuthRemediation = fmt.Sprintf(strings.Join([]string{ "Check that you're supplying a valid token, either via --token,", "through the environment variable %s, or through the config file via `fastly profile`.", "Verify that the token is still valid via `fastly whoami`.", -}, " "), env.Token) +}, " "), env.APIToken) // NetworkRemediation suggests, somewhat unhelpfully, to try again later. var NetworkRemediation = strings.Join([]string{ diff --git a/pkg/global/doc.go b/pkg/global/doc.go index e81c1e744..08ccb9a68 100644 --- a/pkg/global/doc.go +++ b/pkg/global/doc.go @@ -1,2 +1,3 @@ -// Package global defines data structures that are used globally. +// Package global exposes a type to contain global'ish data. +// Effectively we use it to avoid an unfortunate import loop issue. package global diff --git a/pkg/global/global.go b/pkg/global/global.go index 35afd303b..4918815a5 100644 --- a/pkg/global/global.go +++ b/pkg/global/global.go @@ -4,14 +4,33 @@ import ( "io" "github.com/fastly/cli/pkg/api" + "github.com/fastly/cli/pkg/auth" "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/lookup" "github.com/fastly/cli/pkg/manifest" ) -// DefaultEndpoint is the default Fastly API endpoint. -const DefaultEndpoint = "https://api.fastly.com" +// DefaultAPIEndpoint is the default Fastly API endpoint. +const DefaultAPIEndpoint = "https://api.fastly.com" + +// DefaultAccountEndpoint is the default Fastly Accounts endpoint. +const DefaultAccountEndpoint = "https://accounts.fastly.com" + +// APIClientFactory creates a Fastly API client (modeled as an api.Interface) +// from a user-provided API token. It exists as a type in order to parameterize +// the Run helper with it: in the real CLI, we can use NewClient from the Fastly +// API client library via RealClient; in tests, we can provide a mock API +// interface via MockClient. +type APIClientFactory func(token, apiEndpoint string, debugMode bool) (api.Interface, error) + +// Versioners represents all supported versioner types. +type Versioners struct { + CLI github.AssetVersioner + Viceroy github.AssetVersioner + WasmTools github.AssetVersioner +} // Data holds global-ish configuration data from all sources: environment // variables, config files, and flags. It has methods to give each parameter to @@ -27,31 +46,46 @@ const DefaultEndpoint = "https://api.fastly.com" // (e.g. an email address). Otherwise, parameters should be defined in specific // command structs, and parsed as flags. type Data struct { - // Env is all the data that is provided by the environment. - Env config.Environment + // APIClient is a Fastly API client instance. + APIClient api.Interface + // APIClientFactory is a factory function for creating an api.Interface type. + APIClientFactory APIClientFactory + // Args are the command line arguments provided by the user. + Args []string + // AuthServer is an instance of the authentication server type. + // Used for interacting with Fastly's SSO/OAuth authentication provider. + AuthServer auth.Runner // Config is an instance of the CLI configuration data. Config config.File // ConfigPath is the path to the CLI's application configuration. ConfigPath string + // Env is all the data that is provided by the environment. + Env config.Environment + // ErrLog provides an interface for recording errors to disk. + ErrLog fsterr.LogInterface // ExecuteWasmTools is a function that executes the wasm-tools binary. ExecuteWasmTools func(bin string, args []string) error // Flags are all the global CLI flags. Flags Flags - // Manifest is the fastly.toml manifest file. - Manifest manifest.Data - // Output is the output for displaying information (typically os.Stdout) - Output io.Writer - - // Custom interfaces - - // ErrLog provides an interface for recording errors to disk. - ErrLog fsterr.LogInterface - // APIClient is a Fastly API client instance. - APIClient api.Interface // HTTPClient is a HTTP client. HTTPClient api.HTTPClient + // Input is the standard input for accepting input from the user. + Input io.Reader + // Manifest represents the fastly.toml manifest file and associated flags. + Manifest *manifest.Data + // Opener is a function that can open a browser window. + Opener func(string) error + // Output is the output for displaying information (typically os.Stdout) + Output io.Writer // RTSClient is a Fastly API client instance for the Real Time Stats endpoints. RTSClient api.RealtimeStatsInterface + // SkipAuthPrompt is used to indicate to the `sso` command that the + // interactive prompt can be skipped. This is for scenarios where the command + // is executed directly by the user. + SkipAuthPrompt bool + // Versioners contains multiple software versioning checkers. + // e.g. Check for latest CLI or Viceroy version. + Versioners Versioners } // Token yields the Fastly API token. @@ -63,14 +97,17 @@ type Data struct { // - The `profile` manifest field's associated profile token. // - The 'default' profile associated token (if there is one). func (d *Data) Token() (string, lookup.Source) { + // --token if d.Flags.Token != "" { return d.Flags.Token, lookup.SourceFlag } - if d.Env.Token != "" { - return d.Env.Token, lookup.SourceEnvironment + // FASTLY_API_TOKEN + if d.Env.APIToken != "" { + return d.Env.APIToken, lookup.SourceEnvironment } + // --profile if d.Flags.Profile != "" { for k, v := range d.Config.Profiles { if k == d.Flags.Profile { @@ -79,6 +116,7 @@ func (d *Data) Token() (string, lookup.Source) { } } + // `profile` field in fastly.toml if d.Manifest.File.Profile != "" { for k, v := range d.Config.Profiles { if k == d.Manifest.File.Profile { @@ -87,6 +125,7 @@ func (d *Data) Token() (string, lookup.Source) { } } + // [profile] section in app config for _, v := range d.Config.Profiles { if v.Default { return v.Token, lookup.SourceFile @@ -101,34 +140,67 @@ func (d *Data) Verbose() bool { return d.Flags.Verbose } -// Endpoint yields the API endpoint. -func (d *Data) Endpoint() (string, lookup.Source) { - if d.Flags.Endpoint != "" { - return d.Flags.Endpoint, lookup.SourceFlag +// APIEndpoint yields the API endpoint. +func (d *Data) APIEndpoint() (string, lookup.Source) { + if d.Flags.APIEndpoint != "" { + return d.Flags.APIEndpoint, lookup.SourceFlag } - if d.Env.Endpoint != "" { - return d.Env.Endpoint, lookup.SourceEnvironment + if d.Env.APIEndpoint != "" { + return d.Env.APIEndpoint, lookup.SourceEnvironment } - if d.Config.Fastly.APIEndpoint != DefaultEndpoint && d.Config.Fastly.APIEndpoint != "" { + if d.Config.Fastly.APIEndpoint != DefaultAPIEndpoint && d.Config.Fastly.APIEndpoint != "" { return d.Config.Fastly.APIEndpoint, lookup.SourceFile } - return DefaultEndpoint, lookup.SourceDefault // this method should not fail + return DefaultAPIEndpoint, lookup.SourceDefault // this method should not fail +} + +// AccountEndpoint yields the Accounts endpoint. +func (d *Data) AccountEndpoint() (string, lookup.Source) { + if d.Flags.AccountEndpoint != "" { + return d.Flags.AccountEndpoint, lookup.SourceFlag + } + + if d.Env.AccountEndpoint != "" { + return d.Env.AccountEndpoint, lookup.SourceEnvironment + } + + if d.Config.Fastly.AccountEndpoint != DefaultAccountEndpoint && d.Config.Fastly.AccountEndpoint != "" { + return d.Config.Fastly.AccountEndpoint, lookup.SourceFile + } + + return DefaultAccountEndpoint, lookup.SourceDefault // this method should not fail } // Flags represents all of the configuration parameters that can be set with // explicit flags. Consumers should bind their flag values to these fields // directly. +// +// IMPORTANT: Kingpin doesn't support global flags. +// We hack a solution in ../app/run.go (`configureKingpin` function). type Flags struct { + // AcceptDefaults auto-resolves prompts with a default defined. AcceptDefaults bool - AutoYes bool - Debug bool - Endpoint string + // AccountEndpoint is the authentication host address. + AccountEndpoint string + // APIEndpoint is the Fastly API address. + APIEndpoint string + // AutoYes auto-resolves Yes/No prompts by answering "Yes". + AutoYes bool + // Debug enables the CLI's debug mode. + Debug bool + // NonInteractive auto-resolves all prompts. NonInteractive bool - Profile string - Quiet bool - Token string - Verbose bool + // Profile indicates the profile to use (consequently the 'token' used). + Profile string + // Quiet silences all output except direct command output. + Quiet bool + // SSO enables to SSO authentication tokens for the current profile. + SSO bool + // Token is an override for a profile (when passed SSO is disabled). + Token string + // Verbose prints additional output. + Verbose bool } diff --git a/pkg/profile/profile.go b/pkg/profile/profile.go index dc5ed7e2a..562d1b641 100644 --- a/pkg/profile/profile.go +++ b/pkg/profile/profile.go @@ -1,18 +1,12 @@ package profile import ( - "bytes" - "errors" - "fmt" - "io" - "github.com/fastly/cli/pkg/config" - fsterr "github.com/fastly/cli/pkg/errors" - "github.com/fastly/cli/pkg/global" - "github.com/fastly/cli/pkg/manifest" - "github.com/fastly/cli/pkg/text" ) +// DefaultName is the default profile name. +const DefaultName = "user" + // DoesNotExist describes an output error/warning message. const DoesNotExist = "the profile '%s' does not exist" @@ -36,17 +30,17 @@ func Default(p config.Profiles) (string, *config.Profile) { return k, v } } - return "", new(config.Profile) + return "", nil } // Get returns the specified profile. -func Get(name string, p config.Profiles) (string, *config.Profile) { +func Get(name string, p config.Profiles) *config.Profile { for k, v := range p { if k == name { - return k, v + return v } } - return "", new(config.Profile) + return nil } // SetDefault configures the named profile to be the default. @@ -65,6 +59,23 @@ func SetDefault(name string, p config.Profiles) (config.Profiles, bool) { return p, ok } +// SetADefault sets one of the profiles to be the default. +// +// NOTE: This is used by the `sso` command. +// The reason it exists is because there could be profiles that for some reason +// the user has set them all to not be a default. So to avoid errors in the CLI +// we require at least one profile to be a default and this function makes it +// easy to just pick the first profile and generically set it as the default. +func SetADefault(p config.Profiles) (string, config.Profiles) { + var profileName string + for k, v := range p { + profileName = k + v.Default = true + break + } + return profileName, p +} + // Delete removes the named profile from the profile configuration. func Delete(name string, p config.Profiles) bool { var ok bool @@ -82,8 +93,11 @@ type EditOption func(*config.Profile) // Edit modifies the named profile. // -// NOTE: The type assigned to the config.Profiles map key value is a struct. -// Structs are passed by value and so we must return the mutated type. +// IMPORTANT: We must return config.Profiles to safely update in-memory data. +// The type assigned to the config.Profiles map key value is a struct and +// structs are passed by value, so we must return the mutated type so the +// caller so they can reassign the updated struct back to the in-memory data +// and then persist that data back to disk. func Edit(name string, p config.Profiles, opts ...EditOption) (config.Profiles, bool) { var ok bool for k, v := range p { @@ -96,64 +110,3 @@ func Edit(name string, p config.Profiles, opts ...EditOption) (config.Profiles, } return p, ok } - -// Init checks if a profile flag is provided and potentially mutates token. -// -// NOTE: If the specified profile doesn't exist, then we'll let the user decide -// if the default profile (if available) is acceptable to use instead. -func Init(token string, m *manifest.Data, g *global.Data, in io.Reader, out io.Writer) (string, error) { - // First check the fastly.toml manifest 'profile' field. - profile := m.File.Profile - - // Otherwise check the --profile global flag. - if profile == "" { - profile = g.Flags.Profile - } - - // If the user has specified no profile override, via flag nor manifest, then - // we'll just return the token that has potentially been found within the - // CLI's application configuration file. - if profile == "" { - return token, nil - } - - name, p := Get(profile, g.Config.Profiles) - if name != "" { - return p.Token, nil - } - - msg := fmt.Sprintf(DoesNotExist, profile) - - name, p = Default(g.Config.Profiles) - if name == "" { - msg = fmt.Sprintf("%s (no account profiles configured)", msg) - return token, fsterr.RemediationError{ - Inner: fmt.Errorf(msg), - Remediation: fsterr.ProfileRemediation, - } - } - - // DoesNotExist is reused across errors and warning messages. Mostly errors - // and so when used here for a warning message, we need to uppercase the - // first letter so the warning reads like a proper sentence (where as golang - // errors should always be lowercase). - msg = fmt.Sprintf("%s%s. ", bytes.ToUpper([]byte(msg[:1])), msg[1:]) - - msg = fmt.Sprintf("%sThe default profile '%s' (%s) will be used.", msg, name, p.Email) - - if !g.Flags.AutoYes { - text.Warning(out, msg) - - label := "\nWould you like to continue? [y/N] " - cont, err := text.AskYesNo(out, label, in) - if err != nil { - return token, err - } - if !cont { - return token, errors.New("command execution cancelled") - } - } - - text.Break(out) - return p.Token, nil -} diff --git a/pkg/testutil/api.go b/pkg/testutil/api.go index 8c18712e1..f2bd6d469 100644 --- a/pkg/testutil/api.go +++ b/pkg/testutil/api.go @@ -1,9 +1,14 @@ package testutil import ( + "encoding/json" "errors" + "net/http" + "net/http/httptest" "github.com/fastly/go-fastly/v8/fastly" + + "github.com/fastly/cli/pkg/commands/whoami" ) // Err represents a generic error. @@ -61,3 +66,37 @@ func CloneVersionResult(version int) func(i *fastly.CloneVersionInput) (*fastly. func CloneVersionError(_ *fastly.CloneVersionInput) (*fastly.Version, error) { return nil, Err } + +// WhoamiVerifyClient is used by `whoami` and `sso` tests. +type WhoamiVerifyClient whoami.VerifyResponse + +// Do executes the HTTP request. +func (c WhoamiVerifyClient) Do(*http.Request) (*http.Response, error) { + rec := httptest.NewRecorder() + _ = json.NewEncoder(rec).Encode(whoami.VerifyResponse(c)) + return rec.Result(), nil +} + +// WhoamiBasicResponse is used by `whoami` and `sso` tests. +var WhoamiBasicResponse = whoami.VerifyResponse{ + Customer: whoami.Customer{ + ID: "abc", + Name: "Computer Company", + }, + User: whoami.User{ + ID: "123", + Name: "Alice Programmer", + Login: "alice@example.com", + }, + Services: map[string]string{ + "1xxaa": "First service", + "2baba": "Second service", + }, + Token: whoami.Token{ + ID: "abcdefg", + Name: "Token name", + CreatedAt: "2019-01-01T12:00:00Z", + // no ExpiresAt + Scope: "global", + }, +} diff --git a/pkg/testutil/args.go b/pkg/testutil/args.go index 15e4af1bc..3eeefaada 100644 --- a/pkg/testutil/args.go +++ b/pkg/testutil/args.go @@ -7,9 +7,10 @@ import ( "strings" "time" - "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/auth" "github.com/fastly/cli/pkg/config" "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/runtime" @@ -53,10 +54,40 @@ func Args(args string) []string { return s } -// NewRunOpts returns a struct that can be used to populate a call to app.Run() +// MockAuthServer is used to no-op the authentication server. +type MockAuthServer struct { + auth.Runner + + Result chan auth.AuthorizationResult +} + +// AuthURL returns a fully qualified authorization_endpoint. +// i.e. path + audience + scope + code_challenge etc. +func (s MockAuthServer) AuthURL() (string, error) { + return "", nil // no-op +} + +// GetResult returns the results channel +func (s MockAuthServer) GetResult() chan auth.AuthorizationResult { + return s.Result +} + +// SetAPIEndpoint sets the API endpoint. +func (s MockAuthServer) SetAPIEndpoint(_ string) { + // no-op +} + +// Start starts a local server for handling authentication processing. +func (s MockAuthServer) Start() error { + return nil // no-op +} + +// MockGlobalData returns a struct that can be used to populate a call to app.Exec() // while the majority of fields will be pre-populated and only those fields // commonly changed for testing purposes will need to be provided. -func NewRunOpts(args []string, stdout io.Writer) app.RunOpts { +// +// TODO: Move this and other mocks into mocks package. +func MockGlobalData(args []string, stdout io.Writer) *global.Data { var md manifest.Data md.File.Args = args md.File.SetErrLog(errors.Log) @@ -68,10 +99,13 @@ func NewRunOpts(args []string, stdout io.Writer) app.RunOpts { configPath = "NUL" } - return app.RunOpts{ - APIClient: mock.APIClient(mock.API{}), - Args: args, - ConfigFile: config.File{}, + return &global.Data{ + Args: args, + APIClientFactory: mock.APIClient(mock.API{}), + AuthServer: &MockAuthServer{}, + Config: config.File{ + Profiles: TokenProfile(), + }, ConfigPath: configPath, Env: config.Environment{}, ErrLog: errors.Log, @@ -80,6 +114,28 @@ func NewRunOpts(args []string, stdout io.Writer) app.RunOpts { }, HTTPClient: &http.Client{Timeout: time.Second * 5}, Manifest: &md, - Stdout: stdout, + Opener: func(input string) error { + return nil // no-op + }, + Output: stdout, + } +} + +// TokenProfile generates a mock profile token. +func TokenProfile() config.Profiles { + return config.Profiles{ + // IMPORTANT: Tests mock the token to prevent runtime panics. + // + // Tokens are now interactively handled unless a token is provided + // directly via the --token flag or the FASTLY_API_TOKEN env variable. + // + // We force the CLI to skip the interactive prompts by setting a default + // user profile and making sure the timestamp is not expired. + "user": &config.Profile{ + AccessTokenCreated: 9999999999, // Year: 2286 + Default: true, + Email: "test@example.com", + Token: "mock-token", + }, } } diff --git a/pkg/testutil/scenarios.go b/pkg/testutil/scenarios.go index 2befe9220..de5703602 100644 --- a/pkg/testutil/scenarios.go +++ b/pkg/testutil/scenarios.go @@ -4,10 +4,12 @@ import "github.com/fastly/cli/pkg/mock" // TestScenario represents a standard test case to be validated. type TestScenario struct { - API mock.API - Args []string - Name string - WantError string - WantOutput string - WantOutputs []string + API mock.API + Args []string + DontWantOutput string + DontWantOutputs []string + Name string + WantError string + WantOutput string + WantOutputs []string }