Remove refspec and add more fine-grained checkout-after-clone control

Signed-off-by: Lukas Krejci <lkrejci@redhat.com>
7.20.x
Lukas Krejci 2019-04-01 18:09:34 +02:00
parent 5fb17bedfd
commit 1852642c68
7 changed files with 259 additions and 40 deletions

View File

@ -17,10 +17,28 @@ import java.util.Map;
public interface SourceStorage {
/**
* The key with this name in the parameters designates the exact revision the source corresponds
* to. This can be a branch, tag, commit id or anything the particular VCS type understands.
* The key with this name in the parameters designates the branch that should be initially checked
* out from the source location.
*/
String REFSPEC_PARAMETER_NAME = "refspec";
String BRANCH_PARAMETER_NAME = "branch";
/**
* The key with this name in the parameters designates the tag that the initially checked out
* branch should be reset to.
*/
String TAG_PARAMETER_NAME = "tag";
/**
* The key with this name in the parameters designates the commit id that the initially checked
* out branch should be reset to.
*/
String COMMIT_ID_PARAMETER_NAME = "commitId";
/**
* The key with this name in the parameters designates the revision (of any kind) that the
* initially checked out branch should be reset to.
*/
String START_POINT_PARAMETER_NAME = "startPoint";
String getType();

View File

@ -19,8 +19,24 @@ public interface Source {
String getLocation();
/**
* Returns the name of the refspec to check out after the clone. This can be a branch, tag, commit
* id or anything the particular source type understands. It is optional.
* The name of the of the branch to check out after obtaining the source from the location. The
* branch has to already exist in the source otherwise the default branch is used. In case of git,
* this is also the name of the remote branch to push to.
*/
String getRefspec();
String getBranch();
/** The tag or commit id to reset the checked out branch to. */
String getStartPoint();
/**
* The name of the tag to reset the checked out branch to. Note that this is equivalent to
* 'startPoint' and provided for convenience.
*/
String getTag();
/**
* The id of the commit to reset the checked out branch to. Note that this is equivalent to
* 'startPoint' and provided for convenience.
*/
String getCommitId();
}

View File

@ -11,9 +11,12 @@
*/
package org.eclipse.che.api.devfile.server.convert;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.REFSPEC_PARAMETER_NAME;
import static java.lang.String.format;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.BRANCH_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.COMMIT_ID_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.START_POINT_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.TAG_PARAMETER_NAME;
import com.google.common.base.Strings;
import java.net.URI;
import java.net.URISyntaxException;
import org.eclipse.che.api.core.model.workspace.devfile.Project;
@ -39,10 +42,19 @@ public class ProjectConverter {
* @return created devfile project based on the specified workspace project
*/
public ProjectImpl toDevfileProject(ProjectConfigImpl projectConfig) {
String refspec = projectConfig.getSource().getParameters().get(REFSPEC_PARAMETER_NAME);
String branch = projectConfig.getSource().getParameters().get(BRANCH_PARAMETER_NAME);
String startPoint = projectConfig.getSource().getParameters().get(START_POINT_PARAMETER_NAME);
String tag = projectConfig.getSource().getParameters().get(TAG_PARAMETER_NAME);
String commitId = projectConfig.getSource().getParameters().get(COMMIT_ID_PARAMETER_NAME);
SourceImpl source =
new SourceImpl(
projectConfig.getSource().getType(), projectConfig.getSource().getLocation(), refspec);
projectConfig.getSource().getType(),
projectConfig.getSource().getLocation(),
branch,
startPoint,
tag,
commitId);
String path = projectConfig.getPath();
while (path != null && path.startsWith("/")) {
@ -79,16 +91,13 @@ public class ProjectConverter {
return projectConfig;
}
private SourceStorageImpl toSourceStorage(Source source) {
private SourceStorageImpl toSourceStorage(Source source) throws DevfileException {
SourceStorageImpl sourceStorage = new SourceStorageImpl();
sourceStorage.setType(source.getType());
sourceStorage.setLocation(source.getLocation());
String refspec = source.getRefspec();
if (!Strings.isNullOrEmpty(refspec)) {
sourceStorage.getParameters().put(REFSPEC_PARAMETER_NAME, refspec);
}
updateSourceStorage(source, sourceStorage);
return sourceStorage;
}
@ -147,4 +156,35 @@ public class ProjectConverter {
throw new DevfileException("Failed to parse the clonePath.", e);
}
}
private void updateSourceStorage(Source devfileSource, SourceStorageImpl sourceStorage)
throws DevfileException {
String startPoint = devfileSource.getStartPoint();
String tag = devfileSource.getTag();
String commitId = devfileSource.getCommitId();
if ((startPoint != null && tag != null)
|| (startPoint != null && commitId != null)
|| (tag != null && commitId != null)) {
throw new DevfileException(
format(
"Only one of '%s', '%s', '%s' can be specified.",
START_POINT_PARAMETER_NAME, TAG_PARAMETER_NAME, COMMIT_ID_PARAMETER_NAME));
}
if (devfileSource.getBranch() != null) {
sourceStorage.getParameters().put(BRANCH_PARAMETER_NAME, devfileSource.getBranch());
}
// the order of importance is: startPoint > tag > commitId
if (startPoint != null) {
sourceStorage.getParameters().put(START_POINT_PARAMETER_NAME, startPoint);
} else if (tag != null) {
sourceStorage.getParameters().put(TAG_PARAMETER_NAME, tag);
} else if (commitId != null) {
sourceStorage.getParameters().put(COMMIT_ID_PARAMETER_NAME, commitId);
}
}
}

View File

@ -92,10 +92,25 @@
"git@github.com:spring-projects/spring-petclinic.git"
]
},
"refspec": {
"branch": {
"type": "string",
"description": "The name of the refspec to check out after the clone. This can be a branch, tag, commit id or anything the particular source type understands.",
"examples": [ "master", "feature-42", "304df5a" ]
"description": "The name of the of the branch to check out after obtaining the source from the location. The branch has to already exist in the source otherwise the default branch is used. In case of git, this is also the name of the remote branch to push to.",
"examples": [ "master", "feature-42" ]
},
"startPoint": {
"type": "string",
"description": "The tag or commit id to reset the checked out branch to.",
"examples": [ "release/4.2", "349d3ad", "v4.2.0" ]
},
"tag": {
"type": "string",
"description": "The name of the tag to reset the checked out branch to. Note that this is equivalent to 'startPoint' and provided for convenience.",
"examples": [ "v4.2.0" ]
},
"commitId": {
"type": "string",
"description": "The id of the commit to reset the checked out branch to. Note that this is equivalent to 'startPoint' and provided for convenience.",
"examples": [ "349d3ad" ]
}
}
},

