@projectdochelp/s3te 3.4.3 → 3.4.5
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.
package/README.md
CHANGED
|
@@ -293,6 +293,7 @@ GitHub preparation checklist:
|
|
|
293
293
|
6. Add these repository variables:
|
|
294
294
|
- `S3TE_ENVIRONMENT`
|
|
295
295
|
Use the exact environment name from `s3te.config.json`, for example `dev`, `test`, or `prod`.
|
|
296
|
+
This is required for push-based sync when your project has more than one configured environment.
|
|
296
297
|
- `S3TE_GIT_BRANCH` optional
|
|
297
298
|
Use the branch that should trigger the sync job, for example `main`.
|
|
298
299
|
7. In GitHub open `Settings -> Secrets and variables -> Actions -> Secrets`.
|
|
@@ -300,7 +301,9 @@ GitHub preparation checklist:
|
|
|
300
301
|
- `AWS_ACCESS_KEY_ID`
|
|
301
302
|
- `AWS_SECRET_ACCESS_KEY`
|
|
302
303
|
9. Leave `.github/workflows/s3te-sync.yml` unchanged unless you want a custom CI flow. The scaffolded workflow already reads:
|
|
303
|
-
- the environment from `
|
|
304
|
+
- the environment from the manual `workflow_dispatch` input when provided
|
|
305
|
+
- otherwise from `S3TE_ENVIRONMENT`
|
|
306
|
+
- otherwise automatically from `s3te.config.json` when exactly one environment exists
|
|
304
307
|
- the branch from `S3TE_GIT_BRANCH` or defaults to `main`
|
|
305
308
|
- the AWS region from `s3te.config.json`
|
|
306
309
|
|
|
@@ -327,6 +330,7 @@ Where to get the AWS values:
|
|
|
327
330
|
[Manage access keys for IAM users](https://docs.aws.amazon.com/IAM/latest/UserGuide/access-keys-admin-managed.html).
|
|
328
331
|
- `S3TE_ENVIRONMENT`
|
|
329
332
|
This is the environment key from your `s3te.config.json`, for example `test` or `prod`.
|
|
333
|
+
For repositories with multiple environments, set this variable or pass the environment manually when starting `workflow_dispatch`.
|
|
330
334
|
- AWS region
|
|
331
335
|
You do not need to copy this into GitHub. The workflow reads `environments.<name>.awsRegion` directly from `s3te.config.json`.
|
|
332
336
|
|
|
@@ -376,10 +380,13 @@ The scaffolded workflow looks like this:
|
|
|
376
380
|
# Required GitHub repository secrets:
|
|
377
381
|
# - AWS_ACCESS_KEY_ID
|
|
378
382
|
# - AWS_SECRET_ACCESS_KEY
|
|
379
|
-
# Required GitHub repository variable:
|
|
383
|
+
# Required GitHub repository variable for push-based sync in multi-environment projects:
|
|
380
384
|
# - S3TE_ENVIRONMENT (for example dev, test, or prod)
|
|
381
385
|
# Optional GitHub repository variable:
|
|
382
386
|
# - S3TE_GIT_BRANCH (defaults to main)
|
|
387
|
+
# Notes:
|
|
388
|
+
# - workflow_dispatch can override the environment manually
|
|
389
|
+
# - if s3te.config.json contains exactly one environment, no S3TE_ENVIRONMENT variable is needed
|
|
383
390
|
# This workflow reads s3te.config.json at runtime and syncs all variants into their own code buckets.
|
|
384
391
|
name: S3TE Sync
|
|
385
392
|
on:
|
|
@@ -423,7 +430,7 @@ jobs:
|
|
|
423
430
|
WORKFLOW_INPUT_ENVIRONMENT: ${{ inputs.environment }}
|
|
424
431
|
REPOSITORY_S3TE_ENVIRONMENT: ${{ vars.S3TE_ENVIRONMENT }}
|
|
425
432
|
run: |
|
|
426
|
-
node -e "const fs=require('node:fs'); const
|
|
433
|
+
node -e "const fs=require('node:fs'); const fromInput=(process.env.WORKFLOW_INPUT_ENVIRONMENT || '').trim(); const fromVariable=(process.env.REPOSITORY_S3TE_ENVIRONMENT || '').trim(); const config=JSON.parse(fs.readFileSync('s3te.config.json','utf8')); const known=Object.keys(config.environments ?? {}); const requested=(fromInput || fromVariable || (known.length === 1 ? known[0] : '')).trim(); if(!requested){ console.error('Missing S3TE environment. Provide workflow_dispatch input \"environment\" or set GitHub repository variable S3TE_ENVIRONMENT. Known environments: ' + (known.length > 0 ? known.join(', ') : '(none)') + '.'); process.exit(1);} const environmentConfig=config.environments?.[requested]; if(!environmentConfig){ console.error('Unknown environment ' + requested + '. Known environments: ' + (known.length > 0 ? known.join(', ') : '(none)') + '.'); process.exit(1);} fs.appendFileSync(process.env.GITHUB_OUTPUT, 'environment=' + requested + '\n'); fs.appendFileSync(process.env.GITHUB_OUTPUT, 'aws_region=' + environmentConfig.awsRegion + '\n');"
|
|
427
434
|
- name: Configure AWS credentials
|
|
428
435
|
uses: aws-actions/configure-aws-credentials@v4
|
|
429
436
|
with:
|
|
@@ -724,7 +731,8 @@ Filter notes:
|
|
|
724
731
|
- multiple clauses are combined with logical `AND`
|
|
725
732
|
- `__typename` matches the content model, for example `article`
|
|
726
733
|
- supported legacy value wrappers are `S`, `N`, `BOOL`, `NULL`, and `L`
|
|
727
|
-
- results are sorted deterministically; numeric `order`
|
|
734
|
+
- results are sorted deterministically; items with a numeric field `order` are rendered first in ascending order, then items without a numeric `order`, then `contentId`, then `id`
|
|
735
|
+
- this also works with mirrored Webiny content if the model contains a field with the exact field ID `order` and type `number`
|
|
728
736
|
|
|
729
737
|
**Example**
|
|
730
738
|
|
|
@@ -1018,6 +1026,13 @@ That makes the option example above equivalent to a config that contains:
|
|
|
1018
1026
|
|
|
1019
1027
|
Use this for every Webiny model whose entries should be available to S3TE template commands like `dbitem`, `dbmulti`, `dbmultifile`, `dbmultifileitem`, or `dbpart`.
|
|
1020
1028
|
|
|
1029
|
+
If a Webiny model should control the output order for `dbmulti` or `dbmultifile`, add a field with:
|
|
1030
|
+
|
|
1031
|
+
- field ID `order`
|
|
1032
|
+
- field type `number`
|
|
1033
|
+
|
|
1034
|
+
S3TE sorts matching items by that numeric `order` in ascending order. Items without a numeric `order` stay at the end.
|
|
1035
|
+
|
|
1021
1036
|
If different environments should read from different Webiny installations or tenants, run the option command per environment:
|
|
1022
1037
|
|
|
1023
1038
|
```bash
|
package/package.json
CHANGED
|
@@ -36,6 +36,12 @@ function normalizeKey(value) {
|
|
|
36
36
|
return String(value).replace(/\\/g, "/");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function matchesProjectRelativeRoot(key, root) {
|
|
40
|
+
const normalizedKey = normalizeKey(key);
|
|
41
|
+
const normalizedRoot = normalizeKey(root);
|
|
42
|
+
return normalizedKey === normalizedRoot || normalizedKey.startsWith(`${normalizedRoot}/`);
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
function buildSourceId(environment, variant, language, outputKey) {
|
|
40
46
|
return `${environment}#${variant}#${language}#${outputKey}`;
|
|
41
47
|
}
|
|
@@ -312,17 +318,18 @@ export class S3TemplateRepository {
|
|
|
312
318
|
const normalized = normalizeKey(key);
|
|
313
319
|
const activeVariant = this.environmentManifest.variants[this.activeVariantName];
|
|
314
320
|
|
|
315
|
-
if (normalized.
|
|
321
|
+
if (matchesProjectRelativeRoot(normalized, activeVariant.partDir)) {
|
|
322
|
+
const normalizedPartDir = normalizeKey(activeVariant.partDir);
|
|
316
323
|
return {
|
|
317
324
|
bucket: activeVariant.codeBucket,
|
|
318
|
-
objectKey: normalized
|
|
325
|
+
objectKey: `part/${normalized.slice(normalizedPartDir.length + 1)}`
|
|
319
326
|
};
|
|
320
327
|
}
|
|
321
328
|
|
|
322
|
-
if (normalized.startsWith(`${
|
|
329
|
+
if (normalized.startsWith(`${this.activeVariantName}/`)) {
|
|
323
330
|
return {
|
|
324
331
|
bucket: activeVariant.codeBucket,
|
|
325
|
-
objectKey:
|
|
332
|
+
objectKey: normalized
|
|
326
333
|
};
|
|
327
334
|
}
|
|
328
335
|
|
|
@@ -365,10 +365,13 @@ function githubSyncWorkflowTemplate() {
|
|
|
365
365
|
return `# Required GitHub repository secrets:
|
|
366
366
|
# - AWS_ACCESS_KEY_ID
|
|
367
367
|
# - AWS_SECRET_ACCESS_KEY
|
|
368
|
-
# Required GitHub repository variable:
|
|
368
|
+
# Required GitHub repository variable for push-based sync in multi-environment projects:
|
|
369
369
|
# - S3TE_ENVIRONMENT (for example dev, test, or prod)
|
|
370
370
|
# Optional GitHub repository variable:
|
|
371
371
|
# - S3TE_GIT_BRANCH (defaults to main)
|
|
372
|
+
# Notes:
|
|
373
|
+
# - workflow_dispatch can override the environment manually
|
|
374
|
+
# - if s3te.config.json contains exactly one environment, no S3TE_ENVIRONMENT variable is needed
|
|
372
375
|
# This workflow reads s3te.config.json at runtime and syncs all variants into their own code buckets.
|
|
373
376
|
name: S3TE Sync
|
|
374
377
|
|
|
@@ -413,7 +416,7 @@ jobs:
|
|
|
413
416
|
WORKFLOW_INPUT_ENVIRONMENT: \${{ inputs.environment }}
|
|
414
417
|
REPOSITORY_S3TE_ENVIRONMENT: \${{ vars.S3TE_ENVIRONMENT }}
|
|
415
418
|
run: |
|
|
416
|
-
node -e "const fs=require('node:fs'); const
|
|
419
|
+
node -e "const fs=require('node:fs'); const fromInput=(process.env.WORKFLOW_INPUT_ENVIRONMENT || '').trim(); const fromVariable=(process.env.REPOSITORY_S3TE_ENVIRONMENT || '').trim(); const config=JSON.parse(fs.readFileSync('s3te.config.json','utf8')); const known=Object.keys(config.environments ?? {}); const requested=(fromInput || fromVariable || (known.length === 1 ? known[0] : '')).trim(); if(!requested){ console.error('Missing S3TE environment. Provide workflow_dispatch input \"environment\" or set GitHub repository variable S3TE_ENVIRONMENT. Known environments: ' + (known.length > 0 ? known.join(', ') : '(none)') + '.'); process.exit(1);} const environmentConfig=config.environments?.[requested]; if(!environmentConfig){ console.error('Unknown environment ' + requested + '. Known environments: ' + (known.length > 0 ? known.join(', ') : '(none)') + '.'); process.exit(1);} fs.appendFileSync(process.env.GITHUB_OUTPUT, 'environment=' + requested + '\\n'); fs.appendFileSync(process.env.GITHUB_OUTPUT, 'aws_region=' + environmentConfig.awsRegion + '\\n');"
|
|
417
420
|
- name: Configure AWS credentials
|
|
418
421
|
uses: aws-actions/configure-aws-credentials@v4
|
|
419
422
|
with:
|
|
@@ -83,13 +83,42 @@ function compareFilter(actual, expected, filterType) {
|
|
|
83
83
|
return actual === expected;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
function coerceNumericOrderValue(value) {
|
|
87
|
+
if (typeof value === "number") {
|
|
88
|
+
return Number.isFinite(value) ? value : null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (typeof value === "string") {
|
|
92
|
+
const trimmed = value.trim();
|
|
93
|
+
if (!trimmed) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const parsed = Number(trimmed);
|
|
97
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const legacyValue = legacyAttributeValueToPlain(value);
|
|
101
|
+
if (legacyValue !== undefined && legacyValue !== value) {
|
|
102
|
+
return coerceNumericOrderValue(legacyValue);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function readOrderValue(item) {
|
|
109
|
+
const candidate = item?.values?.order ?? item?.order;
|
|
110
|
+
return coerceNumericOrderValue(candidate);
|
|
111
|
+
}
|
|
112
|
+
|
|
86
113
|
function compareOrder(a, b) {
|
|
87
|
-
const
|
|
88
|
-
const
|
|
114
|
+
const aOrder = readOrderValue(a);
|
|
115
|
+
const bOrder = readOrderValue(b);
|
|
116
|
+
const aHasOrder = aOrder !== null;
|
|
117
|
+
const bHasOrder = bOrder !== null;
|
|
89
118
|
|
|
90
119
|
if (aHasOrder && bHasOrder) {
|
|
91
|
-
if (
|
|
92
|
-
return
|
|
120
|
+
if (aOrder !== bOrder) {
|
|
121
|
+
return aOrder - bOrder;
|
|
93
122
|
}
|
|
94
123
|
} else if (aHasOrder && !bHasOrder) {
|
|
95
124
|
return -1;
|