@pgpmjs/core 6.28.0 → 6.28.2

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.
@@ -1,8 +1,8 @@
1
1
  import { PgpmOptions, PgpmWorkspaceConfig } from '@pgpmjs/types';
2
2
  import { PgConfig } from 'pg-env';
3
3
  import { ExtensionInfo } from '../../files';
4
- import { ModuleMap } from '../../modules/modules';
5
4
  import { PackageAnalysisResult, RenameOptions } from '../../files/types';
5
+ import { ModuleMap } from '../../modules/modules';
6
6
  export declare enum PackageContext {
7
7
  Outside = "outside",
8
8
  Workspace = "workspace-root",
@@ -40,7 +40,6 @@ exports.PgpmPackage = exports.PackageContext = void 0;
40
40
  const env_1 = require("@pgpmjs/env");
41
41
  const logger_1 = require("@pgpmjs/logger");
42
42
  const types_1 = require("@pgpmjs/types");
43
- const yanse_1 = __importDefault(require("yanse"));
44
43
  const child_process_1 = require("child_process");
45
44
  const fs_1 = __importDefault(require("fs"));
46
45
  const glob = __importStar(require("glob"));
@@ -48,40 +47,29 @@ const os_1 = __importDefault(require("os"));
48
47
  const parse_package_name_1 = require("parse-package-name");
49
48
  const path_1 = __importStar(require("path"));
50
49
  const pg_cache_1 = require("pg-cache");
51
- const template_scaffold_1 = require("../template-scaffold");
50
+ const yanse_1 = __importDefault(require("yanse"));
52
51
  const extensions_1 = require("../../extensions/extensions");
53
52
  const files_1 = require("../../files");
54
- const parser_1 = require("../../files/plan/parser");
55
- const validators_1 = require("../../files/plan/validators");
56
- const generator_1 = require("../../files/plan/generator");
57
53
  const files_2 = require("../../files");
58
54
  const writer_1 = require("../../files/extension/writer");
55
+ const generator_1 = require("../../files/plan/generator");
56
+ const parser_1 = require("../../files/plan/parser");
57
+ const validators_1 = require("../../files/plan/validators");
59
58
  const client_1 = require("../../migrate/client");
60
59
  const modules_1 = require("../../modules/modules");
61
60
  const package_1 = require("../../packaging/package");
62
61
  const deps_1 = require("../../resolution/deps");
63
62
  const target_utils_1 = require("../../utils/target-utils");
63
+ const template_scaffold_1 = require("../template-scaffold");
64
64
  const logger = new logger_1.Logger('pgpm');
65
65
  /**
66
66
  * Directory name for workspace extensions.
67
67
  * Extensions are installed globally in the workspace's extensions/ directory.
68
68
  */
69
69
  const EXTENSIONS_DIR = 'extensions';
70
- function getUTCTimestamp(d = new Date()) {
71
- return (d.getUTCFullYear() +
72
- '-' + String(d.getUTCMonth() + 1).padStart(2, '0') +
73
- '-' + String(d.getUTCDate()).padStart(2, '0') +
74
- 'T' + String(d.getUTCHours()).padStart(2, '0') +
75
- ':' + String(d.getUTCMinutes()).padStart(2, '0') +
76
- ':' + String(d.getUTCSeconds()).padStart(2, '0') +
77
- 'Z');
78
- }
79
70
  function sortObjectByKey(obj) {
80
71
  return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));
81
72
  }