View File

@ -11,8 +11,12 @@
*/
package org.eclipse.che.api.devfile.server.convert;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.REFSPEC_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.BRANCH_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.COMMIT_ID_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.START_POINT_PARAMETER_NAME;
import static org.eclipse.che.api.core.model.workspace.config.SourceStorage.TAG_PARAMETER_NAME;
import static org.testng.Assert.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import com.google.common.collect.ImmutableMap;
import org.eclipse.che.api.core.model.workspace.devfile.Project;
@ -23,6 +27,7 @@ import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.ProjectImpl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.SourceImpl;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/** @author Sergii Leshchenko */
@ -40,7 +45,8 @@ public class ProjectConverterTest {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", "master"),
new SourceImpl(
"git", "https://github.com/eclipse/che.git", "master", "3434d", null, null),
null);
ProjectConfigImpl workspaceProject = projectConverter.toWorkspaceProject(devfileProject);
@ -50,7 +56,8 @@ public class ProjectConverterTest {
SourceStorageImpl source = workspaceProject.getSource();
assertEquals(source.getType(), "git");
assertEquals(source.getLocation(), "https://github.com/eclipse/che.git");
assertEquals(source.getParameters().get(REFSPEC_PARAMETER_NAME), "master");
assertEquals(source.getParameters().get(BRANCH_PARAMETER_NAME), "master");
assertEquals(source.getParameters().get(START_POINT_PARAMETER_NAME), "3434d");
}
@Test
@ -61,7 +68,8 @@ public class ProjectConverterTest {
SourceStorageImpl sourceStorage = new SourceStorageImpl();
sourceStorage.setType("git");
sourceStorage.setLocation("https://github.com/eclipse/che.git");
sourceStorage.setParameters(ImmutableMap.of(REFSPEC_PARAMETER_NAME, "master"));
sourceStorage.setParameters(
ImmutableMap.of(TAG_PARAMETER_NAME, "v1.0", BRANCH_PARAMETER_NAME, "develop"));
workspaceProject.setSource(sourceStorage);
Project devfileProject = projectConverter.toDevfileProject(workspaceProject);
@ -70,7 +78,8 @@ public class ProjectConverterTest {
Source source = devfileProject.getSource();
assertEquals(source.getType(), "git");
assertEquals(source.getLocation(), "https://github.com/eclipse/che.git");
assertEquals(source.getRefspec(), "master");
assertEquals(source.getBranch(), "develop");
assertEquals(source.getTag(), "v1.0");
assertEquals(devfileProject.getClonePath(), "clone/path");
}
@ -79,7 +88,7 @@ public class ProjectConverterTest {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", "master"),
new SourceImpl("git", "https://github.com/eclipse/che.git", "master", null, null, null),
"down/the/rabbit/hole/myProject");
ProjectConfigImpl workspaceProject = projectConverter.toWorkspaceProject(devfileProject);
@ -96,7 +105,7 @@ public class ProjectConverterTest {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", "master"),
new SourceImpl("git", "https://github.com/eclipse/che.git", "master", null, null, null),
"cant/hack/../../../usr/bin");
projectConverter.toWorkspaceProject(devfileProject);
@ -107,7 +116,7 @@ public class ProjectConverterTest {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", "master"),
new SourceImpl("git", "https://github.com/eclipse/che.git", "master", null, null, null),
"/usr/bin");
projectConverter.toWorkspaceProject(devfileProject);
@ -118,7 +127,7 @@ public class ProjectConverterTest {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", "master"),
new SourceImpl("git", "https://github.com/eclipse/che.git", "master", null, null, null),
"cant/hack/../../usr/bin");
ProjectConfigImpl workspaceProject = projectConverter.toWorkspaceProject(devfileProject);
@ -131,9 +140,59 @@ public class ProjectConverterTest {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", "master"),
new SourceImpl("git", "https://github.com/eclipse/che.git", "master", null, null, null),
"not/../in/root/../..");
projectConverter.toWorkspaceProject(devfileProject);
}
@Test(
expectedExceptions = DevfileException.class,
expectedExceptionsMessageRegExp =
"Only one of '"
+ START_POINT_PARAMETER_NAME
+ "', '"
+ TAG_PARAMETER_NAME
+ "', '"
+ COMMIT_ID_PARAMETER_NAME
+ "' can be specified\\.",
dataProvider = "invalidStartPointOrTagOrCommitIdCombinations")
public void testOnlyOneOfStartPointAttributesAllowed(
String startPoint, String tag, String commitId) throws Exception {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl(
"git", "https://github.com/eclipse/che.git", null, startPoint, tag, commitId),
null);
projectConverter.toWorkspaceProject(devfileProject);
}
@DataProvider
public static Object[][] invalidStartPointOrTagOrCommitIdCombinations() {
return new Object[][] {
new Object[] {"a", "b", null},
new Object[] {"a", null, "b"},
new Object[] {null, "a", "b"},
new Object[] {"a", "b", "c"}
};
}
@Test
public void testUndefinedCloneParametersNotTransferredToWorkspaceConfig() throws Exception {
ProjectImpl devfileProject =
new ProjectImpl(
"myProject",
new SourceImpl("git", "https://github.com/eclipse/che.git", null, null, null, null),
null);
ProjectConfigImpl wsProject = projectConverter.toWorkspaceProject(devfileProject);
SourceStorageImpl wsSource = wsProject.getSource();
assertFalse(wsSource.getParameters().containsKey(BRANCH_PARAMETER_NAME));
assertFalse(wsSource.getParameters().containsKey(START_POINT_PARAMETER_NAME));
assertFalse(wsSource.getParameters().containsKey(TAG_PARAMETER_NAME));
assertFalse(wsSource.getParameters().containsKey(COMMIT_ID_PARAMETER_NAME));
}
}

