diff --git a/README.md b/README.md index e797298..6e6430a 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 @@ -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 @@ -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`). @@ -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` @@ -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. diff --git a/env0.plugin.yaml b/env0.plugin.yaml index 3f47de9..c6e887f 100644 --- a/env0.plugin.yaml +++ b/env0.plugin.yaml @@ -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: | @@ -24,6 +24,7 @@ run: TMP_DIR="" GH_TMP_DIR="" MARKDOWN_FILE="" + JSON_PAYLOAD_FILE="" ORIGINAL_DIR=$(pwd) cleanup() { @@ -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 @@ -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:]') @@ -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 ;;