82
- const getNow = () => process.env.NODE_ENV === 'test'
83
- ? getUTCTimestamp(new Date('2017-08-11T08:11:51Z'))
84
- : getUTCTimestamp(new Date());
85
73
  /**
86
74
  * Truncates workspace extensions to include only modules from the target onwards.
87
75
  * This prevents processing unnecessary modules that come before the target in dependency order.
@@ -398,7 +386,7 @@ class PgpmPackage {
398
386
  cacheTtlMs: options.cacheTtlMs ?? template_scaffold_1.DEFAULT_TEMPLATE_TTL_MS,
399
387
  toolName: options.toolName ?? template_scaffold_1.DEFAULT_TEMPLATE_TOOL_NAME,
400
388
  cwd: this.cwd,
401
- prompter: options.prompter,
389
+ prompter: options.prompter
402
390
  });
403
391
  // Only create pgpm files (pgpm.plan, .control, deploy/revert/verify dirs) for pgpm-managed modules
404
392
  if (isPgpmModule) {
@@ -661,7 +649,7 @@ class PgpmPackage {
661
649
  throw new Error('Change name is required');
662
650
  }
663
651
  if (!(0, validators_1.isValidChangeName)(changeName)) {
664
- throw types_1.errors.INVALID_NAME({ name: changeName, type: 'change', rules: "Change names must follow Sqitch naming rules" });
652
+ throw types_1.errors.INVALID_NAME({ name: changeName, type: 'change', rules: 'Change names must follow Sqitch naming rules' });
665
653
  }
666
654
  if (!this.isInWorkspace() && !this.isInModule()) {
667
655
  throw new Error('This command must be run inside a PGPM workspace or module.');
@@ -1,7 +1,6 @@
1
1
  import { loadConfigSyncFromDir, resolvePgpmPath, walkUp } from '@pgpmjs/env';
2
2
  import { Logger } from '@pgpmjs/logger';
3
3
  import { errors } from '@pgpmjs/types';
4
- import yanse from 'yanse';
5
4
  import { execSync } from 'child_process';
6
5
  import fs from 'fs';
7
6
  import * as glob from 'glob';
@@ -9,40 +8,29 @@ import os from 'os';
9
8
  import { parse } from 'parse-package-name';
10
9
  import path, { dirname, resolve } from 'path';
11
10
  import { getPgPool } from 'pg-cache';
12
- import { DEFAULT_TEMPLATE_REPO, DEFAULT_TEMPLATE_TTL_MS, DEFAULT_TEMPLATE_TOOL_NAME, scaffoldTemplate } from '../template-scaffold';
11
+ import yanse from 'yanse';
13
12
  import { getAvailableExtensions } from '../../extensions/extensions';
14
13
  import { generatePlan, writePlan, writePlanFile } from '../../files';
15
- import { parsePlanFile } from '../../files/plan/parser';
16
- import { isValidTagName, isValidChangeName, parseReference } from '../../files/plan/validators';
17
- import { getNow as getPlanTimestamp } from '../../files/plan/generator';
18
- import { getExtensionInfo, getExtensionName, getInstalledExtensions, parseControlFile, writeExtensions, } from '../../files';
14
+ import { getExtensionInfo, getExtensionName, getInstalledExtensions, parseControlFile, writeExtensions } from '../../files';
19
15
  import { generateControlFileContent, writeExtensionMakefile } from '../../files/extension/writer';
16
+ import { getNow as getPlanTimestamp } from '../../files/plan/generator';
17
+ import { parsePlanFile } from '../../files/plan/parser';
18
+ import { isValidChangeName, isValidTagName, parseReference } from '../../files/plan/validators';
20
19
  import { PgpmMigrate } from '../../migrate/client';
21
20
  import { getExtensionsAndModules, getExtensionsAndModulesChanges, latestChange, latestChangeAndVersion } from '../../modules/modules';
22
21
  import { packageModule } from '../../packaging/package';
23
- import { resolveExtensionDependencies, resolveDependencies } from '../../resolution/deps';
22
+ import { resolveDependencies, resolveExtensionDependencies } from '../../resolution/deps';
24
23
  import { parseTarget } from '../../utils/target-utils';
24
+ import { DEFAULT_TEMPLATE_REPO, DEFAULT_TEMPLATE_TOOL_NAME, DEFAULT_TEMPLATE_TTL_MS, scaffoldTemplate } from '../template-scaffold';
25
25
  const logger = new Logger('pgpm');
26
26
  /**
27
27
  * Directory name for workspace extensions.
28
28
  * Extensions are installed globally in the workspace's extensions/ directory.
29
29
  */
30
30
  const EXTENSIONS_DIR = 'extensions';
