diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml old mode 100644 new mode 100755 diff --git a/.github/workflows/create_jira.yml b/.github/workflows/create_jira.yml new file mode 100755 index 0000000..8180ac0 --- /dev/null +++ b/.github/workflows/create_jira.yml @@ -0,0 +1,39 @@ +name: Create Jira Ticket + +on: + issues: + types: + - opened + +jobs: + create_jira: + name: Create Jira Ticket + runs-on: ubuntu-latest + environment: IssueTracker + steps: + - name: Checkout + uses: actions/checkout@master + - name: Login + uses: atlassian/gajira-login@master + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_TOKEN }} + JIRA_EPIC_KEY: ${{ secrets.JIRA_EPIC_KEY }} + JIRA_PROJECT: ${{ secrets.JIRA_PROJECT }} + + - name: Create + id: create + uses: atlassian/gajira-create@master + with: + project: ${{ secrets.JIRA_PROJECT }} + issuetype: Bug + summary: | + [${{ github.event.repository.name }}] (${{ github.event.issue.number }}): ${{ github.event.issue.title }} + description: | + Github Link: ${{ github.event.issue.html_url }} + ${{ github.event.issue.body }} + fields: '{"parent": {"key": "${{ secrets.JIRA_EPIC_KEY }}"}}' + + - name: Log created issue + run: echo "Issue ${{ steps.create.outputs.issue }} was created" \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/segmentcli.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/segmentcli.xcscheme old mode 100644 new mode 100755 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000..f376ca6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +*Contributing* + +**All third party contributors acknowledge that any contributions they provide will be made under the same open source license that the open source project is provided under. ** + + diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000..908a220 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Twilio inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..b052e91 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +SHELL = /bin/bash + +prefix ?= /usr/local +bindir ?= $(prefix)/bin +libdir ?= $(prefix)/lib +srcdir = Sources + +REPODIR = $(shell pwd) +BUILDDIR = $(REPODIR)/.build +SOURCES = $(wildcard $(srcdir)/**/*.swift) + +.DEFAULT_GOAL = all + +segmentcli: $(SOURCES) + @swift build \ + -c release \ + --disable-sandbox \ + --build-path "$(BUILDDIR)" + +.PHONY: install +install: segmentcli + @install -d "$(bindir)" + @install "$(wildcard $(BUILDDIR)/**/release/segmentcli)" "$(bindir)" + +.PHONY: uninstall +uninstall: + @rm -rf "$(bindir)/segmentcli" + +.PHONY: clean +distclean: + @rm -f $(BUILDDIR)/release + +.PHONY: clean +clean: distclean + @rm -rf $(BUILDDIR) diff --git a/Package.resolved b/Package.resolved old mode 100644 new mode 100755 index 6f927d8..e5a73ef --- a/Package.resolved +++ b/Package.resolved @@ -5,9 +5,18 @@ "package": "Segment", "repositoryURL": "https://github.com/segmentio/analytics-swift.git", "state": { - "branch": "bsneed/cli_additions", - "revision": "f778e2e9c19f4e3052317c5af26a4897ef77cc86", - "version": null + "branch": null, + "revision": "7d47f4b42e6d74fe2de73b8e3c3fc2eeae4a3efd", + "version": "1.7.3" + } + }, + { + "package": "AnalyticsLive", + "repositoryURL": "https://github.com/segment-integrations/analytics-swift-live.git", + "state": { + "branch": null, + "revision": "fa1f3f75ee439544ce3bf69cf99f01a5cdb36bb7", + "version": "3.1.7" } }, { @@ -29,12 +38,12 @@ } }, { - "package": "EdgeFn", - "repositoryURL": "git@github.com:segmentio/EdgeFn-Swift.git", + "package": "JSONSafeEncoding", + "repositoryURL": "https://github.com/segmentio/jsonsafeencoding-swift.git", "state": { - "branch": "main", - "revision": "9e7fe14e458148a8e86ac56e85d52bc13d595288", - "version": null + "branch": null, + "revision": "af6a8b360984085e36c6341b21ecb35c12f47ebd", + "version": "2.0.0" } }, { @@ -78,8 +87,8 @@ "repositoryURL": "https://github.com/segmentio/Sovran-Swift.git", "state": { "branch": null, - "revision": "944c17d7c46bd95fc37f09136cabd172be5b413b", - "version": "1.0.3" + "revision": "24867f3e4ac62027db9827112135e6531b6f4051", + "version": "1.1.2" } }, { @@ -93,11 +102,11 @@ }, { "package": "Substrata", - "repositoryURL": "git@github.com:segmentio/substrata-swift.git", + "repositoryURL": "https://github.com/segmentio/substrata-swift.git", "state": { - "branch": "main", - "revision": "079da728865b9933d41466c588bbc3079ee1ee66", - "version": null + "branch": null, + "revision": "293df9d9ad5339bf24abaf9525518c5019a061b7", + "version": "2.1.0" } }, { diff --git a/Package.swift b/Package.swift old mode 100644 new mode 100755 index 078d52b..2bb85dd --- a/Package.swift +++ b/Package.swift @@ -6,18 +6,18 @@ import PackageDescription let package = Package( name: "segmentcli", platforms: [ - .macOS(.v10_15) + .macOS(.v11) ], dependencies: [ .package(url: "https://github.com/jakeheis/SwiftCLI", from: "6.0.0"), .package(url: "https://github.com/dominicegginton/Spinner", from: "1.1.4"), .package(url: "https://github.com/mtynior/ColorizeSwift.git", from: "1.5.0"), - .package(url: "https://github.com/segmentio/analytics-swift.git", branch: "bsneed/cli_additions"), + .package(url: "https://github.com/segmentio/analytics-swift.git", from: "1.7.3"), .package(url: "https://github.com/swiftcsv/SwiftCSV.git", from: "0.6.1"), .package(url: "https://github.com/AlwaysRightInstitute/Mustache", from: "1.0.0"), .package(url: "https://github.com/antitypical/Result.git", from: "5.0.0"), - .package(url: "git@github.com:segmentio/EdgeFn-Swift.git", branch: "main"), - .package(url: "git@github.com:segmentio/substrata-swift.git", branch: "main") + .package(url: "https://github.com/segment-integrations/analytics-swift-live.git", from: "3.1.7"), + .package(url: "https://github.com/segmentio/substrata-swift.git", from: "2.1.0") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -30,7 +30,7 @@ let package = Package( "SwiftCSV", "Result", .product(name: "Substrata", package: "substrata-swift"), - .product(name: "EdgeFn", package: "EdgeFn-Swift"), + .product(name: "AnalyticsLive", package: "analytics-swift-live"), .product(name: "mustache", package: "Mustache"), .product(name: "Segment", package: "analytics-swift")]), .testTarget( diff --git a/README.md b/README.md old mode 100644 new mode 100755 index fac97b7..637aafa --- a/README.md +++ b/README.md @@ -1,3 +1,91 @@ -# segmentcli +# Segment CLI + +The Segment CLI (segmentcli) is a command line utility used to work with Analytics +Live Plugins in your Segment work space. + +```bash +Usage: segmentcli [options] + +A command line utility to interact with and drive Segment + +Groups: + profile Work with stored profiles on this device + analytics Send custom crafted events to Segment + liveplugins Work with and develop analytics live plugins + sources View and edit workspace sources + +Commands: + auth Authenticate with Segment.com and assign a profile name + import Import CSV data into Segment from + scaffold Create baseline implementation of a given code artifact + repl Segment virtual development environment + help Prints help information + version Prints the current version of this app +``` + +## Getting Started + +### Installing `segmentcli`. + +``` +git clone https://github.com/segment-integrations/segmentcli.git +cd segmentcli +sudo make install +``` + +A binary `segmentcli` will be installed to `/usr/local/bin`. + +## Authenticating + +The command to authenticate is as follows: + +```bash +$ segmentcli auth +``` + +`ProfileName` - is the name you give to this workspace so you can distinguish +between various local profiles. + +`AuthToken` - is the AuthToken associated with your workspace. You must create +an Auth token in your Segment workspace. + +### Creating an Auth Token + +1. Log into https://app.segment.com +1. Navigate to Settings > Workspace Settings > Access Management > Tokens +1. Generate a new token using the "Create token" button with the Workspace Owner role. + +## Using `segmentcli` with Analytics Live. + +### Enabling the Analytics Live Plugins feature + +Reach out to your Customer Support Engineer (CSE) or Customer Success Manager (CSM) +to have them add this feature to your account. Once that is completed, you may continue. + +### Uploading Your Analytics Live Plugins to Your Workspace + +In order to upload your Analytics Live Plugins you'll need the following command: + +```bash +$ segmentcli liveplugins upload +``` + +`SourceId` - This is listed next your Write Key in the Segment app. +`FileName` - The name of the JavaScript file containing your code. + +Note: It will take a few minutes for your Source's setting payload to be update +with the Analytics Live Plugin file URL. + +## Finding Your SourceID + +1. Log into https://app.segment.com +1. Navigate to Connections > Sources +1. Choose the source for which we're adding Analytics Live Plugins +1. Navigate to Settings > API Keys +1. You'll find the "Source ID" at the top of the page. + + +## References + +Learn more about Analytics Live Plugins for [Swift](https://github.com/segment-integrations/analytics-swift-live) and [Kotlin](https://github.com/segment-integrations/analytics-swift-live). -A description of this package. diff --git a/Sources/segmentcli/Commands/Analytics.swift b/Sources/segmentcli/Commands/Analytics.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Commands/Auth.swift b/Sources/segmentcli/Commands/Auth.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Commands/Import.swift b/Sources/segmentcli/Commands/Import.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Commands/EdgeFn.swift b/Sources/segmentcli/Commands/LivePlugins.swift old mode 100644 new mode 100755 similarity index 90% rename from Sources/segmentcli/Commands/EdgeFn.swift rename to Sources/segmentcli/Commands/LivePlugins.swift index c833176..0e56bcd --- a/Sources/segmentcli/Commands/EdgeFn.swift +++ b/Sources/segmentcli/Commands/LivePlugins.swift @@ -12,22 +12,22 @@ import ColorizeSwift import Segment class EdgeFnGroup: CommandGroup { - let name = "edgefn" - let shortDescription = "Work with and develop edge functions" + let name = "liveplugins" + let shortDescription = "Work with and develop analytics live plugins" let children: [Routable] = [EdgeFnLatestCommand(), EdgeFnUpload(), EdgeFnDisable()] init() {} } class EdgeFnDisable: Command { let name = "disable" - let shortDescription = "Disable edge functions for a given source ID" + let shortDescription = "Disable Live Plugins for a given source ID" @Param var sourceId: String func execute() throws { guard let workspace = currentWorkspace else { exitWithError(code: .commandFailed, message: "No authentication tokens found."); return } executeAndWait { semaphore in - let spinner = Spinner(.dots, "Uploading edge function ...") + let spinner = Spinner(.dots, "Uploading live plugin ...") spinner.start() PAPI.shared.edgeFunctions.disable(token: workspace.token, sourceId: sourceId) { data, response, error in @@ -42,14 +42,14 @@ class EdgeFnDisable: Command { switch statusCode { case .ok: // success! - print("Edge functions disabled for \(self.sourceId.italic.bold).") + print("Live plugins disabled for \(self.sourceId.italic.bold).") case .unauthorized: fallthrough case .unauthorized2: exitWithError(code: .commandFailed, message: "Supplied token is not authorized.") case .notFound: - exitWithError(code: .commandFailed, message: "No edge functions were found.") + exitWithError(code: .commandFailed, message: "No live plugins were found.") default: exitWithError("An unknown error occurred.") } @@ -62,7 +62,7 @@ class EdgeFnDisable: Command { class EdgeFnUpload: Command { let name = "upload" - let shortDescription = "Upload an edge function" + let shortDescription = "Upload a Live Plugin" @Param var sourceId: String @Param var filePath: String @@ -102,7 +102,7 @@ class EdgeFnUpload: Command { case .unauthorized2: exitWithError(code: .commandFailed, message: "Supplied token is not authorized.") case .notFound: - exitWithError(code: .commandFailed, message: "No edge functions were found.") + exitWithError(code: .commandFailed, message: "No live plugins were found.") default: exitWithError("An unknown error occurred.") } @@ -134,7 +134,7 @@ class EdgeFnUpload: Command { case .unauthorized2: exitWithError(code: .commandFailed, message: "Supplied token is not authorized.") case .notFound: - exitWithError(code: .commandFailed, message: "No edge functions were found.") + exitWithError(code: .commandFailed, message: "No live plugins were found.") default: exitWithError("An unknown error occurred.") } @@ -144,7 +144,7 @@ class EdgeFnUpload: Command { // call create to make a new connection to the version we just posted. executeAndWait { semaphore in - let spinner = Spinner(.dots, "Creating new edge function version ...") + let spinner = Spinner(.dots, "Creating new live plugin version ...") spinner.start() PAPI.shared.edgeFunctions.createNewVersion(token: workspace.token, sourceId: sourceId, uploadURL: uploadURL) { data, response, error in @@ -170,7 +170,7 @@ class EdgeFnUpload: Command { case .unauthorized2: exitWithError(code: .commandFailed, message: "Supplied token is not authorized.") case .notFound: - exitWithError(code: .commandFailed, message: "No edge functions were found.") + exitWithError(code: .commandFailed, message: "No live plugins were found.") default: exitWithError("An unknown error occurred.") } @@ -183,7 +183,7 @@ class EdgeFnUpload: Command { class EdgeFnLatestCommand: Command { let name = "latest" - let shortDescription = "Get info about the latest Edge Function in use" + let shortDescription = "Get info about the latest Live Plugin in use" @Param var sourceId: String @@ -191,7 +191,7 @@ class EdgeFnLatestCommand: Command { guard let workspace = currentWorkspace else { exitWithError(code: .commandFailed, message: "No authentication tokens found."); return } executeAndWait { semaphore in - let spinner = Spinner(.dots, "Retrieving latest Edge Functino info ...") + let spinner = Spinner(.dots, "Retrieving latest Live Plugin info ...") spinner.start() PAPI.shared.edgeFunctions.latest(token: workspace.token, sourceId: sourceId) { data, response, error in @@ -217,7 +217,7 @@ class EdgeFnLatestCommand: Command { case .unauthorized2: exitWithError(code: .commandFailed, message: "Supplied token is not authorized.") case .notFound: - exitWithError(code: .commandFailed, message: "No edge functions were found.") + exitWithError(code: .commandFailed, message: "No live plugins were found.") default: exitWithError("An unknown error occurred.") } diff --git a/Sources/segmentcli/Commands/Profile.swift b/Sources/segmentcli/Commands/Profile.swift old mode 100644 new mode 100755 index 03db41b..bb4baa3 --- a/Sources/segmentcli/Commands/Profile.swift +++ b/Sources/segmentcli/Commands/Profile.swift @@ -77,7 +77,6 @@ class ProfileSetCommand: Command { } // MARK: - Global option for profile - let specifiedProfileKey = Key("-p", "--profile", description: "Specify a profile name to use for this operation") extension Command { var specifiedProfile: String? { diff --git a/Sources/segmentcli/Commands/REPL.swift b/Sources/segmentcli/Commands/REPL.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Commands/Scaffold.swift b/Sources/segmentcli/Commands/Scaffold.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Commands/Sources.swift b/Sources/segmentcli/Commands/Sources.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/JS Additions/csvJS.swift b/Sources/segmentcli/JS Additions/csvJS.swift old mode 100644 new mode 100755 index 2057a38..c5c3838 --- a/Sources/segmentcli/JS Additions/csvJS.swift +++ b/Sources/segmentcli/JS Additions/csvJS.swift @@ -43,37 +43,31 @@ import Substrata } */ -class CSVJS: JavascriptClass, JSConvertible { - internal let csv: CSV? - - static var className = "CSV" - - static var staticProperties = [String: JavascriptProperty]() - static var staticMethods = [String: JavascriptMethod]() - var instanceProperties: [String: JavascriptProperty] = [ - "rows": JavascriptProperty(get: { weakSelf, this in - guard let self = weakSelf as? CSVJS else { return nil } - return self.csv?.namedRows.count - }) - ] - - var instanceMethods: [String : JavascriptMethod] = [ - "value": JavascriptMethod { weakSelf, this, params in - guard let self = weakSelf as? CSVJS else { return nil } - guard let row = params[0]?.typed(Int.self) else { return nil } - guard let columnName = params[1]?.typed(String.self) else { return nil } - let result = self.csv?.namedRows[row][columnName] - return result +class CSVJS: JSExport { + internal var csv: CSV? = nil + + required init() { + super.init() + + exportProperty(named: "rows") { + guard let csv = self.csv else { throw "No CSV file loaded." } + return csv.namedRows.count + } + + exportMethod(named: "value") { args in + guard let csv = self.csv else { throw "No CSV file loaded." } + guard let row = args.typed(as: Int.self, index: 0) else { return nil } + guard let columnName = args.typed(as: String.self, index: 1) else { return nil } + return csv.namedRows[row][columnName] } - ] + } - public required init(context: JSContext, params: JSConvertible?...) throws { - guard let csvPath = params[0]?.typed(String.self) else { throw "Unable to load specified CSV file." } - let delimiter = params[1]?.typed(String.self) ?? "|" - let loadColumns = params[2]?.typed(Bool.self) ?? true + override func construct(args: [JSConvertible?]) throws { + guard let csvPath = args.typed(as: String.self, index: 0) else { throw "Unable to load specified CSV file." } + let delimiter = args.typed(as: String.self, index: 1) ?? "|" + let loadColumns = args.typed(as: Bool.self, index: 2) ?? true let url = URL(fileURLWithPath: csvPath) self.csv = try CSV(url: url, delimiter: delimiter.first ?? "|", encoding: .utf8, loadColumns: loadColumns) } - } diff --git a/Sources/segmentcli/PAPI/PAPI.swift b/Sources/segmentcli/PAPI/PAPI.swift old mode 100644 new mode 100755 index 21ad07f..2275b80 --- a/Sources/segmentcli/PAPI/PAPI.swift +++ b/Sources/segmentcli/PAPI/PAPI.swift @@ -6,8 +6,15 @@ // import Foundation +import SwiftCLI -let PAPIEndpoint: String = "https://api.segmentapis.com/" +var PAPIEndpoint: String { + if useStagingKey.value { + return "https://api.segmentapis.build/" + } else { + return "https://api.segmentapis.com/" + } +} protocol PAPISection { static var pathEntry: String { get } @@ -53,3 +60,11 @@ class PAPI { } } + +// MARK: - Global option to support staging +let useStagingKey = Flag("--staging", description: "Use Segment staging for operations") +extension Command { + var isStaging: Bool { + return useStagingKey.value + } +} diff --git a/Sources/segmentcli/PAPI/PAPIEdgeFunctions.swift b/Sources/segmentcli/PAPI/PAPIEdgeFunctions.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/PAPI/PAPISources.swift b/Sources/segmentcli/PAPI/PAPISources.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Templates/CSVImporterJS.swift b/Sources/segmentcli/Templates/CSVImporterJS.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Templates/PluginSwift.swift b/Sources/segmentcli/Templates/PluginSwift.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/Utilities/Misc.swift b/Sources/segmentcli/Utilities/Misc.swift old mode 100644 new mode 100755 index ef2738e..aeaf6b9 --- a/Sources/segmentcli/Utilities/Misc.swift +++ b/Sources/segmentcli/Utilities/Misc.swift @@ -20,6 +20,8 @@ func executeAndWait(_ closure: (DispatchSemaphore) -> Void) { // MARK: - Exits & Errors +extension String: @retroactive Error { } + enum ErrorCode: Int { case success = 0 case unknown = 1 diff --git a/Sources/segmentcli/Utilities/Runtime.swift b/Sources/segmentcli/Utilities/Runtime.swift old mode 100644 new mode 100755 index a75a5f1..ef8aec6 --- a/Sources/segmentcli/Utilities/Runtime.swift +++ b/Sources/segmentcli/Utilities/Runtime.swift @@ -9,7 +9,7 @@ import Foundation import Segment import Substrata import SwiftCLI -import EdgeFn +import AnalyticsLive var engine = JSEngine() @@ -41,7 +41,7 @@ func runJSInteractive() { case _ where input.hasPrefix(":print"): let variable = input.replacingOccurrences(of: ":print ", with: "") - if let value = engine.object(key: variable) { + if let value = engine.value(for: variable) { print("\(variable) = \(String(describing: value))") } else { print("\(variable) = nil") @@ -75,16 +75,7 @@ func runJSFile(path scriptFile: String) { do { let url = URL(fileURLWithPath: scriptFile) let code = try String(contentsOf: url) - let readQueue = DispatchQueue(label: "segmentcli.js.execution") - @Atomic var done = false - readQueue.async { - engine.evaluate(script: code) - done = true - } - // don't have a good solution to knowing when async stuff is complete yet. - while done == false { - RunLoop.main.run(until: Date(timeIntervalSinceNow: 10)) - } + engine.evaluate(script: code) } catch { exitWithError(error.localizedDescription) } @@ -95,31 +86,17 @@ func runJSFile(path scriptFile: String) { func runJS(script: String) { configureEngine() - let readQueue = DispatchQueue(label: "segmentcli.js.execution") - @Atomic var done = false - readQueue.async { - engine.evaluate(script: script) - done = true - } - // TODO: don't have a good solution to knowing when async stuff is complete yet. - while done == false { - RunLoop.main.run(until: Date(timeIntervalSinceNow: 10)) - } + engine.evaluate(script: script) } func configureEngine() { - engine.errorHandler = { error in - switch error { - case .evaluationError(let s): - print(s) - default: - print(error) - } + engine.exceptionHandler = { error in + print(error) } // expose our classes - try? engine.expose(name: "Analytics", classType: AnalyticsJS.self) + engine.export(type: AnalyticsJS.self, className: "Analytics") // set the system analytics object. //engine.setObject(key: "analytics", value: AnalyticsJS(wrapping: self.analytics, engine: engine)) diff --git a/Sources/segmentcli/Utilities/Settings.swift b/Sources/segmentcli/Utilities/Settings.swift old mode 100644 new mode 100755 diff --git a/Sources/segmentcli/main.swift b/Sources/segmentcli/main.swift old mode 100644 new mode 100755 index a297cb8..0d36ddd --- a/Sources/segmentcli/main.swift +++ b/Sources/segmentcli/main.swift @@ -1,3 +1,5 @@ +// Copyright 2021 Twilio Inc. + import Foundation import SwiftCLI @@ -16,6 +18,7 @@ func main() { SourcesGroup() ]) + segment.globalOptions.append(useStagingKey) segment.globalOptions.append(specifiedProfileKey) segment.go() diff --git a/Tests/segmentcliTests/segmentcliTests.swift b/Tests/segmentcliTests/segmentcliTests.swift old mode 100644 new mode 100755