Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat: --body supports reading from STDIN (#23)
Browse files Browse the repository at this point in the history
If you do `flag.allowStdin: true` then oclif will read from stdin for
you if the value is `-`, so there's no way to know if the flag value
came from stdin or the user specified a file path (here we need to read
the file).

I don't like having another specific flag just to read from stdin so I
made this a string flag and handle reading from stdin/file in
`flag.parse`.


also:
* made `got` not follow redirects (use `--include` flag and check the `Location` header if need that).
* bumped deps
  • Loading branch information
cristiand391 authored Jan 26, 2024
1 parent 0941d9c commit 06ef90d
Show file tree
Hide file tree
Showing 5 changed files with 2,072 additions and 762 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ FLAGS
-X, --method=<option> [default: GET] The HTTP method for the request.
<options: GET|POST|PUT|PATCH|HEAD|DELETE|OPTIONS|TRACE>
-i, --include Include HTTP response status and headers in the output.
-o, --target-org=username (required) Username or alias of the target org.
--body=file The file to use as the body for the request.
-o, --target-org=username (required) Username or alias of the target org. Not required if the `target-org`
configuration variable is already set.
--body=file The file to use as the body for the request (use "-" to read from standard input).
DESCRIPTION
Makes an authenticated HTTP request to the Salesforce REST API and prints the response.
Expand Down
27 changes: 14 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,39 @@
"type": "module",
"bugs": "https://github.com/cristiand391/sf-plugin-api/issues",
"dependencies": {
"@oclif/core": "^3.10.1",
"@salesforce/core": "^5.3.17",
"@salesforce/sf-plugins-core": "^4.0.0",
"@oclif/core": "^3.18.1",
"@salesforce/core": "^6.5.0",
"@salesforce/sf-plugins-core": "^7.1.4",
"chalk": "^5.3.0",
"got": "^13.0.0",
"proxy-agent": "^6.3.1"
},
"devDependencies": {
"@oclif/plugin-command-snapshot": "^5.0.1",
"@oclif/plugin-command-snapshot": "^5.0.6",
"@types/chai": "^4.3.4",
"@types/inquirer": "^9.0.3",
"@types/mocha": "^10.0.1",
"@types/sinon": "^10.0.13",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"@typescript-eslint/eslint-plugin": "^6.17.0",
"@typescript-eslint/parser": "^6.17.0",
"chai": "^4.3.6",
"eslint": "^8.26.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-salesforce": "^2.0.2",
"eslint-config-salesforce-typescript": "^1.1.1",
"eslint-config-salesforce-typescript": "^3.0.16",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jsdoc": "^46.4.6",
"eslint-plugin-sf-plugin": "^1.16.2",
"eslint-plugin-sf-plugin": "^1.17.1",
"eslint-plugin-unicorn": "^49.0.0",
"mocha": "^10.2.0",
"nock": "^13.3.0",
"oclif": "^3.11.3",
"oclif": "^4.3.9",
"prettier": "^3.0.1",
"shx": "0.3.4",
"sinon": "^15.0.3",
"strip-ansi": "^7.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.2.2",
"ts-node": "^10.9.2",
"typescript": "^5.3.3",
"wireit": "^0.10.0"
},
"engines": {
Expand Down Expand Up @@ -135,7 +136,7 @@
]
},
"test:deprecation-policy": {
"command": "ts-node \"./bin/dev.js\" snapshot:compare",
"command": "node --loader ts-node/esm --no-warnings=ExperimentalWarning \"./bin/dev.js\" snapshot:compare",
"files": [
"src/**/*.ts"
],
Expand Down
37 changes: 23 additions & 14 deletions src/commands/org/api.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { readFile } from 'node:fs/promises';
import { EOL } from 'node:os';
import got, { Headers, Method } from 'got';
import got, { Headers } from 'got';
import chalk from 'chalk';
import { ProxyAgent } from 'proxy-agent';
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { SfError, Org } from '@salesforce/core';
import { Args, ux } from '@oclif/core';
import { readStdin } from '@oclif/core/lib/parser/parse.js';

export class OrgApi extends SfCommand<void> {
public static readonly summary =
Expand All @@ -31,17 +32,14 @@ export class OrgApi extends SfCommand<void> {
// summary is already set in the org flag.
// eslint-disable-next-line sf-plugin/flag-summary
'target-org': Flags.requiredOrg({
// TODO: this is already set in the org flag but getting a wrong type if not set here.
// Fix flag types in oclif.
required: true,
helpValue: 'username',
}),
include: Flags.boolean({
char: 'i',
summary: 'Include HTTP response status and headers in the output.',
default: false,
}),
method: Flags.custom<Method>({
method: Flags.option({
options: [
'GET',
'POST',
Expand All @@ -51,7 +49,7 @@ export class OrgApi extends SfCommand<void> {
'DELETE',
'OPTIONS',
'TRACE',
],
] as const,
summary: 'The HTTP method for the request.',
char: 'X',
default: 'GET',
Expand All @@ -62,8 +60,23 @@ export class OrgApi extends SfCommand<void> {
char: 'H',
multiple: true,
}),
body: Flags.file({
summary: 'The file to use as the body for the request.',
body: Flags.string({
summary:
'The file to use as the body for the request (use "-" to read from standard input).',
parse: async (input) => {
if (input === '-') {
const body = await readStdin();
if (body) {
return body.trim();
} else {
throw new Error(
'Unable to read body: `-` was provided but STDIN is empty.',
);
}
} else {
return readFile(input, 'utf8');
}
},
helpValue: 'file',
}),
};
Expand Down Expand Up @@ -113,13 +126,9 @@ export class OrgApi extends SfCommand<void> {
}`,
...(flags.header ? OrgApi.getHeaders(flags.header) : {}),
},
body:
flags.method === 'GET'
? undefined
: flags.body
? await readFile(flags.body)
: undefined,
body: flags.method === 'GET' ? undefined : flags.body,
throwHttpErrors: false,
followRedirect: false,
});

// Print HTTP response status and headers.
Expand Down
37 changes: 29 additions & 8 deletions test/commands/org/api.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import nock = require('nock');
import { TestContext, MockTestOrgData } from '@salesforce/core/lib/testSetup.js';
import {
TestContext,
MockTestOrgData,
} from '@salesforce/core/lib/testSetup.js';
import { SfError } from '@salesforce/core';
import { expect } from 'chai';
import stripAnsi from 'strip-ansi';
Expand All @@ -13,6 +16,13 @@ describe('org api', () => {

let stdoutSpy: sinon.SinonSpy;

const orgLimitsResponse = {
ActiveScratchOrgs: {
Max: 200,
Remaining: 199,
},
};

beforeEach(async () => {
await $$.stubAuths(testOrg);
stdoutSpy = $$.SANDBOX.stub(process.stdout, 'write');
Expand All @@ -23,13 +33,6 @@ describe('org api', () => {
});

it('should request org limits and default to "GET" HTTP method', async () => {
const orgLimitsResponse = {
ActiveScratchOrgs: {
Max: 200,
Remaining: 199,
},
};

nock(testOrg.instanceUrl)
.get('/services/data/v56.0/limits')
.reply(200, orgLimitsResponse);
Expand Down Expand Up @@ -98,4 +101,22 @@ describe('org api', () => {
);
}
});

it('should not follow redirects', async () => {
nock(testOrg.instanceUrl)
.get('/services/data/v56.0/limites')
.reply(301, orgLimitsResponse, {
location: `${testOrg.instanceUrl}/services/data/v56.0/limits`,
});

await OrgApi.run([
'services/data/v56.0/limites',
'--target-org',
'[email protected]',
]);

const output = stripAnsi(stdoutSpy.args.flat().join(''));

expect(JSON.parse(output)).to.deep.equal(orgLimitsResponse);
});
});
Loading

0 comments on commit 06ef90d

Please sign in to comment.