31
- function getUTCTimestamp(d = new Date()) {
32
- return (d.getUTCFullYear() +
33
- '-' + String(d.getUTCMonth() + 1).padStart(2, '0') +
34
- '-' + String(d.getUTCDate()).padStart(2, '0') +
35
- 'T' + String(d.getUTCHours()).padStart(2, '0') +
36
- ':' + String(d.getUTCMinutes()).padStart(2, '0') +
37
- ':' + String(d.getUTCSeconds()).padStart(2, '0') +
38
- 'Z');
39
- }
40
31
  function sortObjectByKey(obj) {
41
32
  return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));
42
33
  }
43
- const getNow = () => process.env.NODE_ENV === 'test'
44
- ? getUTCTimestamp(new Date('2017-08-11T08:11:51Z'))
45
- : getUTCTimestamp(new Date());
46
34
  /**
47
35
  * Truncates workspace extensions to include only modules from the target onwards.
48
36
  * This prevents processing unnecessary modules that come before the target in dependency order.
@@ -359,7 +347,7 @@ export class PgpmPackage {
359
347
  cacheTtlMs: options.cacheTtlMs ?? DEFAULT_TEMPLATE_TTL_MS,
360
348
  toolName: options.toolName ?? DEFAULT_TEMPLATE_TOOL_NAME,
361
349
  cwd: this.cwd,
362
- prompter: options.prompter,
350
+ prompter: options.prompter
363
351
  });
364
352
  // Only create pgpm files (pgpm.plan, .control, deploy/revert/verify dirs) for pgpm-managed modules
365
353
  if (isPgpmModule) {
@@ -622,7 +610,7 @@ export class PgpmPackage {
622
610
  throw new Error('Change name is required');
623
611
  }
624
612
  if (!isValidChangeName(changeName)) {
625
- throw errors.INVALID_NAME({ name: changeName, type: 'change', rules: "Change names must follow Sqitch naming rules" });
613
+ throw errors.INVALID_NAME({ name: changeName, type: 'change', rules: 'Change names must follow Sqitch naming rules' });
626
614
  }
627
615
  if (!this.isInWorkspace() && !this.isInModule()) {
628
616
  throw new Error('This command must be run inside a PGPM workspace or module.');
@@ -1,8 +1,13 @@
1
1
  import fs from 'fs';
2
2
  /**
3
- * Get a UTC timestamp string
3
+ * Fixed epoch timestamp used for deterministic plan generation.
4
+ * Can be overridden with the PGPM_FROZEN_TIME environment variable.
4
5
  */
