-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add env api
command
#1
Changes from all commits
09c65c2
a9e44f1
2e25606
4e6a644
9c83ce3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
#!/bin/sh | ||
. "$(dirname "$0")/_/husky.sh" | ||
|
||
yarn build && yarn test | ||
yarn build |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
{ | ||
"test": { | ||
"testsPath": "test/**/*.test.ts" | ||
} | ||
"exclude-scripts": ["docs", "pretest", "test", "lint"] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[ | ||
{ | ||
"command": "env:api", | ||
"plugin": "@cristiand391/sf-plugin-api", | ||
"flags": ["body", "header", "include", "method", "target-org"], | ||
"alias": [] | ||
} | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# summary | ||
|
||
Makes an authenticated HTTP request to the Salesforce REST API and prints the response. | ||
cristiand391 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# description | ||
|
||
You must specify a Salesforce org to use, either with the --target-org flag or by setting your default org with the `target-org` configuration variable. | ||
|
||
Read the Salesforce REST API developer guide at: | ||
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm | ||
|
||
# examples | ||
|
||
- List information about limits in your org: | ||
|
||
<%= config.bin %> <%= command.id %> 'services/data/v56.0/limits' --target-org my-org | ||
|
||
- Get response in XML format by specifying the "Accept" HTTP header: | ||
|
||
<%= config.bin %> <%= command.id %> 'services/data/v56.0/limits' --target-org my-org --header 'Accept: application/xml' | ||
|
||
# flags.target-org.summary | ||
|
||
Login username or alias for the target org. | ||
|
||
# flags.method.summary | ||
|
||
The HTTP method for the request. | ||
|
||
# flags.include.summary | ||
|
||
Include HTTP response status and headers in the output. | ||
|
||
# flags.header.summary | ||
|
||
HTTP header in "key:value" format. | ||
|
||
# flags.body.summary | ||
|
||
The file to use as the body for the request. | ||
|
||
# errors.invalid-http-header | ||
|
||
Failed to parse HTTP header: "%s". |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,30 @@ | ||
{ | ||
"name": "@salesforce/plugin-api", | ||
"name": "@cristiand391/sf-plugin-api", | ||
"description": "Plugin to interact with the Salesforce APIs", | ||
"version": "0.0.1", | ||
"author": "Salesforce", | ||
"bugs": "https://github.com/forcedotcom/cli/issues", | ||
"author": { | ||
"name": "Cristian Dominguez", | ||
"url": "https://github.com/cristiand391" | ||
}, | ||
"bugs": "https://github.com/cristiand391/sf-plugin-api/issues", | ||
"dependencies": { | ||
"@oclif/core": "^1.18.0", | ||
"@salesforce/core": "^3.31.17", | ||
"@salesforce/kit": "^1.7.1", | ||
"@salesforce/sf-plugins-core": "^1.17.0", | ||
"tslib": "^2" | ||
"chalk": "^4", | ||
"got": "11.8.5", | ||
"proxy-agent": "^5.0.0", | ||
"proxy-from-env": "^1.1.0" | ||
}, | ||
"devDependencies": { | ||
"@oclif/plugin-command-snapshot": "^3.2.5", | ||
"@oclif/test": "^2.2.4", | ||
"@salesforce/cli-plugins-testkit": "^3.2.3", | ||
"@salesforce/dev-config": "^3.1.0", | ||
"@salesforce/dev-scripts": "^3.1.0", | ||
"@salesforce/plugin-command-reference": "^2.2.8", | ||
"@salesforce/prettier-config": "^0.0.2", | ||
"@salesforce/ts-sinon": "1.4.0", | ||
"@swc/core": "^1.3.11", | ||
"@types/proxy-from-env": "^1.0.1", | ||
"@typescript-eslint/eslint-plugin": "^5.40.0", | ||
"@typescript-eslint/parser": "^5.40.1", | ||
"chai": "^4.3.6", | ||
|
@@ -52,7 +57,7 @@ | |
"/oclif.manifest.json", | ||
"/schemas" | ||
], | ||
"homepage": "https://github.com/salesforcecli/plugin-api", | ||
"homepage": "https://github.com/cristiand391/sf-plugin-api", | ||
"keywords": [ | ||
"force", | ||
"salesforce", | ||
|
@@ -70,32 +75,22 @@ | |
"topicSeparator": " ", | ||
"devPlugins": [ | ||
"@oclif/plugin-help", | ||
"@oclif/plugin-command-snapshot", | ||
"@salesforce/plugin-command-reference" | ||
], | ||
"topics": { | ||
"hello": { | ||
"description": "Commands to say hello." | ||
} | ||
} | ||
"@oclif/plugin-command-snapshot" | ||
] | ||
}, | ||
"repository": "salesforcecli/plugin-api", | ||
"repository": "https://github.com/cristiand391/sf-plugin-api", | ||
"scripts": { | ||
"build": "sf-build", | ||
"clean": "sf-clean", | ||
"clean-all": "sf-clean all", | ||
"clean:lib": "shx rm -rf lib && shx rm -rf coverage && shx rm -rf .nyc_output && shx rm -f oclif.manifest.json", | ||
"compile": "sf-compile", | ||
"docs": "sf-docs", | ||
"format": "sf-format", | ||
"lint": "sf-lint", | ||
"lint": "eslint \"src/**/*.ts\"", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"postpack": "shx rm -f oclif.manifest.json", | ||
"posttest": "yarn lint && yarn test:deprecation-policy && yarn test:json-schema && yarn test:command-reference", | ||
"prepack": "sf-prepack", | ||
"prepare": "sf-install", | ||
"pretest": "sf-compile-test", | ||
"test": "sf-test", | ||
"test:command-reference": "./bin/dev commandreference:generate --erroronwarnings", | ||
"test:deprecation-policy": "./bin/dev snapshot:compare", | ||
"test:json-schema": "./bin/dev schema:compare", | ||
"test:nuts": "nyc mocha \"**/*.nut.ts\" --slow 4500 --timeout 600000 --parallel", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"$ref": "#/definitions/EnvApiResult", | ||
"definitions": { | ||
"EnvApiResult": { | ||
"type": "object", | ||
"properties": { | ||
"path": { | ||
"type": "string" | ||
} | ||
}, | ||
"required": ["path"], | ||
"additionalProperties": false | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* | ||
* Copyright (c) 2022, salesforce.com, inc. | ||
* All rights reserved. | ||
* Licensed under the BSD 3-Clause license. | ||
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
*/ | ||
|
||
import { readFile } from 'node:fs/promises'; | ||
import got, { Headers, Method } from 'got'; | ||
import * as chalk from 'chalk'; | ||
import * as ProxyAgent from 'proxy-agent'; | ||
import { getProxyForUrl } from 'proxy-from-env'; | ||
import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; | ||
import { SfError, Messages, Org } from '@salesforce/core'; | ||
import { CliUx } from '@oclif/core'; | ||
|
||
Messages.importMessagesDirectory(__dirname); | ||
const messages = Messages.load('@cristiand391/sf-plugin-api', 'env.api', [ | ||
'summary', | ||
'description', | ||
'examples', | ||
'flags.target-org.summary', | ||
'flags.method.summary', | ||
'flags.include.summary', | ||
'flags.header.summary', | ||
'flags.body.summary', | ||
'errors.invalid-http-header', | ||
]); | ||
|
||
export default class EnvApi extends SfCommand<string> { | ||
public static summary = messages.getMessage('summary'); | ||
public static description = messages.getMessage('description'); | ||
public static examples = messages.getMessages('examples'); | ||
public static enableJsonFlag = false; | ||
public static flags = { | ||
'target-org': Flags.requiredOrg({ | ||
summary: messages.getMessage('flags.target-org.summary'), | ||
char: 'o', | ||
}), | ||
include: Flags.boolean({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added ✅ curl also has |
||
char: 'i', | ||
summary: messages.getMessage('flags.include.summary'), | ||
default: false, | ||
}), | ||
method: Flags.enum<Method>({ | ||
options: ['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
summary: messages.getMessage('flags.method.summary'), | ||
char: 'X', | ||
default: 'GET', | ||
}), | ||
header: Flags.string({ | ||
summary: messages.getMessage('flags.header.summary'), | ||
char: 'H', | ||
multiple: true, | ||
}), | ||
body: Flags.file({ | ||
summary: messages.getMessage('flags.body.summary'), | ||
}), | ||
}; | ||
|
||
public static args = [ | ||
{ | ||
name: 'endpoint', | ||
description: 'Salesforce API endpoint.', | ||
required: true, | ||
}, | ||
]; | ||
|
||
private static getHeaders(keyValPair: string[]): Headers { | ||
const headers = {}; | ||
|
||
for (const header of keyValPair) { | ||
const split = header.split(':'); | ||
if (split.length !== 2) { | ||
throw new SfError(messages.getMessage('errors.invalid-http-header', [header]), '', [ | ||
'Make sure the header is in a "key:value" format, e.g. "Accept: application/json"', | ||
]); | ||
} | ||
headers[split[0]] = split[1]; | ||
} | ||
|
||
return headers; | ||
} | ||
|
||
public async run(): Promise<string> { | ||
const { flags, args } = await this.parse(EnvApi); | ||
|
||
let body: Buffer; | ||
|
||
if (flags.body) { | ||
body = await readFile(flags.body); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea, the command pass the body file to got as a to get the content-type of the buffer we could use this I'll add a new issue for this 👍🏼 |
||
} | ||
|
||
const org = flags['target-org']; | ||
|
||
await org.refreshAuth(); | ||
|
||
const url = `${org.getField<string>(Org.Fields.INSTANCE_URL)}/${args.endpoint as string}`; | ||
|
||
const res = await got(url, { | ||
agent: { https: ProxyAgent(getProxyForUrl(url)) }, | ||
method: flags.method, | ||
headers: { | ||
Authorization: `Bearer ${org.getConnection().getConnectionOptions().accessToken}`, | ||
...(flags.header ? EnvApi.getHeaders(flags.header) : {}), | ||
}, | ||
body: flags.method === 'GET' ? undefined : body, | ||
throwHttpErrors: false, | ||
}); | ||
|
||
// Print HTTP response status and headers. | ||
if (flags.include) { | ||
let httpInfo = `HTTP/${res.httpVersion} ${res.statusCode} \n`; | ||
|
||
for (const [header] of Object.entries(res.headers)) { | ||
httpInfo += `${chalk.blue.bold(header)}: ${res.headers[header] as string}\n`; | ||
} | ||
this.log(httpInfo); | ||
} | ||
|
||
try { | ||
// Try to pretty-print JSON response. | ||
CliUx.ux.styledJSON(JSON.parse(res.body)); | ||
} catch (err) { | ||
// If response body isn't JSON, just print it to stdout. | ||
this.log(res.body); | ||
} | ||
|
||
if (res.statusCode >= 400) { | ||
process.exitCode = 1; | ||
} | ||
|
||
return res.body; | ||
} | ||
} |
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: re-enable the tests scripts once I add NUTs.
I skipped this as I'll need to set up some hub credentials for this repo.