@pagopa/dx-cli 0.14.4 → 0.15.0

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.
Files changed (3) hide show
  1. package/README.md +3 -0
  2. package/bin/index.js +103 -28
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -122,10 +122,13 @@ This command will:
122
122
 
123
123
  - Check that required tools (e.g., Terraform CLI) are installed
124
124
  - Interactively prompt for project metadata (cloud provider, region, environments, cost center, etc.)
125
+ - **Check that the target GitHub repository does not already exist before proceeding**
125
126
  - Generate a monorepo structure following PagoPA DevEx guidelines
126
127
  - Create a remote GitHub repository using Terraform
127
128
  - Push the initial codebase to the newly created repository
128
129
 
130
+ If the specified GitHub repository already exists, the command will fail early with a clear error message, preventing accidental overwrites.
131
+
129
132
  **Example usage:**
130
133
 
131
134
  ```bash
package/bin/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.ts
4
4
  import "core-js/actual/set/index.js";
5
5
  import { configure, getConsoleSink } from "@logtape/logtape";
6
- import { Octokit as Octokit2 } from "octokit";
6
+ import { Octokit as Octokit3 } from "octokit";
7
7
 
8
8
  // src/adapters/codemods/registry.ts
9
9
  import { okAsync } from "neverthrow";
@@ -765,10 +765,38 @@ import loadMonorepoScaffolder, {
765
765
  import chalk from "chalk";
766
766
  import { Command as Command4 } from "commander";
767
767
  import { $ as $3 } from "execa";
768
- import { okAsync as okAsync2, ResultAsync as ResultAsync6 } from "neverthrow";
768
+ import { errAsync, okAsync as okAsync2, ResultAsync as ResultAsync6 } from "neverthrow";
769
769
  import * as path from "path";
770
770
  import { oraPromise } from "ora";
771
771
 
772
+ // src/domain/github.ts
773
+ var PullRequest = class {
774
+ constructor(url) {
775
+ this.url = url;
776
+ }
777
+ };
778
+ var Repository = class {
779
+ constructor(name, owner) {
780
+ this.name = name;
781
+ this.owner = owner;
782
+ }
783
+ get fullName() {
784
+ return `${this.owner}/${this.name}`;
785
+ }
786
+ get ssh() {
787
+ return `git@github.com:${this.owner}/${this.name}.git`;
788
+ }
789
+ get url() {
790
+ return `https://github.com/${this.owner}/${this.name}`;
791
+ }
792
+ };
793
+ var RepositoryNotFoundError = class extends Error {
794
+ constructor(owner, name) {
795
+ super(`Repository ${owner}/${name} not found`);
796
+ this.name = "RepositoryNotFoundError";
797
+ }
798
+ };
799
+
772
800
  // src/adapters/execa/terraform.ts
773
801
  import { $ as $2 } from "execa";
