From 6b18b0761b726fd9aef1ebcc21b760378f7d4b5c Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Mon, 16 Jun 2014 17:36:12 -0400 Subject: [PATCH] Merge release 1.6.0 --- src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 372 insertions(+), 0 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java new file mode 100644 index 0000000..4687716 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -0,0 +1,372 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.wicket.behavior.SimpleAttributeModifier; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; + +import com.gitblit.Constants; +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.GitBlitException; +import com.gitblit.Keys; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.FileUtils; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.AccessPolicyPanel; +import com.gitblit.wicket.panels.BooleanChoiceOption; +import com.gitblit.wicket.panels.BooleanOption; +import com.gitblit.wicket.panels.RepositoryNamePanel; + +public class NewRepositoryPage extends RootSubPage { + + private final RepositoryModel repositoryModel; + private IModel<Boolean> addReadmeModel; + private Model<String> gitignoreModel; + private IModel<Boolean> addGitflowModel; + private IModel<Boolean> addGitignoreModel; + private AccessPolicyPanel accessPolicyPanel; + private RepositoryNamePanel namePanel; + + public NewRepositoryPage() { + // create constructor + super(); + repositoryModel = new RepositoryModel(); + + setupPage(getString("gb.newRepository"), ""); + + setStatelessHint(false); + setOutputMarkupId(true); + } + + @Override + protected boolean requiresPageMap() { + return true; + } + + @Override + protected Class<? extends BasePage> getRootNavPageClass() { + return RepositoriesPage.class; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + CompoundPropertyModel<RepositoryModel> rModel = new CompoundPropertyModel<>(repositoryModel); + Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", rModel) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + try { + if (!namePanel.updateModel(repositoryModel)) { + return; + } + accessPolicyPanel.updateModel(repositoryModel); + + repositoryModel.owners = new ArrayList<String>(); + repositoryModel.owners.add(GitBlitWebSession.get().getUsername()); + + // setup branch defaults + boolean useGitFlow = addGitflowModel.getObject(); + + repositoryModel.HEAD = Constants.R_MASTER; + repositoryModel.mergeTo = Constants.MASTER; + if (useGitFlow) { + // tickets normally merge to develop unless they are hotfixes + repositoryModel.mergeTo = Constants.DEVELOP; + } + + repositoryModel.allowForks = app().settings().getBoolean(Keys.web.allowForking, true); + + // optionally generate an initial commit + boolean addReadme = addReadmeModel.getObject(); + String gitignore = null; + boolean addGitignore = addGitignoreModel.getObject(); + if (addGitignore) { + gitignore = gitignoreModel.getObject(); + if (StringUtils.isEmpty(gitignore)) { + throw new GitBlitException(getString("gb.pleaseSelectGitIgnore")); + } + } + + // init the repository + app().gitblit().updateRepositoryModel(repositoryModel.name, repositoryModel, true); + + // optionally create an initial commit + initialCommit(repositoryModel, addReadme, gitignore, useGitFlow); + + } catch (GitBlitException e) { + error(e.getMessage()); + return; + } + setRedirect(true); + setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name)); + } + }; + + // do not let the browser pre-populate these fields + form.add(new SimpleAttributeModifier("autocomplete", "off")); + + namePanel = new RepositoryNamePanel("namePanel", repositoryModel); + form.add(namePanel); + + // prepare the default access controls + AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName( + app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name())); + if (AccessRestrictionType.NONE == defaultRestriction) { + defaultRestriction = AccessRestrictionType.PUSH; + } + AuthorizationControl defaultControl = AuthorizationControl.fromName( + app().settings().getString(Keys.git.defaultAuthorizationControl, AuthorizationControl.NAMED.name())); + + if (AuthorizationControl.AUTHENTICATED == defaultControl) { + defaultRestriction = AccessRestrictionType.PUSH; + } + + repositoryModel.authorizationControl = defaultControl; + repositoryModel.accessRestriction = defaultRestriction; + + accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel); + form.add(accessPolicyPanel); + + // + // initial commit options + // + + // add README + addReadmeModel = Model.of(false); + form.add(new BooleanOption("addReadme", + getString("gb.initWithReadme"), + getString("gb.initWithReadmeDescription"), + addReadmeModel)); + + // add .gitignore + File gitignoreDir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore"); + File [] files = gitignoreDir.listFiles(); + if (files == null) { + files = new File[0]; + } + List<String> gitignores = new ArrayList<String>(); + for (File file : files) { + if (file.isFile() && file.getName().endsWith(".gitignore")) { + gitignores.add(StringUtils.stripFileExtension(file.getName())); + } + } + Collections.sort(gitignores); + + gitignoreModel = Model.of(""); + addGitignoreModel = Model.of(false); + form.add(new BooleanChoiceOption<String>("addGitIgnore", + getString("gb.initWithGitignore"), + getString("gb.initWithGitignoreDescription"), + addGitignoreModel, + gitignoreModel, + gitignores).setVisible(gitignores.size() > 0)); + + // TODO consider gitflow at creation (ticket-55) + addGitflowModel = Model.of(false); + form.add(new BooleanOption("addGitFlow", + "Include a .gitflow file", + "This will generate a config file which guides Git clients in setting up Gitflow branches.", + addGitflowModel).setVisible(false)); + + form.add(new Button("create")); + + add(form); + } + + /** + * Prepare the initial commit for the repository. + * + * @param repository + * @param addReadme + * @param gitignore + * @param addGitFlow + * @return true if an initial commit was created + */ + protected boolean initialCommit(RepositoryModel repository, boolean addReadme, String gitignore, + boolean addGitFlow) { + boolean initialCommit = addReadme || !StringUtils.isEmpty(gitignore) || addGitFlow; + if (!initialCommit) { + return false; + } + + // build an initial commit + boolean success = false; + Repository db = app().repositories().getRepository(repositoryModel.name); + ObjectInserter odi = db.newObjectInserter(); + try { + + UserModel user = GitBlitWebSession.get().getUser(); + PersonIdent author = new PersonIdent(user.getDisplayName(), user.emailAddress); + + DirCache newIndex = DirCache.newInCore(); + DirCacheBuilder indexBuilder = newIndex.builder(); + + if (addReadme) { + // insert a README + String title = StringUtils.stripDotGit(StringUtils.getLastPathElement(repositoryModel.name)); + String description = repositoryModel.description == null ? "" : repositoryModel.description; + String readme = String.format("## %s\n\n%s\n\n", title, description); + byte [] bytes = readme.getBytes(Constants.ENCODING); + + DirCacheEntry entry = new DirCacheEntry("README.md"); + entry.setLength(bytes.length); + entry.setLastModified(System.currentTimeMillis()); + entry.setFileMode(FileMode.REGULAR_FILE); + entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes)); + + indexBuilder.add(entry); + } + + if (!StringUtils.isEmpty(gitignore)) { + // insert a .gitignore file + File dir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore"); + File file = new File(dir, gitignore + ".gitignore"); + if (file.exists() && file.length() > 0) { + byte [] bytes = FileUtils.readContent(file); + if (!ArrayUtils.isEmpty(bytes)) { + DirCacheEntry entry = new DirCacheEntry(".gitignore"); + entry.setLength(bytes.length); + entry.setLastModified(System.currentTimeMillis()); + entry.setFileMode(FileMode.REGULAR_FILE); + entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes)); + + indexBuilder.add(entry); + } + } + } + + if (addGitFlow) { + // insert a .gitflow file + Config config = new Config(); + config.setString("gitflow", null, "masterBranch", Constants.MASTER); + config.setString("gitflow", null, "developBranch", Constants.DEVELOP); + config.setString("gitflow", null, "featureBranchPrefix", "feature/"); + config.setString("gitflow", null, "releaseBranchPrefix", "release/"); + config.setString("gitflow", null, "hotfixBranchPrefix", "hotfix/"); + config.setString("gitflow", null, "supportBranchPrefix", "support/"); + config.setString("gitflow", null, "versionTagPrefix", ""); + + byte [] bytes = config.toText().getBytes(Constants.ENCODING); + + DirCacheEntry entry = new DirCacheEntry(".gitflow"); + entry.setLength(bytes.length); + entry.setLastModified(System.currentTimeMillis()); + entry.setFileMode(FileMode.REGULAR_FILE); + entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes)); + + indexBuilder.add(entry); + } + + indexBuilder.finish(); + + if (newIndex.getEntryCount() == 0) { + // nothing to commit + return false; + } + + ObjectId treeId = newIndex.writeTree(odi); + + // Create a commit object + CommitBuilder commit = new CommitBuilder(); + commit.setAuthor(author); + commit.setCommitter(author); + commit.setEncoding(Constants.ENCODING); + commit.setMessage("Initial commit"); + commit.setTreeId(treeId); + + // Insert the commit into the repository + ObjectId commitId = odi.insert(commit); + odi.flush(); + + // set the branch refs + RevWalk revWalk = new RevWalk(db); + try { + // set the master branch + RevCommit revCommit = revWalk.parseCommit(commitId); + RefUpdate masterRef = db.updateRef(Constants.R_MASTER); + masterRef.setNewObjectId(commitId); + masterRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result masterRC = masterRef.update(); + switch (masterRC) { + case NEW: + success = true; + break; + default: + success = false; + } + + if (addGitFlow) { + // set the develop branch for git-flow + RefUpdate developRef = db.updateRef(Constants.R_DEVELOP); + developRef.setNewObjectId(commitId); + developRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result developRC = developRef.update(); + switch (developRC) { + case NEW: + success = true; + break; + default: + success = false; + } + } + } finally { + revWalk.release(); + } + } catch (UnsupportedEncodingException e) { + logger().error(null, e); + } catch (IOException e) { + logger().error(null, e); + } finally { + odi.release(); + db.close(); + } + return success; + } +} -- Gitblit v1.9.1