'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node');
var node = require('@gitbeaker/node');
var zod = require('zod');
var errors = require('@backstage/errors');
var rest = require('@gitbeaker/rest');
var yaml = require('yaml');
var path = require('path');
var backendCommon = require('@backstage/backend-common');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var yaml__default = /*#__PURE__*/_interopDefaultLegacy(yaml);
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);

const commonGitlabConfig = zod.z.object({
  repoUrl: zod.z.string({ description: "Repository Location" }),
  token: zod.z.string({ description: "The token to use for authorization to GitLab" }).optional()
});
const commonGitlabConfigExample = {
  repoUrl: "gitlab.com?owner=namespace-or-owner&repo=project-name",
  token: "${{ secrets.USER_OAUTH_TOKEN }}"
};

const parseRepoHost = (repoUrl) => {
  let parsed;
  try {
    parsed = new URL(`https://${repoUrl}`);
  } catch (error) {
    throw new errors.InputError(
      `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
    );
  }
  return parsed.host;
};
const getToken = (config, integrations) => {
  const host = parseRepoHost(config.repoUrl);
  const integrationConfig = integrations.gitlab.byHost(host);
  if (!integrationConfig) {
    throw new errors.InputError(
      `No matching integration configuration for host ${host}, please check your integrations config`
    );
  }
  const token = config.token || integrationConfig.config.token;
  const tokenType = config.token ? "oauthToken" : "token";
  if (tokenType === "oauthToken") {
    throw new errors.InputError(`OAuth Token is currently not supported`);
  }
  return { token, integrationConfig };
};
const parseRepoUrl = (repoUrl, integrations) => {
  var _a, _b;
  let parsed;
  try {
    parsed = new URL(`https://${repoUrl}`);
  } catch (error) {
    throw new errors.InputError(
      `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
    );
  }
  const host = parsed.host;
  const owner = (_a = parsed.searchParams.get("owner")) != null ? _a : void 0;
  const repo = parsed.searchParams.get("repo");
  const type = (_b = integrations.byHost(host)) == null ? void 0 : _b.type;
  if (!type) {
    throw new errors.InputError(
      `No matching integration configuration for host ${host}, please check your integrations config`
    );
  }
  return { host, owner, repo };
};
function getClient(props) {
  const { host, token, integrations } = props;
  const integrationConfig = integrations.gitlab.byHost(host);
  if (!integrationConfig) {
    throw new errors.InputError(
      `No matching integration configuration for host ${host}, please check your integrations config`
    );
  }
  const { config } = integrationConfig;
  if (!config.token && !token) {
    throw new errors.InputError(`No token available for host ${host}`);
  }
  const requestToken = token || config.token;
  const tokenType = token ? "oauthToken" : "token";
  const gitlabOptions = {
    host: config.baseUrl
  };
  gitlabOptions[tokenType] = requestToken;
  return new rest.Gitlab(gitlabOptions);
}
function convertDate(inputDate, defaultDate) {
  try {
    return inputDate ? new Date(inputDate).toISOString() : new Date(defaultDate).toISOString();
  } catch (error) {
    throw new errors.InputError(`Error converting input date - ${error}`);
  }
}
async function getTopLevelParentGroup(client, groupId) {
  try {
    const topParentGroup = await client.Groups.show(groupId);
    if (topParentGroup.parent_id) {
      return getTopLevelParentGroup(
        client,
        topParentGroup.parent_id
      );
    }
    return topParentGroup;
  } catch (error) {
    throw new errors.InputError(
      `Error finding top-level parent group ID: ${error.message}`
    );
  }
}
async function checkEpicScope(client, projectId, epicId) {
  try {
    const project = await client.Projects.show(projectId);
    if (!project) {
      throw new errors.InputError(
        `Project with id ${projectId} not found. Check your GitLab instance.`
      );
    }
    const topParentGroup = await getTopLevelParentGroup(
      client,
      project.namespace.id
    );
    if (!topParentGroup) {
      throw new errors.InputError(`Couldn't find a suitable top-level parent group.`);
    }
    const epic = (await client.Epics.all(topParentGroup.id)).find(
      (x) => x.id === epicId
    );
    if (!epic) {
      throw new errors.InputError(
        `Epic with id ${epicId} not found in the top-level parent group ${topParentGroup.name}.`
      );
    }
    const epicGroup = await client.Groups.show(epic.group_id);
    const projectNamespace = project.path_with_namespace;
    return projectNamespace.startsWith(epicGroup.full_path);
  } catch (error) {
    throw new errors.InputError(`Could not find epic scope: ${error.message}`);
  }
}

const createGitlabGroupEnsureExistsAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "gitlab:group:ensureExists",
    description: "Ensures a Gitlab group exists",
    supportsDryRun: true,
    schema: {
      input: commonGitlabConfig.merge(
        zod.z.object({
          path: zod.z.array(zod.z.string(), {
            description: "A path of group names that is ensured to exist"
          }).min(1)
        })
      ),
      output: zod.z.object({
        groupId: zod.z.number({ description: "The id of the innermost sub-group" }).optional()
      })
    },
    async handler(ctx) {
      if (ctx.isDryRun) {
        ctx.output("groupId", 42);
        return;
      }
      const { path } = ctx.input;
      const { token, integrationConfig } = getToken(ctx.input, integrations);
      const api = new node.Gitlab({
        host: integrationConfig.config.baseUrl,
        token
      });
      let currentPath = null;
      let parent = null;
      for (const pathElement of path) {
        const fullPath = currentPath ? `${currentPath}/${pathElement}` : pathElement;
        const result = await api.Groups.search(
          fullPath
        );
        const subGroup = result.find(
          (searchPathElem) => searchPathElem.full_path === fullPath
        );
        if (!subGroup) {
          ctx.logger.info(`creating missing group ${fullPath}`);
          parent = await api.Groups.create(
            pathElement,
            pathElement,
            parent ? {
              parent_id: parent.id
            } : {}
          );
        } else {
          parent = subGroup;
        }
        currentPath = fullPath;
      }
      if (parent !== null) {
        ctx.output("groupId", parent == null ? void 0 : parent.id);
      }
    }
  });
};

const createGitlabProjectDeployTokenAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "gitlab:projectDeployToken:create",
    schema: {
      input: commonGitlabConfig.merge(
        zod.z.object({
          projectId: zod.z.union([zod.z.number(), zod.z.string()], {
            description: "Project ID"
          }),
          name: zod.z.string({ description: "Deploy Token Name" }),
          username: zod.z.string({ description: "Deploy Token Username" }).optional(),
          scopes: zod.z.array(zod.z.string(), { description: "Scopes" }).optional()
        })
      ),
      output: zod.z.object({
        deploy_token: zod.z.string({ description: "Deploy Token" }),
        user: zod.z.string({ description: "User" })
      })
    },
    async handler(ctx) {
      ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
      const { projectId, name, username, scopes } = ctx.input;
      const { token, integrationConfig } = getToken(ctx.input, integrations);
      const api = new node.Gitlab({
        host: integrationConfig.config.baseUrl,
        token
      });
      const deployToken = await api.ProjectDeployTokens.add(
        projectId,
        name,
        scopes,
        {
          username
        }
      );
      if (!deployToken.hasOwnProperty("token")) {
        throw new errors.InputError(`No deploy_token given from gitlab instance`);
      }
      ctx.output("deploy_token", deployToken.token);
      ctx.output("user", deployToken.username);
    }
  });
};

const examples$2 = [
  {
    description: "Create a GitLab project access token with minimal options.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "createAccessToken",
          action: "gitlab:projectAccessToken:create",
          name: "Create GitLab Project Access Token",
          input: {
            repoUrl: "gitlab.com?repo=repo&owner=owner",
            projectId: "456"
          }
        }
      ]
    })
  },
  {
    description: "Create a GitLab project access token with custom scopes.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "createAccessToken",
          action: "gitlab:projectAccessToken:create",
          name: "Create GitLab Project Access Token",
          input: {
            repoUrl: "gitlab.com?repo=repo&owner=owner",
            projectId: "789",
            scopes: ["read_registry", "write_repository"]
          }
        }
      ]
    })
  },
  {
    description: "Create a GitLab project access token with a specified name.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "createAccessToken",
          action: "gitlab:projectAccessToken:create",
          name: "Create GitLab Project Access Token",
          input: {
            repoUrl: "gitlab.com?repo=repo&owner=owner",
            projectId: "101112",
            name: "my-custom-token"
          }
        }
      ]
    })
  },
  {
    description: "Create a GitLab project access token with a numeric project ID.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "createAccessToken",
          action: "gitlab:projectAccessToken:create",
          name: "Create GitLab Project Access Token",
          input: {
            repoUrl: "gitlab.com?repo=repo&owner=owner",
            projectId: 42
          }
        }
      ]
    })
  },
  {
    description: "Create a GitLab project access token using specific GitLab integrations.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "createAccessToken",
          action: "gitlab:projectAccessToken:create",
          name: "Create GitLab Project Access Token",
          input: {
            repoUrl: "gitlab.com?repo=repo&owner=owner",
            projectId: "123"
          }
        }
      ]
    })
  }
];

const createGitlabProjectAccessTokenAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "gitlab:projectAccessToken:create",
    examples: examples$2,
    schema: {
      input: commonGitlabConfig.merge(
        zod.z.object({
          projectId: zod.z.union([zod.z.number(), zod.z.string()], {
            description: "Project ID"
          }),
          name: zod.z.string({ description: "Deploy Token Name" }).optional(),
          accessLevel: zod.z.number({ description: "Access Level of the Token" }).optional(),
          scopes: zod.z.array(zod.z.string(), { description: "Scopes" }).optional()
        })
      ),
      output: zod.z.object({
        access_token: zod.z.string({ description: "Access Token" })
      })
    },
    async handler(ctx) {
      ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`);
      const { projectId, name, accessLevel, scopes } = ctx.input;
      const { token, integrationConfig } = getToken(ctx.input, integrations);
      const response = await fetch(
        `${integrationConfig.config.baseUrl}/api/v4/projects/${projectId}/access_tokens`,
        {
          method: "POST",
          // *GET, POST, PUT, DELETE, etc.
          headers: {
            "PRIVATE-TOKEN": token,
            "Content-Type": "application/json"
          },
          body: JSON.stringify({
            name,
            scopes,
            access_level: accessLevel
          })
        }
      );
      const result = await response.json();
      ctx.output("access_token", result.token);
    }
  });
};

const createGitlabProjectVariableAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "gitlab:projectVariable:create",
    schema: {
      input: commonGitlabConfig.merge(
        zod.z.object({
          projectId: zod.z.union([zod.z.number(), zod.z.string()], {
            description: "Project ID"
          }),
          key: zod.z.string({
            description: "The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed"
          }).regex(/^[A-Za-z0-9_]{1,255}$/),
          value: zod.z.string({ description: "The value of a variable" }),
          variableType: zod.z.string({
            description: "Variable Type (env_var or file)"
          }),
          variableProtected: zod.z.boolean({ description: "Whether the variable is protected" }).default(false).optional(),
          masked: zod.z.boolean({ description: "Whether the variable is masked" }).default(false).optional(),
          raw: zod.z.boolean({ description: "Whether the variable is expandable" }).default(false).optional(),
          environmentScope: zod.z.string({ description: "The environment_scope of the variable" }).default("*").optional()
        })
      )
    },
    async handler(ctx) {
      const {
        projectId,
        key,
        value,
        variableType,
        variableProtected = false,
        masked = false,
        raw = false,
        environmentScope = "*"
      } = ctx.input;
      const { token, integrationConfig } = getToken(ctx.input, integrations);
      const api = new node.Gitlab({
        host: integrationConfig.config.baseUrl,
        token
      });
      await api.ProjectVariables.create(projectId, {
        key,
        value,
        variable_type: variableType,
        protected: variableProtected,
        masked,
        raw,
        environment_scope: environmentScope
      });
    }
  });
};

const examples$1 = [
  {
    description: "Create a GitLab issue with minimal options",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "gitlabIssue",
          name: "Issues",
          action: "gitlab:issues:create",
          input: {
            ...commonGitlabConfigExample,
            projectId: 12,
            title: "Test Issue",
            description: "This is the description of the issue"
          }
        }
      ]
    })
  },
  {
    description: "Create a GitLab issue with assignees and date options",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "gitlabIssue",
          name: "Issues",
          action: "gitlab:issues:create",
          input: {
            ...commonGitlabConfigExample,
            projectId: 12,
            title: "Test Issue",
            assignees: [18],
            description: "This is the description of the issue",
            createdAt: "2022-09-27 18:00:00.000",
            dueDate: "2022-09-28 12:00:00.000"
          }
        }
      ]
    })
  },
  {
    description: "Create a GitLab Issue with several options",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "gitlabIssue",
          name: "Issues",
          action: "gitlab:issues:create",
          input: {
            ...commonGitlabConfigExample,
            projectId: 12,
            title: "Test Issue",
            assignees: [18, 15],
            description: "This is the description of the issue",
            confidential: false,
            createdAt: "2022-09-27 18:00:00.000",
            dueDate: "2022-09-28 12:00:00.000",
            discussionToResolve: 1,
            epicId: 1,
            labels: "phase1:label1,phase2:label2"
          }
        }
      ]
    })
  }
];

var IssueType = /* @__PURE__ */ ((IssueType2) => {
  IssueType2["ISSUE"] = "issue";
  IssueType2["INCIDENT"] = "incident";
  IssueType2["TEST"] = "test_case";
  return IssueType2;
})(IssueType || {});
const issueInputProperties = zod.z.object({
  projectId: zod.z.number().describe("Project Id"),
  title: zod.z.string({ description: "Title of the issue" }),
  assignees: zod.z.array(zod.z.number(), {
    description: "IDs of the users to assign the issue to."
  }).optional(),
  confidential: zod.z.boolean({ description: "Issue Confidentiality" }).optional(),
  description: zod.z.string().describe("Issue description").max(1048576).optional(),
  createdAt: zod.z.string().describe("Creation date/time").regex(
    /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/,
    "Invalid date format. Use YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss.SSSZ"
  ).optional(),
  dueDate: zod.z.string().describe("Due date/time").regex(
    /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/,
    "Invalid date format. Use YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss.SSSZ"
  ).optional(),
  discussionToResolve: zod.z.string({
    description: 'Id of a discussion to resolve. Use in combination with "merge_request_to_resolve_discussions_of"'
  }).optional(),
  epicId: zod.z.number({ description: "Id of the linked Epic" }).min(0, "Valid values should be equal or greater than zero").optional(),
  labels: zod.z.string({ description: "Labels to apply" }).optional(),
  issueType: zod.z.nativeEnum(IssueType, {
    description: "Type of the issue"
  }).optional(),
  mergeRequestToResolveDiscussionsOf: zod.z.number({
    description: "IID of a merge request in which to resolve all issues"
  }).optional(),
  milestoneId: zod.z.number({ description: "Global ID of a milestone to assign the issue" }).optional(),
  weight: zod.z.number({ description: "The issue weight" }).min(0).refine((value) => {
    const isValid = value >= 0;
    if (!isValid) {
      return {
        message: "Valid values should be equal or greater than zero"
      };
    }
    return isValid;
  }).optional()
});
const issueOutputProperties = zod.z.object({
  issueUrl: zod.z.string({ description: "Issue Url" }),
  issueId: zod.z.number({ description: "Issue Id" })
});
const createGitlabIssueAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "gitlab:issues:create",
    description: "Creates a Gitlab issue.",
    examples: examples$1,
    schema: {
      input: commonGitlabConfig.merge(issueInputProperties),
      output: issueOutputProperties
    },
    async handler(ctx) {
      try {
        const {
          repoUrl,
          projectId,
          title,
          description = "",
          confidential = false,
          assignees = [],
          createdAt = "",
          dueDate,
          discussionToResolve = "",
          epicId,
          labels = "",
          issueType,
          mergeRequestToResolveDiscussionsOf,
          milestoneId,
          weight,
          token
        } = commonGitlabConfig.merge(issueInputProperties).parse(ctx.input);
        const { host } = parseRepoUrl(repoUrl, integrations);
        const api = getClient({ host, integrations, token });
        let isEpicScoped = false;
        if (epicId) {
          isEpicScoped = await checkEpicScope(
            api,
            projectId,
            epicId
          );
          if (isEpicScoped) {
            ctx.logger.info("Epic is within Project Scope");
          } else {
            ctx.logger.warn(
              "Chosen epic is not within the Project Scope. The issue will be created without an associated epic."
            );
          }
        }
        const mappedCreatedAt = convertDate(
          String(createdAt),
          (/* @__PURE__ */ new Date()).toISOString()
        );
        const mappedDueDate = dueDate ? convertDate(String(dueDate), (/* @__PURE__ */ new Date()).toISOString()) : void 0;
        const issueOptions = {
          description,
          assigneeIds: assignees,
          confidential,
          epicId: isEpicScoped ? epicId : void 0,
          labels,
          createdAt: mappedCreatedAt,
          dueDate: mappedDueDate,
          discussionToResolve,
          issueType,
          mergeRequestToResolveDiscussionsOf,
          milestoneId,
          weight
        };
        const response = await api.Issues.create(
          projectId,
          title,
          issueOptions
        );
        ctx.output("issueId", response.id);
        ctx.output("issueUrl", response.web_url);
      } catch (error) {
        if (error instanceof zod.z.ZodError) {
          throw new errors.InputError(`Validation error: ${error.message}`, {
            validationErrors: error.errors
          });
        }
        throw new errors.InputError(`Failed to create GitLab issue: ${error.message}`);
      }
    }
  });
};

const examples = [
  {
    description: "Initializes a git repository of the content in the workspace, and publishes it to GitLab.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "publish",
          action: "publish:gitlab",
          name: "Publish to GitLab",
          input: {
            repoUrl: "gitlab.com?repo=project_name&owner=group_name"
          }
        }
      ]
    })
  },
  {
    description: "Add a description.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "publish",
          action: "publish:gitlab",
          name: "Publish to GitLab",
          input: {
            repoUrl: "gitlab.com?repo=project_name&owner=group_name",
            description: "Initialize a git repository"
          }
        }
      ]
    })
  },
  {
    description: "Sets the commit message on the repository. The default value is `initial commit`.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "publish",
          action: "publish:gitlab",
          name: "Publish to GitLab",
          input: {
            repoUrl: "gitlab.com?repo=project_name&owner=group_name",
            description: "Initialize a git repository",
            gitCommitMessage: "Started a project."
          }
        }
      ]
    })
  },
  {
    description: "Initializes a git repository with additional settings.",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "publish",
          action: "publish:gitlab",
          name: "Publish to GitLab",
          input: {
            repoUrl: "gitlab.com?repo=project_name&owner=group_name",
            settings: {
              ci_config_path: ".gitlab-ci.yml",
              visibility: "public"
            }
          }
        }
      ]
    })
  },
  {
    description: "Initializes a git repository with branches settings",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "publish",
          action: "publish:gitlab",
          name: "Publish to GitLab",
          input: {
            repoUrl: "gitlab.com?repo=project_name&owner=group_name",
            branches: [
              {
                name: "dev",
                create: true,
                protected: true,
                ref: "master"
              },
              {
                name: "master",
                protected: true
              }
            ]
          }
        }
      ]
    })
  },
  {
    description: "Initializes a git repository with environment variables",
    example: yaml__default["default"].stringify({
      steps: [
        {
          id: "publish",
          action: "publish:gitlab",
          name: "Publish to GitLab",
          input: {
            repoUrl: "gitlab.com?repo=project_name&owner=group_name",
            projectVariables: [
              {
                key: "key1",
                value: "value1",
                protected: true,
                masked: false
              },
              {
                key: "key2",
                value: "value2",
                protected: true,
                masked: false
              }
            ]
          }
        }
      ]
    })
  }
];

function createPublishGitlabAction(options) {
  const { integrations, config } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "publish:gitlab",
    description: "Initializes a git repository of the content in the workspace, and publishes it to GitLab.",
    examples,
    schema: {
      input: {
        type: "object",
        required: ["repoUrl"],
        properties: {
          repoUrl: {
            title: "Repository Location",
            type: "string",
            description: `Accepts the format 'gitlab.com?repo=project_name&owner=group_name' where 'project_name' is the repository name and 'group_name' is a group or username`
          },
          repoVisibility: {
            title: "Repository Visibility",
            description: `Sets the visibility of the repository. The default value is 'private'. (deprecated, use settings.visibility instead)`,
            type: "string",
            enum: ["private", "public", "internal"]
          },
          defaultBranch: {
            title: "Default Branch",
            type: "string",
            description: `Sets the default branch on the repository. The default value is 'master'`
          },
          gitCommitMessage: {
            title: "Git Commit Message",
            type: "string",
            description: `Sets the commit message on the repository. The default value is 'initial commit'`
          },
          gitAuthorName: {
            title: "Default Author Name",
            type: "string",
            description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
          },
          gitAuthorEmail: {
            title: "Default Author Email",
            type: "string",
            description: `Sets the default author email for the commit.`
          },
          sourcePath: {
            title: "Source Path",
            description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
            type: "string"
          },
          token: {
            title: "Authentication Token",
            type: "string",
            description: "The token to use for authorization to GitLab"
          },
          setUserAsOwner: {
            title: "Set User As Owner",
            type: "boolean",
            description: "Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host"
          },
          topics: {
            title: "Topic labels",
            description: "Topic labels to apply on the repository. (deprecated, use settings.topics instead)",
            type: "array",
            items: {
              type: "string"
            }
          },
          settings: {
            title: "Project settings",
            description: "Additional project settings, based on https://docs.gitlab.com/ee/api/projects.html#create-project attributes",
            type: "object",
            properties: {
              path: {
                title: "Project path",
                description: "Repository name for new project. Generated based on name if not provided (generated as lowercase with dashes).",
                type: "string"
              },
              auto_devops_enabled: {
                title: "Auto DevOps enabled",
                description: "Enable Auto DevOps for this project",
                type: "boolean"
              },
              ci_config_path: {
                title: "CI config path",
                description: "Custom CI config path for this project",
                type: "string"
              },
              description: {
                title: "Project description",
                description: "Short project description",
                type: "string"
              },
              topics: {
                title: "Topic labels",
                description: "Topic labels to apply on the repository",
                type: "array",
                items: {
                  type: "string"
                }
              },
              visibility: {
                title: "Project visibility",
                description: "The visibility of the project. Can be private, internal, or public. The default value is private.",
                type: "string",
                enum: ["private", "public", "internal"]
              }
            }
          },
          branches: {
            title: "Project branches settings",
            type: "array",
            items: {
              type: "object",
              required: ["name"],
              properties: {
                name: {
                  title: "Branch name",
                  type: "string"
                },
                protect: {
                  title: "Should branch be protected",
                  description: `Will mark branch as protected. The default value is 'false'`,
                  type: "boolean"
                },
                create: {
                  title: "Should branch be created",
                  description: `If branch does not exist, it will be created from provided ref. The default value is 'false'`,
                  type: "boolean"
                },
                ref: {
                  title: "Branch reference",
                  description: `Branch reference to create branch from. The default value is 'master'`,
                  type: "string"
                }
              }
            }
          },
          projectVariables: {
            title: "Project variables",
            description: "Project variables settings based on Gitlab Project Environments API - https://docs.gitlab.com/ee/api/project_level_variables.html#create-a-variable",
            type: "array",
            items: {
              type: "object",
              required: ["key", "value"],
              properties: {
                key: {
                  title: "Variable key",
                  description: "The key of a variable; must have no more than 255 characters; only A-Z, a-z, 0-9, and _ are allowed",
                  type: "string"
                },
                value: {
                  title: "Variable value",
                  description: "The value of a variable",
                  type: "string"
                },
                description: {
                  title: "Variable description",
                  description: `The description of the variable. The default value is 'null'`,
                  type: "string"
                },
                variable_type: {
                  title: "Variable type",
                  description: `The type of a variable. The default value is 'env_var'`,
                  type: "string",
                  enum: ["env_var", "file"]
                },
                protected: {
                  title: "Variable protection",
                  description: `Whether the variable is protected. The default value is 'false'`,
                  type: "boolean"
                },
                raw: {
                  title: "Variable raw",
                  description: `Whether the variable is in raw format. The default value is 'false'`,
                  type: "boolean"
                },
                environment_scope: {
                  title: "Variable environment scope",
                  description: `The environment_scope of the variable. The default value is '*'`,
                  type: "string"
                }
              }
            }
          }
        }
      },
      output: {
        type: "object",
        properties: {
          remoteUrl: {
            title: "A URL to the repository with the provider",
            type: "string"
          },
          repoContentsUrl: {
            title: "A URL to the root of the repository",
            type: "string"
          },
          projectId: {
            title: "The ID of the project",
            type: "string"
          },
          commitHash: {
            title: "The git commit hash of the initial commit",
            type: "string"
          }
        }
      }
    },
    async handler(ctx) {
      var _a, _b, _c, _d, _e;
      const {
        repoUrl,
        repoVisibility = "private",
        defaultBranch = "master",
        gitCommitMessage = "initial commit",
        gitAuthorName,
        gitAuthorEmail,
        setUserAsOwner = false,
        topics = [],
        settings = {},
        branches = [],
        projectVariables = []
      } = ctx.input;
      const { owner, repo, host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
      if (!owner) {
        throw new errors.InputError(
          `No owner provided for host: ${host}, and repo ${repo}`
        );
      }
      const integrationConfig = integrations.gitlab.byHost(host);
      if (!integrationConfig) {
        throw new errors.InputError(
          `No matching integration configuration for host ${host}, please check your integrations config`
        );
      }
      if (!integrationConfig.config.token && !ctx.input.token) {
        throw new errors.InputError(`No token available for host ${host}`);
      }
      const token = ctx.input.token || integrationConfig.config.token;
      const tokenType = ctx.input.token ? "oauthToken" : "token";
      const client = new node.Gitlab({
        host: integrationConfig.config.baseUrl,
        [tokenType]: token
      });
      let targetNamespaceId;
      try {
        const namespaceResponse = await client.Namespaces.show(owner);
        targetNamespaceId = namespaceResponse.id;
      } catch (e) {
        if (e.response && e.response.statusCode === 404) {
          throw new errors.InputError(
            `The namespace ${owner} is not found or the user doesn't have permissions to access it`
          );
        }
        throw e;
      }
      const { id: userId } = await client.Users.current();
      if (!targetNamespaceId) {
        targetNamespaceId = userId;
      }
      const { id: projectId, http_url_to_repo } = await client.Projects.create({
        namespace_id: targetNamespaceId,
        name: repo,
        visibility: repoVisibility,
        ...topics.length ? { topics } : {},
        ...Object.keys(settings).length ? { ...settings } : {}
      });
      if (setUserAsOwner && integrationConfig.config.token) {
        const adminClient = new node.Gitlab({
          host: integrationConfig.config.baseUrl,
          token: integrationConfig.config.token
        });
        await adminClient.ProjectMembers.add(projectId, userId, 50);
      }
      const remoteUrl = http_url_to_repo.replace(/\.git$/, "");
      const repoContentsUrl = `${remoteUrl}/-/blob/${defaultBranch}`;
      const gitAuthorInfo = {
        name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
        email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
      };
      const commitResult = await pluginScaffolderNode.initRepoAndPush({
        dir: pluginScaffolderNode.getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
        remoteUrl: http_url_to_repo,
        defaultBranch,
        auth: {
          username: "oauth2",
          password: token
        },
        logger: ctx.logger,
        commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
        gitAuthorInfo
      });
      if (branches) {
        for (const branch of branches) {
          const {
            name,
            protect = false,
            create = false,
            ref = "master"
          } = branch;
          if (create) {
            try {
              await client.Branches.create(projectId, name, ref);
            } catch (e) {
              throw new errors.InputError(
                `Branch creation failed for ${name}. ${printGitlabError(e)}`
              );
            }
            ctx.logger.info(
              `Branch ${name} created for ${projectId} with ref ${ref}`
            );
          }
          if (protect) {
            try {
              await client.ProtectedBranches.protect(projectId, name);
            } catch (e) {
              throw new errors.InputError(
                `Branch protection failed for ${name}. ${printGitlabError(e)}`
              );
            }
            ctx.logger.info(`Branch ${name} protected for ${projectId}`);
          }
        }
      }
      if (projectVariables) {
        for (const variable of projectVariables) {
          const variableWithDefaults = Object.assign(variable, {
            variable_type: (_a = variable.variable_type) != null ? _a : "env_var",
            protected: (_b = variable.protected) != null ? _b : false,
            masked: (_c = variable.masked) != null ? _c : false,
            raw: (_d = variable.raw) != null ? _d : false,
            environment_scope: (_e = variable.environment_scope) != null ? _e : "*"
          });
          try {
            await client.ProjectVariables.create(
              projectId,
              variableWithDefaults
            );
          } catch (e) {
            throw new errors.InputError(
              `Environment variable creation failed for ${variableWithDefaults.key}. ${printGitlabError(e)}`
            );
          }
        }
      }
      ctx.output("commitHash", commitResult == null ? void 0 : commitResult.commitHash);
      ctx.output("remoteUrl", remoteUrl);
      ctx.output("repoContentsUrl", repoContentsUrl);
      ctx.output("projectId", projectId);
    }
  });
}
function printGitlabError(error) {
  return JSON.stringify({ code: error.code, message: error.description });
}

