code-foundry 0.1.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/.editorconfig +18 -0
- package/.env.example +3 -0
- package/.gitattributes +9 -0
- package/.githooks/pre-commit +52 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/CODE_OF_CONDUCT.md +41 -0
- package/.github/CONTRIBUTING.md +194 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +56 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +38 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +29 -0
- package/.github/SECURITY.md +23 -0
- package/.github/actions/setup/action.yml +20 -0
- package/.github/dependabot.yml +42 -0
- package/.github/scripts/bootstrap.sh +13 -0
- package/.github/scripts/ci.sh +245 -0
- package/.github/scripts/codeql-languages.sh +22 -0
- package/.github/scripts/doctor.sh +103 -0
- package/.github/scripts/init-repo.sh +109 -0
- package/.github/scripts/security.sh +51 -0
- package/.github/scripts/sitecustomize.py +17 -0
- package/.github/scripts/sync-protection.sh +124 -0
- package/.github/scripts/sync-template.sh +242 -0
- package/.github/template.yml.example +5 -0
- package/.github/workflows/ci.yml +72 -0
- package/.github/workflows/codeql.yml +56 -0
- package/.github/workflows/draft-pr.yml +62 -0
- package/.github/workflows/publish.yml +25 -0
- package/.github/workflows/release-pr.yml +61 -0
- package/.github/workflows/release.yml +23 -0
- package/.github/workflows/security.yml +38 -0
- package/.github/workflows/test.yml +84 -0
- package/.gitignore +73 -0
- package/.mise.toml +8 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +154 -0
- package/LICENSE +616 -0
- package/NOTICE +7 -0
- package/README.md +94 -0
- package/package.json +42 -0
- package/ruff.toml +6 -0
- package/src/cli.mjs +134 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'EOF'
|
|
6
|
+
Usage: sync-template.sh --source PATH_OR_URL [options]
|
|
7
|
+
|
|
8
|
+
Synchronize the repository-owned baseline without replacing project-specific
|
|
9
|
+
README files, mise tool selections, or additional workflows.
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
--languages LIST auto or comma-separated: typescript,rust,python,solidity
|
|
13
|
+
--features LIST all or comma-separated standard features
|
|
14
|
+
--check Preview changes (default)
|
|
15
|
+
--apply Apply changes
|
|
16
|
+
--prune Remove disabled standard workflows
|
|
17
|
+
EOF
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
source_ref="main"
|
|
21
|
+
mode="check"
|
|
22
|
+
source=""
|
|
23
|
+
temp_dir=""
|
|
24
|
+
languages="auto"
|
|
25
|
+
features="all"
|
|
26
|
+
prune=false
|
|
27
|
+
languages_set=false
|
|
28
|
+
features_set=false
|
|
29
|
+
|
|
30
|
+
valid_languages="typescript rust python solidity"
|
|
31
|
+
valid_features="ci codeql security test draft-pr release-pr release dependabot"
|
|
32
|
+
|
|
33
|
+
contains_word() {
|
|
34
|
+
case " $1 " in *" $2 "*) return 0 ;; *) return 1 ;; esac
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
normalize_csv() {
|
|
38
|
+
printf '%s' "$1" | tr ',' ' ' | awk '{$1=$1; print}'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validate_list() {
|
|
42
|
+
local kind="$1" value="$2" valid="$3" item
|
|
43
|
+
[ "$value" = auto ] || [ "$value" = all ] || {
|
|
44
|
+
for item in $(normalize_csv "$value"); do
|
|
45
|
+
contains_word "$valid" "$item" || { echo "Unsupported $kind: $item" >&2; exit 2; }
|
|
46
|
+
done
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
workflow_enabled() {
|
|
51
|
+
local workflow="$1" list
|
|
52
|
+
[ "$features" = all ] && return 0
|
|
53
|
+
list="$(normalize_csv "$features")"
|
|
54
|
+
contains_word "$list" "$workflow"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cleanup() {
|
|
58
|
+
if [ -n "$temp_dir" ]; then rm -rf "$temp_dir"; fi
|
|
59
|
+
}
|
|
60
|
+
trap cleanup EXIT
|
|
61
|
+
|
|
62
|
+
while [ "$#" -gt 0 ]; do
|
|
63
|
+
case "$1" in
|
|
64
|
+
--source) source="${2:?missing source path or URL}"; shift 2 ;;
|
|
65
|
+
--ref) source_ref="${2:?missing ref}"; shift 2 ;;
|
|
66
|
+
--languages) languages="${2:?missing language list}"; languages_set=true; shift 2 ;;
|
|
67
|
+
--features) features="${2:?missing feature list}"; features_set=true; shift 2 ;;
|
|
68
|
+
--check) mode="check"; shift ;;
|
|
69
|
+
--apply) mode="apply"; shift ;;
|
|
70
|
+
--prune) prune=true; shift ;;
|
|
71
|
+
-h|--help) usage; exit 0 ;;
|
|
72
|
+
*) usage >&2; exit 2 ;;
|
|
73
|
+
esac
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
[ -n "$source" ] || { usage >&2; exit 2; }
|
|
77
|
+
if [ -f .github/template.yml ]; then
|
|
78
|
+
if [ "$languages_set" = false ]; then
|
|
79
|
+
configured_languages="$(awk -F': ' '/^languages:/ {print $2; exit}' .github/template.yml)"
|
|
80
|
+
[ -n "$configured_languages" ] && languages="$configured_languages"
|
|
81
|
+
fi
|
|
82
|
+
if [ "$features_set" = false ]; then
|
|
83
|
+
configured_features="$(awk -F': ' '/^features:/ {print $2; exit}' .github/template.yml)"
|
|
84
|
+
[ -n "$configured_features" ] && features="$configured_features"
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
validate_list language "$languages" "$valid_languages"
|
|
88
|
+
validate_list feature "$features" "$valid_features"
|
|
89
|
+
|
|
90
|
+
if [ -d "$source" ] && [ -f "$source/.github/scripts/sync-template.sh" ]; then
|
|
91
|
+
template_root="$source"
|
|
92
|
+
else
|
|
93
|
+
command -v git >/dev/null 2>&1 || { echo "git is required" >&2; exit 1; }
|
|
94
|
+
temp_dir="$(mktemp -d)"
|
|
95
|
+
git clone --quiet --depth 1 --branch "$source_ref" "$source" "$temp_dir/template-repo"
|
|
96
|
+
template_root="$temp_dir/template-repo"
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
files=(
|
|
100
|
+
.editorconfig
|
|
101
|
+
.gitattributes
|
|
102
|
+
.gitignore
|
|
103
|
+
.githooks/pre-commit
|
|
104
|
+
AGENTS.md
|
|
105
|
+
LICENSE
|
|
106
|
+
NOTICE
|
|
107
|
+
ruff.toml
|
|
108
|
+
.prettierrc
|
|
109
|
+
.github/CODEOWNERS
|
|
110
|
+
.github/template.yml.example
|
|
111
|
+
.github/CODE_OF_CONDUCT.md
|
|
112
|
+
.github/CONTRIBUTING.md
|
|
113
|
+
.github/PULL_REQUEST_TEMPLATE.md
|
|
114
|
+
.github/SECURITY.md
|
|
115
|
+
.github/dependabot.yml
|
|
116
|
+
.github/ISSUE_TEMPLATE/bug_report.yml
|
|
117
|
+
.github/ISSUE_TEMPLATE/config.yml
|
|
118
|
+
.github/ISSUE_TEMPLATE/feature_request.yml
|
|
119
|
+
.github/actions/setup/action.yml
|
|
120
|
+
.github/scripts/bootstrap.sh
|
|
121
|
+
.github/scripts/ci.sh
|
|
122
|
+
.github/scripts/codeql-languages.sh
|
|
123
|
+
.github/scripts/doctor.sh
|
|
124
|
+
.github/scripts/security.sh
|
|
125
|
+
.github/scripts/sitecustomize.py
|
|
126
|
+
.github/scripts/sync-template.sh
|
|
127
|
+
.github/scripts/init-repo.sh
|
|
128
|
+
.github/scripts/sync-protection.sh
|
|
129
|
+
.github/workflows/ci.yml
|
|
130
|
+
.github/workflows/codeql.yml
|
|
131
|
+
.github/workflows/draft-pr.yml
|
|
132
|
+
.github/workflows/release-pr.yml
|
|
133
|
+
.github/workflows/release.yml
|
|
134
|
+
.github/workflows/security.yml
|
|
135
|
+
.github/workflows/test.yml
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
filtered_files=()
|
|
139
|
+
for file in "${files[@]}"; do
|
|
140
|
+
case "$file" in
|
|
141
|
+
.github/dependabot.yml) workflow_enabled dependabot && filtered_files+=("$file") ;;
|
|
142
|
+
.github/workflows/ci.yml) workflow_enabled ci && filtered_files+=("$file") ;;
|
|
143
|
+
.github/workflows/codeql.yml) workflow_enabled codeql && filtered_files+=("$file") ;;
|
|
144
|
+
.github/workflows/security.yml) workflow_enabled security && filtered_files+=("$file") ;;
|
|
145
|
+
.github/workflows/test.yml) workflow_enabled test && filtered_files+=("$file") ;;
|
|
146
|
+
.github/workflows/draft-pr.yml) workflow_enabled draft-pr && filtered_files+=("$file") ;;
|
|
147
|
+
.github/workflows/release-pr.yml) workflow_enabled release-pr && filtered_files+=("$file") ;;
|
|
148
|
+
.github/workflows/release.yml) workflow_enabled release && filtered_files+=("$file") ;;
|
|
149
|
+
*) filtered_files+=("$file") ;;
|
|
150
|
+
esac
|
|
151
|
+
done
|
|
152
|
+
files=("${filtered_files[@]}")
|
|
153
|
+
|
|
154
|
+
optional_files=(.mise.toml)
|
|
155
|
+
|
|
156
|
+
# Workflows outside the standard baseline are repository-owned extensions.
|
|
157
|
+
# The sync operation never deletes or replaces them; surface them explicitly
|
|
158
|
+
# so maintainers can verify custom deployment, indexing, or security flows.
|
|
159
|
+
standard_workflow() {
|
|
160
|
+
case "$1" in
|
|
161
|
+
ci.yml|codeql.yml|draft-pr.yml|release-pr.yml|release.yml|security.yml|test.yml) return 0 ;;
|
|
162
|
+
*) return 1 ;;
|
|
163
|
+
esac
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
custom_workflows=()
|
|
167
|
+
if [ -d .github/workflows ]; then
|
|
168
|
+
while IFS= read -r workflow; do
|
|
169
|
+
workflow="${workflow#./}"
|
|
170
|
+
workflow="${workflow#.github/workflows/}"
|
|
171
|
+
standard_workflow "$workflow" || custom_workflows+=("$workflow")
|
|
172
|
+
done < <(find .github/workflows -maxdepth 1 -type f -print | sort)
|
|
173
|
+
fi
|
|
174
|
+
if [ "${#custom_workflows[@]}" -gt 0 ]; then
|
|
175
|
+
printf 'Preserving custom workflows: %s\n' "${custom_workflows[*]}"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
changed=0
|
|
179
|
+
for file in "${files[@]}"; do
|
|
180
|
+
template_file="$template_root/$file"
|
|
181
|
+
# npm renames .gitignore to .npmignore when installing a package. Treat the
|
|
182
|
+
# renamed file as the same template asset so packaged initialization works.
|
|
183
|
+
if [ "$file" = .gitignore ] && [ ! -f "$template_file" ] && [ -f "$template_root/.npmignore" ]; then
|
|
184
|
+
template_file="$template_root/.npmignore"
|
|
185
|
+
fi
|
|
186
|
+
if [ ! -f "$template_file" ]; then
|
|
187
|
+
echo "Template file missing: $file" >&2
|
|
188
|
+
exit 1
|
|
189
|
+
fi
|
|
190
|
+
if [ ! -f "$file" ] || ! cmp -s "$template_file" "$file"; then
|
|
191
|
+
changed=$((changed + 1))
|
|
192
|
+
if [ "$mode" = "check" ]; then
|
|
193
|
+
printf 'Would sync %s\n' "$file"
|
|
194
|
+
else
|
|
195
|
+
mkdir -p "$(dirname "$file")"
|
|
196
|
+
cp "$template_file" "$file"
|
|
197
|
+
case "$file" in
|
|
198
|
+
.githooks/*|.github/scripts/*) chmod +x "$file" ;;
|
|
199
|
+
esac
|
|
200
|
+
printf 'Synced %s\n' "$file"
|
|
201
|
+
fi
|
|
202
|
+
fi
|
|
203
|
+
done
|
|
204
|
+
|
|
205
|
+
for file in "${optional_files[@]}"; do
|
|
206
|
+
if [ ! -f "$file" ]; then
|
|
207
|
+
changed=$((changed + 1))
|
|
208
|
+
if [ "$mode" = "check" ]; then
|
|
209
|
+
printf 'Would initialize %s\n' "$file"
|
|
210
|
+
else
|
|
211
|
+
cp "$template_root/$file" "$file"
|
|
212
|
+
printf 'Initialized %s\n' "$file"
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
done
|
|
216
|
+
|
|
217
|
+
if [ "$mode" = "apply" ]; then
|
|
218
|
+
git config core.hooksPath .githooks
|
|
219
|
+
mkdir -p .github
|
|
220
|
+
cat > .github/template.yml <<EOF
|
|
221
|
+
version: 1
|
|
222
|
+
languages: $languages
|
|
223
|
+
features: $features
|
|
224
|
+
EOF
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
if [ "$prune" = true ]; then
|
|
228
|
+
for workflow in ci codeql security test draft-pr release-pr release; do
|
|
229
|
+
file=".github/workflows/$workflow.yml"
|
|
230
|
+
if [ -f "$file" ] && ! workflow_enabled "$workflow"; then
|
|
231
|
+
changed=$((changed + 1))
|
|
232
|
+
if [ "$mode" = "check" ]; then
|
|
233
|
+
printf 'Would remove disabled standard workflow %s\n' "$file"
|
|
234
|
+
else
|
|
235
|
+
rm "$file"
|
|
236
|
+
printf 'Removed disabled standard workflow %s\n' "$file"
|
|
237
|
+
fi
|
|
238
|
+
fi
|
|
239
|
+
done
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
printf '%s\n' "$changed baseline file(s) differ."
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, staging]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [staging]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
15
|
+
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref }}
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
format:
|
|
23
|
+
name: Format
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v7
|
|
28
|
+
- name: Setup
|
|
29
|
+
uses: ./.github/actions/setup
|
|
30
|
+
with:
|
|
31
|
+
install: true
|
|
32
|
+
- name: Format
|
|
33
|
+
run: bash .github/scripts/ci.sh format
|
|
34
|
+
|
|
35
|
+
lint:
|
|
36
|
+
name: Lint
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout
|
|
40
|
+
uses: actions/checkout@v7
|
|
41
|
+
- name: Setup
|
|
42
|
+
uses: ./.github/actions/setup
|
|
43
|
+
with:
|
|
44
|
+
install: true
|
|
45
|
+
- name: Lint
|
|
46
|
+
run: bash .github/scripts/ci.sh lint
|
|
47
|
+
|
|
48
|
+
type-check:
|
|
49
|
+
name: Type-Check
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
steps:
|
|
52
|
+
- name: Checkout
|
|
53
|
+
uses: actions/checkout@v7
|
|
54
|
+
- name: Setup
|
|
55
|
+
uses: ./.github/actions/setup
|
|
56
|
+
with:
|
|
57
|
+
install: true
|
|
58
|
+
- name: Type-Check
|
|
59
|
+
run: bash .github/scripts/ci.sh type_check
|
|
60
|
+
|
|
61
|
+
build:
|
|
62
|
+
name: Build
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- name: Checkout
|
|
66
|
+
uses: actions/checkout@v7
|
|
67
|
+
- name: Setup
|
|
68
|
+
uses: ./.github/actions/setup
|
|
69
|
+
with:
|
|
70
|
+
install: true
|
|
71
|
+
- name: Build
|
|
72
|
+
run: bash .github/scripts/ci.sh build
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, staging]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [staging]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '31 6 * * 1'
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
actions: read
|
|
14
|
+
contents: read
|
|
15
|
+
packages: read
|
|
16
|
+
security-events: write
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
detect:
|
|
24
|
+
name: Detect
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
outputs:
|
|
27
|
+
languages: ${{ steps.languages.outputs.languages }}
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout
|
|
30
|
+
uses: actions/checkout@v7
|
|
31
|
+
- id: languages
|
|
32
|
+
name: Detect languages
|
|
33
|
+
run: bash .github/scripts/codeql-languages.sh
|
|
34
|
+
|
|
35
|
+
analyze:
|
|
36
|
+
name: Analyze (${{ matrix.name }})
|
|
37
|
+
needs: detect
|
|
38
|
+
if: ${{ !github.event.repository.private }}
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
max-parallel: 4
|
|
43
|
+
matrix:
|
|
44
|
+
include: ${{ fromJSON(needs.detect.outputs.languages) }}
|
|
45
|
+
steps:
|
|
46
|
+
- name: Checkout
|
|
47
|
+
uses: actions/checkout@v7
|
|
48
|
+
- name: Initialize
|
|
49
|
+
uses: github/codeql-action/init@v4
|
|
50
|
+
with:
|
|
51
|
+
languages: ${{ matrix.language }}
|
|
52
|
+
build-mode: ${{ matrix.build-mode }}
|
|
53
|
+
- name: Analyze
|
|
54
|
+
uses: github/codeql-action/analyze@v4
|
|
55
|
+
with:
|
|
56
|
+
category: /language:${{ matrix.language }}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Draft PR
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- 'feat/*'
|
|
7
|
+
- 'fix/*'
|
|
8
|
+
- 'chore/*'
|
|
9
|
+
- 'refactor/*'
|
|
10
|
+
- 'docs/*'
|
|
11
|
+
- 'style/*'
|
|
12
|
+
- 'test/*'
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
pull-requests: write
|
|
17
|
+
|
|
18
|
+
env:
|
|
19
|
+
GH_TOKEN: ${{ github.token }}
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
create-draft-pr:
|
|
23
|
+
name: Create
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
concurrency:
|
|
26
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
27
|
+
cancel-in-progress: true
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v7
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 0
|
|
32
|
+
|
|
33
|
+
- name: Check
|
|
34
|
+
id: check-pr
|
|
35
|
+
run: |
|
|
36
|
+
BRANCH="${{ github.ref_name }}"
|
|
37
|
+
EXISTING=$(gh pr list --base staging --head "$BRANCH" --state open --json number,title 2>/dev/null | jq 'length')
|
|
38
|
+
echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
|
|
39
|
+
|
|
40
|
+
- name: Create
|
|
41
|
+
if: steps.check-pr.outputs.existing == '0'
|
|
42
|
+
run: |
|
|
43
|
+
BRANCH="${{ github.ref_name }}"
|
|
44
|
+
gh pr create \
|
|
45
|
+
--base staging \
|
|
46
|
+
--head "$BRANCH" \
|
|
47
|
+
--draft \
|
|
48
|
+
--title "[WIP] $BRANCH" \
|
|
49
|
+
--body "Draft PR created automatically by CI.
|
|
50
|
+
|
|
51
|
+
This PR is a draft and should not be merged until CI passes and a reviewer (or the Daily Review agent) marks it ready.
|
|
52
|
+
|
|
53
|
+
**CI Status:** Pending — this workflow triggered on push to \`$BRANCH\`."
|
|
54
|
+
|
|
55
|
+
- name: Mark ready
|
|
56
|
+
if: steps.check-pr.outputs.existing == '0'
|
|
57
|
+
run: |
|
|
58
|
+
BRANCH="${{ github.ref_name }}"
|
|
59
|
+
PR_NUMBER=$(gh pr list --base staging --head "$BRANCH" --state open --json number 2>/dev/null | jq '.[0].number')
|
|
60
|
+
if [ -n "$PR_NUMBER" ]; then
|
|
61
|
+
gh pr ready "$PR_NUMBER"
|
|
62
|
+
fi
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Publish Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ['v*.*.*']
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
name: Publish
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
- name: Setup Node
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: 24
|
|
23
|
+
registry-url: https://registry.npmjs.org
|
|
24
|
+
- name: Publish
|
|
25
|
+
run: npm publish --provenance --access public
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Release PR
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [staging]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
pull-requests: write
|
|
10
|
+
|
|
11
|
+
env:
|
|
12
|
+
GH_TOKEN: ${{ github.token }}
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
create-release-pr:
|
|
16
|
+
name: Create
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: true
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v7
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
|
|
26
|
+
- name: Check
|
|
27
|
+
id: check-pr
|
|
28
|
+
run: |
|
|
29
|
+
EXISTING=$(gh pr list --base main --head staging --state open --json number 2>/dev/null | jq 'length')
|
|
30
|
+
echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
|
|
31
|
+
|
|
32
|
+
- name: Create
|
|
33
|
+
if: steps.check-pr.outputs.existing == '0'
|
|
34
|
+
run: |
|
|
35
|
+
DATE=$(date +%Y-%m-%d)
|
|
36
|
+
BODY_FILE="$RUNNER_TEMP/release-pr.md"
|
|
37
|
+
COMMITS=$(git log --no-merges --pretty=format:'- %s (%h)' origin/main..HEAD)
|
|
38
|
+
if [ -z "$COMMITS" ]; then
|
|
39
|
+
COMMITS='- No commits found since main.'
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
cat > "$BODY_FILE" <<EOF
|
|
43
|
+
## Release summary
|
|
44
|
+
|
|
45
|
+
Automated release PR from \`staging\` into \`main\` created on $DATE.
|
|
46
|
+
|
|
47
|
+
### Changes since main
|
|
48
|
+
|
|
49
|
+
$COMMITS
|
|
50
|
+
|
|
51
|
+
### Validation
|
|
52
|
+
|
|
53
|
+
- CI and security checks must pass before merge.
|
|
54
|
+
- Review migrations, configuration changes, and rollback notes.
|
|
55
|
+
EOF
|
|
56
|
+
|
|
57
|
+
gh pr create \
|
|
58
|
+
--base main \
|
|
59
|
+
--head staging \
|
|
60
|
+
--title "Release: staging -> main ($DATE)" \
|
|
61
|
+
--body-file "$BODY_FILE"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ['v*.*.*']
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
release:
|
|
13
|
+
name: Publish
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- name: Create GitHub release
|
|
21
|
+
env:
|
|
22
|
+
GH_TOKEN: ${{ github.token }}
|
|
23
|
+
run: gh release create "${GITHUB_REF_NAME}" --generate-notes --verify-tag
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Security
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, staging]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [staging]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
dependency-audit:
|
|
19
|
+
name: Dependency Audit
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@v7
|
|
24
|
+
- name: Setup
|
|
25
|
+
uses: ./.github/actions/setup
|
|
26
|
+
- name: Audit dependencies
|
|
27
|
+
run: bash .github/scripts/security.sh
|
|
28
|
+
|
|
29
|
+
dependency-review:
|
|
30
|
+
name: Dependency Review
|
|
31
|
+
if: ${{ github.event_name == 'pull_request' && !github.event.repository.private }}
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- name: Review
|
|
35
|
+
uses: actions/dependency-review-action@v5
|
|
36
|
+
with:
|
|
37
|
+
fail-on-severity: high
|
|
38
|
+
license-check: true
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, staging]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [staging]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
|
15
|
+
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.ref }}
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
unit:
|
|
23
|
+
name: Unit
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v7
|
|
28
|
+
- name: Setup
|
|
29
|
+
uses: ./.github/actions/setup
|
|
30
|
+
with:
|
|
31
|
+
install: true
|
|
32
|
+
- name: Unit
|
|
33
|
+
run: bash .github/scripts/ci.sh unit
|
|
34
|
+
- name: Upload coverage
|
|
35
|
+
if: always()
|
|
36
|
+
uses: actions/upload-artifact@v7
|
|
37
|
+
with:
|
|
38
|
+
name: coverage-unit-${{ github.run_id }}
|
|
39
|
+
path: |
|
|
40
|
+
coverage/**
|
|
41
|
+
htmlcov/**
|
|
42
|
+
.coverage*
|
|
43
|
+
target/llvm-cov/**
|
|
44
|
+
if-no-files-found: ignore
|
|
45
|
+
retention-days: 14
|
|
46
|
+
|
|
47
|
+
integration:
|
|
48
|
+
name: Integration
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
steps:
|
|
51
|
+
- name: Checkout
|
|
52
|
+
uses: actions/checkout@v7
|
|
53
|
+
- name: Setup
|
|
54
|
+
uses: ./.github/actions/setup
|
|
55
|
+
with:
|
|
56
|
+
install: true
|
|
57
|
+
- name: Integration
|
|
58
|
+
run: bash .github/scripts/ci.sh integration
|
|
59
|
+
|
|
60
|
+
e2e:
|
|
61
|
+
name: E2E
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
steps:
|
|
64
|
+
- name: Checkout
|
|
65
|
+
uses: actions/checkout@v7
|
|
66
|
+
- name: Setup
|
|
67
|
+
uses: ./.github/actions/setup
|
|
68
|
+
with:
|
|
69
|
+
install: true
|
|
70
|
+
- name: E2E
|
|
71
|
+
run: bash .github/scripts/ci.sh e2e
|
|
72
|
+
|
|
73
|
+
smoke:
|
|
74
|
+
name: Smoke
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
steps:
|
|
77
|
+
- name: Checkout
|
|
78
|
+
uses: actions/checkout@v7
|
|
79
|
+
- name: Setup
|
|
80
|
+
uses: ./.github/actions/setup
|
|
81
|
+
with:
|
|
82
|
+
install: true
|
|
83
|
+
- name: Smoke
|
|
84
|
+
run: bash .github/scripts/ci.sh smoke
|