Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(deploy): create SWA in user-provided Resource Group #613

Merged
merged 2 commits into from Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/www/docs/cli/swa-config.md
Expand Up @@ -83,7 +83,7 @@ Options:
- appName: <undefined>
- dryRun: false
- subscriptionId: <undefined>
- resourceGroupName: <undefined>
- resourceGroup: <undefined>
- tenantId: <undefined>
- clientId: <undefined>
- clientSecret: <undefined>
Expand Down
2 changes: 1 addition & 1 deletion docs/www/docs/cli/swa-deploy.md
Expand Up @@ -163,7 +163,7 @@ Here are the options you can use with `swa deploy`:
- `-pt, --print-token`: print the deployment token (default: `false`)
- `--env [environment]`: the type of deployment environment where to deploy the project (default: "`preview`")
- `-S, --subscription-id <subscriptionId>`: Azure subscription ID used by this project (default: `process.env.AZURE_SUBSCRIPTION_ID`)
- `-R, --resource-group <resourceGroupName>`: Azure resource group used by this project
- `-R, --resource-group <resourceGroup>`: Azure resource group used by this project
- `-T, --tenant-id <tenantId>`: Azure tenant ID (default: `process.env.AZURE_TENANT_ID`)
- `-C, --client-id <clientId>`: Azure client ID
- `-CS, --client-secret <clientSecret>`: Azure client secret
Expand Down
2 changes: 1 addition & 1 deletion docs/www/docs/cli/swa-login.md
Expand Up @@ -20,7 +20,7 @@ This command is used to authenticate with Azure and get a deployment token that
Here are the options you can use with `swa login`:

- `-S, --subscription-id <subscriptionId>`: Azure subscription ID used by this project (default: `process.env.AZURE_SUBSCRIPTION_ID`)
- `-R, --resource-group <resourceGroupName>`: Azure resource group used by this project
- `-R, --resource-group <resourceGroup>`: Azure resource group used by this project
- `-T, --tenant-id <tenantId>`: Azure tenant ID (default: `process.env.AZURE_TENANT_ID`)
- `-C, --client-id <clientId>`: Azure client ID
- `-CS, --client-secret <clientSecret>`: Azure client secret
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/deploy.spec.ts
Expand Up @@ -41,7 +41,7 @@ jest.spyOn(loginModule, "login").mockImplementation(() => {
return Promise.resolve({
credentialChain: {} as any,
subscriptionId: "mock-subscription-id",
resourceGroupName: "mock-resource-group-name",
resourceGroup: "mock-resource-group-name",
staticSiteName: "mock-static-site-name",
});
});
Expand Down
10 changes: 5 additions & 5 deletions src/cli/commands/deploy.ts
Expand Up @@ -157,22 +157,22 @@ export async function deploy(options: SWACLIConfig) {
logger.log(`\nChecking project settings...`);
}

