hamster-web 0.1.0.pre.2 → 0.1.0.pre.3
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.
- checksums.yaml +4 -4
- data/README.md +104 -4
- data/lib/hamster/cli.rb +14 -1
- data/lib/hamster/web/version.rb +1 -1
- data/templates/app/.dockerignore +18 -0
- data/templates/app/AGENTS.md +1 -1
- data/templates/app/Dockerfile +53 -0
- data/templates/app/README.md +65 -2
- data/templates/app/app/application.rb +15 -0
- data/templates/app/app/routes/mappings.rb +1 -0
- data/templates/app/app/routes/up/index/action.rb +14 -0
- data/templates/app/config/application.rb +1 -1
- data/templates/app/public/.keep +0 -0
- metadata +12 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad523636ae12bea5f7c62d7ba64c1f9f343340c3c73952d086cb88ad003ebb33
|
|
4
|
+
data.tar.gz: 8b09067b4f17a7a5031f20b543e9ac8564b63319252c1cfb991da4bf4de0b321
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a714e1f4112d612d6123ee30b7febcb5f5b7eac0138d7c8a01e6b969656654c32dac6e2995aa54bd692131d9e323da62480b3904082cd11512784d04409688ca
|
|
7
|
+
data.tar.gz: 7df33a2df961b34d348399c1d6a3e2051457811f3de7543c76eaa6c5c73099ed3bd6c37234d1bcd38ac4efafdcf28d3b65eb911116e59c43bbeae4b7f4db98f8
|
data/README.md
CHANGED
|
@@ -9,11 +9,11 @@ actions, compiled views, and SQL migrations. Database creation and migration
|
|
|
9
9
|
commands, the console, and schema-aware records/queries are available.
|
|
10
10
|
Telemetry extraction and asset delivery remain under development.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Install the public framework preview from RubyGems:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
gem
|
|
16
|
-
gem install
|
|
15
|
+
gem install bundler --version 2.5.23
|
|
16
|
+
gem install hamster-web --version 0.1.0.pre.3
|
|
17
17
|
hamster new MyApp
|
|
18
18
|
cd my_app
|
|
19
19
|
bin/hamster setup
|
|
@@ -28,7 +28,7 @@ bin/hamster build
|
|
|
28
28
|
bin/hamster serve
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Run framework tests with `ruby -Ilib -e 'Dir["test/*_test.rb"].sort.each { |file|
|
|
31
|
+
Run framework tests with `ruby -Ilib -e 'Dir["test/*_test.rb"].sort.each { |file| require File.expand_path(file) }'`.
|
|
32
32
|
|
|
33
33
|
## Records and queries
|
|
34
34
|
|
|
@@ -59,3 +59,103 @@ configured PostgreSQL database. It reports missing tables/columns, incompatible
|
|
|
59
59
|
types, and unexpected nullability with a nonzero exit status. It never migrates
|
|
60
60
|
or modifies the schema. Configuration is loaded through config/commands.rb,
|
|
61
61
|
a CRuby-only adapter generated with new applications.
|
|
62
|
+
|
|
63
|
+
## Installation contract and Linux verification
|
|
64
|
+
|
|
65
|
+
The clean-install gate targets Ruby 3.3.6, Bundler 2.5.23, Hamster
|
|
66
|
+
0.1.0.pre.3, Spinner 0.1.0.pre.1, PostgreSQL 16.6, and unmodified Spinel/Spin
|
|
67
|
+
revision `10f112c51666e7ffd308e0ab90a69c2184870c06`. The exact CI inputs live
|
|
68
|
+
in `script/ci/versions.env`; Linux compatibility is verified by the native
|
|
69
|
+
smoke workflow. This pin does not include the experimental benchmark runtime.
|
|
70
|
+
|
|
71
|
+
The server gem is named `spinel-spinner`; Ruby application code uses
|
|
72
|
+
`require "spinner"` and the `Spinner` namespace. Hamster installs it as a
|
|
73
|
+
separate, exact-version dependency. The RubyGems package named `spinner` is
|
|
74
|
+
unrelated. Neither framework gem bundles a compiler or a precompiled server.
|
|
75
|
+
|
|
76
|
+
Spinel and its `spin` project tool must be installed before app setup. On
|
|
77
|
+
Debian Bookworm, install `build-essential`, `ca-certificates`, `curl`, `git`,
|
|
78
|
+
`pkg-config`, `libffi-dev`, and `libssl-dev`. PostgreSQL must be available;
|
|
79
|
+
`postgresql-client` provides the smoke test's `psql` checks. Build the pinned
|
|
80
|
+
upstream toolchain into a dedicated installation prefix:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
git clone https://github.com/matz/spinel.git
|
|
84
|
+
cd spinel
|
|
85
|
+
git checkout --detach 10f112c51666e7ffd308e0ab90a69c2184870c06
|
|
86
|
+
make deps
|
|
87
|
+
make -j2
|
|
88
|
+
make install PREFIX="$HOME/.local"
|
|
89
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
90
|
+
spinel --version
|
|
91
|
+
spin --version
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Then run the app generation commands above from an empty directory. Setup
|
|
95
|
+
fetches the PostgreSQL driver revision in the generated `spin.lock` from
|
|
96
|
+
`https://github.com/rubys/spinel-pg`. RubyGems and GitHub network access are
|
|
97
|
+
required. Configure `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_NAME`,
|
|
98
|
+
`DATABASE_USERNAME`, and `DATABASE_PASSWORD` for your PostgreSQL server.
|
|
99
|
+
`DATABASE_ADMIN_NAME` defaults to `postgres`; administrative credentials default
|
|
100
|
+
to the application credentials and need permission to create the database.
|
|
101
|
+
The generated README describes the defaults and build/serve commands.
|
|
102
|
+
|
|
103
|
+
To build a local framework preview instead of installing the public package:
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
gem build hamster-web.gemspec
|
|
107
|
+
gem install --local hamster-web-0.1.0.pre.3.gem
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Run the clean Linux gate locally with Docker running (no local PostgreSQL or
|
|
111
|
+
Spinel installation needed):
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
# Public packages, installed directly from RubyGems:
|
|
115
|
+
bash script/ci/run_native_smoke.sh published
|
|
116
|
+
|
|
117
|
+
# Candidate gem built from this checkout, plus published Spinner:
|
|
118
|
+
mkdir -p tmp
|
|
119
|
+
gem build hamster-web.gemspec --output tmp/hamster-web.gem
|
|
120
|
+
bash script/ci/run_native_smoke.sh candidate tmp/hamster-web.gem
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Each invocation builds an image without caches, installs the compiler from its
|
|
124
|
+
pinned upstream source, and tests in a separate consumer image containing no
|
|
125
|
+
Hamster/Spinner checkout. Only the CI harness and optional candidate gem enter
|
|
126
|
+
that environment. Gems, Bundler settings, and the generated app use fresh
|
|
127
|
+
isolated directories. Package resolution must stay within that gem installation.
|
|
128
|
+
The test creates a disposable database, applies a real migration twice, checks
|
|
129
|
+
its effects and tracking, compiles the app, and asserts HTTP 200 and welcome
|
|
130
|
+
content from the native executable. Containers, their processes, networks, and
|
|
131
|
+
the tagged test image are removed on exit. Docker retains image build layers;
|
|
132
|
+
no restored layers are used by the gate.
|
|
133
|
+
|
|
134
|
+
Logs, lockfiles, resolved package paths, and HTTP output are retained under
|
|
135
|
+
`tmp/native-smoke-<mode>/` (override with `SMOKE_ARTIFACTS_DIR`). GitHub Actions
|
|
136
|
+
uploads those diagnostics even on failure. Pull requests and main test the
|
|
137
|
+
candidate package; weekly and manually triggered runs also test published
|
|
138
|
+
packages. Public pins are advanced deliberately when releases are available.
|
|
139
|
+
|
|
140
|
+
## Generated deployment images
|
|
141
|
+
|
|
142
|
+
New applications include a multi-stage `Dockerfile`, `.dockerignore`, and a
|
|
143
|
+
`GET /up` liveness endpoint. Build with `docker build -t my_app .`; no host Ruby,
|
|
144
|
+
Spinel, or database is needed. The default image runs the native executable as
|
|
145
|
+
UID 10001 on port 4000, with shared libraries, migrations and public assets only.
|
|
146
|
+
Ruby and the compiler are confined to build/operational stages.
|
|
147
|
+
|
|
148
|
+
Build `--target migrations` separately and run that image's `db:migrate`
|
|
149
|
+
command with database settings supplied at runtime before deploying the native
|
|
150
|
+
image. Migrations never run during image build or server startup. `/up` bypasses
|
|
151
|
+
database checkout after the application's initial database/migration verification,
|
|
152
|
+
so it reports process liveness rather than database readiness. The generated
|
|
153
|
+
README includes deployment commands, environment settings and shutdown semantics.
|
|
154
|
+
|
|
155
|
+
Run `bash script/ci/run_app_docker_smoke.sh` to verify the generated image using
|
|
156
|
+
Docker alone. It packages and installs the current framework inside a temporary
|
|
157
|
+
container, generates an app, builds before creating any database, checks secret
|
|
158
|
+
exclusions and runtime linkage, applies a real migration, verifies HTTP and Docker
|
|
159
|
+
health checks as a non-root user without Ruby/Spinel, stops PostgreSQL to test
|
|
160
|
+
liveness, and verifies clean SIGTERM shutdown. Diagnostics are retained in
|
|
161
|
+
`tmp/app-docker-smoke/`. This runs as a separate job in the native smoke workflow.
|
data/lib/hamster/cli.rb
CHANGED
|
@@ -44,6 +44,13 @@ module Hamster
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
def self.require_tool!(executable, instruction)
|
|
48
|
+
paths = executable.include?(File::SEPARATOR) ? [executable] : ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).map { |directory| File.join(directory, executable) }
|
|
49
|
+
return if paths.any? { |path| File.file?(path) && File.executable?(path) }
|
|
50
|
+
|
|
51
|
+
raise "Required executable #{executable.inspect} was not found; #{instruction}"
|
|
52
|
+
end
|
|
53
|
+
|
|
47
54
|
def self.dispatch(command)
|
|
48
55
|
app_root = root
|
|
49
56
|
metadata = JSON.parse(File.read(File.join(app_root, "config/hamster.json")))
|
|
@@ -63,10 +70,13 @@ module Hamster
|
|
|
63
70
|
Console.run(ApplicationCommands.build)
|
|
64
71
|
end
|
|
65
72
|
when "setup"
|
|
73
|
+
require_tool!("bundle", "install Bundler with gem install bundler")
|
|
74
|
+
require_tool!("spin", "install the supported Spinel toolchain (including spin); see the Hamster README") if File.file?(File.join(app_root, "spin.toml"))
|
|
66
75
|
Dir.chdir(app_root) { raise "Dependency installation failed" unless system("bundle", "install") }
|
|
67
76
|
Dir.chdir(app_root) { raise "Spin dependency vendoring failed" unless system("spin", "vendor") } if File.file?(File.join(app_root, "spin.toml"))
|
|
68
77
|
Build::PostgresCompatibility.apply(app_root) if File.file?(File.join(app_root, "spin.toml"))
|
|
69
78
|
when "db:create", "db:migrate"
|
|
79
|
+
require_tool!("spin", "install the supported Spinel toolchain and run bin/hamster setup")
|
|
70
80
|
output, status = Open3.capture2e("spin", "list", "--json", chdir: app_root)
|
|
71
81
|
raise "Cannot resolve PostgreSQL dependency: #{output}" unless status.success?
|
|
72
82
|
pg = JSON.parse(output).find { |package| package["name"] == "pg" }
|
|
@@ -95,6 +105,9 @@ module Hamster
|
|
|
95
105
|
raise issues.join("\n") unless issues.empty?
|
|
96
106
|
puts "Manifest check passed"
|
|
97
107
|
when "build"
|
|
108
|
+
compiler = ENV.fetch("SPINEL", "spinel")
|
|
109
|
+
require_tool!(compiler, "install the supported Spinel toolchain or set SPINEL to its compiler path; see the Hamster README")
|
|
110
|
+
require_tool!("spin", "install the supported Spinel toolchain (including spin)") if File.file?(File.join(app_root, "spin.toml"))
|
|
98
111
|
Build::PostgresCompatibility.apply(app_root) if File.file?(File.join(app_root, "spin.toml"))
|
|
99
112
|
Build::Manifest.generate(app_root)
|
|
100
113
|
issues = Build::Manifest.check(app_root)
|
|
@@ -109,7 +122,7 @@ module Hamster
|
|
|
109
122
|
raise "Spin dependency resolution failed: #{diagnostic}" unless status.success?
|
|
110
123
|
flags.concat(Shellwords.split(output))
|
|
111
124
|
end
|
|
112
|
-
raise "Spinel compilation failed" unless system(
|
|
125
|
+
raise "Spinel compilation failed" unless system(compiler, "bin/server", *flags, "-o", temporary)
|
|
113
126
|
end
|
|
114
127
|
File.rename(temporary, binary)
|
|
115
128
|
ensure
|
data/lib/hamster/web/version.rb
CHANGED
data/templates/app/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Application conventions
|
|
2
2
|
|
|
3
|
-
- Keep one action per endpoint directory
|
|
3
|
+
- Keep one action per endpoint directory; HTML responses can use a sibling view.html.erb.
|
|
4
4
|
- Declare routes in app/routes/mappings.rb.
|
|
5
5
|
- App Ruby files load through config/manifest.rb; do not add local requires.
|
|
6
6
|
- Run bin/hamster manifest after editing application Ruby files or templates.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Build with Docker only; Spinel and Ruby are installed inside the builder.
|
|
2
|
+
ARG RUBY_IMAGE=ruby:3.3.6-bookworm@sha256:347edd0c70ee08d87de9f01b99de2f14a64cedb5d1bfb38457dfe8cd0bf113c5
|
|
3
|
+
ARG RUNTIME_IMAGE=debian:bookworm-slim@sha256:99c0b25c46d0214d5a2091092e7908907dcaecd6a962cde0ac700acee222b6f3
|
|
4
|
+
FROM ${RUBY_IMAGE} AS toolchain
|
|
5
|
+
ARG SPINEL_REVISION=10f112c51666e7ffd308e0ab90a69c2184870c06
|
|
6
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
7
|
+
build-essential ca-certificates curl git libffi-dev libssl-dev pkg-config \
|
|
8
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
9
|
+
RUN mkdir /src && cd /src && git init \
|
|
10
|
+
&& git remote add origin https://github.com/matz/spinel.git \
|
|
11
|
+
&& git fetch --depth 1 origin "$SPINEL_REVISION" && git checkout --detach FETCH_HEAD \
|
|
12
|
+
&& test "$(git rev-parse HEAD)" = "$SPINEL_REVISION" \
|
|
13
|
+
&& make deps && make -j2 && make install PREFIX=/opt/spinel \
|
|
14
|
+
&& rm -rf /src
|
|
15
|
+
ENV PATH="/opt/spinel/bin:${PATH}"
|
|
16
|
+
RUN gem install bundler --version 2.5.23 --no-document \
|
|
17
|
+
&& gem install hamster-web --version __HAMSTER_VERSION__ --no-document
|
|
18
|
+
|
|
19
|
+
FROM toolchain AS builder
|
|
20
|
+
WORKDIR /app
|
|
21
|
+
COPY . .
|
|
22
|
+
# Setup and compilation require no database connection or credentials.
|
|
23
|
+
RUN bin/hamster setup && bin/hamster manifest && bin/hamster manifest:check && bin/hamster build
|
|
24
|
+
RUN mkdir -p /runtime/app/bin /runtime/app/db/migrations /runtime/app/public \
|
|
25
|
+
&& cp bin/__APP_NAME__-server /runtime/app/bin/ \
|
|
26
|
+
&& cp -a db/migrations/. /runtime/app/db/migrations/ \
|
|
27
|
+
&& cp -a public/. /runtime/app/public/ \
|
|
28
|
+
&& ldd bin/__APP_NAME__-server > /runtime/ldd.txt \
|
|
29
|
+
&& cat /runtime/ldd.txt && ! grep -F 'not found' /runtime/ldd.txt
|
|
30
|
+
|
|
31
|
+
# Optional operational image. Migrations run explicitly, never during build/boot.
|
|
32
|
+
FROM builder AS migrations
|
|
33
|
+
ENV HAMSTER_APP_ROOT=/app HAMSTER_ENV=production
|
|
34
|
+
ENTRYPOINT ["bin/hamster"]
|
|
35
|
+
CMD ["db:migrate"]
|
|
36
|
+
|
|
37
|
+
FROM ${RUNTIME_IMAGE} AS runtime
|
|
38
|
+
# Runtime libraries and a small HTTP health probe; no Ruby, gems or compiler.
|
|
39
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
40
|
+
ca-certificates curl libcrypt1 libffi8 libssl3 \
|
|
41
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
42
|
+
WORKDIR /app
|
|
43
|
+
COPY --from=builder /runtime/app/ /app/
|
|
44
|
+
# Check linkage in the actual runtime image as well as in the builder.
|
|
45
|
+
RUN ldd /app/bin/__APP_NAME__-server > /tmp/ldd.txt \
|
|
46
|
+
&& cat /tmp/ldd.txt && ! grep -F 'not found' /tmp/ldd.txt && rm /tmp/ldd.txt
|
|
47
|
+
ENV HAMSTER_APP_ROOT=/app HAMSTER_ENV=production HOST=0.0.0.0 PORT=4000
|
|
48
|
+
USER 10001:10001
|
|
49
|
+
EXPOSE 4000
|
|
50
|
+
STOPSIGNAL SIGTERM
|
|
51
|
+
HEALTHCHECK --interval=10s --timeout=3s --start-period=15s --retries=3 \
|
|
52
|
+
CMD curl --fail --silent --show-error --max-time 2 "http://127.0.0.1:${PORT}/up" > /dev/null || exit 1
|
|
53
|
+
ENTRYPOINT ["/app/bin/__APP_NAME__-server"]
|
data/templates/app/README.md
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
# __APP_NAME__
|
|
2
2
|
|
|
3
3
|
Run `bin/hamster setup` to install gems and vendor the locked Spin PostgreSQL driver.
|
|
4
|
-
Spin and Spinel must already be installed.
|
|
4
|
+
Spin and Spinel must already be installed. The preview installation contract is
|
|
5
|
+
Ruby 3.3.6, Bundler 2.5.23, Hamster __HAMSTER_VERSION__, spinel-spinner
|
|
6
|
+
0.1.0.pre.1, and Spinel/Spin revision
|
|
7
|
+
`10f112c51666e7ffd308e0ab90a69c2184870c06`. See the framework README at
|
|
8
|
+
https://github.com/dostaglou/hamster-web for compiler installation prerequisites.
|
|
9
|
+
Spinner's gem name is `spinel-spinner`; application code uses `require "spinner"`.
|
|
10
|
+
Both gems are available from https://rubygems.org. Configure DATABASE_USERNAME,
|
|
5
11
|
DATABASE_PASSWORD, and optionally DATABASE_HOST and DATABASE_PORT for your local
|
|
6
12
|
PostgreSQL server. DATABASE_NAME defaults to __APP_NAME___development.
|
|
7
13
|
|
|
@@ -14,7 +20,7 @@ then `bin/hamster serve`. Build does not require a database connection.
|
|
|
14
20
|
An empty migration directory is valid; db:migrate initializes migration tracking.
|
|
15
21
|
The server listens on http://127.0.0.1:4000 by default; configure HOST and PORT
|
|
16
22
|
to override it. During framework development, install the local hamster-web
|
|
17
|
-
gem before running setup.
|
|
23
|
+
gem before running setup. Otherwise the pinned framework is installed from RubyGems.
|
|
18
24
|
|
|
19
25
|
Run a deployed binary from the application root or set HAMSTER_APP_ROOT.
|
|
20
26
|
Include db/migrations alongside the binary. PostgreSQL TLS is not supported
|
|
@@ -30,3 +36,60 @@ Each endpoint has an action.rb and optional view.html.erb in app/routes/.
|
|
|
30
36
|
Declare endpoints centrally in app/routes/mappings.rb. Run
|
|
31
37
|
`bin/hamster manifest` after changing Ruby sources or templates and commit
|
|
32
38
|
the generated manifest and view registry with your source changes.
|
|
39
|
+
|
|
40
|
+
## Docker deployment
|
|
41
|
+
|
|
42
|
+
The generated Dockerfile builds the Spinel compiler and `spin` at the pinned
|
|
43
|
+
revision, installs the framework from RubyGems, runs setup and manifest checks,
|
|
44
|
+
and compiles your application. Docker is the only build prerequisite on the
|
|
45
|
+
host. Commit `Gemfile.lock` and `spin.lock` to keep dependency resolution stable.
|
|
46
|
+
No database or database credentials are needed to build either target.
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
docker build -t __APP_NAME__:latest .
|
|
50
|
+
docker build --target migrations -t __APP_NAME__:migrations .
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The default image uses Debian Bookworm slim and UID/GID 10001. It contains the
|
|
54
|
+
native executable, shared runtime libraries, SQL migrations and `public/`;
|
|
55
|
+
Ruby, gems, Spinel, application source and build tools stay in the builder.
|
|
56
|
+
Both builder and runtime verify the executable's shared library linkage with
|
|
57
|
+
`ldd`. Public files are retained for application-managed assets; the image does
|
|
58
|
+
not add an asset-serving route.
|
|
59
|
+
|
|
60
|
+
Provide database settings at container runtime, for example in an uncommitted
|
|
61
|
+
`.env.production` file. Set `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_NAME`,
|
|
62
|
+
`DATABASE_USERNAME`, and `DATABASE_PASSWORD`. The production database name
|
|
63
|
+
defaults to `__APP_NAME___production`. The database must already exist; use
|
|
64
|
+
`db:create` with separate administrative credentials only when provisioning it.
|
|
65
|
+
The Docker context excludes `.env` files, private keys, local gems, compiled
|
|
66
|
+
host binaries, and local Bundler settings. Keep credentials out of Ruby source
|
|
67
|
+
and Docker build arguments as well.
|
|
68
|
+
|
|
69
|
+
Apply migrations explicitly as a deployment step, then start the native image:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
docker run --rm --env-file .env.production __APP_NAME__:migrations
|
|
73
|
+
docker run -d --name __APP_NAME__ --env-file .env.production -p 4000:4000 __APP_NAME__:latest
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `migrations` target includes Ruby and build dependencies for the existing
|
|
77
|
+
Hamster CLI; it is a separate operational image. Its default command is
|
|
78
|
+
`db:migrate`, and an explicit argument can select another command. Neither
|
|
79
|
+
image build nor native server startup applies migrations. Startup verifies the
|
|
80
|
+
configured database and rejects missing migration tracking or pending migrations.
|
|
81
|
+
|
|
82
|
+
The runtime sets `HAMSTER_APP_ROOT=/app`, `HAMSTER_ENV=production`,
|
|
83
|
+
`HOST=0.0.0.0` and `PORT=4000`. Override `PORT` and the port mapping together if
|
|
84
|
+
needed. The executable runs directly as PID 1 and receives SIGTERM. Allow its
|
|
85
|
+
graceful shutdown time when stopping it, for example `docker stop -t 20 __APP_NAME__`.
|
|
86
|
+
Only temporary storage needs to be writable; the CI smoke test runs with a
|
|
87
|
+
read-only root filesystem and a writable `/tmp`.
|
|
88
|
+
|
|
89
|
+
`GET /up` returns HTTP 200 with `OK` after successful startup. This is liveness:
|
|
90
|
+
it checks HTTP dispatch without checking out a database connection. A later
|
|
91
|
+
database outage does not make `/up` fail. It is not a readiness check or a
|
|
92
|
+
promise that application requests can reach PostgreSQL. The route is declared
|
|
93
|
+
in `app/routes/mappings.rb`, and `app/application.rb` bypasses the normal
|
|
94
|
+
database checkout for that path. The Docker health check calls `/up` using the
|
|
95
|
+
configured `PORT`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module __APP_MODULE__
|
|
3
|
+
class Application < Hamster::Application
|
|
4
|
+
def initialize(routes:, database:)
|
|
5
|
+
super(routes: routes, database: database)
|
|
6
|
+
@liveness_router = Hamster::Router.new(routes)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(env)
|
|
10
|
+
# Liveness checks process/HTTP dispatch only, even during a DB outage.
|
|
11
|
+
return @liveness_router.call(env) if env.fetch("PATH_INFO", "/") == "/up"
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module __APP_MODULE__
|
|
3
|
+
module Routes
|
|
4
|
+
module Up
|
|
5
|
+
module Index
|
|
6
|
+
class Action < Hamster::Action::Base
|
|
7
|
+
def call
|
|
8
|
+
respond(body: "OK\n", headers: {"content-type" => "text/plain; charset=utf-8"})
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -9,7 +9,7 @@ module __APP_MODULE__
|
|
|
9
9
|
database = Hamster::Database.new(database_configuration, migrations_path: File.join(root, "db/migrations"))
|
|
10
10
|
begin
|
|
11
11
|
database.verify!
|
|
12
|
-
|
|
12
|
+
Application.new(routes: Routes::Mappings, database: database)
|
|
13
13
|
rescue StandardError
|
|
14
14
|
database.shutdown
|
|
15
15
|
raise
|
|
File without changes
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hamster-web
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.0.pre.
|
|
4
|
+
version: 0.1.0.pre.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dillon Wyatt
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-10-29 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: spinel-spinner
|
|
@@ -93,13 +94,17 @@ files:
|
|
|
93
94
|
- lib/hamster/web/version.rb
|
|
94
95
|
- lib/hamster/web/view.rb
|
|
95
96
|
- lib/hamster/web/view/form.rb
|
|
97
|
+
- templates/app/.dockerignore
|
|
96
98
|
- templates/app/.gitignore
|
|
97
99
|
- templates/app/AGENTS.md
|
|
100
|
+
- templates/app/Dockerfile
|
|
98
101
|
- templates/app/Gemfile
|
|
99
102
|
- templates/app/README.md
|
|
103
|
+
- templates/app/app/application.rb
|
|
100
104
|
- templates/app/app/routes/home/index/action.rb
|
|
101
105
|
- templates/app/app/routes/home/index/view.html.erb
|
|
102
106
|
- templates/app/app/routes/mappings.rb
|
|
107
|
+
- templates/app/app/routes/up/index/action.rb
|
|
103
108
|
- templates/app/app/views/layouts/application.html.erb
|
|
104
109
|
- templates/app/bin/hamster
|
|
105
110
|
- templates/app/bin/server
|
|
@@ -108,11 +113,14 @@ files:
|
|
|
108
113
|
- templates/app/config/database.rb
|
|
109
114
|
- templates/app/config/hamster.json
|
|
110
115
|
- templates/app/db/migrations/.keep
|
|
116
|
+
- templates/app/public/.keep
|
|
111
117
|
- templates/app/spin.lock
|
|
112
118
|
- templates/app/spin.toml
|
|
119
|
+
homepage:
|
|
113
120
|
licenses:
|
|
114
121
|
- MIT
|
|
115
122
|
metadata: {}
|
|
123
|
+
post_install_message:
|
|
116
124
|
rdoc_options: []
|
|
117
125
|
require_paths:
|
|
118
126
|
- lib
|
|
@@ -127,7 +135,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
127
135
|
- !ruby/object:Gem::Version
|
|
128
136
|
version: '0'
|
|
129
137
|
requirements: []
|
|
130
|
-
rubygems_version:
|
|
138
|
+
rubygems_version: 3.5.16
|
|
139
|
+
signing_key:
|
|
131
140
|
specification_version: 4
|
|
132
141
|
summary: A Spinel web framework and application generator
|
|
133
142
|
test_files: []
|