@superblocksteam/cli 1.0.2 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
5
+ const core_1 = require("@oclif/core");
6
+ const util_1 = require("@superblocksteam/util");
7
+ const listr2_1 = require("listr2");
8
+ const lodash_1 = require("lodash");
9
+ const authenticated_command_1 = require("../common/authenticated-command");
10
+ const version_control_1 = require("../common/version-control");
11
+ class Push extends authenticated_command_1.AuthenticatedCommand {
12
+ async run() {
13
+ const { flags, args } = await this.parse(Push);
14
+ const tasks = this.createTasks(args.resource_path, flags.branch);
15
+ await tasks.run();
16
+ }
17
+ createTasks(resourceName, branch) {
18
+ const tasks = new listr2_1.Listr([
19
+ {
20
+ title: "Checking for existing Superblocks project...",
21
+ task: async (ctx) => {
22
+ ctx.pushedResources = {};
23
+ ctx.removedResourceIds = [];
24
+ try {
25
+ [
26
+ ctx.existingSuperblocksRootConfig,
27
+ ctx.superblocksRootConfigPath,
28
+ ] = await (0, util_1.getSuperblocksMonorepoConfigJson)(true);
29
+ ctx.existingSuperblocksResourceConfig =
30
+ await (0, util_1.getSuperblocksResourceConfigIfExists)();
31
+ }
32
+ catch {
33
+ // no existing superblocks config
34
+ this.error("No Superblocks project found in the current folder hierarchy. Run 'superblocks init' to initialize a new project.");
35
+ }
36
+ },
37
+ },
38
+ {
39
+ title: "Checking for existing git repository...",
40
+ task: async (ctx) => {
41
+ try {
42
+ ctx.pushToBranchName =
43
+ branch || (await (0, version_control_1.getCurrentGitBranchIfGit)()) || version_control_1.DEFAULT_BRANCH;
44
+ [ctx.headCommitId, ctx.headCommitMessage] = await (0, version_control_1.getHeadCommit)(ctx.pushToBranchName);
45
+ }
46
+ catch (e) {
47
+ this.error(`Failed to check for existing git repository: ${e.message}. Please make sure to clone or initialize a git repository.`);
48
+ }
49
+ const isDirtyRepo = await (0, version_control_1.isGitRepoDirty)();
50
+ if (isDirtyRepo) {
51
+ this.error(`Your git repository is dirty. Please commit or stash your changes before pushing to Superblocks.`);
52
+ }
53
+ },
54
+ },
55
+ {
56
+ title: "Checking for deleted Superblocks resources...",
57
+ task: async (ctx, task) => {
58
+ var _a, _b, _c;
59
+ try {
60
+ for (const [resourceId, resource] of Object.entries((_b = (_a = ctx.existingSuperblocksRootConfig) === null || _a === void 0 ? void 0 : _a.resources) !== null && _b !== void 0 ? _b : {})) {
61
+ switch (resource === null || resource === void 0 ? void 0 : resource.resourceType) {
62
+ case "APPLICATION": {
63
+ try {
64
+ await this.getSdk().fetchApplication({
65
+ applicationId: resourceId,
66
+ //NOTE(alex): using default branch since we assume that the resource is deleted if it's deleted from the default branch
67
+ branch: version_control_1.DEFAULT_BRANCH,
68
+ });
69
+ }
70
+ catch (error) {
71
+ if (error instanceof util_1.NotFoundError) {
72
+ ctx.removedResourceIds.push(resourceId);
73
+ }
74
+ else {
75
+ throw error;
76
+ }
77
+ }
78
+ break;
79
+ }
80
+ case "BACKEND": {
81
+ try {
82
+ await this.getSdk().fetchApi(resourceId);
83
+ }
84
+ catch (error) {
85
+ if (error instanceof util_1.NotFoundError) {
86
+ ctx.removedResourceIds.push(resourceId);
87
+ }
88
+ else {
89
+ throw error;
90
+ }
91
+ }
92
+ break;
93
+ }
94
+ default: {
95
+ this.warn(`Unsupported resource type, resource: ${JSON.stringify(resource)}`);
96
+ }
97
+ }
98
+ }
99
+ if (ctx.removedResourceIds.length === 0) {
100
+ return;
101
+ }
102
+ const listOfDeletedResources = ctx.removedResourceIds
103
+ .map((id) => `- ${ctx.existingSuperblocksRootConfig.resources[id].location}`)
104
+ .join("\n");
105
+ const removeResourcesFromDisk = await task.prompt([
106
+ {
107
+ name: "removeResourcesFromDisk",
108
+ type: "confirm",
109
+ message: `Warning: The following resources could not be found in Superblocks.
110
+ ${listOfDeletedResources}
111
+
112
+ Automatically removing resources from your local Superblocks project.
113
+
114
+ Would you like to also delete these resources from your filesystem?`,
115
+ },
116
+ ]);
117
+ if (removeResourcesFromDisk) {
118
+ for (const resourceId of ctx.removedResourceIds) {
119
+ const resource = (_c = ctx.existingSuperblocksRootConfig) === null || _c === void 0 ? void 0 : _c.resources[resourceId];
120
+ await (0, version_control_1.removeResourceFromDisk)(resource.location);
121
+ }
122
+ }
123
+ }
124
+ catch (e) {
125
+ this.warn(`Could not check for deleted Superblocks resources. Continuing...: ${e.message}`);
126
+ }
127
+ },
128
+ },
129
+ {
130
+ task: async (ctx, task) => {
131
+ var _a;
132
+ task.title = `Pushing resources to branch ${ctx.pushToBranchName}...`;
133
+ const resourceIdsToPush = await this.getResourceIdsToPush(ctx, task, resourceName);
134
+ const subtasks = [];
135
+ const superblocksRootPath = node_path_1.default.resolve(node_path_1.default.dirname(ctx.superblocksRootConfigPath), "..");
136
+ for (const resourceId of resourceIdsToPush) {
137
+ const resource = (_a = ctx.existingSuperblocksRootConfig) === null || _a === void 0 ? void 0 : _a.resources[resourceId];
138
+ switch (resource === null || resource === void 0 ? void 0 : resource.resourceType) {
139
+ case "APPLICATION": {
140
+ subtasks.push({
141
+ title: `Pushing application ${resource.location}...`,
142
+ task: async (_ctx, task) => {
143
+ const applicationConfig = {
144
+ ...(await (0, version_control_1.readApplicationFromDisk)(superblocksRootPath, resource.location)),
145
+ commitId: ctx.headCommitId,
146
+ commitMessage: ctx.headCommitMessage,
147
+ };
148
+ task.title += `: read from disk`;
149
+ await this.getSdk().pushApplication({
150
+ applicationId: resourceId,
151
+ applicationConfig,
152
+ branch: ctx.pushToBranchName,
153
+ });
154
+ task.title += `: pushed to Superblocks`;
155
+ ctx.pushedResources[resourceId] = resource;
156
+ },
157
+ });
158
+ break;
159
+ }
160
+ default: {
161
+ this.error(`Unsupported resource type, resource: ${JSON.stringify(resource)}
162
+ `);
163
+ }
164
+ }
165
+ }
166
+ return task.newListr(subtasks, {
167
+ concurrent: true,
168
+ });
169
+ },
170
+ },
171
+ ], {
172
+ concurrent: false,
173
+ });
174
+ return tasks;
175
+ }
176
+ async getResourceIdsToPush(ctx, task, resourcePath, supportedResourceTypes = ["APPLICATION"]) {
177
+ var _a, _b, _c;
178
+ const resources = Object.entries((_b = (_a = ctx.existingSuperblocksRootConfig) === null || _a === void 0 ? void 0 : _a.resources) !== null && _b !== void 0 ? _b : {}).filter(([, resource]) => {
179
+ return supportedResourceTypes.includes(resource.resourceType);
180
+ });
181
+ // If there are no resources, or if the user has specified a resource name
182
+ // that doesn't exist, we should throw an error.
183
+ if ((0, lodash_1.isEmpty)(resources)) {
184
+ throw new Error("No resources found in the current project");
185
+ }
186
+ else if (!(0, lodash_1.isEmpty)(resourcePath)) {
187
+ const resource = resources.find(([, resource]) => resource.location === resourcePath);
188
+ if (resource) {
189
+ return [resource[0]];
190
+ }
191
+ throw new Error(`No resource found with the given location: ${resourcePath}`);
192
+ }
193
+ const choices = [];
194
+ const initialSelections = [];
195
+ let counter = 0;
196
+ for (const [resourceId, resource] of resources) {
197
+ choices.push({
198
+ name: resourceId,
199
+ message: resource.location,
200
+ });
201
+ if (((_c = ctx.existingSuperblocksResourceConfig) === null || _c === void 0 ? void 0 : _c.id) === resourceId) {
202
+ initialSelections.push(counter);
203
+ }
204
+ counter++;
205
+ }
206
+ const resourceIdsToPush = choices.length === 1
207
+ ? [choices[0].name]
208
+ : await task.prompt([
209
+ {
210
+ type: "MultiSelect",
211
+ name: "resourceIdsToPush",
212
+ message: `Select resources to push (${version_control_1.MULTI_SELECT_PROMPT_HELP})`,
213
+ choices: choices,
214
+ initial: initialSelections,
215
+ validate: version_control_1.atLeastOneSelection,
216
+ prefix: "▸",
217
+ indicator: "◉",
218
+ },
219
+ ]);
220
+ return resourceIdsToPush;
221
+ }
222
+ }
223
+ Push.description = "Import objects from local filesystem to Superblocks";
224
+ Push.examples = [
225
+ "<%= config.bin %> <%= command.id %>",
226
+ "<%= config.bin %> <%= command.id %> apps/my-app",
227
+ "<%= config.bin %> <%= command.id %> apps/my-app -b feature-branch",
228
+ ];
229
+ Push.flags = {
230
+ branch: core_1.Flags.string({
231
+ char: "b",
232
+ description: "Superblocks branch to push to, the current git branch will be used by default",
233
+ }),
234
+ };
235
+ Push.args = {
236
+ resource_path: core_1.Args.string({
237
+ description: "Superblocks resource location to push (e.g. apps/my-app)",
238
+ }),
239
+ };
240
+ exports.default = Push;
@@ -3,7 +3,7 @@ export default class Remove extends AuthenticatedCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static args: {
6
- resourceLocation: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
6
+ resource_path: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
7
7
  };