const { resourceGroupName, staticSiteName } = (await chooseOrCreateProjectDetails(options, credentialChain, subscriptionId, printToken)) as {
resourceGroupName: string;
const { resourceGroup, staticSiteName } = (await chooseOrCreateProjectDetails(options, credentialChain, subscriptionId, printToken)) as {
resourceGroup: string;
staticSiteName: string;
};

logger.silly(`Project settings:`);
logger.silly({
resourceGroupName,
resourceGroup,
staticSiteName,
subscriptionId,
});

const deploymentTokenResponse = await getStaticSiteDeployment(
credentialChain,
subscriptionId,
resourceGroupName as string,
resourceGroup as string,
staticSiteName as string
);

Expand All @@ -191,7 +191,7 @@ export async function deploy(options: SWACLIConfig) {

const newConfig = { ...currentSwaCliConfig?.config };
newConfig.appName = staticSiteName;
newConfig.resourceGroupName = resourceGroupName;
newConfig.resourceGroup = resourceGroup;
updateSwaCliConfigFile(newConfig);
} else {
logger.silly(`No swa-cli.config.json file found. Skipping saving project settings.`);
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/login.ts
Expand Up @@ -15,7 +15,7 @@ const { readFile, writeFile } = fsPromises;
export function addSharedLoginOptionsToCommand(command: Command) {
command
.option("-S, --subscription-id <subscriptionId>", "Azure subscription ID used by this project", DEFAULT_CONFIG.subscriptionId)
.option("-R, --resource-group <resourceGroupName>", "Azure resource group used by this project", DEFAULT_CONFIG.resourceGroupName)
.option("-R, --resource-group <resourceGroup>", "Azure resource group used by this project", DEFAULT_CONFIG.resourceGroup)
.option("-T, --tenant-id <tenantId>", "Azure tenant ID", DEFAULT_CONFIG.tenantId)
.option("-C, --client-id <clientId>", "Azure client ID", DEFAULT_CONFIG.clientId)
.option("-CS, --client-secret <clientSecret>", "Azure client secret", DEFAULT_CONFIG.clientSecret)
Expand Down
2 changes: 1 addition & 1 deletion src/config.ts
Expand Up @@ -60,7 +60,7 @@ export const DEFAULT_CONFIG: SWACLIConfig = {

// swa login options
subscriptionId: AZURE_SUBSCRIPTION_ID || undefined,
resourceGroupName: AZURE_RESOURCE_GROUP || undefined,
resourceGroup: AZURE_RESOURCE_GROUP || undefined,
tenantId: AZURE_TENANT_ID || undefined,
clientId: AZURE_CLIENT_ID || undefined,
clientSecret: AZURE_CLIENT_SECRET || undefined,
Expand Down
40 changes: 20 additions & 20 deletions src/core/account.ts
Expand Up @@ -76,11 +76,11 @@ export async function authenticateWithAzureIdentity(details: LoginDetails = {},
return new ChainedTokenCredential(...credentials);
}

async function isResourceGroupExists(resourceGroupName: string, subscriptionId: string, credentialChain: TokenCredential): Promise<boolean> {
async function isResourceGroupExists(resourceGroup: string, subscriptionId: string, credentialChain: TokenCredential): Promise<boolean> {
const client = new ResourceManagementClient(credentialChain, subscriptionId);

try {
const rg = await client.resourceGroups.checkExistence(resourceGroupName);
const rg = await client.resourceGroups.checkExistence(resourceGroup);
return rg.body;
} catch (error: any) {
if (error?.code?.includes("ResourceGroupNotFound")) {
Expand All @@ -90,7 +90,7 @@ async function isResourceGroupExists(resourceGroupName: string, subscriptionId:
}
}

async function createResourceGroup(resourcGroupeName: string, credentialChain: TokenCredential, subscriptionId: string) {
async function createResourceGroup(resourceGroup: string, credentialChain: TokenCredential, subscriptionId: string) {
const client = new ResourceManagementClient(credentialChain, subscriptionId);

const { AZURE_REGION_LOCATION } = swaCLIEnv();
Expand All @@ -99,7 +99,7 @@ async function createResourceGroup(resourcGroupeName: string, credentialChain: T
location: AZURE_REGION_LOCATION || DEFAULT_AZURE_LOCATION,
};

const result = await client.resourceGroups.createOrUpdate(resourcGroupeName, resourceGroupEnvelope);
const result = await client.resourceGroups.createOrUpdate(resourceGroup, resourceGroupEnvelope);

logger.silly(result as any);

Expand All @@ -119,21 +119,21 @@ async function gracefullyFail<T>(promise: Promise<T>, errorCode?: number): Promi
}

async function createStaticSite(options: SWACLIConfig, credentialChain: TokenCredential, subscriptionId: string): Promise<StaticSiteARMResource> {
let { appName, resourceGroupName } = options;
let { appName, resourceGroup } = options;

const maxProjectNameLength = 63; // azure convention is 64 characters (zero-indexed)
const defaultStaticSiteName = appName || dasherize(path.basename(process.cwd())).substring(0, maxProjectNameLength);

appName = await chooseProjectName(defaultStaticSiteName, maxProjectNameLength);
resourceGroupName = resourceGroupName || `${appName}-rg`;
resourceGroup = resourceGroup || `${appName}-rg`;

let spinner = ora("Creating a new project...").start();

// if the resource group does not exist, create it
if ((await isResourceGroupExists(resourceGroupName, subscriptionId, credentialChain)) === false) {
logger.silly(`Resource group "${resourceGroupName}" does not exist. Creating one...`);
if ((await isResourceGroupExists(resourceGroup, subscriptionId, credentialChain)) === false) {
logger.silly(`Resource group "${resourceGroup}" does not exist. Creating one...`);
// create the resource group
await createResourceGroup(resourceGroupName, credentialChain, subscriptionId);
await createResourceGroup(resourceGroup, credentialChain, subscriptionId);
}

// create the static web app instance
Expand All @@ -157,7 +157,7 @@ async function createStaticSite(options: SWACLIConfig, credentialChain: TokenCre
logger.silly(`Checking if project "${appName}" already exists...`);

// check if the static site already exists
const project = await gracefullyFail(websiteClient.staticSites.getStaticSite(resourceGroupName, appName), 404);
const project = await gracefullyFail(websiteClient.staticSites.getStaticSite(resourceGroup, appName), 404);
const projectExists = project !== undefined;

if (projectExists) {
Expand All @@ -173,8 +173,8 @@ async function createStaticSite(options: SWACLIConfig, credentialChain: TokenCre
spinner.start(`Updating project "${appName}"...`);
}

logger.silly(`Creating static site "${appName}" in resource group "${resourceGroupName}"...`);
const result = await websiteClient.staticSites.beginCreateOrUpdateStaticSiteAndWait(resourceGroupName, appName, staticSiteEnvelope);
logger.silly(`Creating static site "${appName}" in resource group "${resourceGroup}"...`);
const result = await websiteClient.staticSites.beginCreateOrUpdateStaticSiteAndWait(resourceGroup, appName, staticSiteEnvelope);

logger.silly(`Static site "${appName}" created successfully.`);
logger.silly(result as any);
Expand Down Expand Up @@ -277,10 +277,10 @@ export async function chooseOrCreateProjectDetails(
// get resource group name from static site id:
// /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/swa-resource-groupe-name/providers/Microsoft.Web/sites/swa-static-site
// 0 / 1 / 2 / 3 / 4
const resourceGroupName = staticSite.id.split("/")[4];
const resourceGroup = staticSite.id.split("/")[4];
const staticSiteName = staticSite.name;
return {
resourceGroupName,
resourceGroup,
staticSiteName,
};
} else {
Expand Down Expand Up @@ -317,13 +317,13 @@ export async function listSubscriptions(credentialChain: TokenCredential) {
return subscriptions;
}

export async function listStaticSites(credentialChain: TokenCredential, subscriptionId: string, resourceGroupName?: string) {
export async function listStaticSites(credentialChain: TokenCredential, subscriptionId: string, resourceGroup?: string) {
const staticSites = [];
const websiteClient = new WebSiteManagementClient(credentialChain, subscriptionId);

let staticSiteList = websiteClient.staticSites.list();
if (resourceGroupName) {
staticSiteList = websiteClient.staticSites.listStaticSitesByResourceGroup(resourceGroupName);
if (resourceGroup) {
staticSiteList = websiteClient.staticSites.listStaticSitesByResourceGroup(resourceGroup);
}

for await (let staticSite of staticSiteList) {
Expand All @@ -335,20 +335,20 @@ export async function listStaticSites(credentialChain: TokenCredential, subscrip
export async function getStaticSiteDeployment(
credentialChain: TokenCredential,
subscriptionId: string,
resourceGroupName: string,
resourceGroup: string,
staticSiteName: string
) {
if (!subscriptionId) {
logger.error("An Azure subscription is required to access your deployment token.", true);
}
if (!resourceGroupName) {
if (!resourceGroup) {
logger.error("A resource group is required to access your deployment token.", true);
}
if (!staticSiteName) {
logger.error("A static site name is required to access your deployment token.", true);
}

const websiteClient = new WebSiteManagementClient(credentialChain, subscriptionId);
const deploymentTokenResponse = await websiteClient.staticSites.listStaticSiteSecrets(resourceGroupName, staticSiteName);
const deploymentTokenResponse = await websiteClient.staticSites.listStaticSiteSecrets(resourceGroup, staticSiteName);
return deploymentTokenResponse;
}
2 changes: 1 addition & 1 deletion src/core/utils/options.spec.ts
Expand Up @@ -226,7 +226,7 @@ describe("Testing aliases for each of the commands and their options", () => {
const command = await new Command()
.name("swa")
.option("-S, --subscription-id [subscriptionId]")
.option("-R, --resource-group [resourceGroupName]")
.option("-R, --resource-group [resourceGroup]")
.option("-T, --tenant-id [tenantId]")
.option("-C, --client-id [clientId]")
.option("-CS, --client-secret [clientSecret]")
Expand Down
2 changes: 1 addition & 1 deletion src/swa.d.ts
Expand Up @@ -175,7 +175,7 @@ declare type LoginDetails = {

declare type SWACLISharedLoginOptions = LoginDetails & {
subscriptionId?: string;
resourceGroupName?: string;
resourceGroup?: string;
appName?: string;
useKeychain?: boolean;
clearCredentials?: boolean;
Expand Down