All files / src/commands/scale scale.command.js

54.54% Statements 66/121
100% Branches 1/1
0% Functions 0/2
54.54% Lines 66/121

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122193x 193x 193x 193x 193x 193x 193x 193x 193x                                                                             193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x                                   193x 193x  
import { z } from 'zod';
import { defineCommand } from '../../lib/define-command.js';
import { defineOption } from '../../lib/define-option.js';
import { Logger } from '../../logger.js';
import * as Application from '../../models/application.js';
import { listAvailableFlavors } from '../../models/application.js';
import { buildFlavor, flavor } from '../../parsers.js';
import { aliasOption, appIdOrNameOption } from '../global.options.js';
 
function validateOptions(options) {
  let { flavor, minFlavor, maxFlavor } = options;
  let { instances, minInstances, maxInstances, buildFlavor } = options;

  if ([flavor, minFlavor, maxFlavor, instances, minInstances, maxInstances, buildFlavor].every((v) => v == null)) {
    throw new Error('You should provide at least 1 option');
  }

  if (flavor != null) {
    if (minFlavor != null || maxFlavor != null) {
      throw new Error("You can't use --flavor and --min-flavor or --max-flavor at the same time");
    }
    minFlavor = flavor;
    maxFlavor = flavor;
  }

  if (instances != null) {
    if (minInstances != null || maxInstances != null) {
      throw new Error("You can't use --instances and --min-instances or --max-instances at the same time");
    }
    minInstances = instances;
    maxInstances = instances;
  }

  if (minInstances != null && maxInstances != null && minInstances > maxInstances) {
    throw new Error("min-instances can't be greater than max-instances");
  }

  if (minFlavor != null && maxFlavor != null) {
    const minFlavorIndex = Application.listAvailableFlavors().indexOf(minFlavor);
    const maxFlavorIndex = Application.listAvailableFlavors().indexOf(maxFlavor);
    if (minFlavorIndex > maxFlavorIndex) {
      throw new Error("min-flavor can't be a greater flavor than max-flavor");
    }
  }

  return { minFlavor, maxFlavor, minInstances, maxInstances, buildFlavor };
}
 
export const scaleCommand = defineCommand({
  description: 'Change scalability of an application',
  since: '0.4.0',
  options: {
    flavor: defineOption({
      name: 'flavor',
      schema: z.string().transform(flavor).optional(),
      description: 'The instance size of your application',
      placeholder: 'flavor',
      complete: listAvailableFlavors,
    }),
    minFlavor: defineOption({
      name: 'min-flavor',
      schema: z.string().transform(flavor).optional(),
      description: 'The minimum scale size of your application',
      placeholder: 'flavor',
      complete: listAvailableFlavors,
    }),
    maxFlavor: defineOption({
      name: 'max-flavor',
      schema: z.string().transform(flavor).optional(),
      description: 'The maximum instance size of your application',
      placeholder: 'flavor',
      complete: listAvailableFlavors,
    }),
    instances: defineOption({
      name: 'instances',
      schema: z.coerce.number().int().min(1).max(20).optional(),
      description: 'The number of parallel instances',
      placeholder: 'instances',
    }),
    minInstances: defineOption({
      name: 'min-instances',
      schema: z.coerce.number().int().min(1).max(20).optional(),
      description: 'The minimum number of parallel instances',
      placeholder: 'number',
    }),
    maxInstances: defineOption({
      name: 'max-instances',
      schema: z.coerce.number().int().min(1).max(20).optional(),
      description: 'The maximum number of parallel instances',
      placeholder: 'number',
    }),
    buildFlavor: defineOption({
      name: 'build-flavor',
      schema: z.string().transform(buildFlavor).optional(),
      description: "The size of the build instance, or 'disabled' if you want to disable dedicated build instances",
      placeholder: 'flavor',
    }),
    alias: aliasOption,
    app: appIdOrNameOption,
  },
  args: [],
  async handler(options) {
    const { alias, app: appIdOrName } = options;
    const { minFlavor, maxFlavor, minInstances, maxInstances, buildFlavor } = validateOptions(options);
    const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);

    await Application.setScalability(
      appId,
      ownerId,
      {
        minFlavor,
        maxFlavor,
        minInstances,
        maxInstances,
      },
      buildFlavor,
    );

    Logger.println('App rescaled successfully');
  },
});