5
- function getUTCTimestamp(d = new Date()) {
6
+ const DEFAULT_FROZEN_TIME = '2017-08-11T08:11:51Z';
7
+ /**
8
+ * Get a UTC timestamp string from a Date object.
9
+ */
10
+ function getUTCTimestamp(d) {
6
11
  return (d.getUTCFullYear() +
7
12
  '-' + String(d.getUTCMonth() + 1).padStart(2, '0') +
8
13
  '-' + String(d.getUTCDate()).padStart(2, '0') +
@@ -12,13 +17,38 @@ function getUTCTimestamp(d = new Date()) {
12
17
  'Z');
13
18
  }
14
19
  /**
15
- * Get a timestamp for the plan file
20
+ * Get a timestamp for the plan file.
21
+ * Uses the PGPM_FROZEN_TIME env var if present, otherwise the fixed epoch.
16
22
  */
17
23
  export function getNow() {
18
- return process.env.NODE_ENV === 'test'
19
- ? getUTCTimestamp(new Date('2017-08-11T08:11:51Z'))
20
- : getUTCTimestamp(new Date());
24
+ const frozen = process.env.PGPM_FROZEN_TIME;
25
+ if (frozen) {
26
+ return getUTCTimestamp(new Date(frozen));
27
+ }
28
+ return DEFAULT_FROZEN_TIME;
21
29
  }
30
+ /**
31
+ * Sort dependencies by their order in the supplied plan, so prerequisites
32
+ * (parent migrations) appear before their dependents in the bracket.
33
+ * Internal dependencies are sorted by their plan index, and external
34
+ * dependencies (not in the plan) preserve their original order.
35
+ */
36
+ const sortDependencies = (deps, order) => {
37
+ const originalOrder = new Map(deps.map((dep, index) => [dep, index]));
38
+ return [...deps].sort((a, b) => {
39
+ const aIndex = order.get(a);
40
+ const bIndex = order.get(b);
41
+ const aOriginal = originalOrder.get(a);
42
+ const bOriginal = originalOrder.get(b);
43
+ if (aIndex !== undefined && bIndex !== undefined)
44
+ return aIndex - bIndex || aOriginal - bOriginal;
45
+ if (aIndex !== undefined)
46
+ return -1;
47
+ if (bIndex !== undefined)
48
+ return 1;
49
+ return aOriginal - bOriginal;
50
+ });
51
+ };
22
52
  /**
23
53
  * Generate a plan file content from structured data
24
54
  */
@@ -30,10 +60,13 @@ export function generatePlan(options) {
30
60
  `%project=${moduleName}`,
31
61
  `%uri=${uri || moduleName}`
32
62
  ];
63
+ // Build an order map from the entry list so brackets can be sorted by plan order
64
+ const entryOrder = new Map(entries.map((entry, index) => [entry.change, index]));
33
65
  // Generate the plan entries
34
66
  entries.forEach(entry => {
35
- if (entry.dependencies && entry.dependencies.length > 0) {
36
- planfile.push(`${entry.change} [${entry.dependencies.join(' ')}] ${now} constructive <constructive@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
67
+ const deps = sortDependencies(entry.dependencies || [], entryOrder);
68
+ if (deps.length > 0) {
69
+ planfile.push(`${entry.change} [${deps.join(' ')}] ${now} constructive <constructive@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
37
70
  }
38
71
  else {
39
72
  planfile.push(`${entry.change} ${now} constructive <constructive@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
@@ -1,6 +1,28 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { parseAuthor } from '../../utils/author';
4
+ /**
5
+ * Sort dependencies by their order in the supplied plan, so prerequisites
6
+ * (parent migrations) appear before their dependents in the bracket.
7
+ * Internal dependencies are sorted by their plan index, and external
8
+ * dependencies (not in the plan) preserve their original order.
9
+ */
10
+ const sortDependencies = (deps, order) => {
11
+ const originalOrder = new Map(deps.map((dep, index) => [dep, index]));
12
+ return [...deps].sort((a, b) => {
13
+ const aIndex = order.get(a);
14
+ const bIndex = order.get(b);
15
+ const aOriginal = originalOrder.get(a);
16
+ const bOriginal = originalOrder.get(b);
17
+ if (aIndex !== undefined && bIndex !== undefined)
18
+ return aIndex - bIndex || aOriginal - bOriginal;
19
+ if (aIndex !== undefined)
20
+ return -1;
21
+ if (bIndex !== undefined)
22
+ return 1;
23
+ return aOriginal - bOriginal;
24
+ });
25
+ };
4
26
  /**
5
27
  * Write a PGPM plan file based on the provided rows
6
28
  */
@@ -12,6 +34,8 @@ export function writePgpmPlan(rows, opts) {
12
34
  const authorName = fullName;
13
35
  const authorEmail = email || `${fullName}@5b0c196eeb62`;
14
36
  const duplicates = {};
37
+ // Build an order map from the row list so brackets can be sorted by plan order
38
+ const rowOrder = new Map(rows.map((row, index) => [row.deploy, index]));
15
39
  const plan = opts.replacer(`%syntax-version=1.0.0
16
40
  %project=constructive-extension-name
17
41
  %uri=constructive-extension-name
@@ -24,7 +48,7 @@ ${rows
24
48
  }
25
49
  duplicates[row.deploy] = true;
26
50
  if (row.deps?.length) {
27
- return `${row.deploy} [${row.deps.join(' ')}] ${date()} ${authorName} <${authorEmail}> # add ${row.name}`;
51
+ return `${row.deploy} [${sortDependencies(row.deps, rowOrder).join(' ')}] ${date()} ${authorName} <${authorEmail}> # add ${row.name}`;
28
52
  }
29
53
  return `${row.deploy} ${date()} ${authorName} <${authorEmail}> # add ${row.name}`;
30
54
  })
@@ -50,9 +74,11 @@ export function generatePlanFileContent(plan) {
50
74
  content += `%uri=${uri}\n`;
51
75
  }
52
76
  content += `\n`;
77
+ // Build an order map from the change list so brackets can be sorted by plan order
78
+ const changeOrder = new Map(changes.map((change, index) => [change.name, index]));
53
79
  // Add changes and their associated tags
54
80
  for (const change of changes) {
55
- content += generateChangeLineContent(change);
81
+ content += generateChangeLineContent(change, changeOrder);
56
82
  content += `\n`;
57
83
  const associatedTags = tags.filter(tag => tag.change === change.name);
58
84
  for (const tag of associatedTags) {
@@ -65,12 +91,12 @@ export function generatePlanFileContent(plan) {
65
91
  /**
66
92
  * Generate a line for a change in a plan file
67
93
  */
68
- export function generateChangeLineContent(change) {
94
+ export function generateChangeLineContent(change, changeOrder) {
69
95
  const { name, dependencies, timestamp, planner, email, comment } = change;
70
96
  let line = name;
71
- // Add dependencies if present
97
+ // Add dependencies if present, sorted by plan order
72
98
  if (dependencies && dependencies.length > 0) {
73
- line += ` [${dependencies.join(' ')}]`;
99
+ line += ` [${sortDependencies(dependencies, changeOrder || new Map()).join(' ')}]`;
74
100
  }
75
101
  // Add timestamp if present
76
102
  if (timestamp) {
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Get a timestamp for the plan file
2
+ * Get a timestamp for the plan file.
3
+ * Uses the PGPM_FROZEN_TIME env var if present, otherwise the fixed epoch.
3
4
  */
4
5
  export declare function getNow(): string;
5
6
  export interface PlanEntry {
@@ -8,9 +8,14 @@ exports.generatePlan = generatePlan;
8
8
  exports.writePlan = writePlan;
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  /**
11
- * Get a UTC timestamp string
11
+ * Fixed epoch timestamp used for deterministic plan generation.
12
+ * Can be overridden with the PGPM_FROZEN_TIME environment variable.
12
13
  */
13
- function getUTCTimestamp(d = new Date()) {
14
+ const DEFAULT_FROZEN_TIME = '2017-08-11T08:11:51Z';
15
+ /**
16
+ * Get a UTC timestamp string from a Date object.
17
+ */
18
+ function getUTCTimestamp(d) {
14
19
  return (d.getUTCFullYear() +
15
20
  '-' + String(d.getUTCMonth() + 1).padStart(2, '0') +
16
21
  '-' + String(d.getUTCDate()).padStart(2, '0') +
@@ -20,13 +25,38 @@ function getUTCTimestamp(d = new Date()) {
20
25
  'Z');
21
26
  }
22
27
  /**
23
- * Get a timestamp for the plan file
28
+ * Get a timestamp for the plan file.
29
+ * Uses the PGPM_FROZEN_TIME env var if present, otherwise the fixed epoch.
24
30
  */
25
31
  function getNow() {
26
- return process.env.NODE_ENV === 'test'
27
- ? getUTCTimestamp(new Date('2017-08-11T08:11:51Z'))
28
- : getUTCTimestamp(new Date());
32
+ const frozen = process.env.PGPM_FROZEN_TIME;
33
+ if (frozen) {
34
+ return getUTCTimestamp(new Date(frozen));
35
+ }
36
+ return DEFAULT_FROZEN_TIME;
29
37
  }
38
+ /**
39
+ * Sort dependencies by their order in the supplied plan, so prerequisites
40
+ * (parent migrations) appear before their dependents in the bracket.
41
+ * Internal dependencies are sorted by their plan index, and external
42
+ * dependencies (not in the plan) preserve their original order.
43
+ */
44
+ const sortDependencies = (deps, order) => {
45
+ const originalOrder = new Map(deps.map((dep, index) => [dep, index]));
46
+ return [...deps].sort((a, b) => {
47
+ const aIndex = order.get(a);
48
+ const bIndex = order.get(b);
49
+ const aOriginal = originalOrder.get(a);
50
+ const bOriginal = originalOrder.get(b);
51
+ if (aIndex !== undefined && bIndex !== undefined)
52
+ return aIndex - bIndex || aOriginal - bOriginal;
53
+ if (aIndex !== undefined)
54
+ return -1;
55
+ if (bIndex !== undefined)
56
+ return 1;
57
+ return aOriginal - bOriginal;
58
+ });
59
+ };
30
60
  /**
31
61
  * Generate a plan file content from structured data
32
62
  */
@@ -38,10 +68,13 @@ function generatePlan(options) {
38
68
  `%project=${moduleName}`,
39
69
  `%uri=${uri || moduleName}`
40
70
  ];
71
+ // Build an order map from the entry list so brackets can be sorted by plan order
72
+ const entryOrder = new Map(entries.map((entry, index) => [entry.change, index]));
41
73
  // Generate the plan entries
42
74
  entries.forEach(entry => {
43
- if (entry.dependencies && entry.dependencies.length > 0) {
44
- planfile.push(`${entry.change} [${entry.dependencies.join(' ')}] ${now} constructive <constructive@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
75
+ const deps = sortDependencies(entry.dependencies || [], entryOrder);
76
+ if (deps.length > 0) {
77
+ planfile.push(`${entry.change} [${deps.join(' ')}] ${now} constructive <constructive@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
45
78
  }
46
79
  else {
47
80
  planfile.push(`${entry.change} ${now} constructive <constructive@5b0c196eeb62>${entry.comment ? ` # ${entry.comment}` : ''}`);
@@ -1,4 +1,4 @@
1
- import { Change, PgpmRow, Tag, ExtendedPlanFile } from '../types';
1
+ import { Change, ExtendedPlanFile, PgpmRow, Tag } from '../types';
2
2
  export interface PlanWriteOptions {
3
3
  outdir: string;
4
4
  name: string;
@@ -20,7 +20,7 @@ export declare function generatePlanFileContent(plan: ExtendedPlanFile): string;
20
20
  /**
21
21
  * Generate a line for a change in a plan file
22
22
  */
23
- export declare function generateChangeLineContent(change: Change): string;
23
+ export declare function generateChangeLineContent(change: Change, changeOrder?: Map<string, number>): string;
24
24
  /**
25
25
  * Generate a line for a tag in a plan file
26
26
  */
@@ -11,6 +11,28 @@ exports.generateTagLineContent = generateTagLineContent;
11
11
  const fs_1 = __importDefault(require("fs"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const author_1 = require("../../utils/author");
14
+ /**
15
+ * Sort dependencies by their order in the supplied plan, so prerequisites
16
+ * (parent migrations) appear before their dependents in the bracket.
17
+ * Internal dependencies are sorted by their plan index, and external
18
+ * dependencies (not in the plan) preserve their original order.
19
+ */
20
+ const sortDependencies = (deps, order) => {
21
+ const originalOrder = new Map(deps.map((dep, index) => [dep, index]));
22
+ return [...deps].sort((a, b) => {
23
+ const aIndex = order.get(a);
24
+ const bIndex = order.get(b);
25
+ const aOriginal = originalOrder.get(a);
26
+ const bOriginal = originalOrder.get(b);
27
+ if (aIndex !== undefined && bIndex !== undefined)
28
+ return aIndex - bIndex || aOriginal - bOriginal;
29
+ if (aIndex !== undefined)
30
+ return -1;
31
+ if (bIndex !== undefined)
32
+ return 1;
33
+ return aOriginal - bOriginal;
34
+ });
35
+ };
14
36
  /**
15
37
  * Write a PGPM plan file based on the provided rows
16
38
  */
@@ -22,6 +44,8 @@ function writePgpmPlan(rows, opts) {
22
44
  const authorName = fullName;
23
45
  const authorEmail = email || `${fullName}@5b0c196eeb62`;
24
46
  const duplicates = {};
47
+ // Build an order map from the row list so brackets can be sorted by plan order
48
+ const rowOrder = new Map(rows.map((row, index) => [row.deploy, index]));
25
49
  const plan = opts.replacer(`%syntax-version=1.0.0
26
50
  %project=constructive-extension-name
27
51
  %uri=constructive-extension-name
@@ -34,7 +58,7 @@ ${rows
34
58
  }
35
59
  duplicates[row.deploy] = true;
36
60
  if (row.deps?.length) {
37
- return `${row.deploy} [${row.deps.join(' ')}] ${date()} ${authorName} <${authorEmail}> # add ${row.name}`;
61
+ return `${row.deploy} [${sortDependencies(row.deps, rowOrder).join(' ')}] ${date()} ${authorName} <${authorEmail}> # add ${row.name}`;
38
62
  }
39
63
  return `${row.deploy} ${date()} ${authorName} <${authorEmail}> # add ${row.name}`;
40
64
  })
@@ -60,9 +84,11 @@ function generatePlanFileContent(plan) {
60
84
  content += `%uri=${uri}\n`;
61
85
  }
62
86
  content += `\n`;
87
+ // Build an order map from the change list so brackets can be sorted by plan order
88
+ const changeOrder = new Map(changes.map((change, index) => [change.name, index]));
63
89
  // Add changes and their associated tags
64
90
  for (const change of changes) {
65
- content += generateChangeLineContent(change);
91
+ content += generateChangeLineContent(change, changeOrder);
66
92
  content += `\n`;
67
93
  const associatedTags = tags.filter(tag => tag.change === change.name);
68
94
  for (const tag of associatedTags) {
@@ -75,12 +101,12 @@ function generatePlanFileContent(plan) {
75
101
  /**
76
102
  * Generate a line for a change in a plan file
77
103
  */
78
- function generateChangeLineContent(change) {
104
+ function generateChangeLineContent(change, changeOrder) {
79
105
  const { name, dependencies, timestamp, planner, email, comment } = change;
80
106
  let line = name;
81
- // Add dependencies if present
107
+ // Add dependencies if present, sorted by plan order
82
108
  if (dependencies && dependencies.length > 0) {
83
- line += ` [${dependencies.join(' ')}]`;
109
+ line += ` [${sortDependencies(dependencies, changeOrder || new Map()).join(' ')}]`;
84
110
  }
85
111
  // Add timestamp if present
86
112
  if (timestamp) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pgpmjs/core",
3
- "version": "6.28.0",
3
+ "version": "6.28.2",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PGPM Package and Migration Tools",
6
6
  "main": "index.js",
@@ -48,21 +48,21 @@
48
48
  "makage": "^0.3.0"
49
49
  },
50
50
  "dependencies": {
51
- "@pgpmjs/env": "^2.26.3",
52
- "@pgpmjs/logger": "^2.13.0",
53
- "@pgpmjs/server-utils": "^3.14.3",
54
- "@pgpmjs/types": "^2.33.0",
55
- "csv-to-pg": "^3.20.1",
51
+ "@pgpmjs/env": "^2.26.4",
52
+ "@pgpmjs/logger": "^2.13.1",
53
+ "@pgpmjs/server-utils": "^3.14.4",
54
+ "@pgpmjs/types": "^2.33.1",
55
+ "csv-to-pg": "^3.20.2",
56
56
  "genomic": "^5.6.2",
57
57
  "glob": "^13.0.6",
58
58
  "minimatch": "^10.2.5",
59
59
  "parse-package-name": "^1.0.0",
60
60
  "pg": "^8.21.0",
61
- "pg-cache": "^3.14.2",
62
- "pg-env": "^1.17.0",
61
+ "pg-cache": "^3.14.3",
62
+ "pg-env": "^1.17.1",
63
63
  "pgsql-deparser": "^17.18.3",
64
64
  "pgsql-parser": "^17.9.15",
65
65
  "yanse": "^0.2.1"
66
66
  },
67
- "gitHead": "e2a1337c7ec8366b28c10e550645e44cad6085ff"
67
+ "gitHead": "113036fa4fb581e4d8418a9309524495a423b624"
68
68
  }