pipecraft 0.0.0-releaseit
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/.claude/settings.local.json +35 -0
- package/.github/actions/calculate-version/action.yml +106 -0
- package/.github/actions/create-pr/action.yml +122 -0
- package/.github/actions/create-release/action.yml +74 -0
- package/.github/actions/create-tag/action.yml +94 -0
- package/.github/actions/detect-changes/action.yml +62 -0
- package/.github/actions/manage-branch/action.yml +113 -0
- package/.github/actions/promote-branch/action.yml +352 -0
- package/.github/example/workflows/job.analyze.code.yml +26 -0
- package/.github/example/workflows/job.analyze.docker.yml +32 -0
- package/.github/example/workflows/job.app.api.deploy.yml +127 -0
- package/.github/example/workflows/job.app.api.test.yml +102 -0
- package/.github/example/workflows/job.app.docs.deploy.yml +40 -0
- package/.github/example/workflows/job.app.docs.test.yml +50 -0
- package/.github/example/workflows/job.app.web.deploy.yml +96 -0
- package/.github/example/workflows/job.app.web.test.yml +49 -0
- package/.github/example/workflows/job.changes.yml +82 -0
- package/.github/example/workflows/job.create-pr.yml +96 -0
- package/.github/example/workflows/job.env-check.yml +43 -0
- package/.github/example/workflows/job.fast-forward.yml +103 -0
- package/.github/example/workflows/job.lint.yml +64 -0
- package/.github/example/workflows/job.pr-name.yml +70 -0
- package/.github/example/workflows/job.pr-squash-name.yml +27 -0
- package/.github/example/workflows/job.tag.yml +38 -0
- package/.github/example/workflows/job.version.yml +99 -0
- package/.github/example/workflows/lib.plugin-base.publish.yml +59 -0
- package/.github/example/workflows/pipe.yml +178 -0
- package/.github/example/workflows/scripts/fastforward.sh +51 -0
- package/.github/example/workflows/scripts/pipe-cleaner.sh +70 -0
- package/.github/scripts/fastforward.sh +51 -0
- package/.github/scripts/pipe-cleaner.sh +70 -0
- package/.github/workflows/pipeline.yml +220 -0
- package/.github/workflows/pr-title-check.yml +70 -0
- package/.github/workflows/publish.yml +39 -0
- package/.pipecraftrc.json +78 -0
- package/.release-it.cjs +71 -0
- package/PIPELINE_TESTING_PLAN.md +499 -0
- package/README.md +1101 -0
- package/TRUNK_FLOW_PLAN.md +401 -0
- package/assets/logo_banner.png +0 -0
- package/assets/logo_banner.webp +0 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +364 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/generators/init.tpl.d.ts +3 -0
- package/dist/generators/init.tpl.d.ts.map +1 -0
- package/dist/generators/init.tpl.js +117 -0
- package/dist/generators/init.tpl.js.map +1 -0
- package/dist/generators/workflows.tpl.d.ts +7 -0
- package/dist/generators/workflows.tpl.d.ts.map +1 -0
- package/dist/generators/workflows.tpl.js +73 -0
- package/dist/generators/workflows.tpl.js.map +1 -0
- package/dist/templates/actions/calculate-version.yml.tpl.d.ts +3 -0
- package/dist/templates/actions/calculate-version.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/calculate-version.yml.tpl.js +122 -0
- package/dist/templates/actions/calculate-version.yml.tpl.js.map +1 -0
- package/dist/templates/actions/create-pr.yml.tpl.d.ts +3 -0
- package/dist/templates/actions/create-pr.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/create-pr.yml.tpl.js +145 -0
- package/dist/templates/actions/create-pr.yml.tpl.js.map +1 -0
- package/dist/templates/actions/create-tag.yml.tpl.d.ts +3 -0
- package/dist/templates/actions/create-tag.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/create-tag.yml.tpl.js +111 -0
- package/dist/templates/actions/create-tag.yml.tpl.js.map +1 -0
- package/dist/templates/actions/detect-changes.yml.tpl.d.ts +3 -0
- package/dist/templates/actions/detect-changes.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/detect-changes.yml.tpl.js +79 -0
- package/dist/templates/actions/detect-changes.yml.tpl.js.map +1 -0
- package/dist/templates/actions/manage-branch.yml.tpl.d.ts +3 -0
- package/dist/templates/actions/manage-branch.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/manage-branch.yml.tpl.js +130 -0
- package/dist/templates/actions/manage-branch.yml.tpl.js.map +1 -0
- package/dist/templates/actions/promote-branch.yml.tpl.d.ts +3 -0
- package/dist/templates/actions/promote-branch.yml.tpl.d.ts.map +1 -0
- package/dist/templates/actions/promote-branch.yml.tpl.js +362 -0
- package/dist/templates/actions/promote-branch.yml.tpl.js.map +1 -0
- package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts +16 -0
- package/dist/templates/workflows/pipeline-path-based.yml.tpl.d.ts.map +1 -0
- package/dist/templates/workflows/pipeline-path-based.yml.tpl.js +652 -0
- package/dist/templates/workflows/pipeline-path-based.yml.tpl.js.map +1 -0
- package/dist/types/index.d.ts +63 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ast-path-operations.d.ts +287 -0
- package/dist/utils/ast-path-operations.d.ts.map +1 -0
- package/dist/utils/ast-path-operations.js +419 -0
- package/dist/utils/ast-path-operations.js.map +1 -0
- package/dist/utils/config.d.ts +3 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +49 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/github-setup.d.ts +74 -0
- package/dist/utils/github-setup.d.ts.map +1 -0
- package/dist/utils/github-setup.js +418 -0
- package/dist/utils/github-setup.js.map +1 -0
- package/dist/utils/idempotency.d.ts +47 -0
- package/dist/utils/idempotency.d.ts.map +1 -0
- package/dist/utils/idempotency.js +176 -0
- package/dist/utils/idempotency.js.map +1 -0
- package/dist/utils/preflight.d.ts +55 -0
- package/dist/utils/preflight.d.ts.map +1 -0
- package/dist/utils/preflight.js +261 -0
- package/dist/utils/preflight.js.map +1 -0
- package/dist/utils/versioning.d.ts +41 -0
- package/dist/utils/versioning.d.ts.map +1 -0
- package/dist/utils/versioning.js +219 -0
- package/dist/utils/versioning.js.map +1 -0
- package/docs/USER_JOURNEY_ERRORS.md +352 -0
- package/eslint.config.js +77 -0
- package/examples/basic-config.json +41 -0
- package/examples/monorepo-config.json +49 -0
- package/examples/usage.md +289 -0
- package/package.json +58 -0
- package/scripts/debug-workflows.sh +339 -0
- package/scripts/parse-pipeline.js +29 -0
- package/scripts/test-job-order.cjs +140 -0
- package/scripts/validate-pipeline.cjs +379 -0
- package/scripts/verify-job-order.sh +30 -0
- package/src/cli/index.ts +414 -0
- package/src/generators/init.tpl.ts +126 -0
- package/src/generators/workflows.tpl.ts +80 -0
- package/src/templates/actions/calculate-version.yml.tpl.ts +124 -0
- package/src/templates/actions/create-pr.yml.tpl.ts +147 -0
- package/src/templates/actions/create-tag.yml.tpl.ts +112 -0
- package/src/templates/actions/detect-changes.yml.tpl.ts +87 -0
- package/src/templates/actions/manage-branch.yml.tpl.ts +132 -0
- package/src/templates/actions/promote-branch.yml.tpl.ts +364 -0
- package/src/templates/workflows/pipeline-path-based.yml.tpl.ts +706 -0
- package/src/types/index.ts +64 -0
- package/src/utils/README-ast-path-operations.md +390 -0
- package/src/utils/ast-path-operations.ts +581 -0
- package/src/utils/config.ts +64 -0
- package/src/utils/github-setup.ts +558 -0
- package/src/utils/idempotency.ts +215 -0
- package/src/utils/preflight.ts +306 -0
- package/src/utils/versioning.ts +244 -0
- package/tests/README.md +229 -0
- package/tests/TEST_STRUCTURE.md +256 -0
- package/tests/act/run-act-tests.sh +345 -0
- package/tests/debugging/debug-utils.ts +538 -0
- package/tests/debugging/debug-workflow.test.ts +339 -0
- package/tests/debugging/debug-workflows.sh +339 -0
- package/tests/debugging/iterative-debug.ts +652 -0
- package/tests/debugging/run-debug-tests.sh +431 -0
- package/tests/fixtures/basic-config.json +51 -0
- package/tests/fixtures/invalid-config.json +9 -0
- package/tests/fixtures/pipeline-generated.yml +235 -0
- package/tests/fixtures/pipeline-preserve-comments.yml +245 -0
- package/tests/fixtures/pipeline-user-modified.yml +245 -0
- package/tests/fixtures/test-config.json +58 -0
- package/tests/github-live/README.md +250 -0
- package/tests/github-local/JOB_WORKFLOW_TESTS.md +296 -0
- package/tests/github-local/README.md +240 -0
- package/tests/github-local/run-all-tests.sh +422 -0
- package/tests/github-local/test-job-workflows.sh +631 -0
- package/tests/github-local/test-pipeline-workflow.sh +440 -0
- package/tests/integration/generators.test.ts +578 -0
- package/tests/integration/path-based-template.test.ts +510 -0
- package/tests/integration/simple-path-based.test.ts +415 -0
- package/tests/setup.ts +56 -0
- package/tests/unit/ast-path-operations-extended.test.ts +302 -0
- package/tests/unit/cli.test.ts +541 -0
- package/tests/unit/config-extended.test.ts +412 -0
- package/tests/unit/config.test.ts +152 -0
- package/tests/unit/github-setup.test.ts +189 -0
- package/tests/unit/idempotency-isolated.test.ts +297 -0
- package/tests/unit/job-order.test.ts +157 -0
- package/tests/unit/pipeline-path-based.test.ts +511 -0
- package/tests/unit/validate-pipeline.test.ts +384 -0
- package/tests/unit/versioning-extended.test.ts +279 -0
- package/tests/unit/versioning.test.ts +241 -0
- package/tsconfig.debug.json +17 -0
- package/tsconfig.json +28 -0
- package/vitest.config.ts +51 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { PinionContext, toFile, renderTemplate } from '@featherscloud/pinion'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
|
|
4
|
+
// Template for the Version Calculation GitHub Action
|
|
5
|
+
const versionActionTemplate = (ctx: any) => {
|
|
6
|
+
return `name: 'Calculate Version'
|
|
7
|
+
description: 'Calculate semantic version using release-it and conventional commits'
|
|
8
|
+
author: 'Pipecraft'
|
|
9
|
+
|
|
10
|
+
inputs:
|
|
11
|
+
baseRef:
|
|
12
|
+
description: 'Base reference for version calculation'
|
|
13
|
+
required: false
|
|
14
|
+
default: 'main'
|
|
15
|
+
|
|
16
|
+
outputs:
|
|
17
|
+
version:
|
|
18
|
+
description: 'The determined version'
|
|
19
|
+
value: \${{ steps.set_version.outputs.version }}
|
|
20
|
+
|
|
21
|
+
runs:
|
|
22
|
+
using: 'composite'
|
|
23
|
+
steps:
|
|
24
|
+
- name: Checkout Code
|
|
25
|
+
uses: actions/checkout@v4
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
|
|
29
|
+
- name: Install Node.js
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: 22
|
|
33
|
+
|
|
34
|
+
- name: Configure Git
|
|
35
|
+
shell: bash
|
|
36
|
+
run: |
|
|
37
|
+
git config --global user.name "github-actions[bot]"
|
|
38
|
+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
39
|
+
|
|
40
|
+
- name: Get existing version tag
|
|
41
|
+
id: get_version_old
|
|
42
|
+
shell: bash
|
|
43
|
+
run: |
|
|
44
|
+
set -x # Enable debugging output
|
|
45
|
+
# Get the current commit hash
|
|
46
|
+
git rev-parse HEAD
|
|
47
|
+
COMMIT_HASH=$(git rev-parse HEAD)
|
|
48
|
+
echo "Current commit hash: $COMMIT_HASH"
|
|
49
|
+
|
|
50
|
+
# Check for tags on the current commit
|
|
51
|
+
TAG=$(git tag --points-at $COMMIT_HASH | grep -E '^v[0-9]+\\.[0-9]+\\.[0-9]+\\$' || true)
|
|
52
|
+
echo "Tags found: $TAG"
|
|
53
|
+
|
|
54
|
+
if [ -z "$TAG" ]; then
|
|
55
|
+
echo "No existing tag found on the current commit"
|
|
56
|
+
else
|
|
57
|
+
echo "Found existing tag: $TAG"
|
|
58
|
+
echo "version=$TAG" >> $GITHUB_OUTPUT
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
- name: Set up minimal package.json
|
|
62
|
+
shell: bash
|
|
63
|
+
run: |
|
|
64
|
+
echo '{
|
|
65
|
+
"name": "temporary-lib",
|
|
66
|
+
"version": "0.0.0-release-it"
|
|
67
|
+
}' > package.json
|
|
68
|
+
|
|
69
|
+
- name: Install dependencies
|
|
70
|
+
shell: bash
|
|
71
|
+
run: npm install @release-it/conventional-changelog conventional-changelog-angular
|
|
72
|
+
|
|
73
|
+
- name: Get version
|
|
74
|
+
if: steps.get_version_old.outputs.version == ''
|
|
75
|
+
id: get_version_new
|
|
76
|
+
shell: bash
|
|
77
|
+
run: |
|
|
78
|
+
# Get version and filter out warnings
|
|
79
|
+
RAW_OUTPUT=$(npx release-it --ci --release-version 2>&1 || echo "")
|
|
80
|
+
# Extract just the version number (last line that looks like a version)
|
|
81
|
+
VERSION=$(echo "$RAW_OUTPUT" | grep -E '^[0-9]+\\.[0-9]+\\.[0-9]+' | tail -1 || true)
|
|
82
|
+
|
|
83
|
+
if [[ "$RAW_OUTPUT" == *"No new version to release"* || -z "$VERSION" ]]; then
|
|
84
|
+
echo "No new version to release"
|
|
85
|
+
echo "VERSION=" >> $GITHUB_ENV
|
|
86
|
+
echo "version=" >> $GITHUB_OUTPUT
|
|
87
|
+
else
|
|
88
|
+
echo "New version to release: $VERSION"
|
|
89
|
+
echo "VERSION=v$VERSION" >> $GITHUB_ENV
|
|
90
|
+
echo "version=v$VERSION" >> $GITHUB_OUTPUT
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
- name: Set version output
|
|
94
|
+
id: set_version
|
|
95
|
+
shell: bash
|
|
96
|
+
run: |
|
|
97
|
+
if [ -n "\${{ steps.get_version_old.outputs.version }}" ]; then
|
|
98
|
+
echo "Using old version: \${{ steps.get_version_old.outputs.version }}"
|
|
99
|
+
echo "version=\${{ steps.get_version_old.outputs.version }}" >> $GITHUB_OUTPUT
|
|
100
|
+
elif [ -n "\${{ steps.get_version_new.outputs.version }}" ]; then
|
|
101
|
+
echo "Using new version: \${{ steps.get_version_new.outputs.version }}"
|
|
102
|
+
echo "version=\${{ steps.get_version_new.outputs.version }}" >> $GITHUB_OUTPUT
|
|
103
|
+
else
|
|
104
|
+
echo "No version determined"
|
|
105
|
+
echo "version=" >> $GITHUB_OUTPUT
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
- name: Output version
|
|
109
|
+
shell: bash
|
|
110
|
+
run: |
|
|
111
|
+
echo "Version determined: \${{ steps.set_version.outputs.version }}"`
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const generate = (ctx: PinionContext) =>
|
|
115
|
+
Promise.resolve(ctx)
|
|
116
|
+
.then((ctx) => {
|
|
117
|
+
// Check if file exists to determine merge status
|
|
118
|
+
const filePath = '.github/actions/calculate-version/action.yml'
|
|
119
|
+
const exists = fs.existsSync(filePath)
|
|
120
|
+
const status = exists ? '🔄 Merged with existing' : '📝 Created new'
|
|
121
|
+
console.log(`${status} ${filePath}`)
|
|
122
|
+
return ctx
|
|
123
|
+
})
|
|
124
|
+
.then(renderTemplate(versionActionTemplate, toFile('.github/actions/calculate-version/action.yml')))
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { PinionContext, toFile, renderTemplate } from '@featherscloud/pinion'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import dedent from 'dedent'
|
|
4
|
+
|
|
5
|
+
// Template for the Create PR GitHub Action
|
|
6
|
+
const createprActionTemplate = (ctx: any) => {
|
|
7
|
+
return dedent`name: 'Create Pull Request'
|
|
8
|
+
description: 'Create a pull request between source and target branches'
|
|
9
|
+
author: 'Pipecraft'
|
|
10
|
+
|
|
11
|
+
inputs:
|
|
12
|
+
sourceBranch:
|
|
13
|
+
description: 'Source branch for the PR'
|
|
14
|
+
required: true
|
|
15
|
+
targetBranch:
|
|
16
|
+
description: 'Target branch for the PR'
|
|
17
|
+
required: true
|
|
18
|
+
title:
|
|
19
|
+
description: 'Title for the PR'
|
|
20
|
+
required: true
|
|
21
|
+
body:
|
|
22
|
+
description: 'Body/description for the PR'
|
|
23
|
+
required: false
|
|
24
|
+
labels:
|
|
25
|
+
description: 'Comma-separated list of labels'
|
|
26
|
+
required: false
|
|
27
|
+
token:
|
|
28
|
+
description: 'GitHub token for authentication'
|
|
29
|
+
required: false
|
|
30
|
+
default: \${{ github.token }}
|
|
31
|
+
|
|
32
|
+
outputs:
|
|
33
|
+
prNumber:
|
|
34
|
+
description: 'The created PR number'
|
|
35
|
+
value: \${{ steps.create-pr.outputs.prNumber }}
|
|
36
|
+
prUrl:
|
|
37
|
+
description: 'The created PR URL'
|
|
38
|
+
value: \${{ steps.create-pr.outputs.prUrl }}
|
|
39
|
+
|
|
40
|
+
runs:
|
|
41
|
+
using: 'composite'
|
|
42
|
+
steps:
|
|
43
|
+
- name: Checkout Code
|
|
44
|
+
uses: actions/checkout@v4
|
|
45
|
+
with:
|
|
46
|
+
fetch-depth: 0
|
|
47
|
+
token: \${{ inputs.token }}
|
|
48
|
+
|
|
49
|
+
- name: Check if PR Already Exists
|
|
50
|
+
id: check-existing-pr
|
|
51
|
+
shell: bash
|
|
52
|
+
run: |
|
|
53
|
+
SOURCE="\${{ inputs.sourceBranch }}"
|
|
54
|
+
TARGET="\${{ inputs.targetBranch }}"
|
|
55
|
+
|
|
56
|
+
# Check if PR already exists
|
|
57
|
+
EXISTING_PR=$(gh pr list --head "\$SOURCE" --base "\$TARGET" --json number --jq '.[0].number' 2>/dev/null || echo "")
|
|
58
|
+
|
|
59
|
+
if [ -n "\$EXISTING_PR" ]; then
|
|
60
|
+
echo "exists=true" >> \$GITHUB_OUTPUT
|
|
61
|
+
echo "pr_number=\$EXISTING_PR" >> \$GITHUB_OUTPUT
|
|
62
|
+
echo "⚠️ PR already exists: #\$EXISTING_PR"
|
|
63
|
+
else
|
|
64
|
+
echo "exists=false" >> \$GITHUB_OUTPUT
|
|
65
|
+
echo "✅ No existing PR found"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
- name: Create Pull Request
|
|
69
|
+
if: steps.check-existing-pr.outputs.exists == 'false'
|
|
70
|
+
id: create-pr
|
|
71
|
+
shell: bash
|
|
72
|
+
run: |
|
|
73
|
+
SOURCE="\${{ inputs.sourceBranch }}"
|
|
74
|
+
TARGET="\${{ inputs.targetBranch }}"
|
|
75
|
+
TITLE="\${{ inputs.title }}"
|
|
76
|
+
BODY="\${{ inputs.body }}"
|
|
77
|
+
LABELS="\${{ inputs.labels }}"
|
|
78
|
+
|
|
79
|
+
# Prepare labels array
|
|
80
|
+
LABEL_ARGS=""
|
|
81
|
+
if [ -n "\$LABELS" ]; then
|
|
82
|
+
IFS=',' read -ra LABEL_ARRAY <<< "\$LABELS"
|
|
83
|
+
for label in "\${LABEL_ARRAY[@]}"; do
|
|
84
|
+
LABEL_ARGS="\$LABEL_ARGS --label \"\${label// /}\""
|
|
85
|
+
done
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# Create the PR
|
|
89
|
+
PR_OUTPUT=$(gh pr create \\
|
|
90
|
+
--title "\$TITLE" \\
|
|
91
|
+
--body "\$BODY" \\
|
|
92
|
+
--head "\$SOURCE" \\
|
|
93
|
+
--base "\$TARGET" \\
|
|
94
|
+
\$LABEL_ARGS \\
|
|
95
|
+
--json number,url --jq '.number,.url' 2>&1)
|
|
96
|
+
|
|
97
|
+
if echo "\$PR_OUTPUT" | grep -q '"number":'; then
|
|
98
|
+
PR_NUMBER=$(echo "\$PR_OUTPUT" | jq -r '.number')
|
|
99
|
+
PR_URL=$(echo "\$PR_OUTPUT" | jq -r '.url')
|
|
100
|
+
echo "prNumber=\$PR_NUMBER" >> \$GITHUB_OUTPUT
|
|
101
|
+
echo "prUrl=\$PR_URL" >> \$GITHUB_OUTPUT
|
|
102
|
+
echo "✅ Created PR #\$PR_NUMBER"
|
|
103
|
+
echo "🔗 URL: \$PR_URL"
|
|
104
|
+
else
|
|
105
|
+
echo "❌ Failed to create PR"
|
|
106
|
+
echo "Error output:"
|
|
107
|
+
echo "\$PR_OUTPUT"
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
- name: Use Existing PR
|
|
112
|
+
if: steps.check-existing-pr.outputs.exists == 'true'
|
|
113
|
+
id: use-existing-pr
|
|
114
|
+
shell: bash
|
|
115
|
+
run: |
|
|
116
|
+
PR_NUMBER="\${{ steps.check-existing-pr.outputs.pr_number }}"
|
|
117
|
+
PR_URL="https://github.com/\${{ github.repository }}/pull/\$PR_NUMBER"
|
|
118
|
+
echo "prNumber=\$PR_NUMBER" >> \$GITHUB_OUTPUT
|
|
119
|
+
echo "prUrl=\$PR_URL" >> \$GITHUB_OUTPUT
|
|
120
|
+
echo "✅ Using existing PR #\$PR_NUMBER"
|
|
121
|
+
echo "🔗 URL: \$PR_URL"
|
|
122
|
+
|
|
123
|
+
- name: Action Summary
|
|
124
|
+
shell: bash
|
|
125
|
+
run: |
|
|
126
|
+
if [ "\${{ steps.create-pr.outputs.prNumber }}" != "" ]; then
|
|
127
|
+
echo "✅ Successfully created PR #\${{ steps.create-pr.outputs.prNumber }}"
|
|
128
|
+
echo "🔗 URL: \${{ steps.create-pr.outputs.prUrl }}"
|
|
129
|
+
elif [ "\${{ steps.use-existing-pr.outputs.prNumber }}" != "" ]; then
|
|
130
|
+
echo "ℹ️ Using existing PR #\${{ steps.use-existing-pr.outputs.prNumber }}"
|
|
131
|
+
echo "🔗 URL: \${{ steps.use-existing-pr.outputs.prUrl }}"
|
|
132
|
+
else
|
|
133
|
+
echo "❌ No PR created or found"
|
|
134
|
+
fi`
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const generate = (ctx: PinionContext) =>
|
|
138
|
+
Promise.resolve(ctx)
|
|
139
|
+
.then((ctx) => {
|
|
140
|
+
// Check if file exists to determine merge status
|
|
141
|
+
const filePath = '.github/actions/create-pr/action.yml'
|
|
142
|
+
const exists = fs.existsSync(filePath)
|
|
143
|
+
const status = exists ? '🔄 Merged with existing' : '📝 Created new'
|
|
144
|
+
console.log(`${status} ${filePath}`)
|
|
145
|
+
return ctx
|
|
146
|
+
})
|
|
147
|
+
.then(renderTemplate(createprActionTemplate, toFile('.github/actions/create-pr/action.yml')))
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { PinionContext, toFile, renderTemplate } from '@featherscloud/pinion'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import dedent from 'dedent'
|
|
4
|
+
// Template for the Tag GitHub Action
|
|
5
|
+
const tagActionTemplate = (ctx: any) => {
|
|
6
|
+
return dedent`name: 'Tag Version'
|
|
7
|
+
description: 'Create and push a Git tag for a given version'
|
|
8
|
+
author: 'Pipecraft'
|
|
9
|
+
|
|
10
|
+
inputs:
|
|
11
|
+
version:
|
|
12
|
+
description: 'Version to tag'
|
|
13
|
+
required: true
|
|
14
|
+
tag_prefix:
|
|
15
|
+
description: 'Prefix for the tag (e.g., v)'
|
|
16
|
+
required: false
|
|
17
|
+
default: 'v'
|
|
18
|
+
push:
|
|
19
|
+
description: 'Whether to push the tag to remote'
|
|
20
|
+
required: false
|
|
21
|
+
default: 'true'
|
|
22
|
+
|
|
23
|
+
outputs:
|
|
24
|
+
tag_name:
|
|
25
|
+
description: 'The created tag name'
|
|
26
|
+
value: \${{ steps.tag.outputs.tag_name }}
|
|
27
|
+
success:
|
|
28
|
+
description: 'Whether the tag was created successfully'
|
|
29
|
+
value: \${{ steps.tag.outputs.success }}
|
|
30
|
+
|
|
31
|
+
runs:
|
|
32
|
+
using: 'composite'
|
|
33
|
+
steps:
|
|
34
|
+
- name: Validate Inputs
|
|
35
|
+
id: validate
|
|
36
|
+
shell: bash
|
|
37
|
+
run: |
|
|
38
|
+
if [ -z "\${{ inputs.version }}" ]; then
|
|
39
|
+
echo "❌ Version is required"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Strip v prefix if present and validate version format
|
|
44
|
+
VERSION="\${{ inputs.version }}"
|
|
45
|
+
VERSION="\${VERSION#v}" # Remove v prefix
|
|
46
|
+
|
|
47
|
+
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
48
|
+
echo "❌ Version must be in format [v]x.y.z (e.g., 1.0.0 or v1.0.0)"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
echo "✅ Version format is valid: $VERSION"
|
|
53
|
+
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
54
|
+
|
|
55
|
+
- name: Configure Git
|
|
56
|
+
shell: bash
|
|
57
|
+
run: |
|
|
58
|
+
git config user.name "github-actions[bot]"
|
|
59
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
60
|
+
|
|
61
|
+
- name: Create Tag
|
|
62
|
+
id: tag
|
|
63
|
+
shell: bash
|
|
64
|
+
run: |
|
|
65
|
+
VERSION="\${{ steps.validate.outputs.version }}"
|
|
66
|
+
PREFIX="\${{ inputs.tag_prefix }}"
|
|
67
|
+
TAG_NAME="\${PREFIX}\${VERSION}"
|
|
68
|
+
|
|
69
|
+
# Check if tag already exists
|
|
70
|
+
if git tag -l | grep -q "^\${TAG_NAME}$"; then
|
|
71
|
+
echo "⚠️ Tag \${TAG_NAME} already exists"
|
|
72
|
+
echo "tag_name=\${TAG_NAME}" >> \$GITHUB_OUTPUT
|
|
73
|
+
echo "success=false" >> \$GITHUB_OUTPUT
|
|
74
|
+
exit 0
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Create the tag
|
|
78
|
+
git tag -a "\${TAG_NAME}" -m "Release \${TAG_NAME}"
|
|
79
|
+
echo "✅ Created tag: \${TAG_NAME}"
|
|
80
|
+
|
|
81
|
+
echo "tag_name=\${TAG_NAME}" >> \$GITHUB_OUTPUT
|
|
82
|
+
echo "success=true" >> \$GITHUB_OUTPUT
|
|
83
|
+
|
|
84
|
+
- name: Push Tag
|
|
85
|
+
if: steps.tag.outputs.success == 'true' && inputs.push == 'true'
|
|
86
|
+
shell: bash
|
|
87
|
+
run: |
|
|
88
|
+
TAG_NAME="\${{ steps.tag.outputs.tag_name }}"
|
|
89
|
+
git push origin "\${TAG_NAME}"
|
|
90
|
+
echo "✅ Pushed tag \${TAG_NAME} to remote"
|
|
91
|
+
|
|
92
|
+
- name: Action Summary
|
|
93
|
+
shell: bash
|
|
94
|
+
run: |
|
|
95
|
+
if [ "\${{ steps.tag.outputs.success }}" == "true" ]; then
|
|
96
|
+
echo "✅ Successfully created and pushed tag: \${{ steps.tag.outputs.tag_name }}"
|
|
97
|
+
else
|
|
98
|
+
echo "❌ Failed to create tag: \${{ steps.tag.outputs.tag_name }}"
|
|
99
|
+
fi`
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const generate = (ctx: PinionContext) =>
|
|
103
|
+
Promise.resolve(ctx)
|
|
104
|
+
.then((ctx) => {
|
|
105
|
+
// Check if file exists to determine merge status
|
|
106
|
+
const filePath = '.github/actions/create-tag/action.yml'
|
|
107
|
+
const exists = fs.existsSync(filePath)
|
|
108
|
+
const status = exists ? '🔄 Merged with existing' : '📝 Created new'
|
|
109
|
+
console.log(`${status} ${filePath}`)
|
|
110
|
+
return ctx
|
|
111
|
+
})
|
|
112
|
+
.then(renderTemplate(tagActionTemplate, toFile('.github/actions/create-tag/action.yml')))
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { PinionContext, toFile, renderTemplate } from '@featherscloud/pinion'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import dedent from 'dedent'
|
|
4
|
+
import { DomainConfig } from '../../types/index.js'
|
|
5
|
+
|
|
6
|
+
// Template for the Changes Detection GitHub Action
|
|
7
|
+
const changesActionTemplate = (ctx: any) => {
|
|
8
|
+
const domainOutputs = Object.entries(ctx.domains).map((entry) => {
|
|
9
|
+
const [domainName, domainConfig] = entry as [string, DomainConfig];
|
|
10
|
+
return ` ${domainName}:
|
|
11
|
+
description: 'Whether ${domainName} domain has changes'
|
|
12
|
+
value: \${{ steps.merge.outputs.${domainName} }}`;
|
|
13
|
+
}).join('\n');
|
|
14
|
+
|
|
15
|
+
const domainFilters = Object.entries(ctx.domains).map((entry) => {
|
|
16
|
+
const [domainName, domainConfig] = entry as [string, DomainConfig];
|
|
17
|
+
return ` ${domainName}:\n - '${domainConfig.paths.join("'\\n - '")}'`;
|
|
18
|
+
}).join('\n');
|
|
19
|
+
|
|
20
|
+
const domainEchoes = Object.entries(ctx.domains).map((entry) => {
|
|
21
|
+
const [domainName, domainConfig] = entry as [string, DomainConfig];
|
|
22
|
+
return ` echo "${domainName}=\${{ contains(steps.filter.outputs.changes, '${domainName}') }}" >> $GITHUB_OUTPUT`
|
|
23
|
+
}).join('\n');
|
|
24
|
+
|
|
25
|
+
const domainResults = Object.entries(ctx.domains).map((entry) => {
|
|
26
|
+
const [domainName, domainConfig] = entry as [string, DomainConfig];
|
|
27
|
+
return ` echo " ${domainName}: \${{ contains(steps.filter.outputs.changes, '${domainName}') }}"`
|
|
28
|
+
}).join('\n');
|
|
29
|
+
|
|
30
|
+
return `name: 'Detect Changes'
|
|
31
|
+
description: 'Detect changes in different application domains based on file paths'
|
|
32
|
+
author: 'Pipecraft'
|
|
33
|
+
|
|
34
|
+
inputs:
|
|
35
|
+
baseRef:
|
|
36
|
+
description: 'Base reference to compare against'
|
|
37
|
+
required: false
|
|
38
|
+
default: 'main'
|
|
39
|
+
|
|
40
|
+
outputs:
|
|
41
|
+
${domainOutputs}
|
|
42
|
+
|
|
43
|
+
runs:
|
|
44
|
+
using: 'composite'
|
|
45
|
+
steps:
|
|
46
|
+
- name: Checkout Code
|
|
47
|
+
uses: actions/checkout@v4
|
|
48
|
+
with:
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
|
|
51
|
+
- name: Set Base Branch
|
|
52
|
+
id: set-base
|
|
53
|
+
shell: bash
|
|
54
|
+
run: |
|
|
55
|
+
base_branch=\${{ inputs.baseRef || 'main' }}
|
|
56
|
+
echo "base_branch=$base_branch" >> $GITHUB_OUTPUT
|
|
57
|
+
echo "base_branch=$base_branch" >> $GITHUB_ENV
|
|
58
|
+
|
|
59
|
+
- name: Detect Changes
|
|
60
|
+
uses: dorny/paths-filter@v3
|
|
61
|
+
id: filter
|
|
62
|
+
with:
|
|
63
|
+
base: \${{ steps.set-base.outputs.base_branch }}
|
|
64
|
+
filters: |
|
|
65
|
+
${domainFilters}
|
|
66
|
+
|
|
67
|
+
- name: Merge filter outputs
|
|
68
|
+
id: merge
|
|
69
|
+
shell: bash
|
|
70
|
+
run: |
|
|
71
|
+
${domainEchoes}
|
|
72
|
+
|
|
73
|
+
echo "📋 Change Detection Results:"
|
|
74
|
+
${domainResults}`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const generate = (ctx: PinionContext) =>
|
|
78
|
+
Promise.resolve(ctx)
|
|
79
|
+
.then((ctx) => {
|
|
80
|
+
// Check if file exists to determine merge status
|
|
81
|
+
const filePath = '.github/actions/detect-changes/action.yml'
|
|
82
|
+
const exists = fs.existsSync(filePath)
|
|
83
|
+
const status = exists ? '🔄 Merged with existing' : '📝 Created new'
|
|
84
|
+
console.log(`${status} ${filePath}`)
|
|
85
|
+
return ctx
|
|
86
|
+
})
|
|
87
|
+
.then(renderTemplate(changesActionTemplate, toFile('.github/actions/detect-changes/action.yml')))
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { PinionContext, toFile, renderTemplate } from '@featherscloud/pinion'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import dedent from 'dedent'
|
|
4
|
+
|
|
5
|
+
// Template for the Branch Management GitHub Action
|
|
6
|
+
const branchActionTemplate = (ctx: any) => {
|
|
7
|
+
return dedent`name: 'Branch Management'
|
|
8
|
+
description: 'Manage branches (fast-forward, create, delete)'
|
|
9
|
+
author: 'Pipecraft'
|
|
10
|
+
|
|
11
|
+
inputs:
|
|
12
|
+
action:
|
|
13
|
+
description: 'Action to perform (fast-forward, create, delete)'
|
|
14
|
+
required: true
|
|
15
|
+
targetBranch:
|
|
16
|
+
description: 'Target branch for the action'
|
|
17
|
+
required: true
|
|
18
|
+
sourceBranch:
|
|
19
|
+
description: 'Source branch for the action'
|
|
20
|
+
required: false
|
|
21
|
+
branchName:
|
|
22
|
+
description: 'Name for new branch (for create action)'
|
|
23
|
+
required: false
|
|
24
|
+
|
|
25
|
+
outputs:
|
|
26
|
+
success:
|
|
27
|
+
description: 'Whether the action was successful'
|
|
28
|
+
value: \${{ steps.branch-action.outputs.success }}
|
|
29
|
+
message:
|
|
30
|
+
description: 'Result message'
|
|
31
|
+
value: \${{ steps.branch-action.outputs.message }}
|
|
32
|
+
|
|
33
|
+
runs:
|
|
34
|
+
using: 'composite'
|
|
35
|
+
steps:
|
|
36
|
+
- name: Checkout Code
|
|
37
|
+
uses: actions/checkout@v4
|
|
38
|
+
with:
|
|
39
|
+
fetch-depth: 0
|
|
40
|
+
token: \${{ inputs.token }}
|
|
41
|
+
|
|
42
|
+
- name: Validate Inputs
|
|
43
|
+
id: validate
|
|
44
|
+
shell: bash
|
|
45
|
+
run: |
|
|
46
|
+
ACTION="\${{ inputs.action }}"
|
|
47
|
+
TARGET="\${{ inputs.targetBranch }}"
|
|
48
|
+
SOURCE="\${{ inputs.sourceBranch }}"
|
|
49
|
+
BRANCH_NAME="\${{ inputs.branchName }}"
|
|
50
|
+
|
|
51
|
+
case "\$ACTION" in
|
|
52
|
+
"fast-forward")
|
|
53
|
+
if [ -z "\$SOURCE" ]; then
|
|
54
|
+
echo "❌ Source branch is required for fast-forward"
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
;;
|
|
58
|
+
"create")
|
|
59
|
+
if [ -z "\$BRANCH_NAME" ]; then
|
|
60
|
+
echo "❌ Branch name is required for create action"
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
;;
|
|
64
|
+
"delete")
|
|
65
|
+
if [ -z "\$TARGET" ]; then
|
|
66
|
+
echo "❌ Target branch is required for delete action"
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
;;
|
|
70
|
+
*)
|
|
71
|
+
echo "❌ Invalid action: \$ACTION. Must be fast-forward, create, or delete"
|
|
72
|
+
exit 1
|
|
73
|
+
;;
|
|
74
|
+
esac
|
|
75
|
+
|
|
76
|
+
echo "✅ Input validation passed"
|
|
77
|
+
|
|
78
|
+
- name: Perform Branch Action
|
|
79
|
+
id: branch-action
|
|
80
|
+
shell: bash
|
|
81
|
+
run: |
|
|
82
|
+
ACTION="\${{ inputs.action }}"
|
|
83
|
+
TARGET="\${{ inputs.targetBranch }}"
|
|
84
|
+
SOURCE="\${{ inputs.sourceBranch }}"
|
|
85
|
+
BRANCH_NAME="\${{ inputs.branchName }}"
|
|
86
|
+
|
|
87
|
+
case "\$ACTION" in
|
|
88
|
+
"fast-forward")
|
|
89
|
+
echo "🔄 Fast-forwarding \$TARGET to \$SOURCE"
|
|
90
|
+
git checkout "\$TARGET"
|
|
91
|
+
git merge --ff-only "\$SOURCE"
|
|
92
|
+
git push origin "\$TARGET"
|
|
93
|
+
echo "success=true" >> \$GITHUB_OUTPUT
|
|
94
|
+
echo "message=Successfully fast-forwarded \$TARGET to \$SOURCE" >> \$GITHUB_OUTPUT
|
|
95
|
+
;;
|
|
96
|
+
"create")
|
|
97
|
+
echo "🌱 Creating branch \$BRANCH_NAME from \$TARGET"
|
|
98
|
+
git checkout "\$TARGET"
|
|
99
|
+
git checkout -b "\$BRANCH_NAME"
|
|
100
|
+
git push -u origin "\$BRANCH_NAME"
|
|
101
|
+
echo "success=true" >> \$GITHUB_OUTPUT
|
|
102
|
+
echo "message=Successfully created branch \$BRANCH_NAME" >> \$GITHUB_OUTPUT
|
|
103
|
+
;;
|
|
104
|
+
"delete")
|
|
105
|
+
echo "🗑️ Deleting branch \$TARGET"
|
|
106
|
+
git push origin --delete "\$TARGET"
|
|
107
|
+
echo "success=true" >> \$GITHUB_OUTPUT
|
|
108
|
+
echo "message=Successfully deleted branch \$TARGET" >> \$GITHUB_OUTPUT
|
|
109
|
+
;;
|
|
110
|
+
esac
|
|
111
|
+
|
|
112
|
+
- name: Action Summary
|
|
113
|
+
shell: bash
|
|
114
|
+
run: |
|
|
115
|
+
if [ "\${{ steps.branch-action.outputs.success }}" == "true" ]; then
|
|
116
|
+
echo "✅ \${{ steps.branch-action.outputs.message }}"
|
|
117
|
+
else
|
|
118
|
+
echo "❌ \${{ steps.branch-action.outputs.message }}"
|
|
119
|
+
fi`
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const generate = (ctx: PinionContext) =>
|
|
123
|
+
Promise.resolve(ctx)
|
|
124
|
+
.then((ctx) => {
|
|
125
|
+
// Check if file exists to determine merge status
|
|
126
|
+
const filePath = '.github/actions/manage-branch/action.yml'
|
|
127
|
+
const exists = fs.existsSync(filePath)
|
|
128
|
+
const status = exists ? '🔄 Merged with existing' : '📝 Created new'
|
|
129
|
+
console.log(`${status} ${filePath}`)
|
|
130
|
+
return ctx
|
|
131
|
+
})
|
|
132
|
+
.then(renderTemplate(branchActionTemplate, toFile('.github/actions/manage-branch/action.yml')))
|