project-auto-wizard 0.15.0 → 0.16.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.
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/payload/config/breaking-changes.json +31 -5
- package/payload/config/wizard-prompts.yml +0 -4
- package/payload/scripts/messages.py +162 -26
- package/payload/scripts/version_manager.py +69 -40
- package/payload/version.yml.template +6 -2
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +3 -0
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +64 -1
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +61 -12
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +46 -10
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +40 -11
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +24 -8
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +29 -10
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +57 -23
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +155 -72
- package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +49 -20
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +162 -62
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +184 -87
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +38 -15
- package/payload/workflows/go/PROJECT-GO-CI.yaml +14 -5
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +375 -120
- package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +9 -4
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +12 -4
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +375 -120
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +9 -4
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +38 -9
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +19 -5
- package/payload/workflows/spring/PROJECT-SPRING-CI.yml +71 -35
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +9 -6
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +7 -4
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +425 -144
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +7 -4
- package/src/cli/args.js +32 -22
- package/src/commands/doctor.js +20 -0
- package/src/commands/dry-run.js +9 -1
- package/src/commands/full.js +9 -4
- package/src/commands/interactive.js +29 -30
- package/src/commands/status.js +19 -5
- package/src/context.js +4 -2
- package/src/core/copy/simple.js +31 -0
- package/src/core/copy/workflows.js +2 -2
- package/src/core/deploy-style.js +1 -1
- package/src/core/detect.js +3 -2
- package/src/core/options.js +88 -0
- package/src/core/release-options.js +6 -23
- package/src/core/types.js +15 -8
- package/src/core/version-yml.js +68 -26
- package/src/i18n/catalog/en/cli.js +3 -1
- package/src/i18n/catalog/en/commands.js +15 -0
- package/src/i18n/catalog/en/core2.js +3 -0
- package/src/i18n/catalog/en/ui.js +1 -0
- package/src/i18n/catalog/ko/cli.js +3 -1
- package/src/i18n/catalog/ko/commands.js +15 -0
- package/src/i18n/catalog/ko/core2.js +3 -0
- package/src/i18n/catalog/ko/ui.js +1 -0
- package/src/index.js +7 -3
- package/src/ui/env-plan.js +1 -1
- package/src/ui/prompts.js +9 -5
- package/src/ui/status-cards.js +2 -2
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +0 -241
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +0 -330
|
@@ -106,6 +106,8 @@ jobs:
|
|
|
106
106
|
uses: actions/checkout@v7
|
|
107
107
|
with:
|
|
108
108
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
109
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
110
|
+
path: .paw-msg
|
|
109
111
|
sparse-checkout: |
|
|
110
112
|
.github/scripts/messages.py
|
|
111
113
|
version.yml
|
|
@@ -113,11 +115,16 @@ jobs:
|
|
|
113
115
|
|
|
114
116
|
- name: Load messages
|
|
115
117
|
run: |
|
|
116
|
-
# Keep a copy outside the workspace
|
|
118
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
117
119
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
118
|
-
|
|
120
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
121
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
122
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
123
|
+
rm -rf .paw-msg
|
|
124
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
125
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
119
126
|
{
|
|
120
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
127
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
121
128
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
122
129
|
} >> "$GITHUB_ENV"
|
|
123
130
|
|
|
@@ -206,18 +213,26 @@ jobs:
|
|
|
206
213
|
uses: actions/checkout@v7
|
|
207
214
|
with:
|
|
208
215
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
216
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
217
|
+
path: .paw-msg
|
|
209
218
|
sparse-checkout: |
|
|
210
219
|
.github/scripts/messages.py
|
|
211
220
|
version.yml
|
|
212
221
|
sparse-checkout-cone-mode: false
|
|
213
222
|
|
|
214
223
|
- name: Load messages
|
|
224
|
+
id: load_messages
|
|
215
225
|
run: |
|
|
216
|
-
# Keep a copy outside the workspace
|
|
226
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
217
227
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
218
|
-
|
|
228
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
229
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
230
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
231
|
+
rm -rf .paw-msg
|
|
232
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
233
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
219
234
|
{
|
|
220
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
235
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
221
236
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
222
237
|
} >> "$GITHUB_ENV"
|
|
223
238
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -348,16 +363,16 @@ jobs:
|
|
|
348
363
|
EOF
|
|
349
364
|
|
|
350
365
|
- name: Log in to Docker Hub
|
|
351
|
-
uses: docker/login-action@
|
|
366
|
+
uses: docker/login-action@v4
|
|
352
367
|
with:
|
|
353
368
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
354
369
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
355
370
|
|
|
356
371
|
- name: Set up Docker Buildx
|
|
357
|
-
uses: docker/setup-buildx-action@
|
|
372
|
+
uses: docker/setup-buildx-action@v4
|
|
358
373
|
|
|
359
374
|
- name: Build & push Docker image
|
|
360
|
-
uses: docker/build-push-action@
|
|
375
|
+
uses: docker/build-push-action@v7
|
|
361
376
|
with:
|
|
362
377
|
context: ${{ env.PROJECT_PATH }}
|
|
363
378
|
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
@@ -369,13 +384,16 @@ jobs:
|
|
|
369
384
|
- name: Progress - Docker done
|
|
370
385
|
id: docker_progress
|
|
371
386
|
uses: actions/github-script@v9
|
|
387
|
+
env:
|
|
388
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
389
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_DOCKER_START: ${{ steps.progress.outputs.docker_start }}
|
|
372
390
|
with:
|
|
373
391
|
script: |
|
|
374
392
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
375
393
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
376
394
|
|
|
377
|
-
const commentId =
|
|
378
|
-
const dockerStart =
|
|
395
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
396
|
+
const dockerStart = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_DOCKER_START, 10) || Date.now();
|
|
379
397
|
const now = Date.now();
|
|
380
398
|
const dockerElapsed = now - dockerStart;
|
|
381
399
|
const minutes = Math.floor(dockerElapsed / 60000);
|
|
@@ -552,28 +570,34 @@ jobs:
|
|
|
552
570
|
|
|
553
571
|
- name: Deploy complete comment
|
|
554
572
|
uses: actions/github-script@v9
|
|
573
|
+
env:
|
|
574
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION: ${{ steps.docker_progress.outputs.docker_duration }}
|
|
575
|
+
PAW_IN_STEPS_PR_OUTPUTS_REF: ${{ steps.pr.outputs.ref }}
|
|
576
|
+
PAW_IN_STEPS_PR_OUTPUTS_SHA: ${{ steps.pr.outputs.sha }}
|
|
577
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
578
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DEPLOY_START: ${{ steps.docker_progress.outputs.deploy_start }}
|
|
555
579
|
with:
|
|
556
580
|
script: |
|
|
557
581
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
558
582
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
559
583
|
|
|
560
|
-
const commentId =
|
|
561
|
-
const dockerDuration =
|
|
562
|
-
const deployStart =
|
|
584
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
585
|
+
const dockerDuration = process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION;
|
|
586
|
+
const deployStart = parseInt(process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DEPLOY_START, 10) || Date.now();
|
|
563
587
|
const now = Date.now();
|
|
564
588
|
const deployElapsed = now - deployStart;
|
|
565
589
|
const minutes = Math.floor(deployElapsed / 60000);
|
|
566
590
|
const seconds = Math.floor((deployElapsed % 60000) / 1000);
|
|
567
591
|
const deployDuration = minutes > 0 ? m('wf_preview.dur_min_sec', {minutes, seconds}) : m('wf_preview.dur_sec', {seconds});
|
|
568
592
|
|
|
569
|
-
const projectName =
|
|
570
|
-
const domainSuffix =
|
|
571
|
-
const previewPort =
|
|
572
|
-
const apiDocsPath =
|
|
593
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
594
|
+
const domainSuffix = process.env.PREVIEW_DOMAIN_SUFFIX;
|
|
595
|
+
const previewPort = process.env.PREVIEW_PORT;
|
|
596
|
+
const apiDocsPath = process.env.API_DOCS_PATH;
|
|
573
597
|
const prNumber = context.issue.number;
|
|
574
598
|
const domain = `${projectName}-pr-${prNumber}.${domainSuffix}`;
|
|
575
599
|
const previewUrl = `http://${domain}:${previewPort}`;
|
|
576
|
-
const sha =
|
|
600
|
+
const sha = process.env.PAW_IN_STEPS_PR_OUTPUTS_SHA;
|
|
577
601
|
|
|
578
602
|
// Build the preview environment table (the API Docs row is added only when API_DOCS_PATH is set)
|
|
579
603
|
const envRows = [
|
|
@@ -585,7 +609,7 @@ jobs:
|
|
|
585
609
|
envRows.push(m('wf_preview.env_container_pr', {projectName, prNumber}));
|
|
586
610
|
envRows.push(m('wf_preview.env_commit', {sha}));
|
|
587
611
|
|
|
588
|
-
const branchName =
|
|
612
|
+
const branchName = process.env.PAW_IN_STEPS_PR_OUTPUTS_REF;
|
|
589
613
|
|
|
590
614
|
const body = [
|
|
591
615
|
m('wf_preview.title_pr_deployed'),
|
|
@@ -629,20 +653,23 @@ jobs:
|
|
|
629
653
|
});
|
|
630
654
|
|
|
631
655
|
- name: Build/deploy failure comment
|
|
632
|
-
if: failure()
|
|
656
|
+
if: failure() && steps.load_messages.outcome == 'success'
|
|
633
657
|
uses: actions/github-script@v9
|
|
658
|
+
env:
|
|
659
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION: ${{ steps.docker_progress.outputs.docker_duration }}
|
|
660
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
634
661
|
with:
|
|
635
662
|
script: |
|
|
636
663
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
637
664
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
638
665
|
|
|
639
|
-
const commentId =
|
|
640
|
-
const projectName =
|
|
666
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
667
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
641
668
|
const prNumber = context.issue.number;
|
|
642
669
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
643
670
|
|
|
644
671
|
// Show where it failed based on progress
|
|
645
|
-
const dockerDuration =
|
|
672
|
+
const dockerDuration = process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION;
|
|
646
673
|
|
|
647
674
|
// Work out where it failed - early-stage failures are distinguished too
|
|
648
675
|
let dockerStatus, deployStatus;
|
|
@@ -725,6 +752,8 @@ jobs:
|
|
|
725
752
|
uses: actions/checkout@v7
|
|
726
753
|
with:
|
|
727
754
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
755
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
756
|
+
path: .paw-msg
|
|
728
757
|
sparse-checkout: |
|
|
729
758
|
.github/scripts/messages.py
|
|
730
759
|
version.yml
|
|
@@ -732,11 +761,16 @@ jobs:
|
|
|
732
761
|
|
|
733
762
|
- name: Load messages
|
|
734
763
|
run: |
|
|
735
|
-
# Keep a copy outside the workspace
|
|
764
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
736
765
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
737
|
-
|
|
766
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
767
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
768
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
769
|
+
rm -rf .paw-msg
|
|
770
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
771
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
738
772
|
{
|
|
739
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
773
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
740
774
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
741
775
|
} >> "$GITHUB_ENV"
|
|
742
776
|
|
|
@@ -749,7 +783,7 @@ jobs:
|
|
|
749
783
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
750
784
|
|
|
751
785
|
const issueNumber = context.issue.number;
|
|
752
|
-
const marker =
|
|
786
|
+
const marker = process.env.ISSUE_HELPER_MARKER;
|
|
753
787
|
|
|
754
788
|
console.log(m('wf_preview.log_search_branch', {issueNumber}));
|
|
755
789
|
console.log(m('wf_preview.log_marker', {marker}));
|
|
@@ -794,7 +828,7 @@ jobs:
|
|
|
794
828
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
795
829
|
|
|
796
830
|
const issueNumber = context.issue.number;
|
|
797
|
-
const marker =
|
|
831
|
+
const marker = process.env.ISSUE_HELPER_MARKER;
|
|
798
832
|
|
|
799
833
|
const body = [
|
|
800
834
|
m('wf_preview.title_branch_missing_warn'),
|
|
@@ -838,18 +872,26 @@ jobs:
|
|
|
838
872
|
uses: actions/checkout@v7
|
|
839
873
|
with:
|
|
840
874
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
875
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
876
|
+
path: .paw-msg
|
|
841
877
|
sparse-checkout: |
|
|
842
878
|
.github/scripts/messages.py
|
|
843
879
|
version.yml
|
|
844
880
|
sparse-checkout-cone-mode: false
|
|
845
881
|
|
|
846
882
|
- name: Load messages
|
|
883
|
+
id: load_messages
|
|
847
884
|
run: |
|
|
848
|
-
# Keep a copy outside the workspace
|
|
885
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
849
886
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
850
|
-
|
|
887
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
888
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
889
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
890
|
+
rm -rf .paw-msg
|
|
891
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
892
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
851
893
|
{
|
|
852
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
894
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
853
895
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
854
896
|
} >> "$GITHUB_ENV"
|
|
855
897
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -879,13 +921,16 @@ jobs:
|
|
|
879
921
|
- name: Check branch exists
|
|
880
922
|
id: check_branch
|
|
881
923
|
uses: actions/github-script@v9
|
|
924
|
+
env:
|
|
925
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
926
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER: ${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
882
927
|
with:
|
|
883
928
|
script: |
|
|
884
929
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
885
930
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
886
931
|
|
|
887
|
-
const branchName =
|
|
888
|
-
const issueNumber =
|
|
932
|
+
const branchName = process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME;
|
|
933
|
+
const issueNumber = parseInt(process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER, 10) || 0;
|
|
889
934
|
|
|
890
935
|
console.log(m('wf_preview.log_check_exists', {branchName}));
|
|
891
936
|
|
|
@@ -942,23 +987,28 @@ jobs:
|
|
|
942
987
|
- name: Set issue info
|
|
943
988
|
if: steps.check_branch.outputs.exists == 'true'
|
|
944
989
|
id: issue
|
|
990
|
+
env:
|
|
991
|
+
PAW_BRANCH_NAME: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
945
992
|
run: |
|
|
946
|
-
echo "ref=$
|
|
993
|
+
echo "ref=$PAW_BRANCH_NAME" >> $GITHUB_OUTPUT
|
|
947
994
|
echo "issue_number=${{ needs.get-branch-from-issue.outputs.issue_number }}" >> $GITHUB_OUTPUT
|
|
948
|
-
echo "sha=$(git ls-remote https://github.com/${{ github.repository }}.git refs/heads/$
|
|
995
|
+
echo "sha=$(git ls-remote https://github.com/${{ github.repository }}.git "refs/heads/$PAW_BRANCH_NAME" | cut -c1-7)" >> $GITHUB_OUTPUT
|
|
949
996
|
|
|
950
997
|
# Progress comment system
|
|
951
998
|
- name: Create progress comment
|
|
952
999
|
if: steps.check_branch.outputs.exists == 'true'
|
|
953
1000
|
id: progress
|
|
954
1001
|
uses: actions/github-script@v9
|
|
1002
|
+
env:
|
|
1003
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
1004
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER: ${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
955
1005
|
with:
|
|
956
1006
|
script: |
|
|
957
1007
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
958
1008
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
959
1009
|
|
|
960
|
-
const issueNumber =
|
|
961
|
-
const branchName =
|
|
1010
|
+
const issueNumber = parseInt(process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER, 10) || 0;
|
|
1011
|
+
const branchName = process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME;
|
|
962
1012
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
963
1013
|
const startTime = Date.now();
|
|
964
1014
|
|
|
@@ -1045,18 +1095,18 @@ jobs:
|
|
|
1045
1095
|
|
|
1046
1096
|
- name: Log in to Docker Hub
|
|
1047
1097
|
if: steps.check_branch.outputs.exists == 'true'
|
|
1048
|
-
uses: docker/login-action@
|
|
1098
|
+
uses: docker/login-action@v4
|
|
1049
1099
|
with:
|
|
1050
1100
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
1051
1101
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
1052
1102
|
|
|
1053
1103
|
- name: Set up Docker Buildx
|
|
1054
1104
|
if: steps.check_branch.outputs.exists == 'true'
|
|
1055
|
-
uses: docker/setup-buildx-action@
|
|
1105
|
+
uses: docker/setup-buildx-action@v4
|
|
1056
1106
|
|
|
1057
1107
|
- name: Build & push Docker image
|
|
1058
1108
|
if: steps.check_branch.outputs.exists == 'true'
|
|
1059
|
-
uses: docker/build-push-action@
|
|
1109
|
+
uses: docker/build-push-action@v7
|
|
1060
1110
|
with:
|
|
1061
1111
|
context: ${{ env.PROJECT_PATH }}
|
|
1062
1112
|
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
@@ -1069,14 +1119,18 @@ jobs:
|
|
|
1069
1119
|
if: steps.check_branch.outputs.exists == 'true'
|
|
1070
1120
|
id: docker_progress
|
|
1071
1121
|
uses: actions/github-script@v9
|
|
1122
|
+
env:
|
|
1123
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
1124
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
1125
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_DOCKER_START: ${{ steps.progress.outputs.docker_start }}
|
|
1072
1126
|
with:
|
|
1073
1127
|
script: |
|
|
1074
1128
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1075
1129
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1076
1130
|
|
|
1077
|
-
const commentId =
|
|
1078
|
-
const branchName =
|
|
1079
|
-
const dockerStart =
|
|
1131
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
1132
|
+
const branchName = process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME;
|
|
1133
|
+
const dockerStart = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_DOCKER_START, 10) || Date.now();
|
|
1080
1134
|
const now = Date.now();
|
|
1081
1135
|
const dockerElapsed = now - dockerStart;
|
|
1082
1136
|
const minutes = Math.floor(dockerElapsed / 60000);
|
|
@@ -1257,29 +1311,36 @@ jobs:
|
|
|
1257
1311
|
- name: Deploy complete comment
|
|
1258
1312
|
if: steps.check_branch.outputs.exists == 'true'
|
|
1259
1313
|
uses: actions/github-script@v9
|
|
1314
|
+
env:
|
|
1315
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
1316
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION: ${{ steps.docker_progress.outputs.docker_duration }}
|
|
1317
|
+
PAW_IN_STEPS_ISSUE_OUTPUTS_SHA: ${{ steps.issue.outputs.sha }}
|
|
1318
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
1319
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DEPLOY_START: ${{ steps.docker_progress.outputs.deploy_start }}
|
|
1320
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER: ${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
1260
1321
|
with:
|
|
1261
1322
|
script: |
|
|
1262
1323
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1263
1324
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1264
1325
|
|
|
1265
|
-
const commentId =
|
|
1266
|
-
const branchName =
|
|
1267
|
-
const dockerDuration =
|
|
1268
|
-
const deployStart =
|
|
1326
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
1327
|
+
const branchName = process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME;
|
|
1328
|
+
const dockerDuration = process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION;
|
|
1329
|
+
const deployStart = parseInt(process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DEPLOY_START, 10) || Date.now();
|
|
1269
1330
|
const now = Date.now();
|
|
1270
1331
|
const deployElapsed = now - deployStart;
|
|
1271
1332
|
const minutes = Math.floor(deployElapsed / 60000);
|
|
1272
1333
|
const seconds = Math.floor((deployElapsed % 60000) / 1000);
|
|
1273
1334
|
const deployDuration = minutes > 0 ? m('wf_preview.dur_min_sec', {minutes, seconds}) : m('wf_preview.dur_sec', {seconds});
|
|
1274
1335
|
|
|
1275
|
-
const projectName =
|
|
1276
|
-
const domainSuffix =
|
|
1277
|
-
const previewPort =
|
|
1278
|
-
const apiDocsPath =
|
|
1279
|
-
const issueNumber =
|
|
1336
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
1337
|
+
const domainSuffix = process.env.PREVIEW_DOMAIN_SUFFIX;
|
|
1338
|
+
const previewPort = process.env.PREVIEW_PORT;
|
|
1339
|
+
const apiDocsPath = process.env.API_DOCS_PATH;
|
|
1340
|
+
const issueNumber = parseInt(process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER, 10) || 0;
|
|
1280
1341
|
const domain = `${projectName}-pr-${issueNumber}.${domainSuffix}`;
|
|
1281
1342
|
const previewUrl = `http://${domain}:${previewPort}`;
|
|
1282
|
-
const sha =
|
|
1343
|
+
const sha = process.env.PAW_IN_STEPS_ISSUE_OUTPUTS_SHA;
|
|
1283
1344
|
|
|
1284
1345
|
// Build the preview environment table (the API Docs row is added only when API_DOCS_PATH is set)
|
|
1285
1346
|
const envRows = [
|
|
@@ -1336,20 +1397,25 @@ jobs:
|
|
|
1336
1397
|
});
|
|
1337
1398
|
|
|
1338
1399
|
- name: Build/deploy failure comment
|
|
1339
|
-
if: failure() && steps.check_branch.outputs.exists == 'true'
|
|
1400
|
+
if: failure() && steps.load_messages.outcome == 'success' && steps.check_branch.outputs.exists == 'true'
|
|
1340
1401
|
uses: actions/github-script@v9
|
|
1402
|
+
env:
|
|
1403
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME: ${{ needs.get-branch-from-issue.outputs.branch_name }}
|
|
1404
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION: ${{ steps.docker_progress.outputs.docker_duration }}
|
|
1405
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
1406
|
+
PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER: ${{ needs.get-branch-from-issue.outputs.issue_number }}
|
|
1341
1407
|
with:
|
|
1342
1408
|
script: |
|
|
1343
1409
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1344
1410
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1345
1411
|
|
|
1346
|
-
const commentId =
|
|
1347
|
-
const projectName =
|
|
1348
|
-
const issueNumber =
|
|
1349
|
-
const branchName =
|
|
1412
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
1413
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
1414
|
+
const issueNumber = parseInt(process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_ISSUE_NUMBER, 10) || 0;
|
|
1415
|
+
const branchName = process.env.PAW_IN_NEEDS_GET_BRANCH_FROM_ISSUE_OUTPUTS_BRANCH_NAME;
|
|
1350
1416
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
1351
1417
|
|
|
1352
|
-
const dockerDuration =
|
|
1418
|
+
const dockerDuration = process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION;
|
|
1353
1419
|
|
|
1354
1420
|
let dockerStatus, deployStatus;
|
|
1355
1421
|
let dockerTime = '-';
|
|
@@ -1425,6 +1491,8 @@ jobs:
|
|
|
1425
1491
|
uses: actions/checkout@v7
|
|
1426
1492
|
with:
|
|
1427
1493
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
1494
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
1495
|
+
path: .paw-msg
|
|
1428
1496
|
sparse-checkout: |
|
|
1429
1497
|
.github/scripts/messages.py
|
|
1430
1498
|
version.yml
|
|
@@ -1432,11 +1500,16 @@ jobs:
|
|
|
1432
1500
|
|
|
1433
1501
|
- name: Load messages
|
|
1434
1502
|
run: |
|
|
1435
|
-
# Keep a copy outside the workspace
|
|
1503
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
1436
1504
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
1437
|
-
|
|
1505
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
1506
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
1507
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
1508
|
+
rm -rf .paw-msg
|
|
1509
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
1510
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
1438
1511
|
{
|
|
1439
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
1512
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
1440
1513
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
1441
1514
|
} >> "$GITHUB_ENV"
|
|
1442
1515
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -1463,6 +1536,41 @@ jobs:
|
|
|
1463
1536
|
print("PAW_EOF")
|
|
1464
1537
|
PY
|
|
1465
1538
|
|
|
1539
|
+
# Without the deploy secrets no preview could have been deployed: on close events skip the cleanup quietly,
|
|
1540
|
+
# and on an explicit command report what is missing instead of surfacing a raw SSH action error
|
|
1541
|
+
- name: Deploy pre-check (Secrets)
|
|
1542
|
+
id: precheck
|
|
1543
|
+
env:
|
|
1544
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
1545
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
1546
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
1547
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
1548
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
1549
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
1550
|
+
run: |
|
|
1551
|
+
m() { python3 "$RUNNER_TEMP/paw/messages.py" get "$@"; }
|
|
1552
|
+
|
|
1553
|
+
MISSING=""
|
|
1554
|
+
for NAME in DOCKERHUB_USERNAME SERVER_HOST SERVER_USER; do
|
|
1555
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
1556
|
+
done
|
|
1557
|
+
# SSH_KEY is required when SSH_AUTH_METHOD=key, otherwise SERVER_PASSWORD
|
|
1558
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
1559
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
1560
|
+
else
|
|
1561
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
1562
|
+
fi
|
|
1563
|
+
if [ -n "$MISSING" ]; then
|
|
1564
|
+
if [ "$EVENT_NAME" = "issue_comment" ]; then
|
|
1565
|
+
echo "::error title=$(m wf_preview.precheck_secret_title)::$(m wf_preview.precheck_secret_body missing="$MISSING")"
|
|
1566
|
+
exit 1
|
|
1567
|
+
fi
|
|
1568
|
+
echo "::warning title=$(m wf_preview.precheck_skip_title)::$(m wf_preview.precheck_skip_body missing="$MISSING")"
|
|
1569
|
+
echo "ready=false" >> "$GITHUB_OUTPUT"
|
|
1570
|
+
exit 0
|
|
1571
|
+
fi
|
|
1572
|
+
echo "ready=true" >> "$GITHUB_OUTPUT"
|
|
1573
|
+
|
|
1466
1574
|
- name: Get PR/issue number
|
|
1467
1575
|
id: pr_number
|
|
1468
1576
|
run: |
|
|
@@ -1478,6 +1586,7 @@ jobs:
|
|
|
1478
1586
|
fi
|
|
1479
1587
|
|
|
1480
1588
|
- name: Remove container & image
|
|
1589
|
+
if: steps.precheck.outputs.ready == 'true'
|
|
1481
1590
|
uses: appleboy/ssh-action@v1.0.3
|
|
1482
1591
|
env:
|
|
1483
1592
|
SSH_AUTH_METHOD: ${{ env.SSH_AUTH_METHOD }}
|
|
@@ -1525,17 +1634,20 @@ jobs:
|
|
|
1525
1634
|
|
|
1526
1635
|
- name: Destroy complete comment
|
|
1527
1636
|
if: |
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1637
|
+
steps.precheck.outputs.ready == 'true' && (
|
|
1638
|
+
github.event_name == 'issue_comment' ||
|
|
1639
|
+
(github.event_name == 'pull_request' && github.event.action == 'closed') ||
|
|
1640
|
+
(github.event_name == 'issues' && github.event.action == 'closed'))
|
|
1531
1641
|
uses: actions/github-script@v9
|
|
1642
|
+
env:
|
|
1643
|
+
PAW_IN_STEPS_PR_NUMBER_OUTPUTS_NUMBER: ${{ steps.pr_number.outputs.number }}
|
|
1532
1644
|
with:
|
|
1533
1645
|
script: |
|
|
1534
1646
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1535
1647
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1536
1648
|
|
|
1537
|
-
const number =
|
|
1538
|
-
const projectName =
|
|
1649
|
+
const number = parseInt(process.env.PAW_IN_STEPS_PR_NUMBER_OUTPUTS_NUMBER, 10) || 0;
|
|
1650
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
1539
1651
|
|
|
1540
1652
|
const body = [
|
|
1541
1653
|
m('wf_preview.title_destroyed'),
|
|
@@ -1571,6 +1683,8 @@ jobs:
|
|
|
1571
1683
|
uses: actions/checkout@v7
|
|
1572
1684
|
with:
|
|
1573
1685
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
1686
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
1687
|
+
path: .paw-msg
|
|
1574
1688
|
sparse-checkout: |
|
|
1575
1689
|
.github/scripts/messages.py
|
|
1576
1690
|
version.yml
|
|
@@ -1578,11 +1692,16 @@ jobs:
|
|
|
1578
1692
|
|
|
1579
1693
|
- name: Load messages
|
|
1580
1694
|
run: |
|
|
1581
|
-
# Keep a copy outside the workspace
|
|
1695
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
1582
1696
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
1583
|
-
|
|
1697
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
1698
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
1699
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
1700
|
+
rm -rf .paw-msg
|
|
1701
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
1702
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
1584
1703
|
{
|
|
1585
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
1704
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
1586
1705
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
1587
1706
|
} >> "$GITHUB_ENV"
|
|
1588
1707
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -1609,6 +1728,32 @@ jobs:
|
|
|
1609
1728
|
print("PAW_EOF")
|
|
1610
1729
|
PY
|
|
1611
1730
|
|
|
1731
|
+
# Report the missing secrets by name instead of surfacing a raw SSH action error
|
|
1732
|
+
- name: Deploy pre-check (Secrets)
|
|
1733
|
+
id: precheck
|
|
1734
|
+
env:
|
|
1735
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
1736
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
1737
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
1738
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
1739
|
+
run: |
|
|
1740
|
+
m() { python3 "$RUNNER_TEMP/paw/messages.py" get "$@"; }
|
|
1741
|
+
|
|
1742
|
+
MISSING=""
|
|
1743
|
+
for NAME in SERVER_HOST SERVER_USER; do
|
|
1744
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
1745
|
+
done
|
|
1746
|
+
# SSH_KEY is required when SSH_AUTH_METHOD=key, otherwise SERVER_PASSWORD
|
|
1747
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
1748
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
1749
|
+
else
|
|
1750
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
1751
|
+
fi
|
|
1752
|
+
if [ -n "$MISSING" ]; then
|
|
1753
|
+
echo "::error title=$(m wf_preview.precheck_secret_title)::$(m wf_preview.precheck_secret_body missing="$MISSING")"
|
|
1754
|
+
exit 1
|
|
1755
|
+
fi
|
|
1756
|
+
|
|
1612
1757
|
- name: Check container status
|
|
1613
1758
|
id: status
|
|
1614
1759
|
uses: appleboy/ssh-action@v1.0.3
|
|
@@ -1660,19 +1805,22 @@ jobs:
|
|
|
1660
1805
|
|
|
1661
1806
|
- name: Post status comment
|
|
1662
1807
|
uses: actions/github-script@v9
|
|
1808
|
+
env:
|
|
1809
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_IS_PR: ${{ needs.check-command.outputs.is_pr }}
|
|
1810
|
+
PAW_IN_STEPS_CHECK_RUNNING_OUTCOME: ${{ steps.check_running.outcome }}
|
|
1663
1811
|
with:
|
|
1664
1812
|
script: |
|
|
1665
1813
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1666
1814
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1667
1815
|
|
|
1668
1816
|
const number = context.issue.number;
|
|
1669
|
-
const projectName =
|
|
1670
|
-
const domainSuffix =
|
|
1671
|
-
const previewPort =
|
|
1817
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
1818
|
+
const domainSuffix = process.env.PREVIEW_DOMAIN_SUFFIX;
|
|
1819
|
+
const previewPort = process.env.PREVIEW_PORT;
|
|
1672
1820
|
const domain = `${projectName}-pr-${number}.${domainSuffix}`;
|
|
1673
1821
|
const previewUrl = `http://${domain}:${previewPort}`;
|
|
1674
|
-
const isRunning =
|
|
1675
|
-
const isPr =
|
|
1822
|
+
const isRunning = process.env.PAW_IN_STEPS_CHECK_RUNNING_OUTCOME === 'success';
|
|
1823
|
+
const isPr = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_IS_PR === 'true';
|
|
1676
1824
|
const contextType = isPr ? 'PR' : 'Issue';
|
|
1677
1825
|
|
|
1678
1826
|
let body;
|
|
@@ -1734,18 +1882,26 @@ jobs:
|
|
|
1734
1882
|
uses: actions/checkout@v7
|
|
1735
1883
|
with:
|
|
1736
1884
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
1885
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
1886
|
+
path: .paw-msg
|
|
1737
1887
|
sparse-checkout: |
|
|
1738
1888
|
.github/scripts/messages.py
|
|
1739
1889
|
version.yml
|
|
1740
1890
|
sparse-checkout-cone-mode: false
|
|
1741
1891
|
|
|
1742
1892
|
- name: Load messages
|
|
1893
|
+
id: load_messages
|
|
1743
1894
|
run: |
|
|
1744
|
-
# Keep a copy outside the workspace
|
|
1895
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
1745
1896
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
1746
|
-
|
|
1897
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
1898
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
1899
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
1900
|
+
rm -rf .paw-msg
|
|
1901
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
1902
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
1747
1903
|
{
|
|
1748
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
1904
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
1749
1905
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
1750
1906
|
} >> "$GITHUB_ENV"
|
|
1751
1907
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -1775,12 +1931,14 @@ jobs:
|
|
|
1775
1931
|
- name: Check branch exists and extract info
|
|
1776
1932
|
id: branch_info
|
|
1777
1933
|
uses: actions/github-script@v9
|
|
1934
|
+
env:
|
|
1935
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
1778
1936
|
with:
|
|
1779
1937
|
script: |
|
|
1780
1938
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1781
1939
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1782
1940
|
|
|
1783
|
-
const branchName =
|
|
1941
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
1784
1942
|
const issueNumber = context.issue.number;
|
|
1785
1943
|
|
|
1786
1944
|
console.log(m('wf_preview.log_check_branch', {branchName}));
|
|
@@ -1855,21 +2013,25 @@ jobs:
|
|
|
1855
2013
|
- name: Get latest commit SHA of the branch
|
|
1856
2014
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1857
2015
|
id: get_sha
|
|
2016
|
+
env:
|
|
2017
|
+
PAW_BRANCH_NAME: ${{ needs.check-command.outputs.custom_branch }}
|
|
1858
2018
|
run: |
|
|
1859
|
-
SHA=$(git ls-remote https://github.com/${{ github.repository }}.git refs/heads/$
|
|
2019
|
+
SHA=$(git ls-remote https://github.com/${{ github.repository }}.git "refs/heads/$PAW_BRANCH_NAME" | cut -c1-7)
|
|
1860
2020
|
echo "sha=$SHA" >> $GITHUB_OUTPUT
|
|
1861
2021
|
|
|
1862
2022
|
- name: Create progress comment
|
|
1863
2023
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1864
2024
|
id: progress
|
|
1865
2025
|
uses: actions/github-script@v9
|
|
2026
|
+
env:
|
|
2027
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
1866
2028
|
with:
|
|
1867
2029
|
script: |
|
|
1868
2030
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1869
2031
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1870
2032
|
|
|
1871
2033
|
const issueNumber = context.issue.number;
|
|
1872
|
-
const branchName =
|
|
2034
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
1873
2035
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
1874
2036
|
const startTime = Date.now();
|
|
1875
2037
|
|
|
@@ -1955,14 +2117,14 @@ jobs:
|
|
|
1955
2117
|
|
|
1956
2118
|
- name: Log in to Docker Hub
|
|
1957
2119
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1958
|
-
uses: docker/login-action@
|
|
2120
|
+
uses: docker/login-action@v4
|
|
1959
2121
|
with:
|
|
1960
2122
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
1961
2123
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
1962
2124
|
|
|
1963
2125
|
- name: Set up Docker Buildx
|
|
1964
2126
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1965
|
-
uses: docker/setup-buildx-action@
|
|
2127
|
+
uses: docker/setup-buildx-action@v4
|
|
1966
2128
|
|
|
1967
2129
|
- name: Resolve container name
|
|
1968
2130
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
@@ -1978,7 +2140,7 @@ jobs:
|
|
|
1978
2140
|
|
|
1979
2141
|
- name: Build & push Docker image
|
|
1980
2142
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1981
|
-
uses: docker/build-push-action@
|
|
2143
|
+
uses: docker/build-push-action@v7
|
|
1982
2144
|
with:
|
|
1983
2145
|
context: ${{ env.PROJECT_PATH }}
|
|
1984
2146
|
file: ${{ env.PROJECT_PATH }}/${{ env.DOCKERFILE_PATH }}
|
|
@@ -1991,14 +2153,18 @@ jobs:
|
|
|
1991
2153
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
1992
2154
|
id: docker_progress
|
|
1993
2155
|
uses: actions/github-script@v9
|
|
2156
|
+
env:
|
|
2157
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2158
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
2159
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_DOCKER_START: ${{ steps.progress.outputs.docker_start }}
|
|
1994
2160
|
with:
|
|
1995
2161
|
script: |
|
|
1996
2162
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
1997
2163
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
1998
2164
|
|
|
1999
|
-
const commentId =
|
|
2000
|
-
const branchName =
|
|
2001
|
-
const dockerStart =
|
|
2165
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
2166
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2167
|
+
const dockerStart = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_DOCKER_START, 10) || Date.now();
|
|
2002
2168
|
const now = Date.now();
|
|
2003
2169
|
const dockerElapsed = now - dockerStart;
|
|
2004
2170
|
const minutes = Math.floor(dockerElapsed / 60000);
|
|
@@ -2172,29 +2338,36 @@ jobs:
|
|
|
2172
2338
|
- name: Deploy complete comment
|
|
2173
2339
|
if: steps.branch_info.outputs.branch_exists == 'true'
|
|
2174
2340
|
uses: actions/github-script@v9
|
|
2341
|
+
env:
|
|
2342
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2343
|
+
PAW_IN_STEPS_CONTAINER_OUTPUTS_NAME: ${{ steps.container.outputs.name }}
|
|
2344
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION: ${{ steps.docker_progress.outputs.docker_duration }}
|
|
2345
|
+
PAW_IN_STEPS_GET_SHA_OUTPUTS_SHA: ${{ steps.get_sha.outputs.sha }}
|
|
2346
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
2347
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DEPLOY_START: ${{ steps.docker_progress.outputs.deploy_start }}
|
|
2175
2348
|
with:
|
|
2176
2349
|
script: |
|
|
2177
2350
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
2178
2351
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
2179
2352
|
|
|
2180
|
-
const commentId =
|
|
2181
|
-
const branchName =
|
|
2182
|
-
const dockerDuration =
|
|
2183
|
-
const deployStart =
|
|
2353
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
2354
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2355
|
+
const dockerDuration = process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION;
|
|
2356
|
+
const deployStart = parseInt(process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DEPLOY_START, 10) || Date.now();
|
|
2184
2357
|
const now = Date.now();
|
|
2185
2358
|
const deployElapsed = now - deployStart;
|
|
2186
2359
|
const minutes = Math.floor(deployElapsed / 60000);
|
|
2187
2360
|
const seconds = Math.floor((deployElapsed % 60000) / 1000);
|
|
2188
2361
|
const deployDuration = minutes > 0 ? m('wf_preview.dur_min_sec', {minutes, seconds}) : m('wf_preview.dur_sec', {seconds});
|
|
2189
2362
|
|
|
2190
|
-
const projectName =
|
|
2191
|
-
const domainSuffix =
|
|
2192
|
-
const previewPort =
|
|
2193
|
-
const apiDocsPath =
|
|
2194
|
-
const containerName =
|
|
2363
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
2364
|
+
const domainSuffix = process.env.PREVIEW_DOMAIN_SUFFIX;
|
|
2365
|
+
const previewPort = process.env.PREVIEW_PORT;
|
|
2366
|
+
const apiDocsPath = process.env.API_DOCS_PATH;
|
|
2367
|
+
const containerName = process.env.PAW_IN_STEPS_CONTAINER_OUTPUTS_NAME;
|
|
2195
2368
|
const domain = `${containerName}.${domainSuffix}`;
|
|
2196
2369
|
const previewUrl = `http://${domain}:${previewPort}`;
|
|
2197
|
-
const sha =
|
|
2370
|
+
const sha = process.env.PAW_IN_STEPS_GET_SHA_OUTPUTS_SHA;
|
|
2198
2371
|
|
|
2199
2372
|
// Build the preview environment table
|
|
2200
2373
|
const envRows = [
|
|
@@ -2251,18 +2424,22 @@ jobs:
|
|
|
2251
2424
|
});
|
|
2252
2425
|
|
|
2253
2426
|
- name: Build/deploy failure comment
|
|
2254
|
-
if: failure() && steps.branch_info.outputs.branch_exists == 'true'
|
|
2427
|
+
if: failure() && steps.load_messages.outcome == 'success' && steps.branch_info.outputs.branch_exists == 'true'
|
|
2255
2428
|
uses: actions/github-script@v9
|
|
2429
|
+
env:
|
|
2430
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2431
|
+
PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION: ${{ steps.docker_progress.outputs.docker_duration }}
|
|
2432
|
+
PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID: ${{ steps.progress.outputs.comment_id }}
|
|
2256
2433
|
with:
|
|
2257
2434
|
script: |
|
|
2258
2435
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
2259
2436
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
2260
2437
|
|
|
2261
|
-
const commentId =
|
|
2262
|
-
const branchName =
|
|
2438
|
+
const commentId = parseInt(process.env.PAW_IN_STEPS_PROGRESS_OUTPUTS_COMMENT_ID, 10) || 0;
|
|
2439
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2263
2440
|
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
|
2264
2441
|
|
|
2265
|
-
const dockerDuration =
|
|
2442
|
+
const dockerDuration = process.env.PAW_IN_STEPS_DOCKER_PROGRESS_OUTPUTS_DOCKER_DURATION;
|
|
2266
2443
|
|
|
2267
2444
|
let dockerStatus, deployStatus;
|
|
2268
2445
|
let dockerTime = '-';
|
|
@@ -2338,6 +2515,8 @@ jobs:
|
|
|
2338
2515
|
uses: actions/checkout@v7
|
|
2339
2516
|
with:
|
|
2340
2517
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
2518
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
2519
|
+
path: .paw-msg
|
|
2341
2520
|
sparse-checkout: |
|
|
2342
2521
|
.github/scripts/messages.py
|
|
2343
2522
|
version.yml
|
|
@@ -2345,11 +2524,16 @@ jobs:
|
|
|
2345
2524
|
|
|
2346
2525
|
- name: Load messages
|
|
2347
2526
|
run: |
|
|
2348
|
-
# Keep a copy outside the workspace
|
|
2527
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
2349
2528
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
2350
|
-
|
|
2529
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
2530
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
2531
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
2532
|
+
rm -rf .paw-msg
|
|
2533
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
2534
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
2351
2535
|
{
|
|
2352
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
2536
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
2353
2537
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
2354
2538
|
} >> "$GITHUB_ENV"
|
|
2355
2539
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -2376,16 +2560,45 @@ jobs:
|
|
|
2376
2560
|
print("PAW_EOF")
|
|
2377
2561
|
PY
|
|
2378
2562
|
|
|
2563
|
+
# Report the missing secrets by name instead of surfacing a raw SSH action error
|
|
2564
|
+
- name: Deploy pre-check (Secrets)
|
|
2565
|
+
id: precheck
|
|
2566
|
+
env:
|
|
2567
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
2568
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
2569
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
2570
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
2571
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
2572
|
+
run: |
|
|
2573
|
+
m() { python3 "$RUNNER_TEMP/paw/messages.py" get "$@"; }
|
|
2574
|
+
|
|
2575
|
+
MISSING=""
|
|
2576
|
+
for NAME in DOCKERHUB_USERNAME SERVER_HOST SERVER_USER; do
|
|
2577
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
2578
|
+
done
|
|
2579
|
+
# SSH_KEY is required when SSH_AUTH_METHOD=key, otherwise SERVER_PASSWORD
|
|
2580
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
2581
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
2582
|
+
else
|
|
2583
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
2584
|
+
fi
|
|
2585
|
+
if [ -n "$MISSING" ]; then
|
|
2586
|
+
echo "::error title=$(m wf_preview.precheck_secret_title)::$(m wf_preview.precheck_secret_body missing="$MISSING")"
|
|
2587
|
+
exit 1
|
|
2588
|
+
fi
|
|
2589
|
+
|
|
2379
2590
|
- name: Extract container info from branch name
|
|
2380
2591
|
id: container_info
|
|
2381
2592
|
uses: actions/github-script@v9
|
|
2593
|
+
env:
|
|
2594
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2382
2595
|
with:
|
|
2383
2596
|
script: |
|
|
2384
2597
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
2385
2598
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
2386
2599
|
|
|
2387
|
-
const branchName =
|
|
2388
|
-
const projectName =
|
|
2600
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2601
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
2389
2602
|
|
|
2390
2603
|
// Extract the issue number from the branch name (#number pattern)
|
|
2391
2604
|
const issueMatch = branchName.match(/#(\d+)/);
|
|
@@ -2460,13 +2673,16 @@ jobs:
|
|
|
2460
2673
|
|
|
2461
2674
|
- name: Destroy complete comment
|
|
2462
2675
|
uses: actions/github-script@v9
|
|
2676
|
+
env:
|
|
2677
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2678
|
+
PAW_IN_STEPS_CONTAINER_INFO_OUTPUTS_CONTAINER_NAME: ${{ steps.container_info.outputs.container_name }}
|
|
2463
2679
|
with:
|
|
2464
2680
|
script: |
|
|
2465
2681
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
2466
2682
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
2467
2683
|
|
|
2468
|
-
const branchName =
|
|
2469
|
-
const containerName =
|
|
2684
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2685
|
+
const containerName = process.env.PAW_IN_STEPS_CONTAINER_INFO_OUTPUTS_CONTAINER_NAME;
|
|
2470
2686
|
|
|
2471
2687
|
const body = [
|
|
2472
2688
|
m('wf_preview.title_custom_destroyed'),
|
|
@@ -2506,6 +2722,8 @@ jobs:
|
|
|
2506
2722
|
uses: actions/checkout@v7
|
|
2507
2723
|
with:
|
|
2508
2724
|
ref: ${{ github.event_name == 'pull_request' && github.sha || github.event.repository.default_branch }}
|
|
2725
|
+
# Separate path: a sparse checkout at the workspace root would leave the later full checkout sparse too
|
|
2726
|
+
path: .paw-msg
|
|
2509
2727
|
sparse-checkout: |
|
|
2510
2728
|
.github/scripts/messages.py
|
|
2511
2729
|
version.yml
|
|
@@ -2513,11 +2731,16 @@ jobs:
|
|
|
2513
2731
|
|
|
2514
2732
|
- name: Load messages
|
|
2515
2733
|
run: |
|
|
2516
|
-
# Keep a copy outside the workspace
|
|
2734
|
+
# Keep a copy outside the workspace and drop the sparse clone so the later checkout sees a clean tree
|
|
2517
2735
|
mkdir -p "$RUNNER_TEMP/paw"
|
|
2518
|
-
|
|
2736
|
+
[ -f .paw-msg/.github/scripts/messages.py ] || { echo "::error::messages.py is missing; rerun \`npx project-auto-wizard --mode full --force\`"; exit 1; }
|
|
2737
|
+
cp .paw-msg/.github/scripts/messages.py "$RUNNER_TEMP/paw/messages.py"
|
|
2738
|
+
LANG_CODE=$(cd .paw-msg && python3 "$RUNNER_TEMP/paw/messages.py" lang)
|
|
2739
|
+
rm -rf .paw-msg
|
|
2740
|
+
# The workspace root has no version.yml; pass the language resolved above to every later messages.py call
|
|
2741
|
+
export PROJECT_AUTO_WIZARD_LANG="$LANG_CODE"
|
|
2519
2742
|
{
|
|
2520
|
-
echo "PROJECT_AUTO_WIZARD_LANG=$
|
|
2743
|
+
echo "PROJECT_AUTO_WIZARD_LANG=$LANG_CODE"
|
|
2521
2744
|
echo "PAW_MSG=$(python3 "$RUNNER_TEMP/paw/messages.py" dump wf_preview.)"
|
|
2522
2745
|
} >> "$GITHUB_ENV"
|
|
2523
2746
|
# The deploy script runs on the remote server, where messages.py does not exist:
|
|
@@ -2544,13 +2767,41 @@ jobs:
|
|
|
2544
2767
|
print("PAW_EOF")
|
|
2545
2768
|
PY
|
|
2546
2769
|
|
|
2770
|
+
# Report the missing secrets by name instead of surfacing a raw SSH action error
|
|
2771
|
+
- name: Deploy pre-check (Secrets)
|
|
2772
|
+
id: precheck
|
|
2773
|
+
env:
|
|
2774
|
+
SERVER_HOST: ${{ secrets.SERVER_HOST }}
|
|
2775
|
+
SERVER_USER: ${{ secrets.SERVER_USER }}
|
|
2776
|
+
SERVER_PASSWORD: ${{ secrets.SERVER_PASSWORD }}
|
|
2777
|
+
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
2778
|
+
run: |
|
|
2779
|
+
m() { python3 "$RUNNER_TEMP/paw/messages.py" get "$@"; }
|
|
2780
|
+
|
|
2781
|
+
MISSING=""
|
|
2782
|
+
for NAME in SERVER_HOST SERVER_USER; do
|
|
2783
|
+
[ -n "${!NAME}" ] || MISSING="$MISSING $NAME"
|
|
2784
|
+
done
|
|
2785
|
+
# SSH_KEY is required when SSH_AUTH_METHOD=key, otherwise SERVER_PASSWORD
|
|
2786
|
+
if [ "${SSH_AUTH_METHOD:-password}" = "key" ]; then
|
|
2787
|
+
[ -n "$SSH_KEY" ] || MISSING="$MISSING SSH_KEY"
|
|
2788
|
+
else
|
|
2789
|
+
[ -n "$SERVER_PASSWORD" ] || MISSING="$MISSING SERVER_PASSWORD"
|
|
2790
|
+
fi
|
|
2791
|
+
if [ -n "$MISSING" ]; then
|
|
2792
|
+
echo "::error title=$(m wf_preview.precheck_secret_title)::$(m wf_preview.precheck_secret_body missing="$MISSING")"
|
|
2793
|
+
exit 1
|
|
2794
|
+
fi
|
|
2795
|
+
|
|
2547
2796
|
- name: Extract container info from branch name
|
|
2548
2797
|
id: container_info
|
|
2549
2798
|
uses: actions/github-script@v9
|
|
2799
|
+
env:
|
|
2800
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2550
2801
|
with:
|
|
2551
2802
|
script: |
|
|
2552
|
-
const branchName =
|
|
2553
|
-
const projectName =
|
|
2803
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2804
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
2554
2805
|
|
|
2555
2806
|
// Extract the issue number from the branch name (#number pattern)
|
|
2556
2807
|
const issueMatch = branchName.match(/#(\d+)/);
|
|
@@ -2606,19 +2857,23 @@ jobs:
|
|
|
2606
2857
|
|
|
2607
2858
|
- name: Post status comment
|
|
2608
2859
|
uses: actions/github-script@v9
|
|
2860
|
+
env:
|
|
2861
|
+
PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH: ${{ needs.check-command.outputs.custom_branch }}
|
|
2862
|
+
PAW_IN_STEPS_CHECK_RUNNING_OUTCOME: ${{ steps.check_running.outcome }}
|
|
2863
|
+
PAW_IN_STEPS_CONTAINER_INFO_OUTPUTS_CONTAINER_NAME: ${{ steps.container_info.outputs.container_name }}
|
|
2609
2864
|
with:
|
|
2610
2865
|
script: |
|
|
2611
2866
|
const M = JSON.parse(process.env.PAW_MSG);
|
|
2612
2867
|
const m = (k, p = {}) => M[k].replace(/\{(\w+)\}/g, (s, n) => (n in p ? p[n] : s));
|
|
2613
2868
|
|
|
2614
|
-
const branchName =
|
|
2615
|
-
const containerName =
|
|
2616
|
-
const projectName =
|
|
2617
|
-
const domainSuffix =
|
|
2618
|
-
const previewPort =
|
|
2869
|
+
const branchName = process.env.PAW_IN_NEEDS_CHECK_COMMAND_OUTPUTS_CUSTOM_BRANCH;
|
|
2870
|
+
const containerName = process.env.PAW_IN_STEPS_CONTAINER_INFO_OUTPUTS_CONTAINER_NAME;
|
|
2871
|
+
const projectName = process.env.PROJECT_PATH !== '.' ? process.env.PROJECT_NAME + '-python' : process.env.PROJECT_NAME;
|
|
2872
|
+
const domainSuffix = process.env.PREVIEW_DOMAIN_SUFFIX;
|
|
2873
|
+
const previewPort = process.env.PREVIEW_PORT;
|
|
2619
2874
|
const domain = `${containerName}.${domainSuffix}`;
|
|
2620
2875
|
const previewUrl = `http://${domain}:${previewPort}`;
|
|
2621
|
-
const isRunning =
|
|
2876
|
+
const isRunning = process.env.PAW_IN_STEPS_CHECK_RUNNING_OUTCOME === 'success';
|
|
2622
2877
|
|
|
2623
2878
|
let body;
|
|
2624
2879
|
if (isRunning) {
|