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
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The Overmind plugin installs the Overmind CLI (and GitHub CLI) and executes one
- **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
- **wait-for-simulation**: Retrieves simulation output from Overmind and comments on the relevant GitHub PR
- **wait-for-simulation**: Retrieves simulation output from Overmind and comments on the relevant GitHub PR or GitLab MR

## Inputs

Expand All @@ -17,7 +17,7 @@ The Overmind plugin installs the Overmind CLI (and GitHub CLI) and executes one
| `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. Defaults to `true` when running against a PR, otherwise `false`. | 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`. Automatically detects GitHub or GitLab based on repository URL. | No |

## Usage

Expand Down Expand Up @@ -90,7 +90,7 @@ deploy:

### Wait for Simulation (any step after Overmind run)

Fetch the latest Overmind simulation summary for the current env0 deployment and (optionally) comment on the matching GitHub pull request. By default the plugin posts to GitHub whenever the deployment runs in the context of a PR; set `post_comment: false` to skip commenting. When posting, make sure `GH_TOKEN` is set.
Fetch the latest Overmind simulation summary for the current env0 deployment and (optionally) comment on the matching GitHub pull request or GitLab merge request. By default the plugin posts comments whenever the deployment runs in the context of a PR/MR; set `post_comment: false` to skip commenting. The plugin automatically detects whether the repository is GitHub or GitLab based on the repository URL. When posting to GitHub, make sure `GH_TOKEN` is set. When posting to GitLab, make sure `GITLAB_TOKEN` is set.

```yaml
version: 2
Expand Down Expand Up @@ -139,15 +139,15 @@ deploy:

## How It Works

1. **Installation**: The plugin automatically installs the latest version of both the Overmind CLI and GitHub CLI to a writable directory in your PATH.
1. **Installation**: The plugin automatically installs the latest version of the Overmind CLI and GitHub CLI (for GitHub support) to a writable directory in your PATH. GitLab support uses `curl` which is typically available on most systems.

2. **Authentication**: The API key provided in the `api_key` input is set as the `OVERMIND_API_KEY` environment variable.

3. **Action Execution**: Based on the `action` input, the plugin executes the corresponding Overmind/GitHub workflow:
3. **Action Execution**: Based on the `action` input, the plugin executes the corresponding Overmind/GitHub/GitLab workflow:
- `submit-plan`: Uses `$ENV0_TF_PLAN_JSON` to submit the Terraform plan
- `start-change`: Marks the beginning of a change with a ticket link to the env0 deployment
- `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
- `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`).

Expand All @@ -159,7 +159,8 @@ deploy:
- `ENV0_DEPLOYMENT_LOG_ID`
- `ENV0_ORGANIZATION_ID`
- `ENV0_TF_PLAN_JSON` (for submit-plan action)
- `ENV0_PR_NUMBER` (only when `wait-for-simulation` posts to GitHub, i.e., running against a PR)
- `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)

- A valid Overmind API key with the following required scopes:
- `account:read`
Expand All @@ -170,15 +171,28 @@ 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`).

### Creating a `GH_TOKEN`

`wait-for-simulation` calls `gh pr comment`, which requires a GitHub personal access token. To create one:
`wait-for-simulation` calls `gh pr comment` for GitHub repositories, which requires a GitHub personal access token. To create one:

1. Sign in to GitHub and open https://github.com/settings/tokens/new (or the fine-grained token wizard).
2. Choose **Classic** token, set an expiry that matches your security policy, and select the **repo** scope (read/write is needed to comment on PRs).
3. Generate the token and copy it immediately—GitHub will not show it again.
4. Store the token securely in env0 (for example as an environment variable or secret) and expose it to the plugin as `GH_TOKEN`.

### Creating a `GITLAB_TOKEN`

`wait-for-simulation` uses the GitLab API to post comments on merge requests for GitLab repositories. To create a GitLab personal access token:

1. Sign in to GitLab and navigate to your user settings (or group/project settings for project/group tokens).
2. Go to **Access Tokens** (or **Preferences** > **Access Tokens** for user tokens).
3. Create a new token with the `api` scope (read/write is needed to comment on merge requests).
4. Generate the token and copy it immediately—GitLab will not show it again.
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**: The plugin automatically detects whether a repository is GitHub or GitLab based on the `ENV0_PR_SOURCE_REPOSITORY` environment variable. If the repository URL contains "gitlab", it will use GitLab API; otherwise, it will use GitHub CLI.
## Notes

- The plugin automatically detects the operating system and architecture to download the correct Overmind CLI binary.
Expand Down
102 changes: 86 additions & 16 deletions env0.plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ inputs:
description: "The Overmind instance to connect to (defaults to https://app.overmind.tech)"
required: false
post_comment:
description: "Whether wait-for-simulation should post the Overmind markdown to the PR. Defaults to true when ENV0_PR_NUMBER is set, otherwise false."
description: "Whether wait-for-simulation should post the Overmind markdown to the PR/MR. Defaults to true when ENV0_PR_NUMBER is set, otherwise false. Automatically detects GitHub or GitLab based on repository URL."
required: false
run:
exec: |
Expand All @@ -24,6 +24,7 @@ run:
TMP_DIR=""
GH_TMP_DIR=""
MARKDOWN_FILE=""
JSON_PAYLOAD_FILE=""
ORIGINAL_DIR=$(pwd)

