backstage

Форк
0
190 строк · 5.3 Кб
1
/*
2
 * Copyright 2021 The Backstage Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
import { InputError } from '@backstage/errors';
18
import {
19
  GitLabIntegration,
20
  ScmIntegrationRegistry,
21
} from '@backstage/integration';
22
import { Gitlab, GroupSchema } from '@gitbeaker/rest';
23
import { z } from 'zod';
24
import commonGitlabConfig from './commonGitlabConfig';
25
import * as util from './util';
26

27
export const parseRepoHost = (repoUrl: string): string => {
28
  let parsed;
29
  try {
30
    parsed = new URL(`https://${repoUrl}`);
31
  } catch (error) {
32
    throw new InputError(
33
      `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`,
34
    );
35
  }
36
  return parsed.host;
37
};
38

39
export const getToken = (
40
  config: z.infer<typeof commonGitlabConfig>,
41
  integrations: ScmIntegrationRegistry,
42
): { token: string; integrationConfig: GitLabIntegration } => {
43
  const host = parseRepoHost(config.repoUrl);
44
  const integrationConfig = integrations.gitlab.byHost(host);
45

46
  if (!integrationConfig) {
47
    throw new InputError(
48
      `No matching integration configuration for host ${host}, please check your integrations config`,
49
    );
50
  }
51

52
  const token = config.token || integrationConfig.config.token!;
53

54
  return { token: token, integrationConfig: integrationConfig };
55
};
56

57
export type RepoSpec = {
58
  repo: string;
59
  host: string;
60
  owner?: string;
61
};
62

63
export const parseRepoUrl = (
64
  repoUrl: string,
65
  integrations: ScmIntegrationRegistry,
66
): RepoSpec => {
67
  let parsed;
68
  try {
69
    parsed = new URL(`https://${repoUrl}`);
70
  } catch (error) {
71
    throw new InputError(
72
      `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`,
73
    );
74
  }
75
  const host = parsed.host;
76
  const owner = parsed.searchParams.get('owner') ?? undefined;
77
  const repo: string = parsed.searchParams.get('repo')!;
78

79
  const type = integrations.byHost(host)?.type;
80

81
  if (!type) {
82
    throw new InputError(
83
      `No matching integration configuration for host ${host}, please check your integrations config`,
84
    );
85
  }
86

87
  return { host, owner, repo };
88
};
89

90
export function getClient(props: {
91
  host: string;
92
  token?: string;
93
  integrations: ScmIntegrationRegistry;
94
}): InstanceType<typeof Gitlab> {
95
  const { host, token, integrations } = props;
96
  const integrationConfig = integrations.gitlab.byHost(host);
97

98
  if (!integrationConfig) {
99
    throw new InputError(
100
      `No matching integration configuration for host ${host}, please check your integrations config`,
101
    );
102
  }
103

104
  const { config } = integrationConfig;
105

106
  if (!config.token && !token) {
107
    throw new InputError(`No token available for host ${host}`);
108
  }
109

110
  const requestToken = token || config.token!;
111
  const tokenType = token ? 'oauthToken' : 'token';
112

113
  const gitlabOptions: any = {
114
    host: config.baseUrl,
115
  };
116

117
  gitlabOptions[tokenType] = requestToken;
118
  return new Gitlab(gitlabOptions);
119
}
120

121
export function convertDate(
122
  inputDate: string | undefined,
123
  defaultDate: string,
124
) {
125
  try {
126
    return inputDate
127
      ? new Date(inputDate).toISOString()
128
      : new Date(defaultDate).toISOString();
129
  } catch (error) {
130
    throw new InputError(`Error converting input date - ${error}`);
131
  }
132
}
133

134
export async function getTopLevelParentGroup(
135
  client: InstanceType<typeof Gitlab>,
136
  groupId: number,
137
): Promise<GroupSchema> {
138
  try {
139
    const topParentGroup = await client.Groups.show(groupId);
140
    if (topParentGroup.parent_id) {
141
      return util.getTopLevelParentGroup(
142
        client,
143
        topParentGroup.parent_id as number,
144
      );
145
    }
146
    return topParentGroup as GroupSchema;
147
  } catch (error: any) {
148
    throw new InputError(
149
      `Error finding top-level parent group ID: ${error.message}`,
150
    );
151
  }
152
}
153

154
export async function checkEpicScope(
155
  client: InstanceType<typeof Gitlab>,
156
  projectId: number,
157
  epicId: number,
158
) {
159
  try {
160
    // If project exists, get the top level group id
161
    const project = await client.Projects.show(projectId);
162
    if (!project) {
163
      throw new InputError(
164
        `Project with id ${projectId} not found. Check your GitLab instance.`,
165
      );
166
    }
167
    const topParentGroup = await getTopLevelParentGroup(
168
      client,
169
      project.namespace.id,
170
    );
171
    if (!topParentGroup) {
172
      throw new InputError(`Couldn't find a suitable top-level parent group.`);
173
    }
174
    // Get the epic
175
    const epic = (await client.Epics.all(topParentGroup.id)).find(
176
      (x: any) => x.id === epicId,
177
    );
178
    if (!epic) {
179
      throw new InputError(
180
        `Epic with id ${epicId} not found in the top-level parent group ${topParentGroup.name}.`,
181
      );
182
    }
183

184
    const epicGroup = await client.Groups.show(epic.group_id as number);
185
    const projectNamespace: string = project.path_with_namespace as string;
186
    return projectNamespace.startsWith(epicGroup.full_path as string);
187
  } catch (error: any) {
188
    throw new InputError(`Could not find epic scope: ${error.message}`);
189
  }
190
}
191

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.