diff --git a/.devcontainer/Containerfile b/.devcontainer/Containerfile new file mode 100644 index 00000000..b5d208d0 --- /dev/null +++ b/.devcontainer/Containerfile @@ -0,0 +1,44 @@ +FROM registry.access.redhat.com/ubi9/nodejs-22:9.5-1730543890 + +ARG USERNAME=default +ARG NPM_GLOBAL=/usr/local/share/npm-global + +# Add NPM global to PATH. +ENV PATH=${NPM_GLOBAL}/bin:${PATH} + +USER root + +RUN umask 0002 + +RUN groupadd npm && \ + usermod -a -G npm ${USERNAME} && \ + bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) && \ + chown -R ${USERNAME}:npm /usr/local/ && \ + mkdir -p /opt/app-root/src/.npm && chown -R ${USERNAME}:npm /opt/app-root/src/ && \ + dnf install -y vim + + +USER default + +RUN umask 0002 && \ + mkdir -p ${NPM_GLOBAL} && \ + touch /usr/local/etc/npmrc + +USER root + +RUN chown ${USERNAME}:npm ${NPM_GLOBAL} /usr/local/etc/npmrc && \ + chmod g+s ${NPM_GLOBAL} && \ + npm config -g set prefix ${NPM_GLOBAL} + +USER default + +ARG NODE_MODULES="tslint-to-eslint-config typescript" +RUN npm install -g eslint && \ + npm install -g ${NODE_MODULES} && \ + npm cache clean --force > /dev/null 2>&1 + +WORKDIR /workspaces/ui + +ENTRYPOINT ["npm", "install"] + +EXPOSE 3000/tcp diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..b0d2203e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,26 @@ +{ + "name": "instructlab-ui-devcontainer", + "image": "quay.io/instructlab-ui/devcontainer:latest", + "build": { + "dockerfile": "Containerfile" + }, + "customizations": { + "vscode": { + "extensions": [ + "streetsidesoftware.code-spell-checker", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "DavidAnson.vscode-markdownlint", + "ms-vscode-remote.remote-containers" + ], + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + } + } + }, + "forwardPorts": [3000], + "mounts": [ + "type=bind,source=${localWorkspaceFolder}/.env,target=/workspace/ui/.env,consistency=cached" + ], + "runArgs": ["-p", "3000:3000"] +} diff --git a/Makefile b/Makefile index 12c78583..d812a972 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ endif ILAB_KUBE_CONTEXT?=kind-instructlab-ui ILAB_KUBE_NAMESPACE?=instructlab ILAB_KUBE_CLUSTER_NAME?=instructlab-ui +CONTAINER_ENGINE?=docker +DEVCONTAINER_BINARY_EXISTS ?= $(shell command -v devcontainer) TAG=$(shell git rev-parse HEAD) ##@ Development - Helper commands for development .PHONY: md-lint @@ -201,3 +203,42 @@ undeploy-prod-openshift: ## Undeploy production stack of the InstructLab UI on O $(CMD_PREFIX) if [ -f ./deploy/k8s/overlays/openshift/prod/.env ]; then \ rm ./deploy/k8s/overlays/openshift/prod/.env ; \ fi + +.PHONY: check-dev-container-installed +check-dev-container-installed: + @if [ -z "${DEVCONTAINER_BINARY_EXISTS}" ]; then \ + echo "You do not have devcontainer installed, please isntall it!"; \ + exit 1; \ + fi; + +.PHONY: build-dev-container +build-dev-container: + $(MAKE) check-dev-container-installed + devcontainer build --workspace-folder=./ --docker-path=${CONTAINER_ENGINE} + +.PHONY: start-dev-container +start-dev-container: + $(MAKE) check-dev-container-installed + devcontainer up --workspace-folder=./ --docker-path=${CONTAINER_ENGINE} + +.PHONY: enter-dev-container +enter-dev-container: + $(MAKE) check-dev-container-installed + devcontainer exec --workspace-folder=./ --docker-path=${CONTAINER_ENGINE} bash + +.PHONY: cycle-dev-container +cycle-dev-container: + @image_id=$(shell ${CONTAINER_ENGINE} images | grep "quay.io/instructlab-ui/devcontainer" | awk '{print $$3}') && \ + if [ -n "$$image_id" ]; then \ + CONTAINER_IDS=$(shell ${CONTAINER_ENGINE} ps -a | grep "quay.io/instructlab-ui/devcontainer" | awk '{print $$1}') && \ + if [ -n "$$CONTAINER_IDS" ]; then \ + for CONTAINER_ID in "$$CONTAINER_IDS"; do \ + echo "Stopping and removing container $$CONTAINER_ID of imageid $$image_id..."; \ + ${CONTAINER_ENGINE} rm "$$CONTAINER_ID" -f; \ + done; \ + fi; \ + echo "removing image with id $$image_id and all containers using that image ..."; \ + ${CONTAINER_ENGINE} rmi $$image_id -f; \ + fi; + $(MAKE) build-dev-container + $(MAKE) start-dev-container diff --git a/docs/development.md b/docs/development.md index 05a70b9c..b18c55ee 100644 --- a/docs/development.md +++ b/docs/development.md @@ -252,6 +252,22 @@ The configuration for playwright tests is defined in `playwright.config` file an If you'd like to run a specific single test, use the following command with the appropriate folder path to your test. Example: `npx playwright test tests/routing.spec.ts`. To get a detailed report of the completed tests, run `npx playwright show-report` and you'll get a detailed view. +### How to use the devcontainer + +** NOTE: requires the `devcontainer` binary + +A devcontainer is provided in case you don't want to or can't install these dependencies and tools into you local enviroment. +Additionally, make commands have been provided to make it very easy to spin the environment up or down. To get setup, +simple use the `make cycle-dev-container` target, which will check for existing versions of the devcontainer image, +delete their pods and the image to ensure you have a clean start, build it from scratch and start the container. +Alternatively you can use the `make build-dev-container`, `make start-dev-container` to buildand run the container respectively. +After simply `make enter-dev-container` to exec into it. + +It is compatible with both `docker` and `podman` which you can set with the `CONTAINER_ENGINE` environment variable. +The dev container will mount your local `.env` file into the workspace as well, so you can develop without having to +reconstruct your settings. Currently the `devcontainer` does not support intelligent port reassigment, it is pinned +to port `3000`. + ## Updating the Sealed Secrets for the ArgoCD Application To update the sealed secret, you must communicate with the controller that lives in the `kube-system` namespace of the qa cluster. @@ -271,4 +287,4 @@ to its correct location within this repo. ### Common issues -- `error: cannot get sealed secret service: Unauthorized`: You must be signed in to the qa cluster to be able to communicate with the sealed secrets controller. \ No newline at end of file +- `error: cannot get sealed secret service: Unauthorized`: You must be signed in to the qa cluster to be able to communicate with the sealed secrets controller.