@hybridlabor-api/aos 4.7.2 → 4.9.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/.agents/agents.md +1 -1
- package/.agents/nodes.json +1 -1
- package/.agents/vendor-manifest.json +23 -1
- package/.claude/agents/godmode-media-eventtech.md +1 -1
- package/.claude/hooks/conventional-commits.mjs +125 -0
- package/.claude/hooks/env-file-protection.mjs +105 -0
- package/.claude/hooks/go-gate.mjs +101 -81
- package/.claude/settings.json +13 -0
- package/.opencode/agents/godmode-media-eventtech.md +1 -1
- package/.opencode/plugins/bdb-aos.js +31 -4
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/THIRD_PARTY_NOTICES.md +88 -0
- package/docs/skills_table.md +1 -1
- package/installer.js +309 -101
- package/package.json +6 -2
- package/packages/aos-cli/README.md +80 -0
- package/packages/aos-cli/bin/aos-cli.mjs +134 -0
- package/packages/aos-cli/core-skills.json +12 -0
- package/packages/aos-cli/extensions/aos.ts +321 -0
- package/packages/aos-cli/package-lock.json +1923 -0
- package/packages/aos-cli/package.json +29 -0
- package/packages/aos-cli/scripts/check-theme.mjs +63 -0
- package/packages/aos-cli/themes/aos.json +97 -0
- package/scripts/build-plugin-manifest.mjs +131 -0
- package/scripts/validate-skills.mjs +81 -6
- package/skills/basic/ao-orchestrator/SKILL.md +116 -0
- package/skills/global_config/agenttrail/SKILL.md +6 -1
- package/skills/global_config/ask-tim/SKILL.md +4 -4
- package/skills/global_config/bash-script-generator/SKILL.md +201 -0
- package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
- package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
- package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
- package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
- package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
- package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
- package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
- package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
- package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
- package/skills/global_config/bash-script-validator/SKILL.md +249 -0
- package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
- package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
- package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
- package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
- package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
- package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
- package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
- package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
- package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
- package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
- package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
- package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
- package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
- package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
- package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
- package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
- package/skills/global_config/ci-pipeline/SKILL.md +135 -0
- package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
- package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
- package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
- package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
- package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
- package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
- package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
- package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
- package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
- package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
- package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
- package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
- package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
- package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
- package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
- package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
- package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
- package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
- package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
- package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
- package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
- package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
- package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
- package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
- package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
- package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
- package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
- package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
- package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
- package/skills/global_config/github-actions-generator/SKILL.md +353 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
- package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
- package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
- package/skills/global_config/github-actions-generator/examples/README.md +147 -0
- package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
- package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
- package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
- package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
- package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
- package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
- package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
- package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
- package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
- package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
- package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
- package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
- package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
- package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
- package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
- package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
- package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
- package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
- package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
- package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
- package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
- package/skills/global_config/github-actions-templates/SKILL.md +7 -0
- package/skills/global_config/github-actions-validator/SKILL.md +576 -0
- package/skills/global_config/github-actions-validator/examples/README.md +88 -0
- package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
- package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
- package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
- package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
- package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
- package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
- package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
- package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
- package/skills/global_config/github-actions-validator/references/runners.md +317 -0
- package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
- package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
- package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
- package/skills/global_config/makefile-generator/SKILL.md +614 -0
- package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
- package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
- package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
- package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
- package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
- package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
- package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
- package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
- package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
- package/skills/global_config/makefile-validator/SKILL.md +244 -0
- package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
- package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
- package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
- package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
- package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
- package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
- package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
- package/skills/global_config/{MCP_Manage → mcp-manage}/SKILL.md +3 -3
- package/skills/global_config/requesting-code-review/SKILL.md +98 -0
- package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
- package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
- package/skills/global_config/verification-before-completion/SKILL.md +123 -0
- package/skills/global_config/writing-plans/SKILL.md +126 -46
- package/skills/global_config/writing-plans-legacy/SKILL.md +139 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Generate a production-ready Python Dockerfile with multi-stage build
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
# Default values
|
|
7
|
+
PYTHON_VERSION="${PYTHON_VERSION:-3.12}"
|
|
8
|
+
PORT="${PORT:-8000}"
|
|
9
|
+
OUTPUT_FILE="${OUTPUT_FILE:-Dockerfile}"
|
|
10
|
+
LEGACY_ENTRY="${APP_ENTRY:-app.py}"
|
|
11
|
+
LEGACY_ENTRY_SET="false"
|
|
12
|
+
ENTRY_CMD="${ENTRY_CMD:-}"
|
|
13
|
+
ENTRY_ARGS=()
|
|
14
|
+
|
|
15
|
+
# Usage
|
|
16
|
+
usage() {
|
|
17
|
+
cat <<EOF
|
|
18
|
+
Usage: $0 [OPTIONS]
|
|
19
|
+
|
|
20
|
+
Generate a production-ready Python Dockerfile with multi-stage build.
|
|
21
|
+
|
|
22
|
+
OPTIONS:
|
|
23
|
+
-v, --version VERSION Python version (default: 3.12)
|
|
24
|
+
-p, --port PORT Port to expose (default: 8000)
|
|
25
|
+
-o, --output FILE Output file (default: Dockerfile)
|
|
26
|
+
-e, --entry COMMAND Legacy entry syntax (simple whitespace split only)
|
|
27
|
+
--entry-cmd COMMAND Preferred command binary/executable
|
|
28
|
+
--entry-arg ARG Preferred command argument (repeatable; preserves spaces)
|
|
29
|
+
-h, --help Show this help message
|
|
30
|
+
|
|
31
|
+
EXAMPLES:
|
|
32
|
+
# Basic Python app
|
|
33
|
+
$0
|
|
34
|
+
|
|
35
|
+
# FastAPI app
|
|
36
|
+
$0 --version 3.12 --port 8000
|
|
37
|
+
|
|
38
|
+
# Django app
|
|
39
|
+
$0 --port 8080 --entry "python manage.py runserver 0.0.0.0:8080"
|
|
40
|
+
|
|
41
|
+
# Preferred structured entrypoint (preserves quoted args exactly)
|
|
42
|
+
$0 --entry-cmd python --entry-arg -m --entry-arg uvicorn --entry-arg main:app --entry-arg --log-config --entry-arg "configs/logging prod.yaml"
|
|
43
|
+
|
|
44
|
+
EOF
|
|
45
|
+
exit 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Parse arguments
|
|
49
|
+
while [[ $# -gt 0 ]]; do
|
|
50
|
+
case $1 in
|
|
51
|
+
-v|--version)
|
|
52
|
+
PYTHON_VERSION="$2"
|
|
53
|
+
shift 2
|
|
54
|
+
;;
|
|
55
|
+
-p|--port)
|
|
56
|
+
PORT="$2"
|
|
57
|
+
shift 2
|
|
58
|
+
;;
|
|
59
|
+
-o|--output)
|
|
60
|
+
OUTPUT_FILE="$2"
|
|
61
|
+
shift 2
|
|
62
|
+
;;
|
|
63
|
+
-e|--entry)
|
|
64
|
+
LEGACY_ENTRY="$2"
|
|
65
|
+
LEGACY_ENTRY_SET="true"
|
|
66
|
+
shift 2
|
|
67
|
+
;;
|
|
68
|
+
--entry-cmd)
|
|
69
|
+
ENTRY_CMD="$2"
|
|
70
|
+
shift 2
|
|
71
|
+
;;
|
|
72
|
+
--entry-arg)
|
|
73
|
+
ENTRY_ARGS+=("$2")
|
|
74
|
+
shift 2
|
|
75
|
+
;;
|
|
76
|
+
-h|--help)
|
|
77
|
+
usage
|
|
78
|
+
;;
|
|
79
|
+
*)
|
|
80
|
+
echo "Unknown option: $1"
|
|
81
|
+
usage
|
|
82
|
+
;;
|
|
83
|
+
esac
|
|
84
|
+
done
|
|
85
|
+
|
|
86
|
+
# Escape values that are inserted into JSON-form CMD arrays.
|
|
87
|
+
escape_json_string() {
|
|
88
|
+
local input="$1"
|
|
89
|
+
input="${input//\\/\\\\}"
|
|
90
|
+
input="${input//\"/\\\"}"
|
|
91
|
+
printf '%s' "$input"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Escape values that are inserted into sed replacement strings.
|
|
95
|
+
escape_sed_replacement() {
|
|
96
|
+
local input="$1"
|
|
97
|
+
input="${input//\\/\\\\}"
|
|
98
|
+
input="${input//&/\\&}"
|
|
99
|
+
input="${input//|/\\|}"
|
|
100
|
+
printf '%s' "$input"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Validate mutually exclusive entrypoint interfaces.
|
|
104
|
+
if [[ -n "$ENTRY_CMD" && "$LEGACY_ENTRY_SET" == "true" ]]; then
|
|
105
|
+
echo "ERROR: use either --entry or --entry-cmd/--entry-arg, not both." >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
if [[ -z "$ENTRY_CMD" && ${#ENTRY_ARGS[@]} -gt 0 ]]; then
|
|
110
|
+
echo "ERROR: --entry-arg requires --entry-cmd." >&2
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# Build CMD instruction.
|
|
115
|
+
# Preferred mode:
|
|
116
|
+
# --entry-cmd <cmd> --entry-arg <arg> --entry-arg <arg>
|
|
117
|
+
# Legacy mode:
|
|
118
|
+
# --entry "<simple whitespace-delimited command>"
|
|
119
|
+
# Quoted legacy entries are rejected because they cannot be parsed safely.
|
|
120
|
+
if [[ -n "$ENTRY_CMD" ]]; then
|
|
121
|
+
CMD_PARTS=("$ENTRY_CMD" "${ENTRY_ARGS[@]}")
|
|
122
|
+
else
|
|
123
|
+
if [[ "$LEGACY_ENTRY" == *"\""* || "$LEGACY_ENTRY" == *"'"* ]]; then
|
|
124
|
+
echo "ERROR: quoted --entry values are not supported. Use --entry-cmd/--entry-arg." >&2
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
if [[ "$LEGACY_ENTRY" =~ [[:space:]] ]]; then
|
|
129
|
+
read -r -a CMD_PARTS <<< "$LEGACY_ENTRY"
|
|
130
|
+
else
|
|
131
|
+
CMD_PARTS=("python" "$LEGACY_ENTRY")
|
|
132
|
+
fi
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
if [[ -z "${CMD_PARTS[0]:-}" ]]; then
|
|
136
|
+
echo "ERROR: entry command cannot be empty." >&2
|
|
137
|
+
exit 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
_json_parts=()
|
|
141
|
+
for _token in "${CMD_PARTS[@]}"; do
|
|
142
|
+
_json_parts+=("\"$(escape_json_string "$_token")\"")
|
|
143
|
+
done
|
|
144
|
+
CMD_INSTRUCTION="CMD [$(IFS=', '; echo "${_json_parts[*]}")]"
|
|
145
|
+
CMD_INSTRUCTION_SED="$(escape_sed_replacement "$CMD_INSTRUCTION")"
|
|
146
|
+
|
|
147
|
+
# Generate Dockerfile
|
|
148
|
+
cat > "$OUTPUT_FILE" <<'EOF'
|
|
149
|
+
# syntax=docker/dockerfile:1
|
|
150
|
+
|
|
151
|
+
# Build stage
|
|
152
|
+
FROM python:PYTHON_VERSION-slim AS builder
|
|
153
|
+
WORKDIR /app
|
|
154
|
+
|
|
155
|
+
# Install build dependencies
|
|
156
|
+
# hadolint ignore=DL3008
|
|
157
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
158
|
+
gcc \
|
|
159
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
160
|
+
|
|
161
|
+
# Copy dependency files
|
|
162
|
+
COPY requirements.txt .
|
|
163
|
+
|
|
164
|
+
# Install Python dependencies
|
|
165
|
+
RUN pip install --no-cache-dir --user -r requirements.txt
|
|
166
|
+
|
|
167
|
+
# Production stage
|
|
168
|
+
FROM python:PYTHON_VERSION-slim AS production
|
|
169
|
+
WORKDIR /app
|
|
170
|
+
|
|
171
|
+
# Create non-root user
|
|
172
|
+
RUN useradd -m -u 1001 app
|
|
173
|
+
|
|
174
|
+
# Copy dependencies from builder
|
|
175
|
+
COPY --from=builder /root/.local /home/app/.local
|
|
176
|
+
|
|
177
|
+
# Copy application code
|
|
178
|
+
COPY --chown=app:app . .
|
|
179
|
+
|
|
180
|
+
# Update PATH and set Python production env vars
|
|
181
|
+
ENV PATH=/home/app/.local/bin:$PATH \
|
|
182
|
+
PYTHONUNBUFFERED=1 \
|
|
183
|
+
PYTHONDONTWRITEBYTECODE=1
|
|
184
|
+
|
|
185
|
+
# Switch to non-root user
|
|
186
|
+
USER app
|
|
187
|
+
|
|
188
|
+
# Expose port
|
|
189
|
+
EXPOSE PORT_NUMBER
|
|
190
|
+
|
|
191
|
+
# Health check
|
|
192
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
193
|
+
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:PORT_NUMBER/health').read()" || exit 1
|
|
194
|
+
|
|
195
|
+
# Start application
|
|
196
|
+
CMD_INSTRUCTION_PLACEHOLDER
|
|
197
|
+
EOF
|
|
198
|
+
|
|
199
|
+
# Replace placeholders
|
|
200
|
+
sed -i.bak "s/PYTHON_VERSION/$PYTHON_VERSION/g" "$OUTPUT_FILE"
|
|
201
|
+
sed -i.bak "s/PORT_NUMBER/$PORT/g" "$OUTPUT_FILE"
|
|
202
|
+
sed -i.bak "s|CMD_INSTRUCTION_PLACEHOLDER|$CMD_INSTRUCTION_SED|g" "$OUTPUT_FILE"
|
|
203
|
+
|
|
204
|
+
# Clean up backup files
|
|
205
|
+
rm -f "${OUTPUT_FILE}.bak"
|
|
206
|
+
|
|
207
|
+
echo "✓ Generated Python Dockerfile: $OUTPUT_FILE"
|
|
208
|
+
echo " Python version: $PYTHON_VERSION"
|
|
209
|
+
echo " Port: $PORT"
|
|
210
|
+
if [[ -n "$ENTRY_CMD" ]]; then
|
|
211
|
+
ENTRY_DISPLAY="$ENTRY_CMD"
|
|
212
|
+
for _arg in "${ENTRY_ARGS[@]}"; do
|
|
213
|
+
ENTRY_DISPLAY+=" $(printf '%q' "$_arg")"
|
|
214
|
+
done
|
|
215
|
+
else
|
|
216
|
+
ENTRY_DISPLAY="$LEGACY_ENTRY"
|
|
217
|
+
fi
|
|
218
|
+
echo " Entry point: $ENTRY_DISPLAY"
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Regression tests for dockerfile-generator scripts and examples.
|
|
4
|
+
#
|
|
5
|
+
# Covers:
|
|
6
|
+
# 1. Node/Python structured entrypoint args (--entry-cmd/--entry-arg)
|
|
7
|
+
# 2. Legacy --entry behavior and quote rejection
|
|
8
|
+
# 3. Node multistage example dependency/build flow consistency
|
|
9
|
+
#
|
|
10
|
+
# Exit 0 when all assertions pass; non-zero otherwise.
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
readonly SCRIPT_DIR
|
|
17
|
+
readonly SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
18
|
+
readonly NODE_GENERATOR="$SCRIPT_DIR/generate_nodejs.sh"
|
|
19
|
+
readonly PYTHON_GENERATOR="$SCRIPT_DIR/generate_python.sh"
|
|
20
|
+
readonly NODE_EXAMPLE="$SKILL_DIR/examples/nodejs-multistage.Dockerfile"
|
|
21
|
+
|
|
22
|
+
PASS=0
|
|
23
|
+
FAIL=0
|
|
24
|
+
OUTPUT=""
|
|
25
|
+
EXIT_CODE=0
|
|
26
|
+
|
|
27
|
+
pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
|
28
|
+
fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
29
|
+
|
|
30
|
+
run_capture() {
|
|
31
|
+
EXIT_CODE=0
|
|
32
|
+
OUTPUT=$("$@" 2>&1) || EXIT_CODE=$?
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
assert_exit() {
|
|
36
|
+
local label="$1"
|
|
37
|
+
local expected="$2"
|
|
38
|
+
if [[ "$EXIT_CODE" -eq "$expected" ]]; then
|
|
39
|
+
pass "$label (exit $EXIT_CODE)"
|
|
40
|
+
else
|
|
41
|
+
fail "$label — expected exit $expected, got $EXIT_CODE"
|
|
42
|
+
echo "$OUTPUT" | sed 's/^/ /'
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
assert_output_contains() {
|
|
47
|
+
local label="$1"
|
|
48
|
+
local pattern="$2"
|
|
49
|
+
if echo "$OUTPUT" | grep -qE -- "$pattern"; then
|
|
50
|
+
pass "$label"
|
|
51
|
+
else
|
|
52
|
+
fail "$label — pattern not found: $pattern"
|
|
53
|
+
echo "$OUTPUT" | sed 's/^/ /'
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
assert_file_contains() {
|
|
58
|
+
local label="$1"
|
|
59
|
+
local file="$2"
|
|
60
|
+
local pattern="$3"
|
|
61
|
+
if grep -qE -- "$pattern" "$file"; then
|
|
62
|
+
pass "$label"
|
|
63
|
+
else
|
|
64
|
+
fail "$label — pattern '$pattern' not found in $file"
|
|
65
|
+
sed 's/^/ /' "$file"
|
|
66
|
+
fi
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
assert_file_not_contains() {
|
|
70
|
+
local label="$1"
|
|
71
|
+
local file="$2"
|
|
72
|
+
local pattern="$3"
|
|
73
|
+
if grep -qE -- "$pattern" "$file"; then
|
|
74
|
+
fail "$label — unexpected pattern '$pattern' found in $file"
|
|
75
|
+
grep -nE -- "$pattern" "$file" | sed 's/^/ /'
|
|
76
|
+
else
|
|
77
|
+
pass "$label"
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
TMP_DIR="$(mktemp -d)"
|
|
82
|
+
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
83
|
+
|
|
84
|
+
echo "Running dockerfile-generator regression tests..."
|
|
85
|
+
|
|
86
|
+
echo ""
|
|
87
|
+
echo "[shell syntax checks]"
|
|
88
|
+
if bash -n "$NODE_GENERATOR"; then
|
|
89
|
+
pass "node generator passes bash -n"
|
|
90
|
+
else
|
|
91
|
+
fail "node generator has syntax errors"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
if bash -n "$PYTHON_GENERATOR"; then
|
|
95
|
+
pass "python generator passes bash -n"
|
|
96
|
+
else
|
|
97
|
+
fail "python generator has syntax errors"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
echo ""
|
|
101
|
+
echo "[node generator]"
|
|
102
|
+
NODE_STRUCTURED_OUT="$TMP_DIR/node-structured.Dockerfile"
|
|
103
|
+
run_capture \
|
|
104
|
+
bash "$NODE_GENERATOR" \
|
|
105
|
+
--output "$NODE_STRUCTURED_OUT" \
|
|
106
|
+
--entry-cmd node \
|
|
107
|
+
--entry-arg server.js \
|
|
108
|
+
--entry-arg --message \
|
|
109
|
+
--entry-arg "hello world"
|
|
110
|
+
assert_exit "structured node entry generation succeeds" 0
|
|
111
|
+
assert_file_contains \
|
|
112
|
+
"structured node entry preserves spaced arg" \
|
|
113
|
+
"$NODE_STRUCTURED_OUT" \
|
|
114
|
+
'CMD \["node","server\.js","--message","hello world"\]'
|
|
115
|
+
|
|
116
|
+
NODE_LEGACY_OUT="$TMP_DIR/node-legacy.Dockerfile"
|
|
117
|
+
run_capture \
|
|
118
|
+
bash "$NODE_GENERATOR" \
|
|
119
|
+
--output "$NODE_LEGACY_OUT" \
|
|
120
|
+
--entry "npm start"
|
|
121
|
+
assert_exit "legacy node entry generation succeeds" 0
|
|
122
|
+
assert_file_contains \
|
|
123
|
+
"legacy node entry still tokenizes simple commands" \
|
|
124
|
+
"$NODE_LEGACY_OUT" \
|
|
125
|
+
'CMD \["npm","start"\]'
|
|
126
|
+
|
|
127
|
+
run_capture \
|
|
128
|
+
bash "$NODE_GENERATOR" \
|
|
129
|
+
--output "$TMP_DIR/node-legacy-quoted.Dockerfile" \
|
|
130
|
+
--entry "node server.js --message \"hello world\""
|
|
131
|
+
assert_exit "legacy quoted node entry is rejected" 1
|
|
132
|
+
assert_output_contains \
|
|
133
|
+
"legacy quoted node rejection message is clear" \
|
|
134
|
+
'ERROR: quoted --entry values are not supported\. Use --entry-cmd/--entry-arg\.'
|
|
135
|
+
|
|
136
|
+
run_capture \
|
|
137
|
+
bash "$NODE_GENERATOR" \
|
|
138
|
+
--output "$TMP_DIR/node-invalid-args.Dockerfile" \
|
|
139
|
+
--entry-arg server.js
|
|
140
|
+
assert_exit "--entry-arg without --entry-cmd fails for node" 1
|
|
141
|
+
assert_output_contains \
|
|
142
|
+
"node --entry-arg validation message is clear" \
|
|
143
|
+
'ERROR: --entry-arg requires --entry-cmd\.'
|
|
144
|
+
|
|
145
|
+
echo ""
|
|
146
|
+
echo "[python generator]"
|
|
147
|
+
PY_STRUCTURED_OUT="$TMP_DIR/python-structured.Dockerfile"
|
|
148
|
+
run_capture \
|
|
149
|
+
bash "$PYTHON_GENERATOR" \
|
|
150
|
+
--output "$PY_STRUCTURED_OUT" \
|
|
151
|
+
--entry-cmd python \
|
|
152
|
+
--entry-arg -m \
|
|
153
|
+
--entry-arg uvicorn \
|
|
154
|
+
--entry-arg main:app \
|
|
155
|
+
--entry-arg --log-config \
|
|
156
|
+
--entry-arg "configs/logging prod.yaml"
|
|
157
|
+
assert_exit "structured python entry generation succeeds" 0
|
|
158
|
+
assert_file_contains \
|
|
159
|
+
"structured python entry preserves spaced arg" \
|
|
160
|
+
"$PY_STRUCTURED_OUT" \
|
|
161
|
+
'CMD \["python","-m","uvicorn","main:app","--log-config","configs/logging prod\.yaml"\]'
|
|
162
|
+
|
|
163
|
+
PY_LEGACY_OUT="$TMP_DIR/python-legacy.Dockerfile"
|
|
164
|
+
run_capture \
|
|
165
|
+
bash "$PYTHON_GENERATOR" \
|
|
166
|
+
--output "$PY_LEGACY_OUT" \
|
|
167
|
+
--entry "python app.py"
|
|
168
|
+
assert_exit "legacy python entry generation succeeds" 0
|
|
169
|
+
assert_file_contains \
|
|
170
|
+
"legacy python entry still tokenizes simple commands" \
|
|
171
|
+
"$PY_LEGACY_OUT" \
|
|
172
|
+
'CMD \["python","app\.py"\]'
|
|
173
|
+
|
|
174
|
+
run_capture \
|
|
175
|
+
bash "$PYTHON_GENERATOR" \
|
|
176
|
+
--output "$TMP_DIR/python-legacy-quoted.Dockerfile" \
|
|
177
|
+
--entry "python app.py --message \"hello world\""
|
|
178
|
+
assert_exit "legacy quoted python entry is rejected" 1
|
|
179
|
+
assert_output_contains \
|
|
180
|
+
"legacy quoted python rejection message is clear" \
|
|
181
|
+
'ERROR: quoted --entry values are not supported\. Use --entry-cmd/--entry-arg\.'
|
|
182
|
+
|
|
183
|
+
echo ""
|
|
184
|
+
echo "[node example]"
|
|
185
|
+
assert_file_contains \
|
|
186
|
+
"node example installs full deps before build" \
|
|
187
|
+
"$NODE_EXAMPLE" \
|
|
188
|
+
'RUN npm ci &&'
|
|
189
|
+
assert_file_contains \
|
|
190
|
+
"node example prunes dev dependencies after build" \
|
|
191
|
+
"$NODE_EXAMPLE" \
|
|
192
|
+
'npm prune --omit=dev'
|
|
193
|
+
assert_file_not_contains \
|
|
194
|
+
"node example avoids mixed only=production build flow" \
|
|
195
|
+
"$NODE_EXAMPLE" \
|
|
196
|
+
'npm ci --only=production'
|
|
197
|
+
assert_file_contains \
|
|
198
|
+
"node example runs compiled output" \
|
|
199
|
+
"$NODE_EXAMPLE" \
|
|
200
|
+
'CMD \["node", "dist/index\.js"\]'
|
|
201
|
+
|
|
202
|
+
echo ""
|
|
203
|
+
echo "Passed: $PASS"
|
|
204
|
+
echo "Failed: $FAIL"
|
|
205
|
+
|
|
206
|
+
if [[ "$FAIL" -gt 0 ]]; then
|
|
207
|
+
exit 1
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
echo "All dockerfile-generator regression tests passed."
|