View File

@ -11,6 +11,8 @@
*/
package org.eclipse.che.api.workspace.server.model.impl;
import static java.lang.String.format;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@ -23,6 +25,8 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import org.eclipse.che.api.core.model.workspace.config.SourceStorage;
@ -64,6 +68,20 @@ public class SourceStorageImpl implements SourceStorage {
}
}
@PrePersist
@PreUpdate
public void validate() {
if (parameters != null) {
for (Map.Entry<String, String> e : parameters.entrySet()) {
if (e.getValue() == null) {
throw new IllegalStateException(
format(
"Parameter '%s' of the source %s is null. This is illegal.", e.getKey(), this));
}
}
}
}
@Override
public String getType() {
return type;

View File

@ -19,18 +19,31 @@ public class SourceImpl implements Source {
private String type;
private String location;
private String refspec;
private String branch;
private String startPoint;
private String tag;
private String commitId;
public SourceImpl() {}
public SourceImpl(String type, String location, String refspec) {
public SourceImpl(
String type, String location, String branch, String startPoint, String tag, String commitId) {
this.type = type;
this.location = location;
this.refspec = refspec;
this.branch = branch;
this.startPoint = startPoint;
this.tag = tag;
this.commitId = commitId;
}
public SourceImpl(Source source) {
this(source.getType(), source.getLocation(), source.getRefspec());
this(
source.getType(),
source.getLocation(),
source.getBranch(),
source.getStartPoint(),
source.getTag(),
source.getCommitId());
}
@Override
@ -52,12 +65,39 @@ public class SourceImpl implements Source {
}
@Override
public String getRefspec() {
return refspec;
public String getBranch() {
return branch;
}
public void setRefspec(String refspec) {
this.refspec = refspec;
public void setBranch(String branch) {
this.branch = branch;
}
@Override
public String getStartPoint() {
return startPoint;
}
public void setStartPoint(String startPoint) {
this.startPoint = startPoint;
}
@Override
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
@Override
public String getCommitId() {
return commitId;
}
public void setCommitId(String commitId) {
this.commitId = commitId;
}
@Override
@ -71,12 +111,16 @@ public class SourceImpl implements Source {
SourceImpl source = (SourceImpl) o;
return Objects.equals(getType(), source.getType())
&& Objects.equals(getLocation(), source.getLocation())
&& Objects.equals(getRefspec(), source.getRefspec());
&& Objects.equals(getBranch(), source.getBranch())
&& Objects.equals(getStartPoint(), source.getStartPoint())
&& Objects.equals(getTag(), source.getTag())
&& Objects.equals(getCommitId(), source.getCommitId());
}
@Override
public int hashCode() {
return Objects.hash(getType(), getLocation(), getRefspec());
return Objects.hash(
getType(), getLocation(), getBranch(), getStartPoint(), getTag(), getCommitId());
}
@Override
@ -88,8 +132,17 @@ public class SourceImpl implements Source {
+ ", location='"
+ location
+ '\''
+ ", refspec='"
+ refspec
+ ", branch='"
+ branch
+ '\''
+ ", startPoint='"
+ startPoint
+ '\''
+ ", tag='"
+ tag
+ '\''
+ ", commitId='"
+ commitId
+ '\''
+ '}';
}