mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-10 15:35:49 +01:00
Integrate import repository function into ui
This commit is contained in:
@@ -39,6 +39,12 @@ export type RepositoryCreation = Repository & {
|
|||||||
contextEntries: { [key: string]: any };
|
contextEntries: { [key: string]: any };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type RepositoryImport = Repository & {
|
||||||
|
importUrl?: string;
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type Namespace = {
|
export type Namespace = {
|
||||||
namespace: string;
|
namespace: string;
|
||||||
_links: Links;
|
_links: Links;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
|
|||||||
import CreateUser from "../users/containers/CreateUser";
|
import CreateUser from "../users/containers/CreateUser";
|
||||||
import SingleUser from "../users/containers/SingleUser";
|
import SingleUser from "../users/containers/SingleUser";
|
||||||
import RepositoryRoot from "../repos/containers/RepositoryRoot";
|
import RepositoryRoot from "../repos/containers/RepositoryRoot";
|
||||||
import Create from "../repos/containers/Create";
|
import AddRepository from "../repos/containers/AddRepository";
|
||||||
|
|
||||||
import Groups from "../groups/containers/Groups";
|
import Groups from "../groups/containers/Groups";
|
||||||
import SingleGroup from "../groups/containers/SingleGroup";
|
import SingleGroup from "../groups/containers/SingleGroup";
|
||||||
@@ -77,8 +77,8 @@ class Main extends React.Component<Props> {
|
|||||||
<Route path="/logout" component={Logout} />
|
<Route path="/logout" component={Logout} />
|
||||||
<Redirect exact strict from="/repos" to="/repos/" />
|
<Redirect exact strict from="/repos" to="/repos/" />
|
||||||
<ProtectedRoute exact path="/repos/" component={Overview} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/" component={Overview} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/repos/create" component={Create} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/create" component={AddRepository} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/repos/import" component={Create} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/import" component={AddRepository} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/repos/:namespace" component={Overview} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/:namespace" component={Overview} authenticated={authenticated} />
|
||||||
<ProtectedRoute exact path="/repos/:namespace/:page" component={Overview} authenticated={authenticated} />
|
<ProtectedRoute exact path="/repos/:namespace/:page" component={Overview} authenticated={authenticated} />
|
||||||
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />
|
<ProtectedRoute path="/repo/:namespace/:name" component={RepositoryRoot} authenticated={authenticated} />
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import React, { FC, useEffect, useState } from "react";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { Repository, RepositoryType } from "@scm-manager/ui-types";
|
import { Repository, RepositoryType, RepositoryImport } from "@scm-manager/ui-types";
|
||||||
import { Checkbox, InputField, Level, Select, SubmitButton, Textarea } from "@scm-manager/ui-components";
|
import { Checkbox, InputField, Level, Select, SubmitButton, Textarea } from "@scm-manager/ui-components";
|
||||||
import * as validator from "./repositoryValidation";
|
import * as validator from "./repositoryValidation";
|
||||||
import { CUSTOM_NAMESPACE_STRATEGY } from "../../modules/repos";
|
import { CUSTOM_NAMESPACE_STRATEGY } from "../../modules/repos";
|
||||||
@@ -56,13 +56,13 @@ const Columns = styled.div`
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
createRepository?: (repo: RepositoryCreation, shouldInit: boolean) => void;
|
createRepository?: (repo: RepositoryCreation, shouldInit: boolean) => void;
|
||||||
modifyRepository?: (repo: RepositoryCreation) => void;
|
importRepository?: (repo: RepositoryImport) => void;
|
||||||
importRepository?: (repo: RepositoryCreation) => void;
|
modifyRepository?: (repo: Repository) => void;
|
||||||
repository?: Repository;
|
repository?: Repository;
|
||||||
repositoryTypes?: RepositoryType[];
|
repositoryTypes?: RepositoryType[];
|
||||||
namespaceStrategy?: string;
|
namespaceStrategy?: string;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
indexResources: any;
|
indexResources?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RepositoryCreation = Repository & {
|
type RepositoryCreation = Repository & {
|
||||||
@@ -118,19 +118,14 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
|
|
||||||
const submit = (event: React.FormEvent<HTMLFormElement>) => {
|
const submit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const submitForm = evaluateSubmit();
|
if (isValid()) {
|
||||||
if (isValid() && submitForm) {
|
if (importRepository && isImportPage()) {
|
||||||
submitForm(repo, initRepository);
|
importRepository({ ...repo, url: importUrl, username, password });
|
||||||
}
|
} else if (createRepository && isCreatePage()) {
|
||||||
};
|
createRepository(repo, initRepository);
|
||||||
|
} else if (modifyRepository) {
|
||||||
const evaluateSubmit = () => {
|
modifyRepository(repo);
|
||||||
if (isImportPage()) {
|
}
|
||||||
return importRepository;
|
|
||||||
} else if (isCreatePage()) {
|
|
||||||
return createRepository;
|
|
||||||
} else {
|
|
||||||
return modifyRepository;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,13 +162,8 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
const isImportPage = () => {
|
const isImportPage = () => resolveLocation() === "import";
|
||||||
return resolveLocation() === "import";
|
const isCreatePage = () => resolveLocation() === "create";
|
||||||
};
|
|
||||||
|
|
||||||
const isCreatePage = () => {
|
|
||||||
return resolveLocation() === "create";
|
|
||||||
};
|
|
||||||
|
|
||||||
const createSelectOptions = (repositoryTypes?: RepositoryType[]) => {
|
const createSelectOptions = (repositoryTypes?: RepositoryType[]) => {
|
||||||
if (repositoryTypes) {
|
if (repositoryTypes) {
|
||||||
@@ -311,7 +301,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
if (!repo.name) {
|
if (!repo.name) {
|
||||||
const match = url.match(/([^\/]+)\.git/i);
|
const match = url.match(/([^\/]+)\.git/i);
|
||||||
if (match && match[1]) {
|
if (match && match[1]) {
|
||||||
setRepo({ ...repo, name: match[1] });
|
handleNameChange(match[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setImportUrl(url);
|
setImportUrl(url);
|
||||||
@@ -319,9 +309,8 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
|
|
||||||
const disabled = !isModifiable() && isEditMode();
|
const disabled = !isModifiable() && isEditMode();
|
||||||
|
|
||||||
const getSubmitButtonTranslationKey = () => {
|
const getSubmitButtonTranslationKey = () =>
|
||||||
return isImportPage() ? "repositoryForm.submitImport" : "repositoryForm.submitCreate";
|
isImportPage() ? "repositoryForm.submitImport" : "repositoryForm.submitCreate";
|
||||||
};
|
|
||||||
|
|
||||||
const submitButton = disabled ? null : (
|
const submitButton = disabled ? null : (
|
||||||
<Level
|
<Level
|
||||||
|
|||||||
@@ -25,7 +25,13 @@ import React from "react";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { History } from "history";
|
import { History } from "history";
|
||||||
import { NamespaceStrategies, Repository, RepositoryCreation, RepositoryType } from "@scm-manager/ui-types";
|
import {
|
||||||
|
NamespaceStrategies,
|
||||||
|
Repository,
|
||||||
|
RepositoryCreation,
|
||||||
|
RepositoryImport,
|
||||||
|
RepositoryType
|
||||||
|
} from "@scm-manager/ui-types";
|
||||||
import { Page } from "@scm-manager/ui-components";
|
import { Page } from "@scm-manager/ui-components";
|
||||||
import {
|
import {
|
||||||
fetchRepositoryTypesIfNeeded,
|
fetchRepositoryTypesIfNeeded,
|
||||||
@@ -34,7 +40,13 @@ import {
|
|||||||
isFetchRepositoryTypesPending
|
isFetchRepositoryTypesPending
|
||||||
} from "../modules/repositoryTypes";
|
} from "../modules/repositoryTypes";
|
||||||
import RepositoryForm from "../components/form";
|
import RepositoryForm from "../components/form";
|
||||||
import { createRepo, createRepoReset, getCreateRepoFailure, isCreateRepoPending } from "../modules/repos";
|
import {
|
||||||
|
createRepo,
|
||||||
|
createRepoReset,
|
||||||
|
getCreateRepoFailure,
|
||||||
|
importRepoFromUrl,
|
||||||
|
isCreateRepoPending
|
||||||
|
} from "../modules/repos";
|
||||||
import { getRepositoriesLink } from "../../modules/indexResource";
|
import { getRepositoriesLink } from "../../modules/indexResource";
|
||||||
import {
|
import {
|
||||||
fetchNamespaceStrategiesIfNeeded,
|
fetchNamespaceStrategiesIfNeeded,
|
||||||
@@ -61,13 +73,14 @@ type Props = WithTranslation & {
|
|||||||
initRepository: boolean,
|
initRepository: boolean,
|
||||||
callback: (repo: Repository) => void
|
callback: (repo: Repository) => void
|
||||||
) => void;
|
) => void;
|
||||||
|
importRepoFromUrl: (link: string, repository: RepositoryImport, callback: (repo: Repository) => void) => void;
|
||||||
resetForm: () => void;
|
resetForm: () => void;
|
||||||
|
|
||||||
// context props
|
// context props
|
||||||
history: History;
|
history: History;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Create extends React.Component<Props> {
|
class AddRepository extends React.Component<Props> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.resetForm();
|
this.props.resetForm();
|
||||||
this.props.fetchRepositoryTypesIfNeeded();
|
this.props.fetchRepositoryTypesIfNeeded();
|
||||||
@@ -87,18 +100,15 @@ class Create extends React.Component<Props> {
|
|||||||
repositoryTypes,
|
repositoryTypes,
|
||||||
namespaceStrategies,
|
namespaceStrategies,
|
||||||
createRepo,
|
createRepo,
|
||||||
|
importRepoFromUrl,
|
||||||
error,
|
error,
|
||||||
indexResources
|
indexResources,
|
||||||
|
repoLink,
|
||||||
|
t
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { t, repoLink } = this.props;
|
|
||||||
return (
|
return (
|
||||||
<Page
|
<Page title={t("create.title")} loading={pageLoading} error={error} showContentOnError={true}>
|
||||||
title={t("create.title")}
|
|
||||||
loading={pageLoading}
|
|
||||||
error={error}
|
|
||||||
showContentOnError={true}
|
|
||||||
>
|
|
||||||
<RepositoryForm
|
<RepositoryForm
|
||||||
repositoryTypes={repositoryTypes}
|
repositoryTypes={repositoryTypes}
|
||||||
loading={createLoading}
|
loading={createLoading}
|
||||||
@@ -106,6 +116,9 @@ class Create extends React.Component<Props> {
|
|||||||
createRepository={(repo, initRepository) => {
|
createRepository={(repo, initRepository) => {
|
||||||
createRepo(repoLink, repo, initRepository, (repo: Repository) => this.repoCreated(repo));
|
createRepo(repoLink, repo, initRepository, (repo: Repository) => this.repoCreated(repo));
|
||||||
}}
|
}}
|
||||||
|
importRepository={repo => {
|
||||||
|
importRepoFromUrl(repoLink, repo, (repo: Repository) => this.repoCreated(repo));
|
||||||
|
}}
|
||||||
indexResources={indexResources}
|
indexResources={indexResources}
|
||||||
/>
|
/>
|
||||||
</Page>
|
</Page>
|
||||||
@@ -145,10 +158,13 @@ const mapDispatchToProps = (dispatch: any) => {
|
|||||||
createRepo: (link: string, repository: RepositoryCreation, initRepository: boolean, callback: () => void) => {
|
createRepo: (link: string, repository: RepositoryCreation, initRepository: boolean, callback: () => void) => {
|
||||||
dispatch(createRepo(link, repository, initRepository, callback));
|
dispatch(createRepo(link, repository, initRepository, callback));
|
||||||
},
|
},
|
||||||
|
importRepoFromUrl: (link: string, repository: RepositoryImport, callback: () => void) => {
|
||||||
|
dispatch(importRepoFromUrl(link, repository, callback));
|
||||||
|
},
|
||||||
resetForm: () => {
|
resetForm: () => {
|
||||||
dispatch(createRepoReset());
|
dispatch(createRepoReset());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(Create));
|
export default connect(mapStateToProps, mapDispatchToProps)(withTranslation("repos")(AddRepository));
|
||||||
@@ -75,7 +75,7 @@ class EditRepo extends React.Component<Props> {
|
|||||||
<RepositoryForm
|
<RepositoryForm
|
||||||
repository={this.props.repository}
|
repository={this.props.repository}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
createRepository={repo => {
|
modifyRepository={repo => {
|
||||||
this.props.modifyRepo(repo, this.repoModified);
|
this.props.modifyRepo(repo, this.repoModified);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -25,11 +25,14 @@
|
|||||||
import { apiClient } from "@scm-manager/ui-components";
|
import { apiClient } from "@scm-manager/ui-components";
|
||||||
import * as types from "../../modules/types";
|
import * as types from "../../modules/types";
|
||||||
import {
|
import {
|
||||||
Action, Namespace,
|
Action,
|
||||||
|
Namespace,
|
||||||
NamespaceCollection,
|
NamespaceCollection,
|
||||||
Repository,
|
Repository,
|
||||||
RepositoryCollection,
|
RepositoryCollection,
|
||||||
RepositoryCreation
|
RepositoryCreation,
|
||||||
|
RepositoryImport,
|
||||||
|
Link
|
||||||
} from "@scm-manager/ui-types";
|
} from "@scm-manager/ui-types";
|
||||||
import { isPending } from "../../modules/pending";
|
import { isPending } from "../../modules/pending";
|
||||||
import { getFailure } from "../../modules/failure";
|
import { getFailure } from "../../modules/failure";
|
||||||
@@ -55,6 +58,12 @@ export const CREATE_REPO_SUCCESS = `${CREATE_REPO}_${types.SUCCESS_SUFFIX}`;
|
|||||||
export const CREATE_REPO_FAILURE = `${CREATE_REPO}_${types.FAILURE_SUFFIX}`;
|
export const CREATE_REPO_FAILURE = `${CREATE_REPO}_${types.FAILURE_SUFFIX}`;
|
||||||
export const CREATE_REPO_RESET = `${CREATE_REPO}_${types.RESET_SUFFIX}`;
|
export const CREATE_REPO_RESET = `${CREATE_REPO}_${types.RESET_SUFFIX}`;
|
||||||
|
|
||||||
|
export const IMPORT_REPO = "scm/repos/IMPORT_REPO";
|
||||||
|
export const IMPORT_REPO_PENDING = `${IMPORT_REPO}_${types.PENDING_SUFFIX}`;
|
||||||
|
export const IMPORT_REPO_SUCCESS = `${IMPORT_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||||
|
export const IMPORT_REPO_FAILURE = `${IMPORT_REPO}_${types.FAILURE_SUFFIX}`;
|
||||||
|
export const IMPORT_REPO_RESET = `${IMPORT_REPO}_${types.RESET_SUFFIX}`;
|
||||||
|
|
||||||
export const MODIFY_REPO = "scm/repos/MODIFY_REPO";
|
export const MODIFY_REPO = "scm/repos/MODIFY_REPO";
|
||||||
export const MODIFY_REPO_PENDING = `${MODIFY_REPO}_${types.PENDING_SUFFIX}`;
|
export const MODIFY_REPO_PENDING = `${MODIFY_REPO}_${types.PENDING_SUFFIX}`;
|
||||||
export const MODIFY_REPO_SUCCESS = `${MODIFY_REPO}_${types.SUCCESS_SUFFIX}`;
|
export const MODIFY_REPO_SUCCESS = `${MODIFY_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||||
@@ -178,7 +187,7 @@ export function fetchNamespacesFailure(err: Error): Action {
|
|||||||
|
|
||||||
// fetch repo
|
// fetch repo
|
||||||
export function fetchRepoByLink(repo: Repository) {
|
export function fetchRepoByLink(repo: Repository) {
|
||||||
return fetchRepo(repo._links.self.href, repo.namespace, repo.name);
|
return fetchRepo((repo._links.self as Link).href, repo.namespace, repo.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchRepoByName(link: string, namespace: string, name: string) {
|
export function fetchRepoByName(link: string, namespace: string, name: string) {
|
||||||
@@ -232,6 +241,50 @@ export function fetchRepoFailure(namespace: string, name: string, error: Error):
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// import repo
|
||||||
|
|
||||||
|
export function importRepoFromUrl(link: string, repository: RepositoryImport, callback?: (repo: Repository) => void) {
|
||||||
|
const importLink = link + `import/${repository.type}/url`;
|
||||||
|
return function(dispatch: any) {
|
||||||
|
dispatch(importRepoPending());
|
||||||
|
return apiClient
|
||||||
|
.post(importLink, repository, CONTENT_TYPE)
|
||||||
|
.then(response => {
|
||||||
|
const location = response.headers.get("Location");
|
||||||
|
dispatch(importRepoSuccess());
|
||||||
|
return apiClient.get(location);
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(response => {
|
||||||
|
if (callback) {
|
||||||
|
callback(response);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
dispatch(importRepoFailure(err));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function importRepoPending(): Action {
|
||||||
|
return {
|
||||||
|
type: CREATE_REPO_PENDING
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function importRepoSuccess(): Action {
|
||||||
|
return {
|
||||||
|
type: CREATE_REPO_SUCCESS
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function importRepoFailure(err: Error): Action {
|
||||||
|
return {
|
||||||
|
type: CREATE_REPO_FAILURE,
|
||||||
|
payload: err
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// create repo
|
// create repo
|
||||||
|
|
||||||
export function createRepo(
|
export function createRepo(
|
||||||
@@ -294,7 +347,7 @@ export function modifyRepo(repository: Repository, callback?: () => void) {
|
|||||||
dispatch(modifyRepoPending(repository));
|
dispatch(modifyRepoPending(repository));
|
||||||
|
|
||||||
return apiClient
|
return apiClient
|
||||||
.put(repository._links.update.href, repository, CONTENT_TYPE)
|
.put((repository._links.update as Link).href, repository, CONTENT_TYPE)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(modifyRepoSuccess(repository));
|
dispatch(modifyRepoSuccess(repository));
|
||||||
if (callback) {
|
if (callback) {
|
||||||
@@ -353,7 +406,7 @@ export function deleteRepo(repository: Repository, callback?: () => void) {
|
|||||||
return function(dispatch: any) {
|
return function(dispatch: any) {
|
||||||
dispatch(deleteRepoPending(repository));
|
dispatch(deleteRepoPending(repository));
|
||||||
return apiClient
|
return apiClient
|
||||||
.delete(repository._links.delete.href)
|
.delete((repository._links.delete as Link).href)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(deleteRepoSuccess(repository));
|
dispatch(deleteRepoSuccess(repository));
|
||||||
if (callback) {
|
if (callback) {
|
||||||
|
|||||||
@@ -25,17 +25,18 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import de.otto.edison.hal.Embedded;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import lombok.ToString;
|
import lombok.Getter;
|
||||||
import lombok.Value;
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.FeatureNotSupportedException;
|
|
||||||
import sonia.scm.NotFoundException;
|
import sonia.scm.NotFoundException;
|
||||||
import sonia.scm.Type;
|
import sonia.scm.Type;
|
||||||
import sonia.scm.repository.InternalRepositoryException;
|
import sonia.scm.repository.InternalRepositoryException;
|
||||||
@@ -47,7 +48,6 @@ import sonia.scm.repository.RepositoryType;
|
|||||||
import sonia.scm.repository.api.Command;
|
import sonia.scm.repository.api.Command;
|
||||||
import sonia.scm.repository.api.RepositoryService;
|
import sonia.scm.repository.api.RepositoryService;
|
||||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||||
import sonia.scm.util.IOUtil;
|
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
@@ -56,19 +56,10 @@ import javax.ws.rs.Path;
|
|||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
@@ -80,12 +71,14 @@ public class RepositoryImportResource {
|
|||||||
|
|
||||||
private final RepositoryManager manager;
|
private final RepositoryManager manager;
|
||||||
private final RepositoryServiceFactory serviceFactory;
|
private final RepositoryServiceFactory serviceFactory;
|
||||||
|
private final ResourceLinks resourceLinks;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public RepositoryImportResource(RepositoryManager manager,
|
public RepositoryImportResource(RepositoryManager manager,
|
||||||
RepositoryServiceFactory serviceFactory) {
|
RepositoryServiceFactory serviceFactory, ResourceLinks resourceLinks) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.serviceFactory = serviceFactory;
|
this.serviceFactory = serviceFactory;
|
||||||
|
this.resourceLinks = resourceLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
@@ -171,7 +164,7 @@ public class RepositoryImportResource {
|
|||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Path("{type}/url")
|
@Path("{type}/url")
|
||||||
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
|
@Consumes(VndMediaType.REPOSITORY)
|
||||||
@Operation(summary = "Import repository from url", description = "Imports the repository for the given url.", tags = "Repository")
|
@Operation(summary = "Import repository from url", description = "Imports the repository for the given url.", tags = "Repository")
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
responseCode = "201",
|
responseCode = "201",
|
||||||
@@ -198,7 +191,7 @@ public class RepositoryImportResource {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
public Response importFromUrl(@Context UriInfo uriInfo,
|
public Response importFromUrl(@Context UriInfo uriInfo,
|
||||||
@PathParam("type") String type, UrlImportRequest request) {
|
@PathParam("type") String type, RepositoryImportDto request) {
|
||||||
RepositoryPermissions.create().check();
|
RepositoryPermissions.create().check();
|
||||||
checkNotNull(request, "request is required");
|
checkNotNull(request, "request is required");
|
||||||
checkArgument(!Strings.isNullOrEmpty(request.getName()),
|
checkArgument(!Strings.isNullOrEmpty(request.getName()),
|
||||||
@@ -220,17 +213,7 @@ public class RepositoryImportResource {
|
|||||||
handleImportFailure(ex, repository);
|
handleImportFailure(ex, repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response.created(createRepositoryLocation(uriInfo, repository)).build();
|
return Response.created(URI.create(resourceLinks.repository().self(repository.getNamespace(), repository.getName()))).build();
|
||||||
}
|
|
||||||
|
|
||||||
private URI createRepositoryLocation(UriInfo uriInfo, Repository repository) {
|
|
||||||
return URI.create(
|
|
||||||
String.format(
|
|
||||||
"%s/repos/%s",
|
|
||||||
uriInfo.getBaseUri().toString().replace("/api/", "/"),
|
|
||||||
repository.getNamespaceAndName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
@@ -408,81 +391,81 @@ public class RepositoryImportResource {
|
|||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Start bundle import.
|
// * Start bundle import.
|
||||||
*
|
// *
|
||||||
* @param type repository type
|
// * @param type repository type
|
||||||
* @param name name of the repository
|
// * @param name name of the repository
|
||||||
* @param inputStream bundle stream
|
// * @param inputStream bundle stream
|
||||||
* @param compressed true if the bundle is gzip compressed
|
// * @param compressed true if the bundle is gzip compressed
|
||||||
* @return imported repository
|
// * @return imported repository
|
||||||
*/
|
// */
|
||||||
private Repository doImportFromBundle(String type, String namespace, String name,
|
// private Repository doImportFromBundle(String type, String namespace, String name,
|
||||||
InputStream inputStream, boolean compressed) {
|
// InputStream inputStream, boolean compressed) {
|
||||||
RepositoryPermissions.create().check();
|
// RepositoryPermissions.create().check();
|
||||||
|
//
|
||||||
checkArgument(!Strings.isNullOrEmpty(name),
|
// checkArgument(!Strings.isNullOrEmpty(name),
|
||||||
"request does not contain name of the repository");
|
// "request does not contain name of the repository");
|
||||||
checkNotNull(inputStream, "bundle inputStream is required");
|
// checkNotNull(inputStream, "bundle inputStream is required");
|
||||||
|
//
|
||||||
Repository repository;
|
// Repository repository;
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
Type t = type(type);
|
// Type t = type(type);
|
||||||
checkSupport(t, Command.UNBUNDLE, "bundle");
|
// checkSupport(t, Command.UNBUNDLE, "bundle");
|
||||||
repository = create(namespace, name, type);
|
// repository = create(namespace, name, type);
|
||||||
importFromBundle(repository, inputStream, compressed);
|
// importFromBundle(repository, inputStream, compressed);
|
||||||
} catch (IOException ex) {
|
// } catch (IOException ex) {
|
||||||
logger.warn("could not create temporary file", ex);
|
// logger.warn("could not create temporary file", ex);
|
||||||
|
//
|
||||||
throw new WebApplicationException(ex);
|
// throw new WebApplicationException(ex);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return repository;
|
// return repository;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private void importFromBundle(Repository repository, InputStream inputStream, boolean compressed) throws IOException {
|
// private void importFromBundle(Repository repository, InputStream inputStream, boolean compressed) throws IOException {
|
||||||
File file = File.createTempFile("scm-import-", ".bundle");
|
// File file = File.createTempFile("scm-import-", ".bundle");
|
||||||
|
//
|
||||||
try (RepositoryService service = serviceFactory.create(repository)) {
|
// try (RepositoryService service = serviceFactory.create(repository)) {
|
||||||
long length = Files.asByteSink(file).writeFrom(inputStream);
|
// long length = Files.asByteSink(file).writeFrom(inputStream);
|
||||||
|
//
|
||||||
logger.info("copied {} bytes to temp, start bundle import", length);
|
// logger.info("copied {} bytes to temp, start bundle import", length);
|
||||||
service.getUnbundleCommand().setCompressed(compressed).unbundle(file);
|
// service.getUnbundleCommand().setCompressed(compressed).unbundle(file);
|
||||||
} catch (InternalRepositoryException ex) {
|
// } catch (InternalRepositoryException ex) {
|
||||||
handleImportFailure(ex, repository);
|
// handleImportFailure(ex, repository);
|
||||||
} finally {
|
// } finally {
|
||||||
IOUtil.delete(file);
|
// IOUtil.delete(file);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private List<Type> findImportableTypes() {
|
// private List<Type> findImportableTypes() {
|
||||||
List<Type> types = new ArrayList<>();
|
// List<Type> types = new ArrayList<>();
|
||||||
Collection<Type> handlerTypes = manager.getTypes();
|
// Collection<Type> handlerTypes = manager.getTypes();
|
||||||
|
//
|
||||||
for (Type t : handlerTypes) {
|
// for (Type t : handlerTypes) {
|
||||||
RepositoryHandler handler = manager.getHandler(t.getName());
|
// RepositoryHandler handler = manager.getHandler(t.getName());
|
||||||
|
//
|
||||||
if (handler != null) {
|
// if (handler != null) {
|
||||||
try {
|
// try {
|
||||||
if (handler.getImportHandler() != null) {
|
// if (handler.getImportHandler() != null) {
|
||||||
types.add(t);
|
// types.add(t);
|
||||||
}
|
// }
|
||||||
} catch (FeatureNotSupportedException ex) {
|
// } catch (FeatureNotSupportedException ex) {
|
||||||
if (logger.isTraceEnabled()) {
|
// if (logger.isTraceEnabled()) {
|
||||||
logger.trace("import handler is not supported", ex);
|
// logger.trace("import handler is not supported", ex);
|
||||||
} else if (logger.isInfoEnabled()) {
|
// } else if (logger.isInfoEnabled()) {
|
||||||
logger.info("{} handler does not support import of repositories",
|
// logger.info("{} handler does not support import of repositories",
|
||||||
t.getName());
|
// t.getName());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else if (logger.isWarnEnabled()) {
|
// } else if (logger.isWarnEnabled()) {
|
||||||
logger.warn("could not find handler for type {}", t.getName());
|
// logger.warn("could not find handler for type {}", t.getName());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return types;
|
// return types;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle creation failures.
|
* Handle creation failures.
|
||||||
@@ -518,49 +501,49 @@ public class RepositoryImportResource {
|
|||||||
Response.Status.INTERNAL_SERVER_ERROR);
|
Response.Status.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Import repositories from a specific type.
|
// * Import repositories from a specific type.
|
||||||
*
|
// *
|
||||||
* @param repositories repository list
|
// * @param repositories repository list
|
||||||
* @param type type of repository
|
// * @param type type of repository
|
||||||
*/
|
// */
|
||||||
private void importFromDirectory(List<Repository> repositories, String type) {
|
// private void importFromDirectory(List<Repository> repositories, String type) {
|
||||||
RepositoryHandler handler = manager.getHandler(type);
|
// RepositoryHandler handler = manager.getHandler(type);
|
||||||
|
//
|
||||||
if (handler != null) {
|
// if (handler != null) {
|
||||||
logger.info("start directory import for repository type {}", type);
|
// logger.info("start directory import for repository type {}", type);
|
||||||
|
//
|
||||||
try {
|
// try {
|
||||||
List<String> repositoryNames =
|
// List<String> repositoryNames =
|
||||||
handler.getImportHandler().importRepositories(manager);
|
// handler.getImportHandler().importRepositories(manager);
|
||||||
|
//
|
||||||
if (repositoryNames != null) {
|
// if (repositoryNames != null) {
|
||||||
for (String repositoryName : repositoryNames) {
|
// for (String repositoryName : repositoryNames) {
|
||||||
// TODO #8783
|
// // TODO #8783
|
||||||
/*Repository repository = null; //manager.get(type, repositoryName);
|
// /*Repository repository = null; //manager.get(type, repositoryName);
|
||||||
|
//
|
||||||
if (repository != null)
|
// if (repository != null)
|
||||||
{
|
// {
|
||||||
repositories.add(repository);
|
// repositories.add(repository);
|
||||||
}
|
// }
|
||||||
else if (logger.isWarnEnabled())
|
// else if (logger.isWarnEnabled())
|
||||||
{
|
// {
|
||||||
logger.warn("could not find imported repository {}",
|
// logger.warn("could not find imported repository {}",
|
||||||
repositoryName);
|
// repositoryName);
|
||||||
}*/
|
// }*/
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} catch (FeatureNotSupportedException ex) {
|
// } catch (FeatureNotSupportedException ex) {
|
||||||
throw new WebApplicationException(ex, Response.Status.BAD_REQUEST);
|
// throw new WebApplicationException(ex, Response.Status.BAD_REQUEST);
|
||||||
} catch (IOException ex) {
|
// } catch (IOException ex) {
|
||||||
throw new WebApplicationException(ex);
|
// throw new WebApplicationException(ex);
|
||||||
} catch (InternalRepositoryException ex) {
|
// } catch (InternalRepositoryException ex) {
|
||||||
throw new WebApplicationException(ex);
|
// throw new WebApplicationException(ex);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
throw new WebApplicationException(Response.Status.BAD_REQUEST);
|
// throw new WebApplicationException(Response.Status.BAD_REQUEST);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private Type type(String type) {
|
private Type type(String type) {
|
||||||
RepositoryHandler handler = manager.getHandler(type);
|
RepositoryHandler handler = manager.getHandler(type);
|
||||||
@@ -574,18 +557,17 @@ public class RepositoryImportResource {
|
|||||||
return handler.getType();
|
return handler.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Getter
|
||||||
* Request for importing external repositories which are accessible via url.
|
@Setter
|
||||||
*/
|
@NoArgsConstructor
|
||||||
@XmlRootElement(name = "import")
|
@SuppressWarnings("java:S2160")
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
public static class RepositoryImportDto extends RepositoryDto {
|
||||||
@Value
|
|
||||||
@ToString
|
|
||||||
public static class UrlImportRequest {
|
|
||||||
private String namespace;
|
|
||||||
private String name;
|
|
||||||
private String url;
|
private String url;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
RepositoryImportDto(Links links, Embedded embedded) {
|
||||||
|
super(links, embedded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user