function createGitlabApi(options) {
  const { integrations, token: providedToken, repoUrl } = options;
  const { host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
  const integrationConfig = integrations.gitlab.byHost(host);
  if (!integrationConfig) {
    throw new errors.InputError(
      `No matching integration configuration for host ${host}, please check your integrations config`
    );
  }
  if (!integrationConfig.config.token && !providedToken) {
    throw new errors.InputError(`No token available for host ${host}`);
  }
  const token = providedToken != null ? providedToken : integrationConfig.config.token;
  const tokenType = providedToken ? "oauthToken" : "token";
  return new node.Gitlab({
    host: integrationConfig.config.baseUrl,
    [tokenType]: token
  });
}

const createPublishGitlabMergeRequestAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "publish:gitlab:merge-request",
    schema: {
      input: {
        required: ["repoUrl", "branchName"],
        type: "object",
        properties: {
          repoUrl: {
            type: "string",
            title: "Repository Location",
            description: `Accepts the format 'gitlab.com?repo=project_name&owner=group_name' where 'project_name' is the repository name and 'group_name' is a group or username`
          },
          /** @deprecated projectID is passed as query parameters in the repoUrl */
          projectid: {
            type: "string",
            title: "projectid",
            description: "Project ID/Name(slug) of the Gitlab Project"
          },
          title: {
            type: "string",
            title: "Merge Request Name",
            description: "The name for the merge request"
          },
          description: {
            type: "string",
            title: "Merge Request Description",
            description: "The description of the merge request"
          },
          branchName: {
            type: "string",
            title: "Source Branch Name",
            description: "The source branch name of the merge request"
          },
          targetBranchName: {
            type: "string",
            title: "Target Branch Name",
            description: "The target branch name of the merge request"
          },
          sourcePath: {
            type: "string",
            title: "Working Subdirectory",
            description: "Subdirectory of working directory to copy changes from"
          },
          targetPath: {
            type: "string",
            title: "Repository Subdirectory",
            description: "Subdirectory of repository to apply changes to"
          },
          token: {
            title: "Authentication Token",
            type: "string",
            description: "The token to use for authorization to GitLab"
          },
          commitAction: {
            title: "Commit action",
            type: "string",
            enum: ["create", "update", "delete"],
            description: "The action to be used for git commit. Defaults to create."
          },
          removeSourceBranch: {
            title: "Delete source branch",
            type: "boolean",
            description: "Option to delete source branch once the MR has been merged. Default: false"
          },
          assignee: {
            title: "Merge Request Assignee",
            type: "string",
            description: "User this merge request will be assigned to"
          }
        }
      },
      output: {
        type: "object",
        properties: {
          targetBranchName: {
            title: "Target branch name of the merge request",
            type: "string"
          },
          projectid: {
            title: "Gitlab Project id/Name(slug)",
            type: "string"
          },
          projectPath: {
            title: "Gitlab Project path",
            type: "string"
          },
          mergeRequestUrl: {
            title: "MergeRequest(MR) URL",
            type: "string",
            description: "Link to the merge request in GitLab"
          }
        }
      }
    },
    async handler(ctx) {
      const {
        assignee,
        branchName,
        targetBranchName,
        description,
        repoUrl,
        removeSourceBranch,
        targetPath,
        sourcePath,
        title,
        token
      } = ctx.input;
      const { owner, repo, project } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
      const repoID = project ? project : `${owner}/${repo}`;
      const api = createGitlabApi({
        integrations,
        token,
        repoUrl
      });
      let assigneeId = void 0;
      if (assignee !== void 0) {
        try {
          const assigneeUser = await api.Users.username(assignee);
          assigneeId = assigneeUser[0].id;
        } catch (e) {
          ctx.logger.warn(
            `Failed to find gitlab user id for ${assignee}: ${e}. Proceeding with MR creation without an assignee.`
          );
        }
      }
      let fileRoot;
      if (sourcePath) {
        fileRoot = backendCommon.resolveSafeChildPath(ctx.workspacePath, sourcePath);
      } else if (targetPath) {
        fileRoot = backendCommon.resolveSafeChildPath(ctx.workspacePath, targetPath);
      } else {
        fileRoot = ctx.workspacePath;
      }
      const fileContents = await pluginScaffolderNode.serializeDirectoryContents(fileRoot, {
        gitignore: true
      });
      const actions = fileContents.map((file) => {
        var _a;
        return {
          action: (_a = ctx.input.commitAction) != null ? _a : "create",
          filePath: targetPath ? path__default["default"].posix.join(targetPath, file.path) : file.path,
          encoding: "base64",
          content: file.content.toString("base64"),
          execute_filemode: file.executable
        };
      });
      let targetBranch = targetBranchName;
      if (!targetBranch) {
        const projects = await api.Projects.show(repoID);
        const { default_branch: defaultBranch } = projects;
        targetBranch = defaultBranch;
      }
      try {
        await api.Branches.create(repoID, branchName, String(targetBranch));
      } catch (e) {
        throw new errors.InputError(
          `The branch creation failed. Please check that your repo does not already contain a branch named '${branchName}'. ${e}`
        );
      }
      try {
        await api.Commits.create(repoID, branchName, ctx.input.title, actions);
      } catch (e) {
        throw new errors.InputError(
          `Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${e}`
        );
      }
      try {
        const mergeRequestUrl = await api.MergeRequests.create(
          repoID,
          branchName,
          String(targetBranch),
          title,
          {
            description,
            removeSourceBranch: removeSourceBranch ? removeSourceBranch : false,
            assigneeId
          }
        ).then((mergeRequest) => {
          return mergeRequest.web_url;
        });
        ctx.output("projectid", repoID);
        ctx.output("targetBranchName", targetBranch);
        ctx.output("projectPath", repoID);
        ctx.output("mergeRequestUrl", mergeRequestUrl);
      } catch (e) {
        throw new errors.InputError(`Merge request creation failed${e}`);
      }
    }
  });
};

