Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .deepsource.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ environment = [
name = "docker"

[analyzers.meta]
dockerfile_paths = [".devcontainer/experimental/Dockerfile"]
dockerfile_paths = [".devcontainer/Dockerfile"]
2 changes: 0 additions & 2 deletions .devcontainer/.dockerignore

This file was deleted.

21 changes: 21 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Everything else comes from features. This exists only because fish does not
# need a feature: Debian trixie ships fish 4.0.2, so installing it is one apt
# call, and doing it here bakes it into a cached image layer.
#
# The alternative considered was ghcr.io/devcontainers-extra/features/fish-apt-get,
# which downloads the 20 MB nanolayer binary and runs it as root to invoke a
# second feature that runs exactly the apt call below -- more than twice the
# size of the package it installs, for a package the distribution already has.
FROM mcr.microsoft.com/devcontainers/typescript-node:4-24-trixie

# DL3008 wants `fish=4.0.2-1`. Pinning an apt package is not the same bargain
# as pinning an npm one: Debian drops superseded versions from the archive, so
# the first security update to fish would leave this asking for a version that
# no longer exists and fail the build outright. Nothing tracks apt pins to
# raise a PR the way renovate does for everything else here. The previous
# Dockerfile suppressed this same rule for the same reason.
# skipcq: DOK-DL3008
RUN apt-get update \
&& apt-get install -y --no-install-recommends fish \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
19 changes: 19 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"features": {
"ghcr.io/devcontainers-extra/features/pnpm:2": {
"version": "2.0.5",
"resolved": "ghcr.io/devcontainers-extra/features/pnpm@sha256:694c2b6182435c9e9c06f6071728b087c1181b38c18cecf0defe2ab8c11cddd6",
"integrity": "sha256:694c2b6182435c9e9c06f6071728b087c1181b38c18cecf0defe2ab8c11cddd6"
},
"ghcr.io/devcontainers/features/git-lfs:1": {
"version": "1.2.5",
"resolved": "ghcr.io/devcontainers/features/git-lfs@sha256:71c2b371cf12ab7fcec47cf17369c6f59156100dad9abf9e4c593049d789de72",
"integrity": "sha256:71c2b371cf12ab7fcec47cf17369c6f59156100dad9abf9e4c593049d789de72"
},
"ghcr.io/devcontainers/features/java:1": {
"version": "1.8.1",
"resolved": "ghcr.io/devcontainers/features/java@sha256:8157bab2d8d71e40b2f3128c162fab763e2b11038fdd33784549290a5d386b48",
"integrity": "sha256:8157bab2d8d71e40b2f3128c162fab763e2b11038fdd33784549290a5d386b48"
}
}
}
81 changes: 48 additions & 33 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,64 @@
// For format details, see https://aka.ms/devcontainer.json. For config options,
// see documentation located at the following URL:
// https://github.com/OpenINF/docker-fisher
// see https://containers.dev.
{
"name": "🦞 OpenINF GrimesAI Salvage Tex: Lunar (OpenINF Community)",
"name": "OpenINF portal",

// A stock image plus features. The Dockerfile beside this file adds exactly
// one thing on top of that image -- fish, which trixie packages itself -- and
// is not a return to maintaining a base image.
"build": {
"dockerfile": "./experimental/Dockerfile"
"dockerfile": "Dockerfile"
},

// No Node version appears in this file on purpose. It lives in package.json's
// `engines.node` and in .nvmrc -- the first is what pnpm enforces, the second
// is what nvm.fish reads for a bare `nvm use`. Both files are needed by their
// own tool, so post-create.sh checks they agree rather than adding a third
// copy here.
"features": {
// pnpm self-manages to the version in `packageManager`, so any recent
// release is enough to bootstrap.
"ghcr.io/devcontainers-extra/features/pnpm:2": {},
// Required by vnu-jar, which backs `verify.svg` and
// `verify.htmlValidForVNU`. Without it both tasks fail with
// `command not found: java`.
"ghcr.io/devcontainers/features/java:1": {
"version": "21",
"installMaven": false,
"installGradle": false
},
// .gitattributes routes archives, images and fonts through LFS.
"ghcr.io/devcontainers/features/git-lfs:1": {}
},

// browser-sync, started by `pnpm start`, serves on 3000 with its UI on 3001.
"forwardPorts": [3000, 3001],

// So `dprint`, `biome`, `nps`, `eleventy` and friends work when typed
// directly, not only under `pnpm exec`. The old setup did this with
// `fish_add_path (pnpm bin)` in config.fish, which left every non-fish
// caller -- CI, editor tasks, agents -- without them. Here it applies to the
// whole container, which is also how the workflows do it (they append
// node_modules/.bin to GITHUB_PATH).
"remoteEnv": {
"PATH": "${containerWorkspaceFolder}/node_modules/.bin:${containerEnv:PATH}"
},
"runArgs": [],
// Configure tool-specific properties.

"postCreateCommand": "bash .devcontainer/post-create.sh",

"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container-specific settings.json values on container
// create.
"settings": {
// Declared, not just selected. VS Code can usually discover fish from
// /etc/shells on its own, but the previous configuration named it
// explicitly and there is no reason to depend on the discovery.
"terminal.integrated.profiles.linux": {
"fish": {
"path": "fish"
}
},
"terminal.integrated.defaultProfile.linux": "fish"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
// https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments
"aaron-bond.better-comments",
Expand All @@ -41,8 +78,6 @@
"KatjanaKosic.vscode-json5",
// https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml
"redhat.vscode-xml",
// https://marketplace.visualstudio.com/items?itemName=rubocop.vscode-rubocop
// "rubocop.vscode-rubocop",
// https://marketplace.visualstudio.com/items?itemName=Shopify.theme-check-vscode
"Shopify.theme-check-vscode",
// https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker
Expand All @@ -54,26 +89,6 @@
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available
// locally.
"forwardPorts": [
4000, // Jekyll server
35729, // Live reload server
2222 // OpenSSH server
],
"overrideCommand": false,

"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
"workspaceFolder": "/workspace",

// Use 'postCreateCommand' to run commands after creating the container.
// https://code.visualstudio.com/docs/devcontainers/create-dev-container#_rebuild
"postCreateCommand": "fish -i '${containerWorkspaceFolder}/tools/devcontainer/post-create.fish'",
"postStartCommand": "fish -i '${containerWorkspaceFolder}/tools/devcontainer/post-start.fish'",
"remoteEnv": {
"PATH": "${containerEnv:PATH}:~/.rbenv/shims/"
},
// Comment out to connect as root instead.
// More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
"remoteUser": "node"
}
36 changes: 0 additions & 36 deletions .devcontainer/experimental/Dockerfile

This file was deleted.

134 changes: 134 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
# ------------------------------------------------------------------------------
# Copyright (c) The OpenINF Authors & Friends. All rights reserved.
# License: MIT OR Apache-2.0 OR BlueOak-1.0.0
# ------------------------------------------------------------------------------
#
# Runs once, after the container is created.
#
# Two Node version managers are set up here on purpose, because they do
# different jobs and neither can do the other's:
#
# nvm.fish - what you use. `nvm use` with no arguments reads .nvmrc, and it
# switches the version for your fish session only, which is what
# you want from an interactive version switch.
# the image's nvm - sets the container-wide baseline. The image puts
# /usr/local/share/nvm/current/bin on the container's PATH and
# sets NVM_SYMLINK_CURRENT, so `nvm use` here repoints a symlink
# that every non-fish process follows: editor tasks, CI, agents.
#
# nvm.fish cannot serve that second role -- it prepends to fish's own PATH and
# keeps its versions under $XDG_DATA_HOME/nvm, so nothing outside fish sees it.
# The image's nvm cannot serve the first -- it is not a fish program.

set -euo pipefail

readonly FISHER_VERSION=4.4.8
readonly NVM_FISH_VERSION=2.2.17

# .nvmrc is what nvm.fish reads; engines.node is what pnpm enforces. Both files
# have to exist for their own tool, so the only thing to guard is that they say
# the same thing -- an exact version, since a floating alias like lts/krypton
# resolves to whatever the newest release in that line happens to be and will
# eventually stop matching the exact pin in package.json.
required="$(node -p 'require("./package.json").engines.node')"
declared="$(tr -d '[:space:]' < .nvmrc)"

if [ "${declared}" != "${required}" ]; then
cat >&2 <<EOF
.nvmrc says "${declared}" but package.json requires exactly "${required}".

nvm.fish resolves \`nvm use\` from .nvmrc, so they have to agree or the version
you get in fish will be rejected by engine-strict.
EOF
exit 1
fi

# ------------------------------------------------------------------------------
# Container-wide baseline, for everything that is not a fish session.
# ------------------------------------------------------------------------------

# Nothing below is silenced. nvm reports several failures through nvm_echo,
# which writes to stdout, so redirecting it away turns a diagnosable problem
# into a bare non-zero exit -- `nvm use` on a version that is not installed
# returns 3 and says why, but only if you let it speak.

echo "==> Node ${required} (image ships $(node -v))"

# Sourcing nvm.sh is allowed to fail. It auto-detects .nvmrc in the working
# directory and tries to activate that version as it loads; in a container
# where nothing is installed yet, that resolves to N/A and returns 3. Under
# `set -e` that killed this script before it reached the install below, with no
# message, because the explanation goes through nvm_echo to stdout.
# shellcheck source=/dev/null
. "${NVM_DIR}/nvm.sh" || true

if ! nvm install "${required}"; then
echo "Failed to install Node ${required} via ${NVM_DIR}." >&2
exit 1
fi

nvm alias default "${required}"
nvm use "${required}"

if [ "$(node -v)" != "v${required}" ]; then
echo "Expected v${required} after nvm use, got $(node -v)." >&2
exit 1
fi

echo "==> Dependencies"

# Corepack prompts before fetching the pinned pnpm, which fails where there is
# no terminal to answer it.
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
corepack enable
pnpm install

# ------------------------------------------------------------------------------
# fish tooling
# ------------------------------------------------------------------------------

echo "==> fish tooling"

# The old base image shipped fisher; a stock image does not. The curl is
# fisher's own bootstrap: it defines the function in memory, which is then used
# to install fisher properly so it survives into later sessions. Both are
# pinned rather than tracking a branch, since this is remote code being sourced.
#
# nvm.fish comes from upstream. The OpenINF fork it used to come from is
# byte-identical to it -- zero commits ahead or behind -- so the fork bought
# nothing and cost a second source to keep watching.
#
# One `fisher install` for both, rather than one each, so this is a single pass.
fish -c "
curl -fsSL https://raw.githubusercontent.com/jorgebucaran/fisher/${FISHER_VERSION}/functions/fisher.fish | source
and fisher install jorgebucaran/fisher@${FISHER_VERSION} jorgebucaran/nvm.fish@${NVM_FISH_VERSION}
"

# Install the pinned version into nvm.fish's own store so a bare `nvm use`
# works immediately, and set nvm_default_version, which is what nvm.fish's
# conf.d reads to activate a version in new interactive sessions. `nvm use`
# alone would not do it: it sets a session variable, so it would apply to this
# one throwaway shell and nothing else.
fish -c "
nvm install (cat .nvmrc)
and set --universal nvm_default_version (cat .nvmrc)
" >/dev/null 2>&1 || true

# gpg needs its keyring to exist before commit signing works. VS Code forwards
# the host's gpg-agent, so no key material is created or copied here.
gpg --list-keys >/dev/null 2>&1 || true

cat <<EOF

Ready, on Node $(node -v).

pnpm start browser-sync dev server on http://localhost:3000
pnpm build production build into _site/
pnpm test the full verify suite

In fish, \`nvm use\` reads .nvmrc. Switching there affects that session only;
the container baseline stays on the version package.json pins.

To sign commits: git config --global commit.gpgsign true
EOF
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lts/krypton
24.19.0
7 changes: 7 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ allowBuilds:
es5-ext: false
esbuild: false
vnu-jar: false

# The dprint VS Code extension resolves its executable from
# node_modules/@dprint/<platform>. That package is an optionalDependency of
# dprint, so pnpm keeps it in the virtual store where the extension cannot see
# it -- which is why the extension used to need a separately installed dprint.
publicHoistPattern:
- '@dprint/*'
21 changes: 0 additions & 21 deletions tools/devcontainer/post-create.fish

This file was deleted.

Loading