cleanup() {
Expand All @@ -36,6 +37,9 @@ run:
if [ -n "${MARKDOWN_FILE}" ] && [ -f "${MARKDOWN_FILE}" ]; then
rm -f "${MARKDOWN_FILE}"
fi
if [ -n "${JSON_PAYLOAD_FILE}" ] && [ -f "${JSON_PAYLOAD_FILE}" ]; then
rm -f "${JSON_PAYLOAD_FILE}"
fi
}
trap cleanup EXIT

Expand Down Expand Up @@ -295,7 +299,7 @@ run:
--ticket-link "${ticket_link}"
;;
wait-for-simulation)
echo "Waiting for Overmind simulation and commenting on PR..."
echo "Waiting for Overmind simulation and commenting on PR/MR..."
should_post_comment="${inputs.post_comment}"
if [ -n "${should_post_comment}" ]; then
should_post_comment=$(echo "${should_post_comment}" | tr '[:upper:]' '[:lower:]')
Expand Down Expand Up @@ -340,25 +344,91 @@ run:
echo "Error: ENV0_PR_SOURCE_REPOSITORY environment variable is not set but post_comment=true"
exit 1
fi
if [ -z "${GH_BINARY}" ] || [ ! -x "${GH_BINARY}" ]; then
echo "Error: GitHub CLI was not installed correctly"
exit 1
fi

if ! "${GH_BINARY}" auth status >/dev/null 2>&1; then
echo "Warning: GitHub CLI authentication not detected. Ensure GH_TOKEN is configured."
# Detect if this is a GitLab repository
if echo "${ENV0_PR_SOURCE_REPOSITORY}" | grep -q "gitlab"; then
# GitLab merge request
if [ -z "${GITLAB_TOKEN}" ]; then
echo "Error: GITLAB_TOKEN environment variable is not set but repository appears to be GitLab"
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}"

# Remove protocol if present
REPO_STR=$(echo "${REPO_STR}" | sed 's|^https\?://||')

# Extract host (default to gitlab.com if not specified)
if echo "${REPO_STR}" | grep -q "/"; then
GITLAB_HOST=$(echo "${REPO_STR}" | cut -d'/' -f1)
PROJECT_PATH=$(echo "${REPO_STR}" | cut -d'/' -f2-)
else
# If no host, assume gitlab.com
GITLAB_HOST="gitlab.com"
PROJECT_PATH="${REPO_STR}"
fi

# Ensure we have https:// prefix for API calls
if [ "${GITLAB_HOST}" != "gitlab.com" ] && ! echo "${GITLAB_HOST}" | grep -q "^https\?://"; then
GITLAB_BASE_URL="https://${GITLAB_HOST}"
elif [ "${GITLAB_HOST}" = "gitlab.com" ]; then
GITLAB_BASE_URL="https://gitlab.com"
else
GITLAB_BASE_URL="${GITLAB_HOST}"
fi

# URL encode the project path (handle spaces and special chars)
PROJECT_PATH_ENCODED=$(echo "${PROJECT_PATH}" | sed 's|/|%2F|g' | sed 's| |%20|g')

MR_IID="${ENV0_PR_NUMBER}"
API_URL="${GITLAB_BASE_URL}/api/v4/projects/${PROJECT_PATH_ENCODED}/merge_requests/${MR_IID}/notes"

echo "Posting simulation results to GitLab MR ${PROJECT_PATH}!${MR_IID}..."

# Create JSON payload file using jq
JSON_PAYLOAD_FILE=$(mktemp)
jq -n --rawfile body "${MARKDOWN_FILE}" '{body: $body}' > "${JSON_PAYLOAD_FILE}"

# Post comment using curl
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
-H "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
-H "Content-Type: application/json" \
--data-binary "@${JSON_PAYLOAD_FILE}" \
"${API_URL}")

# Clean up JSON payload file
rm -f "${JSON_PAYLOAD_FILE}"

if [ "${HTTP_CODE}" -ge 200 ] && [ "${HTTP_CODE}" -lt 300 ]; then
echo "✓ Simulation results posted to GitLab MR"
else
echo "Error: Failed to post comment to GitLab MR (HTTP ${HTTP_CODE})"
exit 1
fi
else
# GitHub pull request
if [ -z "${GH_BINARY}" ] || [ ! -x "${GH_BINARY}" ]; then
echo "Error: GitHub CLI was not installed correctly"
exit 1
fi

if ! "${GH_BINARY}" auth status >/dev/null 2>&1; then
echo "Warning: GitHub CLI authentication not detected. Ensure GH_TOKEN is configured."
fi

echo "Posting simulation results to ${ENV0_PR_SOURCE_REPOSITORY}#${ENV0_PR_NUMBER}..."
"${GH_BINARY}" pr comment "${ENV0_PR_NUMBER}" \
--repo "${ENV0_PR_SOURCE_REPOSITORY}" \
--body-file "${MARKDOWN_FILE}"
echo "✓ Simulation results posted to GitHub PR"
fi

echo "Posting simulation results to ${ENV0_PR_SOURCE_REPOSITORY}#${ENV0_PR_NUMBER}..."
"${GH_BINARY}" pr comment "${ENV0_PR_NUMBER}" \
--repo "${ENV0_PR_SOURCE_REPOSITORY}" \
--body-file "${MARKDOWN_FILE}"
echo "✓ Simulation results posted to GitHub PR"
else
if [ -n "${ENV0_PR_NUMBER}" ]; then
echo "Skipping GitHub comment because post_comment=false."
echo "Skipping comment because post_comment=false."
else
echo "Skipping GitHub comment because ENV0_PR_NUMBER is not set."
echo "Skipping comment because ENV0_PR_NUMBER is not set."
fi
fi
;;
Expand Down