Skip to content

Commit

Permalink
non-TTY check for required variables:
Browse files Browse the repository at this point in the history
Added a check in non-TTY environments for `account_id`, `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN`. If `account_id` exists in `wrangler.toml`
then `CLOUDFLARE_ACCOUNT_ID` is not needed in non-TTY scope. The `CLOUDFLARE_API_TOKEN` is necessary in non-TTY scope and will always error if missing.

resolves #827
  • Loading branch information
JacobMGEvans committed May 4, 2022
1 parent 50cbe61 commit 40a5f50
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 21 deletions.
30 changes: 26 additions & 4 deletions packages/wrangler/src/__tests__/publish.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ describe("publish", () => {
});

it("drops a user into the login flow if they're unauthenticated", async () => {
// Should not throw missing Errors in TTY environment
writeWranglerToml();
writeWorkerSource();
mockSubDomainRequest();
Expand Down Expand Up @@ -178,7 +177,7 @@ describe("publish", () => {
expect(std.err).toMatchInlineSnapshot(`""`);
});

it("should throw an error in non-TTY if 'account_id' & 'CLOUDFLARE_ACCOUNT_ID' is missing", async () => {
it("should throw an error in non-TTY & there is more than one account associated with API token", async () => {
setIsTTY(false);
process.env = {
CLOUDFLARE_API_TOKEN: "hunter2",
Expand Down Expand Up @@ -233,10 +232,33 @@ describe("publish", () => {
await expect(runWrangler("publish index.js")).rejects.toThrowError();

expect(std.err).toMatchInlineSnapshot(`
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mMissing 'CLOUDFLARE_API_TOKEN' from non-TTY environment, please see docs for more info: TBD[0m
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mIn a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN.[0m
"
`);
});
it("should throw error with no account ID provided and no members retrieved", async () => {
setIsTTY(false);
writeWranglerToml({
account_id: undefined,
});
process.env = {
CLOUDFLARE_API_TOKEN: "picard",
CLOUDFLARE_ACCOUNT_ID: undefined,
};
writeWorkerSource();
mockSubDomainRequest();
mockUploadWorkerRequest();
mockOAuthServerCallback();
mockGetMemberships({
success: false,
result: [],
});

X [ERROR] Did not login, quitting...
await expect(runWrangler("publish index.js")).rejects.toThrowError();

expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] Failed to automatically retrieve account IDs for the logged in user. In a non-interactive environment, it is mandatory to specify an account ID, either by assigning its value to CLOUDFLARE_ACCOUNT_ID, or as \`account_id\` in your \`wrangler.toml\` file.
"
`);
Expand Down
7 changes: 2 additions & 5 deletions packages/wrangler/src/__tests__/secret.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { mockAccountId, mockApiToken } from "./helpers/mock-account-id";
import { setMockResponse, unsetAllMocks } from "./helpers/mock-cfetch";
import { mockConsoleMethods } from "./helpers/mock-console";
import { mockConfirm, mockPrompt } from "./helpers/mock-dialogs";
import { useMockIsTTY } from "./helpers/mock-istty";
import { mockOAuthFlow } from "./helpers/mock-oauth-flow";
import { useMockStdin } from "./helpers/mock-stdin";
import { runInTempDir } from "./helpers/run-in-tmp";
Expand All @@ -13,14 +12,13 @@ import { runWrangler } from "./helpers/run-wrangler";
describe("wrangler secret", () => {
const std = mockConsoleMethods();
const { mockGetMemberships } = mockOAuthFlow();
const { setIsTTY } = useMockIsTTY();

runInTempDir();
mockAccountId();
mockApiToken();

afterEach(() => {
unsetAllMocks();
setIsTTY(true);
});

describe("put", () => {
Expand Down Expand Up @@ -180,7 +178,7 @@ describe("wrangler secret", () => {
await expect(
runWrangler("secret put the-key --name script-name")
).rejects.toThrowErrorMatchingInlineSnapshot(
`"No account id found, quitting..."`
`"Failed to automatically retrieve account IDs for the logged in user. In a non-interactive environment, it is mandatory to specify an account ID, either by assigning its value to CLOUDFLARE_ACCOUNT_ID, or as \`account_id\` in your \`wrangler.toml\` file."`
);
});

Expand All @@ -204,7 +202,6 @@ describe("wrangler secret", () => {
});

it("should error if a user has multiple accounts, and has not specified an account in wrangler.toml", async () => {
setIsTTY(false);
mockGetMemberships({
success: true,
result: [
Expand Down
6 changes: 6 additions & 0 deletions packages/wrangler/src/__tests__/whoami.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import { writeAuthConfigFile } from "../user";
import { getUserInfo, WhoAmI } from "../whoami";
import { setMockResponse } from "./helpers/mock-cfetch";
import { mockConsoleMethods } from "./helpers/mock-console";
import { useMockIsTTY } from "./helpers/mock-istty";
import { runInTempDir } from "./helpers/run-in-tmp";
import type { UserInfo } from "../whoami";

describe("getUserInfo()", () => {
runInTempDir({ homedir: "./home" });
const std = mockConsoleMethods();
const { setIsTTY } = useMockIsTTY();

beforeEach(() => {
setIsTTY(true);
});

it("should return undefined if there is no config file", async () => {
const userInfo = await getUserInfo();
Expand Down
16 changes: 8 additions & 8 deletions packages/wrangler/src/pages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -842,11 +842,11 @@ const createDeployment: CommandModule<
const config = getConfigCache<PagesConfigCache>(
PAGES_CONFIG_CACHE_FILENAME
);
const isInteractive = process.stdin.isTTY;
const accountId = await requireAuth(config, isInteractive);
const accountId = await requireAuth(config);

projectName ??= config.project_name;

const isInteractive = process.stdin.isTTY;
if (!projectName && isInteractive) {
const existingOrNew = await new Promise<"new" | "existing">((resolve) => {
const { unmount } = render(
Expand Down Expand Up @@ -1605,8 +1605,8 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
const config = getConfigCache<PagesConfigCache>(
PAGES_CONFIG_CACHE_FILENAME
);
const isInteractive = process.stdin.isTTY;
const accountId = await requireAuth(config, isInteractive);

const accountId = await requireAuth(config);

const projects: Array<Project> = await listProjects({ accountId });

Expand Down Expand Up @@ -1650,9 +1650,9 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
const config = getConfigCache<PagesConfigCache>(
PAGES_CONFIG_CACHE_FILENAME
);
const isInteractive = process.stdin.isTTY;
const accountId = await requireAuth(config, isInteractive);
const accountId = await requireAuth(config);

const isInteractive = process.stdin.isTTY;
if (!projectName && isInteractive) {
projectName = await prompt("Enter the name of your new project:");
}
Expand Down Expand Up @@ -1735,11 +1735,11 @@ export const pages: BuilderCallback<unknown, unknown> = (yargs) => {
const config = getConfigCache<PagesConfigCache>(
PAGES_CONFIG_CACHE_FILENAME
);
const isInteractive = process.stdin.isTTY;
const accountId = await requireAuth(config, isInteractive);
const accountId = await requireAuth(config);

projectName ??= config.project_name;

const isInteractive = process.stdin.isTTY;
if (!projectName && isInteractive) {
const projects = await listProjects({ accountId });
projectName = await new Promise((resolve) => {
Expand Down
11 changes: 7 additions & 4 deletions packages/wrangler/src/user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,9 @@ export function getAPIToken(): string | undefined {
!localAPIToken &&
!LocalState.accessToken?.value
) {
logger.error(
"Missing 'CLOUDFLARE_API_TOKEN' from non-TTY environment, please see docs for more info: TBD"
throw new Error(
"In a non-interactive environment, it's necessary to set a CLOUDFLARE_API_TOKEN environment variable for wrangler to work. Please go to https://developers.cloudflare.com/api/tokens/create/ for instructions on how to create an api token, and assign its value to CLOUDFLARE_API_TOKEN."
);

return;
}

return localAPIToken ?? LocalState.accessToken?.value;
Expand Down Expand Up @@ -1142,6 +1140,11 @@ export async function getAccountId(
.join("\n")
);
}
} else {
if (!isInteractive)
throw new Error(
`Failed to automatically retrieve account IDs for the logged in user. In a non-interactive environment, it is mandatory to specify an account ID, either by assigning its value to CLOUDFLARE_ACCOUNT_ID, or as \`account_id\` in your \`wrangler.toml\` file.`
);
}
return accountId;
}
Expand Down

0 comments on commit 40a5f50

Please sign in to comment.