Skip to content

Commit

Permalink
Merge pull request #30 from joshuanianji/pnpm-global-store
Browse files Browse the repository at this point in the history
(feat) PNPM Global Mount Feature
  • Loading branch information
joshuanianji authored Jan 1, 2024
2 parents 9c8c453 + 821f6b8 commit 94c8f28
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 11 deletions.
35 changes: 35 additions & 0 deletions src/mount-pnpm-store/NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Important Implementation Details

### Ensuring PNPM is installed

This feature does not install PNPM by itself and expects `pnpm` to be installed already, either by a base image or by a feature. It fails quietly if pnpm is not installed.

If you are installing pnpm with a feature, you may need to ensure it is run **before** `mount-pnpm-store`. To make this work, use the [`overrideFeatureInstallOrder` property](https://containers.dev/implementors/features/#overrideFeatureInstallOrder), since the default feature installation order is based on ID (alphanumerically i think). Here is an example using `features/node`:

```json
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/joshuanianji/devcontainer-features/mount-pnpm-store": {}
},
"overrideFeatureInstallOrder": [
"ghcr.io/devcontainers/features/node",
"ghcr.io/joshuanianji/devcontainer-features/mount-pnpm-store"
]
```

### Volume Mount Naming

The volume mount is called `global-devcontainer-pnpm-store`, so ensure that no other docker volumes match this name.

## Changelog

| Version | Notes |
| ------- | ---------------------------------------------------- |
| 0.0.0 | Initial Version |

## References

- [PNPM Devcontainer Setup by PatrickChoDev](https://gist.github.com/PatrickChoDev/81d36159aca4dc687b8c89983e64da2e)
16 changes: 16 additions & 0 deletions src/mount-pnpm-store/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "Mount PNPM Store",
"id": "mount-pnpm-store",
"version": "0.0.0",
"documentationURL": "https://github.com/joshuanianji/devcontainer-features/tree/main/src/mount-pnpm-store",
"description": "Mounts the pnpm store to a volume to share between multiple devcontainers, and sets pnpm store to ~/.pnpm-store. Fails if pnpm is not installed.",
"options": {},
"mounts": [
{
"source": "global-devcontainer-pnpm-store",
"target": "/dc/pnpm-store",
"type": "volume"
}
],
"installsAfter": []
}
44 changes: 44 additions & 0 deletions src/mount-pnpm-store/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh
set -e

echo "Activating feature 'mount-pnpm-store'"
echo "User: ${_REMOTE_USER} User home: ${_REMOTE_USER_HOME}"

if [ -z "$_REMOTE_USER" ] || [ -z "$_REMOTE_USER_HOME" ]; then
echo "***********************************************************************************"
echo "*** Require _REMOTE_USER and _REMOTE_USER_HOME to be set (by dev container CLI) ***"
echo "***********************************************************************************"
exit 1
fi

# make /dc/mounted-pnpm-store folder if doesn't exist
mkdir -p "/dc/mounted-pnpm-store"

# as to why we move around the folder, check `github-cli-persistence/install.sh`
if [ -e "$_REMOTE_USER_HOME/.pnpm-store" ]; then
echo "Moving existing .pnpm-store folder to .pnpm-store-old"
mv "$_REMOTE_USER_HOME/.pnpm-store" "$_REMOTE_USER_HOME/.pnpm-store-old"
fi

ln -s /dc/mounted-pnpm-store "$_REMOTE_USER_HOME/.pnpm-store"
# chown the entire `.config` folder because devcontainers creates
# a `~/.config/vscode-dev-containers` folder later on
chown -R "$_REMOTE_USER:$_REMOTE_USER" "$_REMOTE_USER_HOME/.pnpm-store"

# chown mount (only attached on startup)
cat << EOF >> "$_REMOTE_USER_HOME/.bashrc"
sudo chown -R "$_REMOTE_USER:$_REMOTE_USER" /dc/mounted-pnpm-store
EOF
chown -R $_REMOTE_USER $_REMOTE_USER_HOME/.bashrc

# set pnpm store location
# if pnpm is not installed, print out a warning
if type pnpm > /dev/null 2>&1; then
echo "Setting pnpm store location to $_REMOTE_USER_HOME/.pnpm-store"
# we have to run the `pnpm config set store-dir` as the remote user
# because the remote user is the one that will be using pnpm
runuser -l $_REMOTE_USER -c "pnpm config set store-dir $_REMOTE_USER_HOME/.pnpm-store --global"
else
echo "WARN: pnpm is not installed! Please ensure pnpm is installed and in your PATH."
echo "WARN: pnpm store location will not be set."
fi
2 changes: 1 addition & 1 deletion test/aws-cli-persistence/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"with_node": {
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18",
"features": {
"aws-cli-persistence": {},
"ghcr.io/devcontainers/features/aws-cli": {}
Expand Down
2 changes: 1 addition & 1 deletion test/github-cli-persistence/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"with_node": {
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18",
"features": {
"github-cli-persistence": {},
"ghcr.io/devcontainers/features/github-cli": {}
Expand Down
2 changes: 1 addition & 1 deletion test/lamdera/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"v1.1.0": {
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18",
"features": {
"lamdera": {
"version": "1.1.0"
Expand Down
7 changes: 0 additions & 7 deletions test/lamdera/v1.1.0.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ set -e
# Optional: Import test library
source dev-container-features-test-lib

# NOTE: this is an "auto-generated" test, which means it will be
# executed against an auto-generated devcontainer.json that
# includes the 'lamdera' Feature with no options.
#
# https://github.com/devcontainers/cli/blob/main/docs/features/test.md
#

# check that running the binary by itself works
check "normal" bash -c "lamdera"

Expand Down
20 changes: 20 additions & 0 deletions test/mount-pnpm-store/scenarios.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"with_node": {
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18",
"features": {
"mount-pnpm-store": {}
}
},
"with_pnpm": {
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"mount-pnpm-store": {}
},
"overrideFeatureInstallOrder": [
"ghcr.io/devcontainers/features/node", "./mount-pnpm-store"
]
}
}
25 changes: 25 additions & 0 deletions test/mount-pnpm-store/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

set -e

# Optional: Import test library
source dev-container-features-test-lib

# NOTE: this is an "auto-generated" test, which means it will be
# executed against an auto-generated devcontainer.json that
# includes the 'mount-pnpm-store' feature with no options.
#
# https://github.com/devcontainers/cli/blob/main/docs/features/test.md
#
# From my tests, this means the `pnpm` CLI will not be installed

# check that `~/.pnpm-store` and `/dc/mounted-pnpm-store` exist`
check "config" bash -c "ls -la ~ | grep '.pnpm-store'"
check "dc" bash -c "ls -la /dc | grep 'mounted-pnpm-store'"

# check that `~/.pnpm-store` is a symlink
# https://unix.stackexchange.com/a/96910
check "~/.pnpm-store is a symlink" bash -c "test -L ~/.pnpm-store && test -d ~/.pnpm-store"

# Report result
reportResults
21 changes: 21 additions & 0 deletions test/mount-pnpm-store/with_node.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

set -e

# tests installing pnpm mount when pnpm is already installed in the base image

# Optional: Import test library
source dev-container-features-test-lib

# user is `node` in dev container

echo "User: $(whoami)"
pnpm config list

# check that `pnpm config get store-dir` equals /home/node/.pnpm-store
pnpmConfig=$(pnpm config get store-dir)
echo "pnpm config get store-dir: '$pnpmConfig'"
check "config" test $pnpmConfig = "/home/node/.pnpm-store"

# Report result
reportResults
19 changes: 19 additions & 0 deletions test/mount-pnpm-store/with_pnpm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash

set -e

# tests installing pnpm with a feature

# Optional: Import test library
source dev-container-features-test-lib

echo "User: $(whoami)"
pnpm config list

# check that `pnpm config get store-dir` returns /home/vscode/.pnpm-store
pnpmConfig=$(pnpm config get store-dir)
echo "pnpm config get store-dir: '$pnpmConfig'"
check "config" test $pnpmConfig = "/home/vscode/.pnpm-store"

# Report result
reportResults
2 changes: 1 addition & 1 deletion test/terraform-cli-persistence/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"with_node": {
"image": "mcr.microsoft.com/devcontainers/javascript-node:0-18",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18",
"features": {
"terraform-cli-persistence": {},
"ghcr.io/devcontainers/features/terraform:1": {}
Expand Down

0 comments on commit 94c8f28

Please sign in to comment.