-
Notifications
You must be signed in to change notification settings - Fork 158
Add Mise module #1068
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add Mise module #1068
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
39b408f
Add Mise module
droopy4096 44f48bc
mise-install: place primary tf block inside h1 section
droopy4096 1e68e09
Add Mise module
droopy4096 2c75a8a
mise-install: place primary tf block inside h1 section
droopy4096 b9ce1f0
Update logo
droopy4096 228234d
merged upstream
droopy4096 8833035
mise-install: restricted-environment readiness (install_url, install_…
droopy4096 509b49b
Merge branch 'main' into main
bpmct File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| --- | ||
| display_name: "D Makovey" | ||
| bio: "Lifelong tinkerer" | ||
| avatar: "./.images/avatar.png" | ||
| github: "droopy4096" | ||
| status: "community" | ||
| --- | ||
|
|
||
| # D Makovey | ||
|
|
||
| Lifelong tinkerer and breaker of things |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| --- | ||
| display_name: mise install | ||
| description: Install mise and run `mise install` inside a cloned repository. | ||
| icon: ../../../../.icons/mise.svg | ||
| verified: false | ||
| tags: [helper, mise, devtools] | ||
| --- | ||
|
|
||
| # mise install | ||
|
|
||
| Installs [`mise`](https://mise.jdx.dev/getting-started.html) on the workspace and runs `mise install` inside a repository directory so language runtimes and tools declared in `.mise.toml` / `.tool-versions` are provisioned before the user starts working. | ||
|
|
||
| Designed to compose with the [`coder/git-clone`](https://registry.coder.com/modules/coder/git-clone) module: pass `module.git_clone.repo_dir` as `repo_dir`. | ||
|
|
||
| ```tf | ||
| module "mise_install" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| } | ||
| ``` | ||
|
|
||
| The install script downloads `mise` from `https://mise.run` into `install_dir` (defaults to `$HOME/.local/bin`) and appends `mise activate` to `~/.bashrc` and `~/.zshrc`. The post-install script then runs `mise trust` (optional) and `mise install` inside `repo_dir`. | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Compose with `coder/git-clone` | ||
|
|
||
| ```tf | ||
| module "git_clone" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/coder/git-clone/coder" | ||
| version = "2.0.3" | ||
| agent_id = coder_agent.main.id | ||
| url = "https://github.com/example/repo" | ||
| } | ||
|
|
||
| module "mise_install" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| } | ||
| ``` | ||
|
|
||
| ### Disable shell activation and `mise trust` | ||
|
|
||
| Use this when the workspace image already activates `mise` globally, or the repository does not use `.mise.toml`: | ||
|
|
||
| ```tf | ||
| module "mise_install" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| activate_shells = [] | ||
| mise_trust = false | ||
| } | ||
| ``` | ||
|
|
||
| ### Custom install directory | ||
|
|
||
| ```tf | ||
| module "mise_install" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| install_dir = "$HOME/.mise/bin" | ||
| } | ||
| ``` | ||
|
|
||
| ### Air-gapped / mirrored installer | ||
|
|
||
| Point the installer at an internal mirror, pin the release, and skip the download entirely by using the `mise` already baked into the workspace image: | ||
|
|
||
| ```tf | ||
| # Fully mirrored: download the installer from an internal HTTPS mirror | ||
| # and pin the mise release for reproducibility. | ||
| module "mise_install" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| install_url = "https://artifacts.internal.example.com/mise/install.sh" | ||
| mise_version = "v2024.9.0" | ||
| } | ||
|
|
||
| # Bring-your-own binary: the image already ships mise; skip the download. | ||
| module "mise_install_byo" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| install_mise = false | ||
| mise_bin = "/opt/mise/bin/mise" # optional; omit if 'mise' is on PATH | ||
| } | ||
| ``` | ||
|
|
||
| ## Network egress | ||
|
|
||
| This module reaches the following external endpoints. Mirror or allow-list them (or use `install_mise = false`) in restricted environments: | ||
|
|
||
| | When | Endpoint | Overridable via | | ||
| | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | ||
| | Install phase (only when `install_mise = true`) | `https://mise.run` — installer shell script | `install_url` | | ||
| | Install phase (transitive from installer) | `https://github.com/jdx/mise/releases/*` — mise binary release assets | Mirror inside `install_url`'s script or use `install_mise = false` + `mise_bin` | | ||
| | Post-install phase (`mise install`) | `https://mise.jdx.dev/*` — plugin registry and metadata | `MISE_*` env vars (see mise docs); not exposed by this module | | ||
| | Post-install phase (transitive) | Language-runtime hosts (`python.org`, `nodejs.org`, `go.dev`, etc.) — driven by `.mise.toml` / `.tool-versions` in `repo_dir` | Configure `mise` plugins/mirrors in the image | | ||
|
|
||
| If your environment blocks all outbound traffic, set `install_mise = false`, ship `mise` in the image, and mirror the plugin/runtime hosts `mise install` needs at runtime. | ||
|
|
||
| ## Execution order | ||
|
|
||
| This module uses [`coder/coder-utils`](https://registry.coder.com/modules/coder/coder-utils) to run two ordered scripts via `coder exp sync`: | ||
|
|
||
| 1. **Install Script** — installs `mise` and (optionally) configures shell activation. | ||
| 2. **Post-Install Script** — waits for the clone to complete, then runs `mise trust` and `mise install` in `repo_dir`. | ||
|
|
||
| Coder starts every `coder_script` on an agent in parallel, so this module's post-install script cannot use `coder exp sync` to wait on `git-clone` (git-clone does not participate in `coder exp sync`). Instead, the post-install script polls for `${repo_dir}/.git` and only runs `mise install` once the clone has finished. The bound is controlled by `wait_seconds` (default `300`). If the timeout expires, the script logs a message and exits `0` without running `mise install`. | ||
|
|
||
| ### Custom wait timeout | ||
|
|
||
| ```tf | ||
| module "mise_install" { | ||
| count = data.coder_workspace.me.start_count | ||
| source = "registry.coder.com/droopy4096/mise-install/coder" | ||
| version = "1.0.0" | ||
| agent_id = coder_agent.main.id | ||
| repo_dir = module.git_clone[count.index].repo_dir | ||
| wait_seconds = 900 # wait up to 15 minutes for large clones | ||
| } | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| Scripts and logs are written under a per-module root: | ||
|
|
||
| - Scripts: `$HOME/.coder-modules/droopy4096/mise-install/scripts/{install.sh,post_install.sh}` | ||
| - Logs: `$HOME/.coder-modules/droopy4096/mise-install/logs/{install.log,post_install.log}` | ||
|
|
||
| If `mise install` fails, inspect `post_install.log` for the exact `mise` output. Common causes: | ||
|
|
||
| - Missing `.mise.toml` / `.tool-versions` in `repo_dir`. | ||
| - Untrusted config (rerun with `mise_trust = true`). | ||
| - Network egress blocked to endpoints listed under [Network egress](#network-egress). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| terraform { | ||
| required_version = ">= 1.0" | ||
|
|
||
| required_providers { | ||
| coder = { | ||
| source = "coder/coder" | ||
| version = ">= 2.13" | ||
| } | ||
| } | ||
| } | ||
|
|
||
| variable "agent_id" { | ||
| description = "The ID of a Coder agent." | ||
| type = string | ||
| } | ||
|
|
||
| variable "repo_dir" { | ||
| description = "Absolute path to the repository where `mise install` should run. Typically wired to `module.git-clone.repo_dir`." | ||
| type = string | ||
| } | ||
|
|
||
| variable "mise_trust" { | ||
| description = "Whether to run `mise trust` on the repository before `mise install`. Required for projects that ship a `.mise.toml`." | ||
| type = bool | ||
| default = true | ||
| } | ||
|
|
||
| variable "activate_shells" { | ||
| description = "Shell rc files to append `mise activate` to. Pass an empty list to skip activation." | ||
| type = list(string) | ||
| default = ["bash", "zsh"] | ||
|
|
||
| validation { | ||
| condition = alltrue([for s in var.activate_shells : contains(["bash", "zsh"], s)]) | ||
| error_message = "activate_shells entries must be one of: bash, zsh." | ||
| } | ||
| } | ||
|
|
||
| variable "install_dir" { | ||
| description = "Directory to install the `mise` binary into. Passed to the mise installer as `MISE_INSTALL_PATH`'s parent." | ||
| type = string | ||
| default = "$HOME/.local/bin" | ||
| } | ||
|
|
||
| variable "install_mise" { | ||
| description = "Whether to download and install `mise`. Set to false in restricted or air-gapped environments where the workspace image already ships `mise`; the module will then only configure shell activation and run `mise install`." | ||
| type = bool | ||
| default = true | ||
| } | ||
|
|
||
| variable "install_url" { | ||
| description = "URL of the mise installer script. Override to point at an internal mirror in restricted environments. Ignored when `install_mise = false`." | ||
| type = string | ||
| default = "https://mise.run" | ||
| } | ||
|
|
||
| variable "mise_version" { | ||
| description = "Pin the mise release to install by setting `MISE_VERSION` before invoking the installer (e.g. `\"v2024.9.0\"`). Empty means install the latest release advertised by `install_url`. Ignored when `install_mise = false`." | ||
| type = string | ||
| default = "" | ||
| } | ||
|
|
||
| variable "mise_bin" { | ||
| description = "Absolute path to a pre-installed `mise` binary (e.g. `/opt/mise/bin/mise` baked into a workspace image). When non-empty, its directory is prepended to PATH so this module and downstream scripts pick it up. Combine with `install_mise = false` to fully opt out of downloading." | ||
| type = string | ||
| default = "" | ||
| } | ||
|
|
||
| variable "wait_seconds" { | ||
| description = "Maximum seconds to wait for `repo_dir/.git` to appear (i.e. for the git-clone module to finish) before skipping `mise install`." | ||
| type = number | ||
| default = 300 | ||
|
|
||
| validation { | ||
| condition = var.wait_seconds >= 0 | ||
| error_message = "wait_seconds must be non-negative." | ||
| } | ||
| } | ||
|
|
||
| variable "icon" { | ||
| description = "Icon shown in the Coder UI for the coder_script resources this module creates." | ||
| type = string | ||
| default = "/icon/code.svg" | ||
| } | ||
|
|
||
| locals { | ||
| module_directory = "$HOME/.coder-modules/droopy4096/mise-install" | ||
|
|
||
| install_script = templatefile("${path.module}/scripts/install.sh.tftpl", { | ||
| ARG_INSTALL_DIR = var.install_dir | ||
| ARG_ACTIVATE_SHELLS = join(" ", var.activate_shells) | ||
| ARG_INSTALL_MISE = tostring(var.install_mise) | ||
| ARG_INSTALL_URL = var.install_url | ||
| ARG_MISE_VERSION = var.mise_version | ||
| ARG_MISE_BIN = var.mise_bin | ||
| }) | ||
|
|
||
| post_install_script = templatefile("${path.module}/scripts/post_install.sh.tftpl", { | ||
| ARG_REPO_DIR = var.repo_dir | ||
| ARG_MISE_TRUST = tostring(var.mise_trust) | ||
| ARG_INSTALL_DIR = var.install_dir | ||
| ARG_MISE_BIN = var.mise_bin | ||
| ARG_WAIT_SECONDS = tostring(var.wait_seconds) | ||
| }) | ||
| } | ||
|
|
||
| module "coder_utils" { | ||
| source = "registry.coder.com/coder/coder-utils/coder" | ||
| version = "0.0.1" | ||
|
|
||
| agent_id = var.agent_id | ||
| module_directory = local.module_directory | ||
| display_name_prefix = "mise" | ||
| icon = var.icon | ||
| install_script = local.install_script | ||
| post_install_script = local.post_install_script | ||
| } | ||
|
|
||
| output "repo_dir" { | ||
| description = "The repository directory where `mise install` was run." | ||
| value = var.repo_dir | ||
| } | ||
|
|
||
| output "scripts" { | ||
| description = "Ordered list of `coder exp sync` names produced by this module, in run order." | ||
| value = module.coder_utils.scripts | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.