const createGitlabRepoPushAction = (options) => {
  const { integrations } = options;
  return pluginScaffolderNode.createTemplateAction({
    id: "gitlab:repo:push",
    schema: {
      input: {
        required: ["repoUrl", "branchName", "commitMessage"],
        type: "object",
        properties: {
          repoUrl: {
            type: "string",
            title: "Repository Location",
            description: `Accepts the format 'gitlab.com?repo=project_name&owner=group_name' where 'project_name' is the repository name and 'group_name' is a group or username`
          },
          branchName: {
            type: "string",
            title: "Source Branch Name",
            description: "The branch name for the commit"
          },
          commitMessage: {
            type: "string",
            title: "Commit Message",
            description: `The commit message`
          },
          sourcePath: {
            type: "string",
            title: "Working Subdirectory",
            description: "Subdirectory of working directory to copy changes from"
          },
          targetPath: {
            type: "string",
            title: "Repository Subdirectory",
            description: "Subdirectory of repository to apply changes to"
          },
          token: {
            title: "Authentication Token",
            type: "string",
            description: "The token to use for authorization to GitLab"
          },
          commitAction: {
            title: "Commit action",
            type: "string",
            enum: ["create", "update", "delete"],
            description: "The action to be used for git commit. Defaults to create."
          }
        }
      },
      output: {
        type: "object",
        properties: {
          projectid: {
            title: "Gitlab Project id/Name(slug)",
            type: "string"
          },
          projectPath: {
            title: "Gitlab Project path",
            type: "string"
          },
          commitHash: {
            title: "The git commit hash of the commit",
            type: "string"
          }
        }
      }
    },
    async handler(ctx) {
      var _a;
      const {
        branchName,
        repoUrl,
        targetPath,
        sourcePath,
        token,
        commitAction
      } = ctx.input;
      const { owner, repo, project } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations);
      const repoID = project ? project : `${owner}/${repo}`;
      const api = createGitlabApi({
        integrations,
        token,
        repoUrl
      });
      let fileRoot;
      if (sourcePath) {
        fileRoot = backendCommon.resolveSafeChildPath(ctx.workspacePath, sourcePath);
      } else {
        fileRoot = ctx.workspacePath;
      }
      const fileContents = await pluginScaffolderNode.serializeDirectoryContents(fileRoot, {
        gitignore: true
      });
      const actions = fileContents.map((file) => ({
        action: commitAction != null ? commitAction : "create",
        filePath: targetPath ? path__default["default"].posix.join(targetPath, file.path) : file.path,
        encoding: "base64",
        content: file.content.toString("base64"),
        execute_filemode: file.executable
      }));
      let branchExists = false;
      try {
        await api.Branches.show(repoID, branchName);
        branchExists = true;
      } catch (e) {
        if (((_a = e.response) == null ? void 0 : _a.statusCode) !== 404) {
          throw new errors.InputError(
            `Failed to check status of branch '${branchName}'. Please make sure that branch already exists or Backstage has permissions to create one. ${e}`
          );
        }
      }
      if (!branchExists) {
        try {
          const projects = await api.Projects.show(repoID);
          const { default_branch: defaultBranch } = projects;
          await api.Branches.create(repoID, branchName, String(defaultBranch));
        } catch (e) {
          throw new errors.InputError(
            `The branch '${branchName}' was not found and creation failed with error. Please make sure that branch already exists or Backstage has permissions to create one. ${e}`
          );
        }
      }
      try {
        const commit = await api.Commits.create(
          repoID,
          branchName,
          ctx.input.commitMessage,
          actions
        );
        ctx.output("projectid", repoID);
        ctx.output("projectPath", repoID);
        ctx.output("commitHash", commit.id);
      } catch (e) {
        throw new errors.InputError(
          `Committing the changes to ${branchName} failed. Please check that none of the files created by the template already exists. ${e}`
        );
      }
    }
  });
};

exports.IssueType = IssueType;
exports.createGitlabGroupEnsureExistsAction = createGitlabGroupEnsureExistsAction;
exports.createGitlabIssueAction = createGitlabIssueAction;
exports.createGitlabProjectAccessTokenAction = createGitlabProjectAccessTokenAction;
exports.createGitlabProjectDeployTokenAction = createGitlabProjectDeployTokenAction;
exports.createGitlabProjectVariableAction = createGitlabProjectVariableAction;
exports.createGitlabRepoPushAction = createGitlabRepoPushAction;
exports.createPublishGitlabAction = createPublishGitlabAction;
exports.createPublishGitlabMergeRequestAction = createPublishGitlabMergeRequestAction;
//# sourceMappingURL=index.cjs.js.map