8
8
  run(): Promise<void>;
9
9
  private createTasks;
@@ -40,7 +40,7 @@ class Remove extends authenticated_command_1.AuthenticatedCommand {
40
40
  task: (ctx, task) => task.newListr([
41
41
  {
42
42
  title: "Fetching applications...",
43
- enabled: () => !args.resourceLocation,
43
+ enabled: () => !args.resource_path,
44
44
  task: async (ctx, task) => {
45
45
  // applications choices
46
46
  const applications = await this.getSdk().fetchApplications();
@@ -104,8 +104,8 @@ class Remove extends authenticated_command_1.AuthenticatedCommand {
104
104
  }
105
105
  async getResourcesToRemove(ctx, task, args) {
106
106
  var _a;
107
- if (args.resourceLocation) {
108
- const [resourceId] = getResourceIdFromLocation(ctx, args.resourceLocation);
107
+ if (args.resource_path) {
108
+ const [resourceId] = getResourceIdFromLocation(ctx, args.resource_path);
109
109
  return [resourceId];
110
110
  }
111
111
  else {
@@ -169,7 +169,7 @@ Remove.examples = [
169
169
  "<%= config.bin %> <%= command.id %> apps/my-spectacular-app",
170
170
  ];
171
171
  Remove.args = {
172
- resourceLocation: core_1.Args.string({
172
+ resource_path: core_1.Args.string({
173
173
  description: "Superblocks resource location (i.e. apps/my-spectacular-app)",
174
174
  }),
175
175
  };
@@ -126,8 +126,10 @@ class AuthenticatedApplicationCommand extends AuthenticatedCommand {
126
126
  }
127
127
  core_1.ux.action.start("Checking application...");
128
128
  try {
129
+ const branch = (await (0, version_control_1.getCurrentGitBranchIfGit)()) || version_control_1.DEFAULT_BRANCH;
129
130
  const application = await this.getSdk().fetchApplication({
130
131
  applicationId: this.applicationConfig.id,
132
+ branch: branch,
131
133
  });
132
134
  core_1.ux.action.stop();
133
135
  if ((_b = (_a = application === null || application === void 0 ? void 0 : application.application) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.cliVersion) {
@@ -191,7 +193,8 @@ ${(0, colorette_1.cyan)("superblocks migrate")}`);
191
193
  core_1.ux.action.stop();
192
194
  try {
193
195
  core_1.ux.action.start("Registering components...");
194
- await this.getSdk().registerComponents(this.applicationConfig.id, configs, injectedHeaders);
196
+ const branch = await (0, version_control_1.getCurrentGitBranchIfGit)();
197
+ await this.getSdk().registerComponents(this.applicationConfig.id, configs, branch, injectedHeaders);
195
198
  core_1.ux.action.stop();
196
199
  }
197
200
  catch (e) {
@@ -1,15 +1,27 @@
1
- import { ViewMode } from "@superblocksteam/sdk";
1
+ import { ApplicationWrapper, ViewMode } from "@superblocksteam/sdk";
2
2
  import { VersionedResourceConfig } from "@superblocksteam/util";
3
3
  export declare const LATEST_EDITS_MODE = "latest-edits";
4
4
  export declare const MOST_RECENT_COMMIT_MODE = "most-recent-commit";
5
5
  export declare const DEPLOYED_MODE = "deployed";
6
+ export declare const DEFAULT_BRANCH = "main";
6
7
  export declare const modeFlagValuesMap: Record<string, string>;
7
8
  export declare function modeFlagToViewMode(modeFlag: ModeFlag): ViewMode;
8
9
  export type ModeFlag = (keyof typeof modeFlagValuesMap)[number];
9
10
  export declare const SELECT_PROMPT_HELP = "Use \u2191/\u2193 arrow keys, Enter to confirm";
10
11
  export declare const MULTI_SELECT_PROMPT_HELP = "Type to filter, Use \u2191/\u2193 arrow keys, Space to select, Enter to confirm";
11
12
  export declare const atLeastOneSelection: (value: string[]) => string | true;
13
+ export declare function readApplicationFromDisk(rootPath: string, existingRelativeLocation: string): Promise<ApplicationWrapper>;
12
14
  export declare function writeResourceToDisk(resourceType: string, resourceId: string, resource: any, rootPath: string, existingRelativeLocation?: string): Promise<VersionedResourceConfig>;
13
15
  export declare function removeResourceFromDisk(resourceLocation: string): Promise<void>;
14
16
  export declare function getMode(task: any, mode: ModeFlag): Promise<ViewMode>;
15
17
  export declare function sortByKey(obj: unknown): unknown;
18
+ /**
19
+ * Returns the current git branch, or undefined if not in a git repo
20
+ */
21
+ export declare function getCurrentGitBranchIfGit(): Promise<string | null>;
22
+ /**
23
+ * Returns the current git branch, or throws if not in a git repo
24
+ */
25
+ export declare function getCurrentGitBranch(): Promise<string>;
26
+ export declare function getHeadCommit(branch: string): Promise<[string, string]>;
27
+ export declare function isGitRepoDirty(): Promise<boolean>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sortByKey = exports.getMode = exports.removeResourceFromDisk = exports.writeResourceToDisk = exports.atLeastOneSelection = exports.MULTI_SELECT_PROMPT_HELP = exports.SELECT_PROMPT_HELP = exports.modeFlagToViewMode = exports.modeFlagValuesMap = exports.DEPLOYED_MODE = exports.MOST_RECENT_COMMIT_MODE = exports.LATEST_EDITS_MODE = void 0;
3
+ exports.isGitRepoDirty = exports.getHeadCommit = exports.getCurrentGitBranch = exports.getCurrentGitBranchIfGit = exports.sortByKey = exports.getMode = exports.removeResourceFromDisk = exports.writeResourceToDisk = exports.readApplicationFromDisk = exports.atLeastOneSelection = exports.MULTI_SELECT_PROMPT_HELP = exports.SELECT_PROMPT_HELP = exports.modeFlagToViewMode = exports.modeFlagValuesMap = exports.DEFAULT_BRANCH = exports.DEPLOYED_MODE = exports.MOST_RECENT_COMMIT_MODE = exports.LATEST_EDITS_MODE = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const https = tslib_1.__importStar(require("https"));
6
6
  const node_path_1 = tslib_1.__importDefault(require("node:path"));
@@ -10,11 +10,13 @@ const colorette_1 = require("colorette");
10
10
  const fs = tslib_1.__importStar(require("fs-extra"));
11
11
  const lodash_1 = require("lodash");
12
12
  const lodash_2 = tslib_1.__importDefault(require("lodash"));
13
+ const simple_git_1 = require("simple-git");
13
14
  const slugify_1 = tslib_1.__importDefault(require("slugify"));
14
15
  const yaml_1 = require("yaml");
15
16
  exports.LATEST_EDITS_MODE = "latest-edits";
16
17
  exports.MOST_RECENT_COMMIT_MODE = "most-recent-commit";
17
18
  exports.DEPLOYED_MODE = "deployed";
19
+ exports.DEFAULT_BRANCH = "main";
18
20
  exports.modeFlagValuesMap = {
19
21
  [exports.LATEST_EDITS_MODE]: "Latest edits",
20
22
  [exports.MOST_RECENT_COMMIT_MODE]: "Most recent commit",
@@ -87,8 +89,38 @@ async function downloadFile(rootDirectory, filepath, url) {
87
89
  }
88
90
  return Promise.resolve("");
89
91
  }
92
+ async function readYamlFile(path) {
93
+ return (0, yaml_1.parse)(await fs.readFile(path, "utf8"));
94
+ }
95
+ // NOTE: If a change is made to how applications are read from disk, please update
96
+ // logic to write applications to disk in the "writeResourceToDisk" function accordingly.
97
+ async function readApplicationFromDisk(rootPath, existingRelativeLocation) {
98
+ const application = await readYamlFile(`${rootPath}/${existingRelativeLocation}/application.yaml`);
99
+ const page = await readYamlFile(`${rootPath}/${existingRelativeLocation}/page.yaml`);
100
+ const apisDirName = `${rootPath}/${existingRelativeLocation}/apis`;
101
+ const apis = [];
102
+ if (await fs.pathExists(apisDirName)) {
103
+ const apiFiles = await fs.readdir(apisDirName);
104
+ for (const apiFile of apiFiles) {
105
+ const apiContent = await readYamlFile(`${apisDirName}/${apiFile}`);
106
+ // This mimics the shape of the ApiV3Dto object
107
+ apis.push({
108
+ id: apiContent.metadata.id,
109
+ apiPb: apiContent,
110
+ });
111
+ }
112
+ }
113
+ return {
114
+ application,
115
+ apis,
116
+ page,
117
+ };
118
+ }
119
+ exports.readApplicationFromDisk = readApplicationFromDisk;
120
+ // NOTE: If a change is made to how applications are written to disk, please update
121
+ // logic to read applications from disk in the "readApplicationFromDisk" function accordingly.
90
122
  async function writeResourceToDisk(resourceType, resourceId, resource, rootPath, existingRelativeLocation) {
91
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
123
+ var _a, _b, _c, _d, _e, _f;
92
124
  switch (resourceType) {
93
125
  case "APPLICATION": {
94
126
  const parentDirName = "apps";
@@ -105,6 +137,7 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
105
137
  if (resource.page) {
106
138
  const pageContent = (0, yaml_1.stringify)(resource.page, {
107
139
  sortMapEntries: true,
140
+ blockQuote: "literal",
108
141
  });
109
142
  await fs.outputFile(`${appDirName}/page.yaml`, pageContent);
110
143
  }
@@ -119,10 +152,11 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
119
152
  };
120
153
  if (resource.apis) {
121
154
  for (const api of resource.apis) {
122
- const originalApiName = (_d = (_c = (_b = api.apiPb) === null || _b === void 0 ? void 0 : _b.metadata) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : api.actions.name;
155
+ const originalApiName = api.apiPb.metadata.name;
123
156
  const apiName = slugifyName(originalApiName);
124
157
  const apiContent = (0, yaml_1.stringify)(api.apiPb, {
125
158
  sortMapEntries: true,
159
+ blockQuote: "literal",
126
160
  });
127
161
  const handleApi = async () => {
128
162
  await fs.outputFile(`${apisDirName}/${apiName}.yaml`, apiContent);
@@ -136,7 +170,7 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
136
170
  await fs.writeFile(`${appDirName}/${util_1.RESOURCE_CONFIG_PATH}`, JSON.stringify(sortByKey(applicationConfig), null, 2));
137
171
  const createdFiles = await Promise.resolve(
138
172
  // Defensive check for when application settings are missing componentFiles
139
- (_f = (_e = resource.componentFiles) === null || _e === void 0 ? void 0 : _e.map((file) => downloadFile(appDirName, file.filename, file.url))) !== null && _f !== void 0 ? _f : []);
173
+ (_c = (_b = resource.componentFiles) === null || _b === void 0 ? void 0 : _b.map((file) => downloadFile(appDirName, file.filename, file.url))) !== null && _c !== void 0 ? _c : []);
140
174
  // print out failed downloads synchronously here
141
175
  createdFiles
142
176
  .filter((createdFiles) => createdFiles.length)
@@ -150,7 +184,7 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
150
184
  }
151
185
  case "BACKEND": {
152
186
  const parentDirName = "backends";
153
- const apiName = slugifyName((_j = (_h = (_g = resource.apiPb) === null || _g === void 0 ? void 0 : _g.metadata) === null || _h === void 0 ? void 0 : _h.name) !== null && _j !== void 0 ? _j : resource.actions.name);
187
+ const apiName = slugifyName((_f = (_e = (_d = resource.apiPb) === null || _d === void 0 ? void 0 : _d.metadata) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : resource.actions.name);
154
188
  const newRelativeLocation = `${parentDirName}/${apiName}`;
155
189
  const relativeLocation = existingRelativeLocation !== null && existingRelativeLocation !== void 0 ? existingRelativeLocation : newRelativeLocation;
156
190
  const backendDirName = node_path_1.default.resolve(rootPath, relativeLocation);
@@ -159,6 +193,7 @@ async function writeResourceToDisk(resourceType, resourceId, resource, rootPath,
159
193
  }
160
194
  const backendContent = (0, yaml_1.stringify)(resource.apiPb, {
161
195
  sortMapEntries: true,
196
+ blockQuote: "literal",
162
197
  });
163
198
  await fs.outputFile(`${backendDirName}/api.yaml`, backendContent);
164
199
  const backendConfig = {
@@ -217,3 +252,52 @@ function sortByKey(obj) {
217
252
  return obj;
218
253
  }
219
254
  exports.sortByKey = sortByKey;
255
+ /**
256
+ * Returns the current git branch, or undefined if not in a git repo
257
+ */
258
+ async function getCurrentGitBranchIfGit() {
259
+ const git = (0, simple_git_1.simpleGit)();
260
+ try {
261
+ const status = await git.status();
262
+ const currentBranch = status.current;
263
+ return currentBranch;
264
+ }
265
+ catch {
266
+ // ignore
267
+ }
268
+ return null;
269
+ }
270
+ exports.getCurrentGitBranchIfGit = getCurrentGitBranchIfGit;
271
+ /**
272
+ * Returns the current git branch, or throws if not in a git repo
273
+ */
274
+ async function getCurrentGitBranch() {
275
+ const currentBranch = await getCurrentGitBranchIfGit();
276
+ if (!currentBranch) {
277
+ throw new Error("No git repository found");
278
+ }
279
+ return currentBranch;
280
+ }
281
+ exports.getCurrentGitBranch = getCurrentGitBranch;
282
+ async function getHeadCommit(branch) {
283
+ const git = (0, simple_git_1.simpleGit)();
284
+ let headCommitId;
285
+ let headCommitMessage;
286
+ const logResponse = await git.show(["--no-patch", "--format=%H%n%s", branch]);
287
+ const logLines = logResponse.split("\n");
288
+ if (logLines.length > 1) {
289
+ headCommitId = logLines[0];
290
+ headCommitMessage = logLines[1];
291
+ }
292
+ if (!headCommitId || !headCommitMessage) {
293
+ throw new Error(`Failed to get head commit for branch '${branch}'`);
294
+ }
295
+ return [headCommitId, headCommitMessage];
296
+ }
297
+ exports.getHeadCommit = getHeadCommit;
298
+ async function isGitRepoDirty() {
299
+ const git = (0, simple_git_1.simpleGit)();
300
+ const status = await git.status();
301
+ return !status.isClean();
302
+ }
303
+ exports.isGitRepoDirty = isGitRepoDirty;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.2",
2
+ "version": "1.1.1",
3
3
  "commands": {
4
4
  "init": {
5
5
  "id": "init",
@@ -28,8 +28,8 @@
28
28
  }
29
29
  },
30
30
  "args": {
31
- "resourceUrl": {
32
- "name": "resourceUrl",
31
+ "resource_url": {
32
+ "name": "resource_url",
33
33
  "description": "Superblocks resource URL (i.e. https://app.superblocks.com/applications/<application_id>/pages/<page_id>)",
34
34
  "required": false
35
35
  }
@@ -79,8 +79,7 @@
79
79
  "examples": [
80
80
  "<%= config.bin %> <%= command.id %>",
81
81
  "<%= config.bin %> <%= command.id %> apps/my-app",
82
- "<%= config.bin %> <%= command.id %> backends/my-workflow",
83
- "<%= config.bin %> <%= command.id %> backends/my-scheduled-job"
82
+ "<%= config.bin %> <%= command.id %> apps/my-app -b feature-branch"
84
83
  ],
85
84
  "flags": {
86
85
  "mode": {
@@ -95,16 +94,52 @@
95
94
  "deployed"
96
95
  ],
97
96
  "default": "latest-edits"
97
+ },
98
+ "branch": {
99
+ "name": "branch",
100
+ "type": "option",
101
+ "char": "b",
102
+ "description": "Superblocks branch to pull from, the current git branch will be used by default",
103
+ "multiple": false
98
104
  }
99
105
  },
100
106
  "args": {
101
- "only": {
102
- "name": "only",
103
- "description": "Superblocks resource location to pull (i.e. apps/my-app or backends/my-workflow)",
107
+ "resource_path": {
108
+ "name": "resource_path",
109
+ "description": "Superblocks resource location to pull (i.e. apps/my-app)",
104
110
  "required": false
105
111
  }
106
112
  }
107
113
  },
114
+ "push": {
115
+ "id": "push",
116
+ "description": "Import objects from local filesystem to Superblocks",
117
+ "strict": true,
118
+ "pluginName": "@superblocksteam/cli",
119
+ "pluginAlias": "@superblocksteam/cli",
120
+ "pluginType": "core",
121
+ "aliases": [],
122
+ "examples": [
123
+ "<%= config.bin %> <%= command.id %>",
124
+ "<%= config.bin %> <%= command.id %> apps/my-app",
125
+ "<%= config.bin %> <%= command.id %> apps/my-app -b feature-branch"
126
+ ],
127
+ "flags": {
128
+ "branch": {
129
+ "name": "branch",
130
+ "type": "option",
131
+ "char": "b",
132
+ "description": "Superblocks branch to push to, the current git branch will be used by default",
133
+ "multiple": false
134
+ }
135
+ },
136
+ "args": {
137
+ "resource_path": {
138
+ "name": "resource_path",
139
+ "description": "Superblocks resource location to push (e.g. apps/my-app)"
140
+ }
141
+ }
142
+ },
108
143
  "rm": {
109
144
  "id": "rm",
110
145
  "description": "Remove a Superblocks resource from the local Superblocks project and delete the resource folder directory locally (if it exists)",
@@ -119,8 +154,8 @@
119
154
  ],
120
155
  "flags": {},
121
156
  "args": {
122
- "resourceLocation": {
123
- "name": "resourceLocation",
157
+ "resource_path": {
158
+ "name": "resource_path",
124
159
  "description": "Superblocks resource location (i.e. apps/my-spectacular-app)"
125
160
  }
126
161
  }
@@ -166,9 +201,18 @@
166
201
  "pluginType": "core",
167
202
  "aliases": [],
168
203
  "examples": [
169
- "<%= config.bin %> components upload"
204
+ "<%= config.bin %> components upload",
205
+ "<%= config.bin %> components upload -b feature-branch"
170
206
  ],
171
- "flags": {},
207
+ "flags": {
208
+ "branch": {
209
+ "name": "branch",
210
+ "type": "option",
211
+ "char": "b",
212
+ "description": "Superblocks branch to push to, the current (local) git branch will be used by default",
213
+ "multiple": false
214
+ }
215
+ },
172
216
  "args": {}
173
217
  },
174
218
  "components:watch": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superblocksteam/cli",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "Official Superblocks CLI",
5
5
  "bin": {
6
6
  "superblocks": "bin/run"
@@ -18,11 +18,11 @@
18
18
  "@oclif/core": "^2.11.7",
19
19
  "@oclif/plugin-help": "^5.2.16",
20
20
  "@oclif/plugin-plugins": "^3.1.10",
21
- "@superblocksteam/css-plugin": "1.0.2",
22
- "@superblocksteam/react-shim": "1.0.2",
23
- "@superblocksteam/sdk": "1.0.2",
24
- "@superblocksteam/util": "1.0.2",
25
- "@superblocksteam/vite-custom-component-reload-plugin": "1.0.2",
21
+ "@superblocksteam/css-plugin": "1.1.1",
22
+ "@superblocksteam/react-shim": "1.1.1",
23
+ "@superblocksteam/sdk": "1.1.1",
24
+ "@superblocksteam/util": "1.1.1",
25
+ "@superblocksteam/vite-custom-component-reload-plugin": "1.1.1",
26
26
  "@vitejs/plugin-react": "^4.0.4",
27
27
  "colorette": "^2.0.19",
28
28
  "enquirer": "^2.3.6",
@@ -30,6 +30,7 @@
30
30
  "listr2": "6.6.0",
31
31
  "lodash": "^4.17.21",
32
32
  "semver": "^7.5.4",
33
+ "simple-git": "^3.20.0",
33
34
  "slugify": "^1.6.6",
34
35
  "vite": "^4.4.8",
35
36
  "vite-plugin-inspect": "^0.7.28",
@@ -41,7 +42,7 @@
41
42
  "@types/chai": "^4",
42
43
  "@types/fs-extra": "^11.0.1",
43
44
  "@types/mocha": "^9.0.0",
44
- "@types/node": "^16.18.38",
45
+ "@types/node": "^16.18.39",
45
46
  "@typescript-eslint/eslint-plugin": "^5.60.1",
46
47
  "@typescript-eslint/parser": "^5.60.1",
47
48
  "chai": "^4",
@@ -59,7 +60,7 @@
59
60
  "typescript": "^5.1.6"
60
61
  },
61
62
  "scripts": {
62
- "preinstall": "node -e 'if (process.versions.node.split(`.`)[0] < 16) { console.error(`Incompatible Node version: Please use Node.js v16 or higher`); process.exit(1);}'",
63
+ "preinstall": "node -e \"if (process.versions.node.split('.')[0] < 16) { console.error('Incompatible Node version: Please use Node.js v16 or higher'); process.exit(1);}\"",
63
64
  "build": "tsc --build",
64
65
  "clean": "npm run clean:build && rm -rf node_modules",
65
66
  "clean:build": "tsc --build --clean && rm -rf dist tsconfig.tsbuildinfo",