feat(python): detect python projects with start.py or bot.py (#416)

* feat(python): detect python projects with start.py or bot.py

Refactor Detect() to use getMainPythonFile() instead of duplicating
the sentinel file check. Add start.py to the list of recognized
Python entry files.

Add test case and example for bot.py-only detection.

Fixes PRO-4625

* update
This commit is contained in:
Jake Runzer
2026-01-07 16:24:00 -05:00
committed by GitHub
parent 4b1321b0f7
commit a1a8a4ac0c
5 changed files with 117 additions and 2 deletions
@@ -0,0 +1,104 @@
{
"deploy": {
"base": {
"image": "ghcr.io/railwayapp/railpack-runtime:latest"
},
"inputs": [
{
"include": [
"/mise/shims",
"/mise/installs",
"/usr/local/bin/mise",
"/etc/mise/config.toml",
"/root/.local/state/mise"
],
"step": "packages:mise"
},
{
"step": "build"
},
{
"exclude": [
".venv"
],
"include": [
"."
],
"step": "build"
}
],
"startCommand": "python bot.py",
"variables": {
"PIP_DEFAULT_TIMEOUT": "100",
"PIP_DISABLE_PIP_VERSION_CHECK": "1",
"PYTHONDONTWRITEBYTECODE": "1",
"PYTHONFAULTHANDLER": "1",
"PYTHONHASHSEED": "random",
"PYTHONUNBUFFERED": "1"
}
},
"steps": [
{
"assets": {
"mise.toml": "[mise.toml]"
},
"commands": [
{
"path": "/mise/shims"
},
{
"customName": "create mise config",
"name": "mise.toml",
"path": "/etc/mise/config.toml"
},
{
"cmd": "mise install",
"customName": "install mise packages: python"
}
],
"inputs": [
{
"image": "ghcr.io/railwayapp/railpack-builder:latest"
}
],
"name": "packages:mise",
"variables": {
"MISE_CACHE_DIR": "/mise/cache",
"MISE_CONFIG_DIR": "/mise",
"MISE_DATA_DIR": "/mise",
"MISE_IDIOMATIC_VERSION_FILE_ENABLE_TOOLS": "python,node,ruby,elixir,go,java,yarn",
"MISE_INSTALLS_DIR": "/mise/installs",
"MISE_NODE_VERIFY": "false",
"MISE_PARANOID": "1",
"MISE_PYTHON_COMPILE": "false",
"MISE_SHIMS_DIR": "/mise/shims",
"MISE_TRUSTED_CONFIG_PATHS": "/app"
}
},
{
"inputs": [
{
"step": "packages:mise"
}
],
"name": "install"
},
{
"inputs": [
{
"step": "install"
},
{
"include": [
"."
],
"local": true
}
],
"name": "build",
"secrets": [
"*"
]
}
]
}
+2 -2
View File
@@ -31,7 +31,7 @@ func (p *PythonProvider) Initialize(ctx *generate.GenerateContext) error {
}
func (p *PythonProvider) Detect(ctx *generate.GenerateContext) (bool, error) {
hasPython := ctx.App.HasFile("main.py") ||
hasPython := p.getMainPythonFile(ctx) != "" ||
p.hasRequirements(ctx) ||
p.hasPyproject(ctx) ||
p.hasPipfile(ctx)
@@ -123,7 +123,7 @@ func (p *PythonProvider) GetStartCommand(ctx *generate.GenerateContext) string {
}
func (p *PythonProvider) getMainPythonFile(ctx *generate.GenerateContext) string {
for _, file := range []string{"main.py", "app.py", "bot.py", "hello.py", "server.py"} {
for _, file := range []string{"main.py", "app.py", "start.py", "bot.py", "hello.py", "server.py"} {
if ctx.App.HasFile(file) {
return file
}
+5
View File
@@ -34,6 +34,11 @@ func TestDetect(t *testing.T) {
path: "../../../examples/python-uv",
want: true,
},
{
name: "bot.py only",
path: "../../../examples/python-bot-only",
want: true,
},
{
name: "no python",
path: "../../../examples/go-mod",
+1
View File
@@ -0,0 +1 @@
print("Hello from bot.py")
+5
View File
@@ -0,0 +1,5 @@
[
{
"expectedOutput": "Hello from bot.py"
}
]