From 27f32d396423dd65340b5271027c4662378b5b9f Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Mon, 9 Mar 2026 17:19:14 +0000 Subject: [PATCH] feat: support self-hosted GitLab (ENG-3025) Self-hosted GitLab environments lack ENV0_PR_SOURCE_REPOSITORY and GITLAB_TOKEN. This adds fallbacks so the plugin works out of the box: - Use ENV0_TEMPLATE_REPOSITORY to derive the GitLab API URL when ENV0_PR_SOURCE_REPOSITORY is unavailable - Accept ENV0_VCS_ACCESS_TOKEN as a fallback for GITLAB_TOKEN - Construct a stable MR URL as --ticket-link so Overmind deduplicates changes across multiple plans for the same merge request - Strip trailing .git from repository URLs Made-with: Cursor --- README.md | 68 +++++++++++++++++++++++++++++++++++------------- env0.plugin.yaml | 47 ++++++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 2f53e79..d70e430 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ This plugin integrates [Overmind](https://www.overmind.tech/) with env0 to track ## Overview The Overmind plugin installs the Overmind CLI (and GitHub CLI) and executes one of four actions: + - **submit-plan**: Submits a Terraform plan to Overmind for analysis - **start-change**: Marks the beginning of a change in Overmind - **end-change**: Marks the completion of a change in Overmind @@ -12,14 +13,14 @@ The Overmind plugin installs the Overmind CLI (and GitHub CLI) and executes one ## Inputs -| Input | Description | Required | -|-------|-------------|----------| -| `action` | The action to perform. Must be one of: `submit-plan`, `start-change`, `end-change`, `wait-for-simulation` | Yes | -| `api_key` | Overmind API key for authentication. Must have the following scopes: `account:read`, `changes:write`, `config:write`, `request:receive`, `sources:read`, `source:write` | Yes | -| `tags` | A comma-separated list of key=value tags to attach to the change (only used with `submit-plan` action) | No | -| `post_comment` | Whether `wait-for-simulation` should post the Overmind markdown to GitHub PR or GitLab MR. Defaults to `true` when running against a PR/MR, otherwise `false`. When `true`, `comment_provider` must be set. | No | -| `comment_provider` | Where `wait-for-simulation` should post comments when `post_comment=true`. Must be one of: `github`, `gitlab`. | No | -| `on_failure` | Behavior when the plugin step errors. `fail` (default) fails the step and blocks the deployment; `pass` allows the deployment to continue even if this step errors. Must be one of: `fail`, `pass`. | No | +| Input | Description | Required | +| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| `action` | The action to perform. Must be one of: `submit-plan`, `start-change`, `end-change`, `wait-for-simulation` | Yes | +| `api_key` | Overmind API key for authentication. Must have the following scopes: `account:read`, `changes:write`, `config:write`, `request:receive`, `sources:read`, `source:write` | Yes | +| `tags` | A comma-separated list of key=value tags to attach to the change (only used with `submit-plan` action) | No | +| `post_comment` | Whether `wait-for-simulation` should post the Overmind markdown to GitHub PR or GitLab MR. Defaults to `true` when running against a PR/MR, otherwise `false`. When `true`, `comment_provider` must be set. | No | +| `comment_provider` | Where `wait-for-simulation` should post comments when `post_comment=true`. Must be one of: `github`, `gitlab`. | No | +| `on_failure` | Behavior when the plugin step errors. `fail` (default) fails the step and blocks the deployment; `pass` allows the deployment to continue even if this step errors. Must be one of: `fail`, `pass`. | No | ## Usage @@ -105,7 +106,7 @@ deploy: inputs: action: wait-for-simulation api_key: ${OVERMIND_API_KEY} - post_comment: false # optional override + post_comment: false # optional override ``` If you want to post a comment, set `comment_provider` explicitly: @@ -140,17 +141,48 @@ deploy: comment_provider: gitlab ``` -### Fail-safe: allow deployment to continue on plugin errors +### Self-Hosted GitLab -By default, if the plugin step fails (e.g. Overmind API error, missing env var, network issue), env0 treats the step as failed and can block the deployment. To allow the deployment to continue even when this step errors, set `on_failure: pass`: +For self-hosted GitLab environments where `ENV0_PR_SOURCE_REPOSITORY` is not available, the plugin falls back to `ENV0_TEMPLATE_REPOSITORY` to derive the GitLab API URL for posting merge request comments. + +For authentication, the plugin uses `GITLAB_TOKEN` if set, otherwise falls back to `ENV0_VCS_ACCESS_TOKEN`. The token must have the GitLab `api` scope to post MR comments. ```yaml +version: 2 +deploy: + steps: + terraformPlan: + after: - name: Submit Plan to Overmind - use: https://github.com/your-org/env0-plugin + use: https://github.com/overmindtech/env0-plugin inputs: action: submit-plan api_key: ${OVERMIND_API_KEY} - on_failure: pass # deployment continues even if this step fails + + terraformApply: + after: + - name: Post Overmind Simulation (Self-Hosted GitLab) + use: https://github.com/overmindtech/env0-plugin + inputs: + action: wait-for-simulation + api_key: ${OVERMIND_API_KEY} + post_comment: true + comment_provider: gitlab +``` + +No `GITLAB_TOKEN` is needed if `ENV0_VCS_ACCESS_TOKEN` is already available in your env0 environment. + +### Fail-safe: allow deployment to continue on plugin errors + +By default, if the plugin step fails (e.g. Overmind API error, missing env var, network issue), env0 treats the step as failed and can block the deployment. To allow the deployment to continue even when this step errors, set `on_failure: pass`: + +```yaml +- name: Submit Plan to Overmind + use: https://github.com/your-org/env0-plugin + inputs: + action: submit-plan + api_key: ${OVERMIND_API_KEY} + on_failure: pass # deployment continues even if this step fails ``` Use `on_failure: pass` when the Overmind integration is optional and you do not want plugin failures to block deployments. @@ -170,7 +202,7 @@ deploy: inputs: action: submit-plan api_key: ${OVERMIND_API_KEY} - + terraformApply: before: - name: Mark Change Started @@ -198,7 +230,7 @@ deploy: - `end-change`: Marks the completion of a change with a ticket link to the env0 deployment - `wait-for-simulation`: Retrieves Overmind simulation results as Markdown and (when `post_comment=true`) posts them to the GitHub PR or GitLab MR (automatically detected based on repository URL) -4. **Ticket Links**: All actions automatically construct a ticket link to the env0 deployment using environment variables (`ENV0_PROJECT_ID`, `ENV0_ENVIRONMENT_ID`, `ENV0_DEPLOYMENT_LOG_ID`, `ENV0_ORGANIZATION_ID`). +4. **Ticket Links**: When `ENV0_PR_NUMBER` is set (i.e., the deployment is triggered by a PR/MR), the plugin constructs a stable merge request URL from `ENV0_PR_SOURCE_REPOSITORY` (or `ENV0_TEMPLATE_REPOSITORY` as a fallback) and `ENV0_PR_NUMBER`. This ensures multiple plans for the same MR update the same Overmind change. For non-PR deployments, the ticket link falls back to the env0 deployment URL. ## Requirements @@ -209,7 +241,7 @@ deploy: - `ENV0_ORGANIZATION_ID` - `ENV0_TF_PLAN_JSON` (for submit-plan action) - `ENV0_PR_NUMBER` (only when `wait-for-simulation` posts comments, i.e., running against a PR/MR) - - `ENV0_PR_SOURCE_REPOSITORY` (only when `wait-for-simulation` posts comments, used to detect GitHub vs GitLab) + - `ENV0_PR_SOURCE_REPOSITORY` (only when `wait-for-simulation` posts comments to GitHub; for GitLab, falls back to `ENV0_TEMPLATE_REPOSITORY`) - A valid Overmind API key with the following required scopes: - `account:read` @@ -220,7 +252,7 @@ deploy: - `source:write` - GitHub authentication for the CLI when `wait-for-simulation` posts to GitHub (set `GH_TOKEN`). -- GitLab authentication when `wait-for-simulation` posts to GitLab (set `GITLAB_TOKEN`). +- GitLab authentication when `wait-for-simulation` posts to GitLab (set `GITLAB_TOKEN`, or rely on `ENV0_VCS_ACCESS_TOKEN` which is automatically available in self-hosted GitLab environments). The token must have the GitLab `api` scope. ### Creating a `GH_TOKEN` @@ -242,9 +274,9 @@ deploy: 5. Store the token securely in env0 (for example as an environment variable or secret) and expose it to the plugin as `GITLAB_TOKEN`. **Note**: When `post_comment=true`, you must set `comment_provider` to `github` or `gitlab`. + ## Notes - The plugin automatically detects the operating system and architecture to download the correct Overmind CLI binary. - The installation directory is automatically selected from writable directories in your PATH. - For the `submit-plan` action, the `ENV0_TF_PLAN_JSON` environment variable must be set (this is automatically provided by env0 after a terraform plan step). - diff --git a/env0.plugin.yaml b/env0.plugin.yaml index 15e7cef..0ef9c12 100644 --- a/env0.plugin.yaml +++ b/env0.plugin.yaml @@ -213,6 +213,21 @@ run: # Construct the env0 deployment URL for the ticket-link ticket_link="https://app.env0.com/p/${ENV0_PROJECT_ID}/environments/${ENV0_ENVIRONMENT_ID}/deployments/${ENV0_DEPLOYMENT_LOG_ID}?organizationId=${ENV0_ORGANIZATION_ID}" + # Override ticket_link with a stable MR/PR URL when available, + # so Overmind deduplicates changes within the same MR/PR + if [ -n "${ENV0_PR_NUMBER}" ]; then + REPO_URL="" + if [ -n "${ENV0_PR_SOURCE_REPOSITORY}" ]; then + REPO_URL="${ENV0_PR_SOURCE_REPOSITORY}" + elif [ -n "${ENV0_TEMPLATE_REPOSITORY}" ]; then + REPO_URL="${ENV0_TEMPLATE_REPOSITORY}" + fi + if [ -n "${REPO_URL}" ]; then + REPO_URL=$(echo "${REPO_URL}" | sed 's|\.git$||') + ticket_link="${REPO_URL}/-/merge_requests/${ENV0_PR_NUMBER}" + fi + fi + # Build description from env0 deployment info description="Env0 Deployment: ${ENV0_PROJECT_NAME} - ${ENV0_ENVIRONMENT_NAME} (${ENV0_DEPLOYMENT_TYPE})" if [ -n "${ENV0_DEPLOYER_NAME}" ]; then @@ -347,10 +362,6 @@ run: echo "Error: ENV0_PR_NUMBER environment variable is not set but post_comment=true" exit 1 fi - if [ -z "${ENV0_PR_SOURCE_REPOSITORY}" ]; then - echo "Error: ENV0_PR_SOURCE_REPOSITORY environment variable is not set but post_comment=true" - exit 1 - fi comment_provider=$(echo "${inputs.comment_provider}" | tr '[:upper:]' '[:lower:]') if [ -z "${comment_provider}" ]; then @@ -361,17 +372,28 @@ run: case "${comment_provider}" in gitlab) # GitLab merge request - if [ -z "${GITLAB_TOKEN}" ]; then - echo "Error: GITLAB_TOKEN environment variable is not set but comment_provider=gitlab" + + # Fall back to ENV0_TEMPLATE_REPOSITORY for self-hosted GitLab + # where ENV0_PR_SOURCE_REPOSITORY is not available + if [ -n "${ENV0_PR_SOURCE_REPOSITORY}" ]; then + REPO_STR="${ENV0_PR_SOURCE_REPOSITORY}" + elif [ -n "${ENV0_TEMPLATE_REPOSITORY}" ]; then + REPO_STR="${ENV0_TEMPLATE_REPOSITORY}" + else + echo "Error: Neither ENV0_PR_SOURCE_REPOSITORY nor ENV0_TEMPLATE_REPOSITORY is set" exit 1 fi - # Extract GitLab base URL and project path from repository string - # ENV0_PR_SOURCE_REPOSITORY format: "group/project" or "https://gitlab.com/group/project" or "gitlab.com/group/project" - REPO_STR="${ENV0_PR_SOURCE_REPOSITORY}" + # Fall back to ENV0_VCS_ACCESS_TOKEN for self-hosted GitLab + GITLAB_TOKEN="${GITLAB_TOKEN:-${ENV0_VCS_ACCESS_TOKEN}}" + if [ -z "${GITLAB_TOKEN}" ]; then + echo "Error: Neither GITLAB_TOKEN nor ENV0_VCS_ACCESS_TOKEN is set" + exit 1 + fi - # Remove protocol if present + # Remove protocol and trailing .git if present REPO_STR=$(echo "${REPO_STR}" | sed 's|^https\?://||') + REPO_STR=$(echo "${REPO_STR}" | sed 's|\.git$||') # Extract host (default to gitlab.com if not specified) if echo "${REPO_STR}" | grep -q "/"; then @@ -422,6 +444,11 @@ run: fi ;; github) + if [ -z "${ENV0_PR_SOURCE_REPOSITORY}" ]; then + echo "Error: ENV0_PR_SOURCE_REPOSITORY environment variable is not set but comment_provider=github" + exit 1 + fi + install_github_cli # GitHub pull request