Merge branch 'develop' into feature/optional_dependency_annotation

This commit is contained in:
Sebastian Sdorra
2020-04-15 09:24:57 +02:00
10 changed files with 281 additions and 133 deletions

View File

@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
## 2.0.0-rc7 - 2020-04-09
### Added
- Fire various plugin events ([#1088](https://github.com/scm-manager/scm-manager/pull/1088))
- Display version for plugins ([#1089](https://github.com/scm-manager/scm-manager/pull/1089)

1
Jenkinsfile vendored
View File

@@ -53,6 +53,7 @@ node('docker') {
// merge release branch into master
sh "git checkout master"
sh "git reset --hard origin/master"
sh "git merge --ff-only ${env.BRANCH_NAME}"
// set tag

View File

@@ -14,7 +14,7 @@ git fetch && git checkout develop && git reset --hard origin/develop
Change "Unreleased" header in `CHANGELOG.md` to `<version> - <current date>`
## Create release branch:
## Create release branch
`git checkout -b release/<version>`
@@ -37,6 +37,7 @@ Jenkins will
- merge with master branch
- build and deploy everything
- set the new development version for the develop branch
- delete the release branch
## Make a party
@@ -44,7 +45,7 @@ Jenkins will
To release a new version of a Plugin for SCM-Manager v2 you have to do the following steps (replace placeholder `<version>` accordingly, eg. with `2.1.0`):
## Update to latest version
## Check out default branch
Make sure you have no changes you want to keep!
@@ -52,68 +53,55 @@ Make sure you have no changes you want to keep!
git fetch && git checkout develop && git reset --hard origin/develop
```
## Set new version
## Update SCM parent if necessary
Edit `pom.xml`:
If you need to update the parent of the plugin to a new release of SCM-Manager, change it now:
- `version` and `scm.tag` have to be set to the new version.
- ensure that all dependencies to other scm resources have released versions
- ensure `parent.version` points to stable release
- `pom.xml`: `parent.version`
- `package.json`: `dependencies.ui-plugins`
Edit `package.json`:
```
rm -rf node_modules yarn.lock
mvn clean install
git add yarn.lock pom.xml package.json
git commit -m "Update to new version of SCM-Manager"
git push
```
- `version` has to be set to the new version.
- ensure that all dependencies to other scm resources have released versions
- ensure the version of `@scm-manager/ui-plugins` points to the same version as `parent.version` in the `pom.xml`
Wait for Jenkins to be green.
## Create release branch
```
git checkout -b release/<version>
```
## Modify Changelog
Change "Unreleased" header in `CHANGELOG.md` to `<version> - <current date>`
## Remove old dependencies
`rm -rf node_modules yarn.lock`
## Build
`mvn clean install`
## Commit and push release
```
git commit -am "Release version <version>"
git push origin develop
git commit -am "Prepare release of <version>"
```
## Merge with master branch
The merge should be possible with a fast forward. If this fails, check for changes on the `master` branch that are not present on the `develop` branch. Merge these changes into the `develop` branch, first!
## Push release branch
```
git checkout master && git pull && git merge develop --ff-only && git push origin master
git push origin release/<version>
```
## Create and push tag
## Wait for Jenkins build
```
git tag -s -a <version> -m "<version>"
git push --tags origin
```
Jenkins will
## Prepare next development version
- update versions in pom.xml and package.json
- merge with master branch
- build and deploy everything
- set the new development version for the develop branch
- delete the release branch
```
git checkout develop
```
Edit `pom.xml`: `version` has to be set to the new development version, `tag` to `HEAD`.
Edit `package.json`: `version` has to be set to the new development version.
```
git commit -am "Prepare for next development iteration"
git push origin develop
```
## Attention: Creating new plugins
If you are creating a new plugin which doesn't exist in the SCM-Manager Plugin-Center yet, your plugin will not be shown after the release. First you have to create a `index.md` in the Plugin-Center Repository.

View File

@@ -494,7 +494,7 @@
<plugin>
<groupId>sonia.scm.maven</groupId>
<artifactId>smp-maven-plugin</artifactId>
<version>1.0.0-rc5</version>
<version>1.0.0-rc6</version>
</plugin>
<plugin>
@@ -902,7 +902,7 @@
<!-- test libraries -->
<mockito.version>2.28.2</mockito.version>
<hamcrest.version>1.3</hamcrest.version>
<junit.version>5.6.0</junit.version>
<junit.version>5.6.1</junit.version>
<!-- logging libraries -->
<slf4j.version>1.7.30</slf4j.version>
@@ -913,7 +913,7 @@
<resteasy.version>4.5.2.Final</resteasy.version>
<jersey-client.version>1.19.4</jersey-client.version>
<jackson.version>2.10.3</jackson.version>
<guice.version>4.2.2</guice.version>
<guice.version>4.2.3</guice.version>
<jaxb.version>2.3.1</jaxb.version>
<hibernate-validator.version>6.1.2.Final</hibernate-validator.version>

View File

@@ -21,15 +21,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.repository.spi;
import org.apache.commons.lang.exception.CloneFailedException;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc2.SvnCheckout;
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.SvnWorkDirFactory;
import sonia.scm.repository.util.SimpleWorkdirFactory;
@@ -37,7 +37,6 @@ import sonia.scm.repository.util.WorkdirProvider;
import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory<File, File, SvnContext> implements SvnWorkDirFactory {
@@ -60,7 +59,7 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory<File, File, Sv
try {
source = SVNURL.fromFile(context.getDirectory());
} catch (SVNException ex) {
throw new CloneFailedException(ex.getMessage());
throw new InternalRepositoryException(getScmRepository(context), "error creating svn url from central directory", ex);
}
try {
@@ -69,7 +68,7 @@ public class SimpleSvnWorkDirFactory extends SimpleWorkdirFactory<File, File, Sv
checkout.setSource(SvnTarget.fromURL(source));
checkout.run();
} catch (SVNException ex) {
throw new CloneFailedException(ex.getMessage());
throw new InternalRepositoryException(getScmRepository(context), "error running svn checkout", ex);
} finally {
svnOperationFactory.dispose();
}

View File

@@ -27,6 +27,8 @@ import { storiesOf } from "@storybook/react";
import CardColumn from "./CardColumn";
import Icon from "./Icon";
import styled from "styled-components";
import { DateFromNow } from ".";
import repository from "./__resources__/repository";
const Wrapper = styled.div`
margin: 2rem;
@@ -35,22 +37,36 @@ const Wrapper = styled.div`
const Container: FC = ({ children }) => <Wrapper>{children}</Wrapper>;
const title = <strong>title</strong>;
const avatar = <Icon name="icons fa-2x fa-fw" />;
const link = "/foo/bar";
const avatar = <Icon name="icons fa-2x fa-fw" />;
const title = <strong>title</strong>;
const footerLeft = <small>left footer</small>;
const footerRight = <small>right footer</small>;
const baseDate = "2020-03-26T12:13:42+02:00";
storiesOf("CardColumn", module)
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
.addDecorator(storyFn => <Container>{storyFn()}</Container>)
.add("default", () => (
<CardColumn
link={link}
avatar={avatar}
title={title}
description="A description can be added here."
avatar={avatar}
link={link}
footerLeft={footerLeft}
footerRight={footerRight}
/>
));
))
.add("minimal", () => (
<CardColumn
title={title}
footerLeft={footerLeft}
footerRight={footerRight}
/>
))
.add("with hoverable date", () => (
<CardColumn title={title} footerLeft={footerLeft} footerRight={
<small className="level-item">
<DateFromNow baseDate={baseDate} date={repository.creationDate}/>
</small>} />
));

View File

@@ -21,19 +21,19 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import React, { ReactNode } from "react";
import React, { FC, ReactNode } from "react";
import classNames from "classnames";
import styled from "styled-components";
import { Link } from "react-router-dom";
type Props = {
link?: string;
avatar?: ReactNode;
title: ReactNode;
description?: string;
avatar: ReactNode;
contentRight?: ReactNode;
footerLeft: ReactNode;
footerRight: ReactNode;
link?: string;
action?: () => void;
className?: string;
};
@@ -74,53 +74,63 @@ const RightMarginDiv = styled.div`
const InheritFlexShrinkDiv = styled.div`
flex-shrink: inherit;
pointer-events: all;
`;
export default class CardColumn extends React.Component<Props> {
createLink = () => {
const { link, action } = this.props;
if (link) {
return <Link className="overlay-column" to={link} />;
} else if (action) {
return (
<a
className="overlay-column"
onClick={e => {
e.preventDefault();
action();
}}
href="#"
/>
);
}
return null;
};
const CardColumn: FC<Props> = ({
link,
avatar,
title,
description,
contentRight,
footerLeft,
footerRight,
action,
className
}) => {
const renderAvatar = avatar ? <AvatarWrapper className="media-left">{avatar}</AvatarWrapper> : null;
const renderDescription = description ? <p className="shorten-text">{description}</p> : null;
const renderContentRight = contentRight ? <ContentRight>{contentRight}</ContentRight> : null;
render() {
const { avatar, title, description, contentRight, footerLeft, footerRight, className } = this.props;
const link = this.createLink();
return (
<>
{link}
<NoEventWrapper className={classNames("media", className)}>
<AvatarWrapper className="media-left">{avatar}</AvatarWrapper>
<FlexFullHeight className={classNames("media-content", "text-box", "is-flex")}>
<div className="is-flex">
<ContentLeft className="content">
<p className="shorten-text is-marginless">{title}</p>
<p className="shorten-text">{description}</p>
</ContentLeft>
<ContentRight>{contentRight}</ContentRight>
</div>
<FooterWrapper className={classNames("level", "is-flex")}>
<RightMarginDiv className="level-left is-hidden-mobile">{footerLeft}</RightMarginDiv>
<InheritFlexShrinkDiv className="level-right is-block is-mobile is-marginless shorten-text">
{footerRight}
</InheritFlexShrinkDiv>
</FooterWrapper>
</FlexFullHeight>
</NoEventWrapper>
</>
let createLink = null;
if (link) {
createLink = <Link className="overlay-column" to={link} />;
} else if (action) {
createLink = (
<a
className="overlay-column"
onClick={e => {
e.preventDefault();
action();
}}
href="#"
/>
);
}
}
return (
<>
{createLink}
<NoEventWrapper className={classNames("media", className)}>
{renderAvatar}
<FlexFullHeight className={classNames("media-content", "text-box", "is-flex")}>
<div className="is-flex">
<ContentLeft className="content">
<p className="shorten-text is-marginless">{title}</p>
{renderDescription}
</ContentLeft>
{renderContentRight}
</div>
<FooterWrapper className={classNames("level", "is-flex")}>
<RightMarginDiv className="level-left is-hidden-mobile">{footerLeft}</RightMarginDiv>
<InheritFlexShrinkDiv className="level-right is-block is-mobile is-marginless shorten-text">
{footerRight}
</InheritFlexShrinkDiv>
</FooterWrapper>
</FlexFullHeight>
</NoEventWrapper>
</>
);
};
export default CardColumn;

View File

@@ -44,5 +44,8 @@ storiesOf("CardColumnSmall", module)
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
.addDecorator(storyFn => <Container>{storyFn()}</Container>)
.add("default", () => (
<CardColumnSmall link={link} icon={icon} contentLeft={contentLeft} contentRight={contentRight} />
<CardColumnSmall link={link} avatar={icon} contentLeft={contentLeft} contentRight={contentRight} />
))
.add("minimal", () => (
<CardColumnSmall link={link} contentLeft={contentLeft} contentRight={contentRight} />
));

View File

@@ -29,7 +29,7 @@ import { Link } from "react-router-dom";
type Props = {
link: string;
icon: ReactNode;
avatar?: ReactNode;
contentLeft: ReactNode;
contentRight: ReactNode;
footer?: ReactNode;
@@ -62,21 +62,24 @@ const StyledLink = styled(Link)`
}
`;
const IconWrapper = styled.figure`
const AvatarWrapper = styled.figure`
margin-right: 0.5rem;
`;
const CardColumnSmall: FC<Props> = ({ link, icon, contentLeft, contentRight, footer }) => {
const CardColumnSmall: FC<Props> = ({ link, avatar, contentLeft, contentRight, footer }) => {
const renderAvatar = avatar ? <AvatarWrapper className="media-left">{avatar}</AvatarWrapper> : null;
const renderFooter = footer ? <small>{footer}</small> : null;
return (
<StyledLink to={link}>
<div className="media">
<IconWrapper className="media-left">{icon}</IconWrapper>
{renderAvatar}
<FlexFullHeight className={classNames("media-content", "text-box", "is-flex")}>
<CenteredItems className="is-flex">
<ContentLeft>{contentLeft}</ContentLeft>
<ContentRight>{contentRight}</ContentRight>
</CenteredItems>
<small>{footer}</small>
{renderFooter}
</FlexFullHeight>
</div>
</StyledLink>

View File

@@ -486,9 +486,6 @@ exports[`Storyshots CardColumn default 1`] = `
A description can be added here.
</p>
</div>
<div
className="CardColumn__ContentRight-sc-1w6lsih-5 kyEPRa"
/>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
@@ -501,7 +498,7 @@ exports[`Storyshots CardColumn default 1`] = `
</small>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 jkwBTE level-right is-block is-mobile is-marginless shorten-text"
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small>
right footer
@@ -513,6 +510,109 @@ exports[`Storyshots CardColumn default 1`] = `
</div>
`;
exports[`Storyshots CardColumn minimal 1`] = `
<div
className="CardColumnstories__Wrapper-sc-1ztucl-0 IFDjP"
>
<article
className="CardColumn__NoEventWrapper-sc-1w6lsih-0 kZKqpc media"
>
<div
className="CardColumn__FlexFullHeight-sc-1w6lsih-2 cAdfGj media-content text-box is-flex"
>
<div
className="is-flex"
>
<div
className="CardColumn__ContentLeft-sc-1w6lsih-4 dumWkw content"
>
<p
className="shorten-text is-marginless"
>
<strong>
title
</strong>
</p>
</div>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
>
<div
className="CardColumn__RightMarginDiv-sc-1w6lsih-6 dbLPPh level-left is-hidden-mobile"
>
<small>
left footer
</small>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small>
right footer
</small>
</div>
</div>
</div>
</article>
</div>
`;
exports[`Storyshots CardColumn with hoverable date 1`] = `
<div
className="CardColumnstories__Wrapper-sc-1ztucl-0 IFDjP"
>
<article
className="CardColumn__NoEventWrapper-sc-1w6lsih-0 kZKqpc media"
>
<div
className="CardColumn__FlexFullHeight-sc-1w6lsih-2 cAdfGj media-content text-box is-flex"
>
<div
className="is-flex"
>
<div
className="CardColumn__ContentLeft-sc-1w6lsih-4 dumWkw content"
>
<p
className="shorten-text is-marginless"
>
<strong>
title
</strong>
</p>
</div>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
>
<div
className="CardColumn__RightMarginDiv-sc-1w6lsih-6 dbLPPh level-left is-hidden-mobile"
>
<small>
left footer
</small>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small
className="level-item"
>
<time
className="DateFromNow__DateElement-sc-16hnz72-0 ehlCzi"
title="2020-03-23 09:26:01"
>
3 days ago
</time>
</small>
</div>
</div>
</div>
</article>
</div>
`;
exports[`Storyshots CardColumnSmall default 1`] = `
<div
className="CardColumnSmallstories__Wrapper-ofr817-0 fwZASP"
@@ -526,7 +626,7 @@ exports[`Storyshots CardColumnSmall default 1`] = `
className="media"
>
<figure
className="CardColumnSmall__IconWrapper-tk9h0o-5 bEHHUw media-left"
className="CardColumnSmall__AvatarWrapper-tk9h0o-5 jvTAoV media-left"
>
<i
className="fas fa-icons fa-2x fa-fw has-text-grey-light"
@@ -555,7 +655,47 @@ exports[`Storyshots CardColumnSmall default 1`] = `
</small>
</div>
</div>
<small />
</div>
</div>
</a>
</div>
`;
exports[`Storyshots CardColumnSmall minimal 1`] = `
<div
className="CardColumnSmallstories__Wrapper-ofr817-0 fwZASP"
>
<a
className="CardColumnSmall__StyledLink-tk9h0o-4 bSCFyE"
href="/foo/bar"
onClick={[Function]}
>
<div
className="media"
>
<div
className="CardColumnSmall__FlexFullHeight-tk9h0o-0 fwRxNw media-content text-box is-flex"
>
<div
className="CardColumnSmall__CenteredItems-tk9h0o-3 eHPOKj is-flex"
>
<div
className="CardColumnSmall__ContentLeft-tk9h0o-1 ihirgF"
>
<strong
className="is-marginless"
>
main content
</strong>
</div>
<div
className="CardColumnSmall__ContentRight-tk9h0o-2 jZRaNn"
>
<small>
more text
</small>
</div>
</div>
</div>
</div>
</a>
@@ -34564,9 +34704,6 @@ exports[`Storyshots RepositoryEntry Avatar EP 1`] = `
The starship Heart of Gold was the first spacecraft to make use of the Infinite Improbability Drive
</p>
</div>
<div
className="CardColumn__ContentRight-sc-1w6lsih-5 kyEPRa"
/>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
@@ -34612,7 +34749,7 @@ exports[`Storyshots RepositoryEntry Avatar EP 1`] = `
</a>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 jkwBTE level-right is-block is-mobile is-marginless shorten-text"
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small
className="level-item"
@@ -34681,9 +34818,6 @@ exports[`Storyshots RepositoryEntry Before Title EP 1`] = `
The starship Heart of Gold was the first spacecraft to make use of the Infinite Improbability Drive
</p>
</div>
<div
className="CardColumn__ContentRight-sc-1w6lsih-5 kyEPRa"
/>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
@@ -34729,7 +34863,7 @@ exports[`Storyshots RepositoryEntry Before Title EP 1`] = `
</a>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 jkwBTE level-right is-block is-mobile is-marginless shorten-text"
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small
className="level-item"
@@ -34795,9 +34929,6 @@ exports[`Storyshots RepositoryEntry Default 1`] = `
The starship Heart of Gold was the first spacecraft to make use of the Infinite Improbability Drive
</p>
</div>
<div
className="CardColumn__ContentRight-sc-1w6lsih-5 kyEPRa"
/>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
@@ -34843,7 +34974,7 @@ exports[`Storyshots RepositoryEntry Default 1`] = `
</a>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 jkwBTE level-right is-block is-mobile is-marginless shorten-text"
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small
className="level-item"
@@ -34909,9 +35040,6 @@ exports[`Storyshots RepositoryEntry Quick Link EP 1`] = `
The starship Heart of Gold was the first spacecraft to make use of the Infinite Improbability Drive
</p>
</div>
<div
className="CardColumn__ContentRight-sc-1w6lsih-5 kyEPRa"
/>
</div>
<div
className="CardColumn__FooterWrapper-sc-1w6lsih-3 jlTqlS level is-flex"
@@ -34964,7 +35092,7 @@ exports[`Storyshots RepositoryEntry Quick Link EP 1`] = `
</a>
</div>
<div
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 jkwBTE level-right is-block is-mobile is-marginless shorten-text"
className="CardColumn__InheritFlexShrinkDiv-sc-1w6lsih-7 MkNLN level-right is-block is-mobile is-marginless shorten-text"
>
<small
className="level-item"