774
802
  var tf$ = $2({
@@ -804,18 +832,6 @@ var decode = (schema) => (data) => ResultAsync5.fromPromise(
804
832
  );
805
833
 
806
834
  // src/adapters/commander/commands/init.ts
807
- var Repository = class {
808
- constructor(name, owner) {
809
- this.name = name;
810
- this.owner = owner;
811
- }
812
- get ssh() {
813
- return `git@github.com:${this.owner}/${this.name}.git`;
814
- }
815
- get url() {
816
- return `https://github.com/${this.owner}/${this.name}`;
817
- }
818
- };
819
835
  var withSpinner = (text, successText, failText, promise) => ResultAsync6.fromPromise(
820
836
  oraPromise(promise, {
821
837
  failText,
@@ -827,7 +843,20 @@ var withSpinner = (text, successText, failText, promise) => ResultAsync6.fromPro
827
843
  return new Error(failText, { cause });
828
844
  }
829
845
  );
830
- var validateAnswers = (answers) => okAsync2(answers);
846
+ var validateAnswers = (githubService) => (answers) => ResultAsync6.fromPromise(
847
+ githubService.getRepository(answers.repoOwner, answers.repoName),
848
+ (error) => error
849
+ ).andThen(
850
+ ({ fullName }) => errAsync(new Error(`Repository ${fullName} already exists.`))
851
+ ).orElse(
852
+ (error) => error instanceof RepositoryNotFoundError ? (
853
+ // If repository is not found, it's safe to proceed
854
+ okAsync2(answers)
855
+ ) : (
856
+ // Otherwise, propagate the error
857
+ errAsync(error)
858
+ )
859
+ ).map(() => answers);
831
860
  var runGeneratorActions = (generator) => (answers) => withSpinner(
832
861
  "Creating workspace files...",
833
862
  "Workspace files created successfully!",
@@ -919,8 +948,8 @@ var initializeGitRepository = (repository) => {
919
948
  pushToOrigin()
920
949
  ).map(() => ({ branchName, repository }));
921
950
  };
922
- var handleNewGitHubRepository = (octokit2) => (answers) => createRemoteRepository(answers).andThen(initializeGitRepository).andThen(
923
- (localWorkspace) => createPullRequest(octokit2)(localWorkspace).map((pr) => ({
951
+ var handleNewGitHubRepository = (githubService) => (answers) => createRemoteRepository(answers).andThen(initializeGitRepository).andThen(
952
+ (localWorkspace) => createPullRequest(githubService)(localWorkspace).map((pr) => ({
924
953
  pr,
925
954
  repository: localWorkspace.repository
926
955
  }))
@@ -936,14 +965,14 @@ var makeInitResult = (answers, { pr, repository }) => {
936
965
  repository
937
966
  };
938
967
  };
939
- var createPullRequest = (octokit2) => ({
968
+ var createPullRequest = (githubService) => ({
940
969
  branchName,
941
970
  repository
942
971
  }) => withSpinner(
943
972
  "Creating Pull Request...",
944
973
  "Pull Request created successfully!",
945
974
  "Failed to create Pull Request.",
946
- octokit2.rest.pulls.create({
975
+ githubService.createPullRequest({
947
976
  base: "main",
948
977
  body: "This PR contains the scaffolded monorepo structure.",
949
978
  head: branchName,
@@ -951,9 +980,9 @@ var createPullRequest = (octokit2) => ({
951
980
  repo: repository.name,
952
981
  title: "Scaffold repository"
953
982
  })
954
- ).map(({ data }) => ({ url: data.html_url })).orElse(() => okAsync2(void 0));
983
+ ).orElse(() => okAsync2(void 0));
955
984
  var makeInitCommand = ({
956
- octokit: octokit2
985
+ gitHubService: gitHubService2
957
986
  }) => new Command4().name("init").description(
958
987
  "Command to initialize resources (like projects, subscriptions, ...)"
959
988
  ).addCommand(
@@ -961,10 +990,10 @@ var makeInitCommand = ({
961
990
  await checkPreconditions().andThen(initPlop).andTee(loadMonorepoScaffolder).andThen((plop) => getGenerator(plop)(PLOP_MONOREPO_GENERATOR_NAME)).andThen(
962
991
  (generator) => (
963
992
  // Ask the user the questions defined in the plop generator
964
- getPrompts(generator).andThen(decode(answersSchema)).andThen(validateAnswers).andThen(runGeneratorActions(generator))
993
+ getPrompts(generator).andThen(decode(answersSchema)).andThen(validateAnswers(gitHubService2)).andThen(runGeneratorActions(generator))
965
994
  )
966
995
  ).andThen(
967
- (answers) => handleNewGitHubRepository(octokit2)(answers).map(
996
+ (answers) => handleNewGitHubRepository(gitHubService2)(answers).map(
968
997
  (repoPr) => makeInitResult(answers, repoPr)
969
998
  )
970
999
  ).match(displaySummary, exitWithError(this));
@@ -1004,7 +1033,7 @@ var makeSavemoneyCommand = () => new Command5("savemoney").description(
1004
1033
  // src/adapters/commander/index.ts
1005
1034
  var makeCli = (deps2, config2, cliDeps) => {
1006
1035
  const program2 = new Command6();
1007
- program2.name("dx").description("The CLI for DX-Platform").version("0.14.4");
1036
+ program2.name("dx").description("The CLI for DX-Platform").version("0.15.0");
1008
1037
  program2.addCommand(makeDoctorCommand(deps2, config2));
1009
1038
  program2.addCommand(makeCodemodCommand(cliDeps));
1010
1039
  program2.addCommand(makeInitCommand(deps2));
@@ -1152,6 +1181,51 @@ var makeRepositoryReader = () => ({
1152
1181
  readFile
1153
1182
  });
1154
1183
 
1184
+ // src/adapters/octokit/index.ts
1185
+ import { RequestError } from "octokit";
1186
+ var OctokitGitHubService = class {
1187
+ #octokit;
1188
+ constructor(octokit2) {
1189
+ this.#octokit = octokit2;
1190
+ }
1191
+ async createPullRequest(params) {
1192
+ try {
1193
+ const { data } = await this.#octokit.rest.pulls.create({
1194
+ base: params.base,
1195
+ body: params.body,
1196
+ head: params.head,
1197
+ owner: params.owner,
1198
+ repo: params.repo,
1199
+ title: params.title
1200
+ });
1201
+ return new PullRequest(data.html_url);
1202
+ } catch (error) {
1203
+ throw new Error(
1204
+ `Failed to create pull request in ${params.owner}/${params.repo}`,
1205
+ {
1206
+ cause: error
1207
+ }
1208
+ );
1209
+ }
1210
+ }
1211
+ async getRepository(owner, name) {
1212
+ try {
1213
+ const { data } = await this.#octokit.rest.repos.get({
1214
+ owner,
1215
+ repo: name
1216
+ });
1217
+ return new Repository(data.name, data.owner.login);
1218
+ } catch (error) {
1219
+ if (error instanceof RequestError && error.status === 404) {
1220
+ throw new RepositoryNotFoundError(owner, name);
1221
+ }
1222
+ throw new Error(`Failed to fetch repository ${owner}/${name}`, {
1223
+ cause: error
1224
+ });
1225
+ }
1226
+ }
1227
+ };
1228
+
1155
1229
  // src/config.ts
1156
1230
  var getConfig = () => ({
1157
1231
  minVersions: {
@@ -1160,9 +1234,9 @@ var getConfig = () => ({
1160
1234
  });
1161
1235
 
1162
1236
  // src/use-cases/apply-codemod.ts
1163
- import { errAsync, okAsync as okAsync4, ResultAsync as ResultAsync9 } from "neverthrow";
1237
+ import { errAsync as errAsync2, okAsync as okAsync4, ResultAsync as ResultAsync9 } from "neverthrow";
1164
1238
  var getCodemodById = (registry2, id) => registry2.getById(id).andThen(
1165
- (codemod) => codemod ? okAsync4(codemod) : errAsync(new Error(`Codemod with id ${id} not found`))
1239
+ (codemod) => codemod ? okAsync4(codemod) : errAsync2(new Error(`Codemod with id ${id} not found`))
1166
1240
  );
1167
1241
  var safeGetInfo = (getInfo2) => ResultAsync9.fromPromise(
1168
1242
  getInfo2(),
@@ -1203,11 +1277,12 @@ await configure({
1203
1277
  var repositoryReader = makeRepositoryReader();
1204
1278
  var packageJsonReader = makePackageJsonReader();
1205
1279
  var validationReporter = makeValidationReporter();
1206
- var octokit = new Octokit2({
1280
+ var octokit = new Octokit3({
1207
1281
  auth: process.env.GITHUB_TOKEN
1208
1282
  });
1283
+ var gitHubService = new OctokitGitHubService(octokit);
1209
1284
  var deps = {
1210
- octokit,
1285
+ gitHubService,
1211
1286
  packageJsonReader,
1212
1287
  repositoryReader,
1213
1288
  validationReporter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.14.4",
3
+ "version": "0.15.0",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -33,8 +33,8 @@
33
33
  "semver": "^7.7.2",
34
34
  "yaml": "^2.8.2",
35
35
  "zod": "^4.2.1",
36
- "@pagopa/monorepo-generator": "^0.14.1",
37
- "@pagopa/dx-savemoney": "^0.1.4"
36
+ "@pagopa/dx-savemoney": "^0.1.4",
37
+ "@pagopa/monorepo-generator": "^0.15.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@tsconfig/node22": "22.0.2",